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;