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

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

commit eb5adefa80147baf145eca78286667badfb3f020
Author: Alan M. Carroll <a...@apache.org>
AuthorDate: Wed Dec 4 15:23:05 2019 -0600

    Change IPSpace::blend to take an arbitrary type for the blending color.
---
 doc/building.en.rst                 | 38 ++++++++++++++++++++++++
 doc/code/IPSpace.en.rst             | 22 +++++++-------
 swoc++/include/swoc/DiscreteRange.h | 58 +++++++++++++++++++++----------------
 swoc++/include/swoc/swoc_ip.h       | 43 +++++++++++++--------------
 unit_tests/test_ip.cc               |  2 +-
 5 files changed, 106 insertions(+), 57 deletions(-)

diff --git a/doc/building.en.rst b/doc/building.en.rst
new file mode 100644
index 0000000..ee0b744
--- /dev/null
+++ b/doc/building.en.rst
@@ -0,0 +1,38 @@
+.. 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.
+
+.. include:: common-defs.rst
+
+.. _building:
+
+Building
+********
+
+The library is usually built using CMake, but is also intended to be buildable 
as a part for
+`SCons <http://scons.org>`__ using the `Parts 
<https://pypi.org/project/scons-parts/>` extensions.
+For this reason the overall codebase is split into the library code and the 
test code. As a library
+only the library code needs to be built, which is the part 
"swoc++/swoc++.part". For example, to
+get the 1.0.8 release as a library in a larger project, the top level 
"Sconstruct" would have ::
+
+   Part("swoc++/swoc++.part"
+     , vcs_type=VcsGit(server="github.com"
+       , repository="SolidWallOfCode/libswoc"
+       , tag="1.0.8"))
+
+The object that depends on this library would then have ::
+
+   DependsOn([
+      # ... other dependencies
+      , Component("swoc++")
+      , # ... more dependencies
+   ])
diff --git a/doc/code/IPSpace.en.rst b/doc/code/IPSpace.en.rst
index 832d799..fa2ef35 100644
--- a/doc/code/IPSpace.en.rst
+++ b/doc/code/IPSpace.en.rst
@@ -120,15 +120,19 @@ Blend
 +++++
 
 The :libswoc:`swoc::IPSpace::blend` method requires a range and a "blender", 
which is a functor
-that combines two :code:`PAYLOAD` instances. The signature is ::
+that blends a :arg:`color` into a :code:`PAYLOAD` instances. The signature is 
::
 
-  bool blender(PAYLOAD & lhs, PAYLOAD const& rhs)
+  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 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:`payload` argument
+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
@@ -138,19 +142,17 @@ payload are removed from the container. This allows 
payloads to be "unblended",
 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 be reasonble to decide the empty 
bitmask and any
+empty bitmasks in the container, but it would also be reasonble 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.
 
 Similarly, if the goal is to remove ranges that have a specific payload, then 
a blender that returns
 :code:`false` if :arg:`lhs` matches that specific payload and :code:`true` if 
not, should be used.
 
-There is a small implementation wrinkle, however. Because the blending logic 
cannot assume the
-result of blending a payload with an equal payload results in the same 
payload, it must do a test to
-determine the result. I.e. if :arg:`lhs == rhs` for the arguments, it cannot 
be assumed that after
-the blend :arg:`lhs` remains unchanged (consider the bitmask unsetting blender 
earlier). The blender
-may want to return something special in this case, which can be detected by 
comparing :code:`&lhs ==
-&rhs`. If true then this is the test case, otherwise it is not.
+There is a small implementation wrinkle, however, in dealing with unmapped 
addresses. The
+:arg:`color` is not necessarily a :code:`PAYLOAD` and therefore must be 
converted in to one. This
+is done by default constructing a :code:`PAYLOAD` instance and then calling 
:code:`blend` on that
+and the :arg:`color`. If this returns :code:`false` then unmapped addresses 
will remain unmapped.
 
 History
 *******
diff --git a/swoc++/include/swoc/DiscreteRange.h 
b/swoc++/include/swoc/DiscreteRange.h
index b8914ff..21d177e 100644
--- a/swoc++/include/swoc/DiscreteRange.h
+++ b/swoc++/include/swoc/DiscreteRange.h
@@ -671,22 +671,24 @@ public:
    */
   self_type &erase(range_type const &range);
 
-  /** Blend a @a payload to a @a range.
+  /** Blend a @a color to a @a range.
    *
-   * @tparam blender Functor to blend payloads.
+   * @tparam F Functor to blend payloads.
+   * @tparam U type to blend in to payloads.
    * @param range Range for blending.
-   * @param payload Payload to blend.
+   * @param color Payload to blend.
    * @return @a this
    *
-   * @a payload is blended to values in @a range. If a value is not present, 
its payload is set
-   * to @a payload. If the value is present, its payload is set to the blend 
of the existing payload
-   * and @a payload using @blender. The existing payload is passed as the 
first argument and @a
-   * payload as the second argument. The functor is expected to update the 
first argument to be the
-   * blended payload. The function must return a @c bool to indicate whether 
the blend resulted in
-   * a valid color. If @c false is returned, the blended region is removed 
from the space.
+   * @a color is blended to values in @a range. If an address in @a range does 
not have a payload,
+   * its payload is set a default constructed @c PAYLOAD blended with @a 
color. If such an address
+   * does have a payload, @a color is blended in to that payload using 
@blender. The existing color
+   * is passed as the first argument and @a color as the second argument. The 
functor is expected to
+   * update the first argument to be the blended color. The function must 
return a @c bool to
+   * indicate whether the blend resulted in a valid color. If @c false is 
returned, the blended
+   * region is removed from the space.
    */
-  template < typename F >
-  self_type &blend(range_type const &range, PAYLOAD const &payload, F && 
blender);
+  template < typename F, typename U = PAYLOAD >
+  self_type &blend(range_type const &range, U const &color, F && blender);
 
   /** Fill @a range with @a payload.
    *
@@ -699,7 +701,12 @@ public:
    */
   self_type &fill(range_type const &range, PAYLOAD const &payload);
 
-  PAYLOAD * find(METRIC const &addr);
+  /** Find the payload at @a metric.
+   *
+   * @param metric The metric for which to search.
+   * @return The payload for @a metric if found, @c nullptr if not found.
+   */
+  PAYLOAD * find(METRIC const &metric);
 
   /// @return The number of distinct ranges.
   size_t count() const;
@@ -812,17 +819,17 @@ DiscreteSpace<METRIC, PAYLOAD>::head() -> Node *{
 
 template <typename METRIC, typename PAYLOAD>
 PAYLOAD *
-DiscreteSpace<METRIC, PAYLOAD>::find(METRIC const &addr) {
+DiscreteSpace<METRIC, PAYLOAD>::find(METRIC const &metric) {
   auto n = _root; // current node to test.
   while (n) {
-    if (addr < n->min()) {
-      if (n->_hull.contains(addr)) {
+    if (metric < n->min()) {
+      if (n->_hull.contains(metric)) {
         n = n->left();
       } else {
         return nullptr;
       }
-    } else if (n->max() < addr) {
-      if (n->_hull.contains(addr)) {
+    } else if (n->max() < metric) {
+      if (n->_hull.contains(metric)) {
         n = n->right();
       } else {
         return nullptr;
@@ -1147,16 +1154,17 @@ DiscreteSpace<METRIC, 
PAYLOAD>::fill(DiscreteSpace::range_type const &range, PAY
 }
 
 template<typename METRIC, typename PAYLOAD>
-template<typename F>
+template<typename F, typename U>
 auto
-DiscreteSpace<METRIC, PAYLOAD>::blend(DiscreteSpace::range_type const&range, 
PAYLOAD const&payload
+DiscreteSpace<METRIC, PAYLOAD>::blend(DiscreteSpace::range_type const&range, U 
const& color
                                       , F &&blender) -> self_type & {
-  // Do a base check for the color to use on unmapped values. If self blending 
on @a payload
+  // Do a base check for the color to use on unmapped values. If self blending 
on @a color
   // is @c false, then do not color currently unmapped values.
-  PAYLOAD plain_color { payload };
-  bool plain_color_p = blender(plain_color, plain_color);
-  // Used to hold a temporary blended node - @c release if put in space, 
otherwise cleaned up.
+  auto plain_color = PAYLOAD();
+  bool plain_color_p = blender(plain_color, color);
+
   auto node_cleaner = [&] (Node * ptr) -> void { _fa.destroy(ptr); };
+  // Used to hold a temporary blended node - @c release if put in space, 
otherwise cleaned up.
   using unique_node = std::unique_ptr<Node, decltype(node_cleaner)>;
 
   // Rightmost node of interest with n->_min <= min.
@@ -1246,7 +1254,7 @@ DiscreteSpace<METRIC, 
PAYLOAD>::blend(DiscreteSpace::range_type const&range, PAY
     // Create a node with the blend for the overlap and then update / replace 
@a n as needed.
     auto max { right_ext_p ? range.max() : n->max() }; // smallest boundary of 
range and @a n.
     unique_node fill { _fa.make(n->min(), max, n->payload()), node_cleaner };
-    bool fill_p = blender(fill->payload(), payload); // fill or clear?
+    bool fill_p = blender(fill->payload(), color); // fill or clear?
     auto next_n = next(n); // cache this in case @a n is removed.
     range_min = fill->max(); // blend will be updated to one past @a fill
     ++range_min;
@@ -1262,7 +1270,7 @@ DiscreteSpace<METRIC, 
PAYLOAD>::blend(DiscreteSpace::range_type const&range, PAY
           return *this;
         }
       } else {
-        // PROBLEM - not collapsing into @a pred(n) when it's adjacent / 
matching payload.
+        // PROBLEM - not collapsing into @a pred(n) when it's adjacent / 
matching color.
         // But @a pred may have been removed above, not reliable at this point.
         pred = prev(n);
         if (pred && pred->payload() == fill->payload()) {
diff --git a/swoc++/include/swoc/swoc_ip.h b/swoc++/include/swoc/swoc_ip.h
index e504e15..f440caa 100644
--- a/swoc++/include/swoc/swoc_ip.h
+++ b/swoc++/include/swoc/swoc_ip.h
@@ -651,35 +651,36 @@ public:
    */
   self_type & fill(IPRange const& range, PAYLOAD const& payload);
 
-  /** Blend @a payload in to the @a range.
+  /** Blend @a color in to the @a range.
    *
    * @tparam F Blending functor type (deduced).
+   * @tparam U Data to blend in to payloads.
    * @param range Target range.
-   * @param payload Payload for @a range.
+   * @param color Data to blend in to existing payloads in @a range.
    * @param blender Blending functor.
    * @return @a this
    *
-   * @a blender is required to have the signature <tt>void(PAYLOAD& lhs , 
PAYLOAD CONST&rhs)</tt>.
-   * It must act as a compound assignment operator, blending @a B into @a A. 
That is, if the
-   * result of blending B in to A is defined as "A @ B" for the binary 
operator "@", then
-   * @a blender computes "A @= B".
+   * @a blender is required to have the signature <tt>void(PAYLOAD& lhs , U 
CONST&rhs)</tt>. It must
+   * act as a compound assignment operator, blending @a rhs into @a lhs. That 
is, if the result of
+   * blending @a rhs in to @a lhs is defined as "lhs @ rhs" for the binary 
operator "@", then @a
+   * blender computes "lhs @= rhs".
    *
-   * Every address in @a range is assigned a payload. If the address does not 
already have a
-   * payload, it is assigned @a payload. If the address has a payload of A it 
is updated by
-   * invoking @a blender on the existing payload and @a payload.
+   * Every address in @a range is assigned a payload. If the address does not 
already have a color,
+   * it is assigned the default constructed @c PAYLOAD blended with @a color. 
If the address has a
+   * color of A it is updated by invoking @a blender on the existing payload 
and @a color.
    */
-  template < typename F >
-  self_type & blend(IPRange const& range, PAYLOAD const& payload, F && 
blender);
+  template < typename F , typename U = PAYLOAD >
+  self_type & blend(IPRange const& range, U const& color, F && blender);
 
-  template < typename F >
-  self_type & blend(IP4Range const& range, PAYLOAD const& payload, F && 
blender) {
-    _ip4.blend(range, payload, blender);
+  template < typename F , typename U = PAYLOAD >
+  self_type & blend(IP4Range const& range, U const& color, F && blender) {
+    _ip4.blend(range, color, blender);
     return *this;
   }
 
-  template < typename F >
-  self_type & blend(IP6Range const& range, PAYLOAD const& payload, F && 
blender) {
-    _ip6.blend(range, payload, blender);
+  template < typename F , typename U = PAYLOAD >
+  self_type & blend(IP6Range const& range, U const& color, F && blender) {
+    _ip6.blend(range, color, blender);
     return *this;
   }
 
@@ -1220,12 +1221,12 @@ template < typename PAYLOAD > auto 
IPSpace<PAYLOAD>::fill(swoc::IPRange const &r
 }
 
 template<typename PAYLOAD>
-template<typename F>
-auto IPSpace<PAYLOAD>::blend(IPRange const&range, PAYLOAD const&payload, 
F&&blender) -> self_type &{
+template<typename F, typename U >
+auto IPSpace<PAYLOAD>::blend(IPRange const&range, U const&color, F&&blender) 
-> self_type & {
   if (range.is(AF_INET)) {
-    _ip4.blend(range, payload, blender);
+    _ip4.blend(range, color, blender);
   } else if (range.is(AF_INET6)) {
-    _ip6.blend(range, payload, blender);
+    _ip6.blend(range, color, blender);
   }
   return *this;
 }
diff --git a/unit_tests/test_ip.cc b/unit_tests/test_ip.cc
index b7a1aee..953c2cf 100644
--- a/unit_tests/test_ip.cc
+++ b/unit_tests/test_ip.cc
@@ -472,7 +472,7 @@ TEST_CASE("IP Space YNETDB", "[libswoc][ipspace][ynetdb]") {
     }
 
     auto BF = [](Payload&lhs, Payload const&rhs) -> bool {
-      if (&lhs != &rhs) {
+      if (! lhs._colo.empty()) {
         std::cout << "Overlap " << lhs._descr << " with " << rhs._descr << 
std::endl;
       }
       return true;

Reply via email to