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

bneradt pushed a commit to branch dev-1-0-12
in repository https://gitbox.apache.org/repos/asf/trafficserver-libswoc.git

commit 024b1608c9e78e84b9a73ebee0401e8152105988
Author: Alan M. Carroll <[email protected]>
AuthorDate: Sun Feb 23 20:08:47 2020 -0600

    Some documentation and example updates.
---
 doc/code/IPSpace.en.rst             | 49 ++++++++++++-------------
 swoc++/CMakeLists.txt               |  2 +-
 swoc++/include/swoc/bwf_std.h       | 10 ++++++
 unit_tests/CMakeLists.txt           |  1 +
 unit_tests/ex_ipspace_properties.cc | 71 +++++++++++++++++++++++++++++++++++--
 unit_tests/test_ip.cc               | 64 +++++++++++++++++++--------------
 6 files changed, 142 insertions(+), 55 deletions(-)

diff --git a/doc/code/IPSpace.en.rst b/doc/code/IPSpace.en.rst
index fa2ef35..e5918cd 100644
--- a/doc/code/IPSpace.en.rst
+++ b/doc/code/IPSpace.en.rst
@@ -1,15 +1,4 @@
-.. Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
-   agreements.  See the NOTICE file distributed with this work for additional 
information regarding
-   copyright ownership.  The ASF licenses this file to you under the Apache 
License, Version 2.0
-   (the "License"); you may not use this file except in compliance with the 
License.  You may obtain
-   a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software 
distributed under the License
-   is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
-   or implied.  See the License for the specific language governing 
permissions and limitations
-   under the License.
+.. SPDX-License-Identifier: Apache-2.0
 
 .. include:: ../common-defs.rst
 
@@ -119,30 +108,38 @@ blend
 Blend
 +++++
 
+Blending is different than marking or filling, as the latter two apply the 
payload passed to the
+method. That is, if an address is marked by either method, it is marked with 
precisely the payload
+passed to the method. :code:`blend` is different because it can cause an 
address to be marked by
+a payload that was not explicitly passed in to any coloring method. Instead of 
replacing an
+existing payload, it enables computing the resulting payload from the existing 
payload and a value
+passed to the method.
+
 The :libswoc:`swoc::IPSpace::blend` method requires a range and a "blender", 
which is a functor
 that blends a :arg:`color` into a :code:`PAYLOAD` instances. The signature is 
::
 
   bool blender(PAYLOAD & payload, U const& color)
 
-The type :code:`U` is that same as the template argument :code:`U` to the 
method, which must be
-compatible with the second argument to the :code:`blend` method. The argument 
passed to
-:code:`blender` is the second argument to :code:`blend`.
+The type :code:`U` is that same as the template argument :code:`U` to the 
:code:`blend` method,
+which must be compatible with the second argument to the :code:`blend` method. 
The argument passed
+to :code:`blender` is the second argument to :code:`blend`.
 
 The method is modeled on C++ `compound assignment operators
 
<https://en.cppreference.com/w/cpp/language/operator_assignment#Builtin_compound_assignment>`__.
 If
-the blend operation is thought of as the "@" operator, then the blend functor 
performs :code:`lhs @=
-rhs`. That is, :arg:`lhs` is modified to be the combination of :arg:`lhs` and 
:arg`rhs`. :arg:`lhs`
-is always the previous payload already in the space, and :arg:`rhs` is the 
:arg:`color` argument
-to the :code:`blend` method. The internal logic handles copying the payload 
instances as needed.
-
-The return value indicates whether the combined result in :arg:`lhs` is a 
valid payload or not. If
-it is the method should return :code:`true`. In general most implementations 
will :code:`return
-true;` in all cases. If the method returns :code:`false` then the address(es) 
for the combined
-payload are removed from the container. This allows payloads to be 
"unblended", for one payload to
-cancel out another, or to do selective erasing of ranges.
+the blend operation is thought of as the "@" operator, then the blend functor 
performs
+:code:`lhs @=rhs`. That is, :arg:`lhs` is modified to be the combination of 
:arg:`lhs` and :arg`rhs`.
+:arg:`lhs` is always the previous payload already in the space, and :arg:`rhs` 
is the :arg:`color`
+argument to the :code:`blend` method. The internal logic handles copying the 
payload instances as
+needed.
+
+The return value of the blender indicates whether the combined result in 
:arg:`lhs` is a valid
+payload or not. If it is the method should return :code:`true`. In general 
most implementations will
+:code:`return true;` in all cases. If the method returns :code:`false` then 
the address(es) for the
+combined payload are removed from the container. This allows payloads to be 
"unblended", for one
+payload to cancel out another, or to do selective erasing of ranges.
 
 As an example, consider the case where the payload is a bitmask. It might be 
reasonable to keep
-empty bitmasks in the container, but it would also be reasonble to decide the 
empty bitmask and any
+empty bitmasks in the container, but it would also be reasonable to decide the 
empty bitmask and any
 address mapped to it should removed entirely from the container. In such a 
case, a blender that
 clears bits in the payloads should return :code:`false` when the result is the 
empty bitmask.
 
diff --git a/swoc++/CMakeLists.txt b/swoc++/CMakeLists.txt
index a5f52fc..067ba2d 100644
--- a/swoc++/CMakeLists.txt
+++ b/swoc++/CMakeLists.txt
@@ -45,7 +45,7 @@ set(CC_FILES
     )
 
 add_library(swoc++ STATIC ${CC_FILES})
-add_compile_options(-Wall -Wextra -Werror -Wno-ignored-qualifiers 
-Wno-unused-parameter -Wno-format-truncation -Wno-cast-function-type 
-Wno-stringop-overflow -Wno-invalid-offsetof)
+add_compile_options(-Wall -Wextra -Werror -Wno-ignored-qualifiers 
-Wno-unused-parameter -Wno-format-truncation -Wno-stringop-overflow 
-Wno-invalid-offsetof)
 
 # Not quite sure how this works, but I think it generates one of two paths 
depending on the context.
 # That is, the generator functions return non-empty strings only in the 
corresponding context.
diff --git a/swoc++/include/swoc/bwf_std.h b/swoc++/include/swoc/bwf_std.h
index d6b092a..2b200f7 100644
--- a/swoc++/include/swoc/bwf_std.h
+++ b/swoc++/include/swoc/bwf_std.h
@@ -25,10 +25,12 @@
 
 #include <atomic>
 #include <chrono>
+#include <bitset>
 #include "swoc/bwf_base.h"
 
 namespace std
 {
+/// Format atomics by stripping the atomic and formatting the underlying type.
 template <typename T>
 swoc::BufferWriter &
 bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, atomic<T> const 
&v) {
@@ -37,4 +39,12 @@ bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, 
atomic<T> const &v)
 
 swoc::BufferWriter &bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const 
&spec, error_code const &ec);
 
+template < size_t N >
+swoc::BufferWriter &bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const& 
spec, bitset<N> const& bits) {
+  for ( unsigned idx = 0 ; idx < N ; ++idx) {
+    w.write(bits[idx] ? '1' : '0');
+  }
+  return w;
+}
+
 } // end namespace std
diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt
index 5bddd95..fd17d9f 100644
--- a/unit_tests/CMakeLists.txt
+++ b/unit_tests/CMakeLists.txt
@@ -28,3 +28,4 @@ add_executable(test_libswoc
 
 target_link_libraries(test_libswoc PUBLIC swoc++)
 set_target_properties(test_libswoc PROPERTIES CLANG_FORMAT_DIRS 
${CMAKE_CURRENT_SOURCE_DIR})
+add_definitions(-DVERBOSE_EXAMPLE_OUTPUT=1)
diff --git a/unit_tests/ex_ipspace_properties.cc 
b/unit_tests/ex_ipspace_properties.cc
index d00cafb..8ee8e9c 100644
--- a/unit_tests/ex_ipspace_properties.cc
+++ b/unit_tests/ex_ipspace_properties.cc
@@ -14,8 +14,7 @@
 #include <swoc/TextView.h>
 #include <swoc/swoc_ip.h>
 #include <swoc/bwf_ip.h>
-#include <swoc/Scalar.h>
-#include <swoc/swoc_file.h>
+#include <swoc/bwf_std.h>
 
 using namespace std::literals;
 using namespace swoc::literals;
@@ -36,6 +35,74 @@ using swoc::MemSpan;
 using swoc::MemArena;
 
 using W = swoc::LocalBufferWriter<256>;
+namespace {
+bool Verbose_p =
+#if VERBOSE_EXAMPLE_OUTPUT
+    true
+#else
+    false
+#endif
+    ;
+}
+
+TEST_CASE("IPSpace bitset blending", "[libswoc][ipspace][bitset][blending]") {
+  // Color each address with a set of bits.
+  using PAYLOAD = std::bitset<32>;
+  // Declare the IPSpace.
+  using Space = swoc::IPSpace<PAYLOAD>;
+
+  // Dump the ranges to stdout.
+  auto dump = [](Space&space) -> void {
+    if (Verbose_p) {
+      std::cout << W().print("{} ranges\n", space.count());
+      for (auto &&[r, payload] : space) {
+        std::cout << W().print("{:12}-{:12} : {}\n", r.min(), r.max(), 
payload);
+      }
+    }
+  };
+
+  // Blend functor which computes a union of the bitsets.
+  auto blender = [](PAYLOAD& lhs, PAYLOAD const& rhs) -> bool {
+    lhs |= rhs;
+    return lhs != 0;
+  };
+
+  // test ranges.
+  std::array<std::tuple<TextView, std::initializer_list<unsigned>>, 9> ranges 
= {
+      {
+          { "100.0.0.0-100.0.0.255", { 0 } }
+          , { "100.0.1.0-100.0.1.255", { 1 } }
+          , { "100.0.2.0-100.0.2.255", { 2 } }
+          , { "100.0.3.0-100.0.3.255", { 3 } }
+          , { "100.0.4.0-100.0.4.255", { 4 } }
+          , { "100.0.5.0-100.0.5.255", { 5 } }
+          , { "100.0.6.0-100.0.6.255", { 6 } }
+          , { "100.0.0.0-100.0.0.255", { 31 } }
+          , { "100.0.1.0-100.0.1.255", { 30 } }
+      }};
+
+  // The IPSpace instance.
+  Space space;
+
+  // For each test range, compute the bitset from the list of bit indices.
+  for (auto &&[text, bit_list] : ranges) {
+    PAYLOAD bits; // zero bitset.
+    for (auto bit : bit_list) {
+      bits[bit] = true;
+    }
+    space.blend(IPRange{text}, bits, blender);
+  }
+
+  dump(space);
+
+  auto resetter = [](PAYLOAD& lhs, PAYLOAD const& rhs) -> bool {
+    auto mask = rhs;
+    lhs &= mask.flip();
+    return lhs != 0;
+  };
+  space.blend(IPRange{"100.0.2.128-100.0.3.127"}, PAYLOAD{"1111"}, resetter);
+  dump(space);
+}
 
 // ---
 
diff --git a/unit_tests/test_ip.cc b/unit_tests/test_ip.cc
index e3b5d74..4cec9f1 100644
--- a/unit_tests/test_ip.cc
+++ b/unit_tests/test_ip.cc
@@ -400,29 +400,17 @@ TEST_CASE("IPSpace bitset", "[libswoc][ipspace][bitset]") 
{
 TEST_CASE("IPSpace docJJ", "[libswoc][ipspace][docJJ]") {
   using PAYLOAD = std::bitset<32>;
   using Space = swoc::IPSpace<PAYLOAD>;
-
-  auto dump = [](Space&space) -> void {
-    swoc::LocalBufferWriter<1024> w;
-    std::cout << "Dumping " << space.count() << " ranges" << std::endl;
-    for (auto &&[r, payload] : space) {
-      w.clear().print("{}-{} :", r.min(), r.max());
-      std::cout << w << payload << std::endl;
-    }
-  };
-  auto reverse_dump = [](Space&space) -> void {
-    swoc::LocalBufferWriter<1024> w;
-    std::cout << "Dumping " << space.count() << " ranges" << std::endl;
-    for (auto spot = space.end(); spot != space.begin();) {
-      auto &&[r, payload]{*--spot};
-      w.clear().print("{} :", r);
-      std::cout << w << payload << std::endl;
-    }
-  };
-
   auto blender = [](PAYLOAD& lhs, PAYLOAD const& rhs) -> bool {
     lhs |= rhs;
     return true;
   };
+  auto make_bits = [](std::initializer_list<unsigned> idx) -> PAYLOAD {
+    PAYLOAD bits;
+    for (auto bit : idx) {
+      bits[bit] = true;
+    }
+    return bits;
+  };
 
   std::array<std::tuple<TextView, std::initializer_list<unsigned>>, 9> ranges 
= {
       {
@@ -437,17 +425,41 @@ TEST_CASE("IPSpace docJJ", "[libswoc][ipspace][docJJ]") {
           , { "100.0.1.0-100.0.1.255", { 30 } }
       }};
 
+  std::array<std::initializer_list<unsigned>, 7> results = {{
+        { 0, 31 }
+      , { 1, 30 }
+      , { 2 }
+      , { 3 }
+      , { 4 }
+      , { 5 }
+      , { 6 }
+  }};
+
   Space space;
 
   for (auto &&[text, bit_list] : ranges) {
-    PAYLOAD bits;
-    for (auto bit : bit_list) {
-      bits[bit] = true;
-    }
-    space.blend(IPRange{text}, bits, blender);
+    space.blend(IPRange{text}, make_bits(bit_list), blender);
+  }
+
+  // Check iteration - verify forward and reverse iteration yield the correct 
number of ranges
+  // and the range payloads match what is expected.
+  REQUIRE(space.count() == results.size());
+  unsigned idx;
+
+  idx = 0;
+  for ( auto const& [ range, bits ] : space) {
+    REQUIRE(idx < results.size());
+    CHECK(bits == make_bits(results[idx]));
+    ++idx;
+  }
+
+  idx = results.size();
+  for ( auto spot = space.end() ; spot != space.begin() ; ) {
+    auto const& [ range, bits ] { *--spot };
+    REQUIRE(idx > 0);
+    --idx;
+    CHECK(bits == make_bits(results[idx]));
   }
-  dump(space);
-  reverse_dump(space);
 }
 
 #if 0

Reply via email to