You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2018/07/13 22:06:07 UTC

[trafficserver] branch master updated: Doc: Tweak to fix doc issues in IntrusiveDList documentation.

This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 84f429f  Doc: Tweak to fix doc issues in IntrusiveDList documentation.
84f429f is described below

commit 84f429f9a329df496a8c95f7faae8d7eadd2aba7
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Tue Jul 10 16:29:18 2018 -0500

    Doc: Tweak to fix doc issues in IntrusiveDList documentation.
---
 .../internal-libraries/intrusive-list.en.rst       | 65 +++++++++++++++-------
 lib/ts/unit-tests/test_IntrusiveDList.cc           | 27 ++++++++-
 2 files changed, 68 insertions(+), 24 deletions(-)

diff --git a/doc/developer-guide/internal-libraries/intrusive-list.en.rst b/doc/developer-guide/internal-libraries/intrusive-list.en.rst
index c8527f5..7a9c3b6 100644
--- a/doc/developer-guide/internal-libraries/intrusive-list.en.rst
+++ b/doc/developer-guide/internal-libraries/intrusive-list.en.rst
@@ -40,28 +40,27 @@ Definition
 
    .. type:: value_type
 
-      The class for elements in the container, deduced from the return types of the link accessor methods
-      in :class:`L`.
+      The type of elements in the container, deduced from the return types of the link accessor methods
+      in :arg:`L`.
 
-   .. class:: L
-
-      .. function:: static IntrusiveDList::value_type*& next_ptr(IntrusiveDList::value_type* elt)
+   :arg:`L`
+      .. function:: static value_type * & next_ptr(value_type * elt)
 
          Return a reference to the next element pointer embedded in the element :arg:`elt`.
 
-      .. function:: static IntrusiveDList::value_type*& prev_ptr(IntrusiveDList::value_type* elt)
+      .. function:: static value_type * & prev_ptr(value_type * elt)
 
          Return a reference to the previous element pointer embedded in the element :arg:`elt`.
 
-   .. function:: value_type* head()
+   .. function:: value_type * head()
 
       Return a pointer to the head element in the list. This may be :code:`nullptr` if the list is empty.
 
-   .. function:: value_type* tail()
+   .. function:: value_type * tail()
 
       Return a pointer to the tail element in the list. This may be :code:`nullptr` if the list is empty.
 
-   .. function:: IntrusiveDList& clear()
+   .. function:: IntrusiveDList & clear()
 
       Remove all elements from the list. This only removes, no deallocation nor destruction is performed.
 
@@ -69,14 +68,22 @@ Definition
 
       Return the number of elements in the list.
 
-   .. function:: IntrusiveDList& append(value_type * elt)
+   .. function:: IntrusiveDList & append(value_type * elt)
 
       Append :arg:`elt` to the list.
 
-   .. function:: IntrusiveDList& prepend(value_type * elt)
+   .. function:: IntrusiveDList & prepend(value_type * elt)
 
       Prepend :arg:`elt` to the list.
 
+   .. function:: value_type * take_head()
+
+      Remove the head element and return a pointer to it. May be :code:`nullptr` if the list is empty.
+
+   .. function:: value_type * take_tail()
+
+      Remove the tail element and return a pointer to it. May be :code:`nullptr` if the list is empty.
+
 Usage
 *****
 
@@ -95,40 +102,56 @@ In this example the goal is to have a list of :code:`Message` objects. First the
 along with the internal linkage support.
 
 .. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
-   :lines: 37-62
+   :lines: 38-63
 
-The struct :code:`Linkage` is used both to provide the descriptor to :class:`IntrusiveDList` but to
-contain the link pointers as well. This isn't necessary - the links could have been direct members
+The struct :code:`Linkage` is used both to provide the descriptor to :class:`IntrusiveDList` and to
+contain the link pointers. This isn't necessary - the links could have been direct members
 and the implementation of the link accessor methods adjusted. Because the links are intended to be
 used only by a specific container class (:code:`Container`) the struct is made protected.
 
 The implementation of the link accessor methods.
 
 .. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
-   :lines: 64-73
+   :lines: 65-74
 
-An example method to check if the message is in a list.
+A method to check if the message is in a list.
 
 .. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
-   :lines: 75-79
+   :lines: 76-80
 
 The container class for the messages could be implemented as
 
 .. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
-   :lines: 81-96
+   :lines: 82-99
 
 The :code:`debug` method takes a format string (:arg:`fmt`) and an arbitrary set of arguments, formats
 the arguments in to the string, and adds the new message to the list.
 
 .. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
-   :lines: 119-128
+   :lines: 122-131
+
+The :code:`print` method demonstrates the use of the range :code:`for` loop on a list.
+
+.. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
+   :lines: 142-148
+
+The maximum severity level can also be computed even more easily using :code:`std::max_element`.
+This find the element with the maximum severity and returns that severity, or :code:`LVL_DEBUG` if
+no element is found (which happens if the list is empty).
+
+.. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
+   :lines: 134-140
 
 Other methods for the various severity levels would be implemented in a similar fashion. Because the
 intrusive list does not do memory management, the container must clean that up itself, as in the
-:code:`clear` method. The STL iteration support makes this easy.
+:code:`clear` method. A bit of care must be exercised because the links are in the elements, and
+these links are used for iteration therefore using an iterator that references a deleted object is
+risky. One approach, illustrated here, is to use :func:`IntrusiveDList::take_head` to remove the
+element before destroying it. Another option is to allocation the elements in a :class:`MemArena` to
+avoid the need for any explicit cleanup.
 
 .. literalinclude:: ../../../lib/ts/unit-tests/test_IntrusiveDList.cc
-   :lines: 103-111
+   :lines: 106-114
 
 Design Notes
 ************
diff --git a/lib/ts/unit-tests/test_IntrusiveDList.cc b/lib/ts/unit-tests/test_IntrusiveDList.cc
index afbf24f..a9cb775 100644
--- a/lib/ts/unit-tests/test_IntrusiveDList.cc
+++ b/lib/ts/unit-tests/test_IntrusiveDList.cc
@@ -24,6 +24,7 @@
 #include <iostream>
 #include <string_view>
 #include <string>
+#include <algorithm>
 
 #include <ts/IntrusiveDList.h>
 #include <ts/BufferWriter.h>
@@ -36,7 +37,7 @@
 
 class Message
 {
-  using self_type = Message;
+  using self_type = Message; ///< Self reference type.
 
 public:
   // Message severity level.
@@ -90,6 +91,8 @@ public:
 
   size_t count() const;
   self_type &clear();
+  Message::Severity max_severity() const;
+  void print() const;
 
 protected:
   MessageList _msgs;
@@ -103,8 +106,9 @@ Container::~Container()
 auto
 Container::clear() -> self_type &
 {
-  for (auto &&msg : _msgs) {
-    delete &msg;
+  Message *msg;
+  while (nullptr != (msg = _msgs.take_head())) {
+    delete msg;
   }
   _msgs.clear();
   return *this;
@@ -127,6 +131,22 @@ Container::debug(std::string_view fmt, Args &&... args) -> self_type &
   return *this;
 }
 
+Message::Severity
+Container::max_severity() const
+{
+  auto spot = std::max_element(_msgs.begin(), _msgs.end(),
+                               [](Message const &lhs, Message const &rhs) { return lhs._severity < rhs._severity; });
+  return spot == _msgs.end() ? Message::Severity::LVL_DEBUG : spot->_severity;
+}
+
+void
+Container::print() const
+{
+  for (auto &&elt : _msgs) {
+    std::cout << static_cast<unsigned int>(elt._severity) << ": " << elt._text << std::endl;
+  }
+}
+
 TEST_CASE("IntrusiveDList Example", "[libts][IntrusiveDList]")
 {
   Container container;
@@ -136,6 +156,7 @@ TEST_CASE("IntrusiveDList Example", "[libts][IntrusiveDList]")
   // Destructor is checked for non-crashing as container goes out of scope.
 }
 
+// End of documentation example code.
 // --------------------
 
 struct Thing {