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

bneradt pushed a commit to branch doc-lexicon
in repository https://gitbox.apache.org/repos/asf/trafficserver-libswoc.git

commit ce6fe32d7b2011be69fc07553e3f10c086a05417
Author: Alan M. Carroll <a...@apache.org>
AuthorDate: Mon May 25 09:47:56 2020 -0500

    Lexicon: Documentation and examples.
    Doxygen: Fixed problem with inline namespace.
---
 doc/Doxyfile               |  2 +-
 doc/code/Lexicon.en.rst    | 54 ++++++++++++++++++++++++++++++++++++
 doc/code/TextView.en.rst   |  9 ++++--
 doc/namespace-filter.sh    |  3 ++
 tools/update-version.sh    |  2 +-
 unit_tests/ex_Lexicon.cc   | 68 ++++++++++++++++++++++++++++++++++++++++------
 unit_tests/test_Lexicon.cc |  2 +-
 7 files changed, 126 insertions(+), 14 deletions(-)

diff --git a/doc/Doxyfile b/doc/Doxyfile
index 0ad9afb..6e3048d 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -912,7 +912,7 @@ IMAGE_PATH             =
 # need to set EXTENSION_MAPPING for the extension otherwise the files are not
 # properly processed by doxygen.
 
-INPUT_FILTER           =
+INPUT_FILTER           = ./namespace-filter.sh
 
 # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
 # basis. Doxygen will compare the file name with each pattern and apply the
diff --git a/doc/code/Lexicon.en.rst b/doc/code/Lexicon.en.rst
index b960d04..64468b5 100644
--- a/doc/code/Lexicon.en.rst
+++ b/doc/code/Lexicon.en.rst
@@ -106,6 +106,12 @@ The file loading and parsing is then:
    :start-after: doc.load.begin
    :end-before: doc.load.end
 
+with the simulated file contents
+
+.. literalinclude:: ../../unit_tests/ex_Lexicon.cc
+   :start-after: doc.file.begin
+   :end-before: doc.file.end
+
 This uses the Lexicon to convert the strings in the file to the enumeration 
values, which are the
 bitset indices. The defalt is set to ``INVALID`` so that any string that 
doesn't match a string
 in the Lexicon is mapped to ``INVALID``.
@@ -121,6 +127,54 @@ can be accessed like ::
 
    if (flags[NetType::PROD]) { ... }
 
+Constructing
+============
+
+To make the class more flexible it can be constructed in a variety of ways. 
For static the entire
+class can be initialized in the constructor. For dynamic use any subset can be 
initialized. In
+the previous example, the instance was initialized with all of the defined 
values and a default
+for missing names. Because this fully constructs it, it can be marked 
``const`` to prevent
+accidental changes. It could also have been constructed with a default name:
+
+.. literalinclude:: ../../unit_tests/ex_Lexicon.cc
+   :start-after: doc.ctor.1.begin
+   :end-before: doc.ctor.1.end
+
+Note the default name was put before the default value. Because they are 
distinct types, the
+defaults can be added in either order, but must always follow the field 
defintions. The defaults can
+also be omitted entirely, which is common if the Lexicon is used for output 
and not parsing, where
+the enumeration is always valid because all enumeration values are in the 
Lexicon.
+
+.. literalinclude:: ../../unit_tests/ex_Lexicon.cc
+   :start-after: doc.ctor.2.begin
+   :end-before: doc.ctor.2.end
+
+For dynamic use, it is common to have just the defaults, and not any of the 
fields, although of course
+if some "built in" names and values are needed those can be added as in the 
previous examples.
+
+.. literalinclude:: ../../unit_tests/ex_Lexicon.cc
+   :start-after: doc.ctor.3.begin
+   :end-before: doc.ctor.3.end
+
+As before both, either, or none of the defaults are required.
+
+Finally, here is a example of using Lexicon to translate a boolean value, 
allowing for various alternative
+forms for the true and false names.
+
+.. literalinclude:: ../../unit_tests/ex_Lexicon.cc
+   :start-after: doc.ctor.4.begin
+   :end-before: doc.ctor.4.end
+
+The set of value names is easily changed. The ``BoolTag`` type is used to be 
able to indicate when a
+name doesn't match anything in the Lexicon. Each field is a value and then a 
list of names, instead
+of just the pair of a value and name as in the previous examples. If a 
``BoolTag`` was passed in to
+the Lexicon, it would return "true", "false", or throw an exception for 
``BoolTag::INVALID`` because
+that value is missing and there is no default name. The strings returned are 
returned because they
+are the first elements in the list of names. This is fine for any debugging or 
diagnostic messages
+because only the ``true`` and ``false`` values would be stored, ``INVALID`` 
indicates a parsing
+error. The enumeration values were chosen so casting from ``bool`` to 
``BoolTag`` yields the
+appropriate string.
+
 Design Notes
 ************
 
diff --git a/doc/code/TextView.en.rst b/doc/code/TextView.en.rst
index 63cd632..4b9963e 100644
--- a/doc/code/TextView.en.rst
+++ b/doc/code/TextView.en.rst
@@ -240,9 +240,12 @@ similar suffixes with the same meaning as the affix 
methods. This can be done fo
 character, one of a set of characters, or a predicate. The most common use is 
with the predicate
 :code:`isspace` which removes leading and/or trailing whitespace as needed.
 
-Numeric conversions are provided, in signed (:libswoc:`svtoi`) and unsigned 
(:libswoc:`svtou`) flavors.
-These functions are designed to be "complete" in the sense that any other 
string to integer conversion
-can be mapped to one of these functions.
+Numeric conversions are provided, in signed (:libswoc:`svtoi`), unsigned 
(:libswoc:`svtou`), and
+floating point (:libswoc:`svtod`) flavors. The integer functions are designed 
to be "complete" in
+the sense that any other string to integer conversion can be mapped to one of 
these functions. The
+floating point conversion is sufficiently accurate - it will return a floating 
point value that is
+within one epsilon of the exact value, but not always the closest. This is 
fine for general use such
+as in configurations, but possibly not quite enough for high precision work.
 
 The standard functions :code:`strcmp`, :code:`strcasecmp`, and :code:`memcmp` 
are overloaded when
 at least of the parameters is a |TV|. The length is taken from the view, 
rather than being an explicit
diff --git a/doc/namespace-filter.sh b/doc/namespace-filter.sh
new file mode 100755
index 0000000..1a74cdb
--- /dev/null
+++ b/doc/namespace-filter.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+echo "Filtering $1" >2
+cat $1 | sed --expr 's/inline namespace SWOC_VERSION_NS {//' | sed --expr 
's/}} \/\/ namespace swoc/} \/\/ namespace swoc/'
diff --git a/tools/update-version.sh b/tools/update-version.sh
index 5fc3d0e..8402946 100644
--- a/tools/update-version.sh
+++ b/tools/update-version.sh
@@ -6,7 +6,7 @@ if [ -z "$3" ] ; then
 fi
 
 # Header
-sed -i -E code/include/swoc/swoc_version.h --expr "s/SWOC_VERSION_NS 
_[0-9]+_[0-9]+_[0-9]+/SWOC_VERSION_NS _$1_$2_$3/"wqq
+sed -i -E code/include/swoc/swoc_version.h --expr "s/SWOC_VERSION_NS 
_[0-9]+_[0-9]+_[0-9]+/SWOC_VERSION_NS _$1_$2_$3/"
 sed -i code/include/swoc/swoc_version.h --expr "s/\(MAJOR_VERSION *= 
*\).*\$/\\1$1;/"
 sed -i code/include/swoc/swoc_version.h --expr "s/\(MINOR_VERSION *= 
*\).*\$/\\1$2;/"
 sed -i code/include/swoc/swoc_version.h --expr "s/\(POINT_VERSION *= 
*\).*\$/\\1$3;/"
diff --git a/unit_tests/ex_Lexicon.cc b/unit_tests/ex_Lexicon.cc
index 7a53b12..34281a7 100644
--- a/unit_tests/ex_Lexicon.cc
+++ b/unit_tests/ex_Lexicon.cc
@@ -31,7 +31,7 @@ static constexpr size_t N_TYPES = size_t(NetType::INVALID);
 
 // Set up a Lexicon to convert between the enumeration and strings.
 // doc.2.begin
-swoc::Lexicon<NetType> NetTypeNames { {{NetType::EXTERNAL, "external"},
+swoc::Lexicon<NetType> const NetTypeNames { {{NetType::EXTERNAL, "external"},
                                        {NetType::PROD, "prod"},
                                        {NetType::SECURE, "secure"},
                                        {NetType::EDGE, "edge"}},
@@ -45,13 +45,15 @@ using Flags = std::bitset<N_TYPES>;
 TEST_CASE("Lexicon Example", "[libts][Lexicon]") {
   swoc::IPSpace<Flags> space; // Space in which to store the flags.
   // Load the file contents
+  // doc.file.begin
   swoc::TextView text { R"(
     10.0.0.2-10.0.0.254,edge
     10.12.0.0/25,prod
-    10.15.0.10-10.15.0.99,prod,secure
-    172.16.0.0/22,external,secure
-    192.168.17.0/23,external,prod
+    10.15.37.10-10.15.37.99,prod,secure
+    172.19.0.0/22,external,secure
+    192.168.18.0/23,external,prod
   )" };
+  // doc.file.end
   // doc.load.begin
   // Process all the lines in the file.
   while (text) {
@@ -64,7 +66,7 @@ TEST_CASE("Lexicon Example", "[libts][Lexicon]") {
         auto token = line.take_prefix_at(',');
         auto idx   = NetTypeNames[token];
         if (idx != NetType::INVALID) { // one of the valid strings
-          flags.set(idx); // set the bit
+          flags.set(static_cast<int>(idx)); // set the bit
         }
       }
       space.mark(r, flags); // store the flags in the spae.
@@ -73,14 +75,64 @@ TEST_CASE("Lexicon Example", "[libts][Lexicon]") {
   // doc.load.end
 
   using AddrCase = std::tuple<swoc::IPAddr, Flags>;
-  std::array<AddrCase, 5> AddrList = { {"10.0.0.6", 0x8} , {"172.19.20.31", 
0x5}, {"192.168.18.19", 3}
-  , {"10.15.0.57", 0x6}, {"10.12.0.126", 0x2}};
+  using swoc::IPAddr;
+  std::array<AddrCase, 5> AddrList = {{
+    {IPAddr{"10.0.0.6"}, 0x8}
+  , {IPAddr{"172.19.3.31"}, 0x5}
+  , {IPAddr{"192.168.18.19"}, 0x3}
+  , {IPAddr{"10.15.37.57"}, 0x6}
+  , {IPAddr{"10.12.0.126"}, 0x2}
+  }};
 
   for ( auto const& [ addr, bits ] : AddrList ) {
     // doc.lookup.begin
-    auto && [ range, flags ] = space.find(addr);
+    auto && [ range, flags ] = *space.find(addr);
     // doc.lookup.end
     REQUIRE(flags == bits);
   }
   // doc.lookup.end
 }
+namespace {
+
+// doc.ctor.1.begin
+swoc::Lexicon<NetType> const Example1 {
+  {{NetType::EXTERNAL, "external"},
+  {NetType::PROD, "prod"},
+  {NetType::SECURE, "secure"},
+  {NetType::EDGE, "edge"}},
+"*invalid*", // default name for undefined values
+  NetType::INVALID // default value for undefined name
+};
+// doc.ctor.1.end
+
+// doc.ctor.2.begin
+swoc::Lexicon<NetType> const Example2 {
+    {{NetType::EXTERNAL, "external"},
+        {NetType::PROD, "prod"},
+        {NetType::SECURE, "secure"},
+        {NetType::EDGE, "edge"}},
+};
+// doc.ctor.2.end
+
+// doc.ctor.3.begin
+swoc::Lexicon<NetType> Example3 {
+    "*invalid*", // default name for undefined values
+    NetType::INVALID // default value for undefined name
+};
+// doc.ctor.3.end
+
+// doc.ctor.4.begin
+enum BoolTag {
+  INVALID = -1,
+  False = 0,
+  True = 1,
+};
+
+swoc::Lexicon<BoolTag> const BoolNames {
+  {{ BoolTag::True, { "true", "1", "on", "enable", "Y", "yes" }}
+  , { BoolTag::False, { "false", "0", "off", "disable", "N", "no" }}}
+  , BoolTag::INVALID };
+// doc.ctor.4.end
+
+
+} // namespace
diff --git a/unit_tests/test_Lexicon.cc b/unit_tests/test_Lexicon.cc
index e2df5cc..a72bd72 100644
--- a/unit_tests/test_Lexicon.cc
+++ b/unit_tests/test_Lexicon.cc
@@ -26,7 +26,7 @@ namespace
 };
 }
 
-TEST_CASE("Lexicon Example", "[libts][Lexicon]")
+TEST_CASE("Lexicon", "[libts][Lexicon]")
 {
   ExampleNames exnames{{Example::Value_0, {"zero", "0"}},
                        {Example::Value_1, {"one", "1"}},

Reply via email to