+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_STRIPED_SET_ADAPTER_H
+#define CDSLIB_INTRUSIVE_STRIPED_SET_ADAPTER_H
+
+#include <cds/opt/options.h>
+#include <cds/intrusive/striped_set/resizing_policy.h>
+#include <cds/opt/hash.h>
+#include <cds/opt/compare.h> // cds::opt::details::make_comparator - for some adapt specializations
+
+namespace cds { namespace intrusive {
+
+ /// StripedSet related definitions
+ namespace striped_set {
+ /// Default adapter for intrusive striped/refinable hash set
+ /**
+ By default, the metafunction does not make any transformation for container type \p Container.
+ \p Container should provide interface suitable for the hash set.
+
+ The \p Options template argument contains option pack
+ that will be passed to \p cds::intrusive::StripedSet.
+
+ <b>Bucket interface</b>
+
+ The result of metafunction is a container (a bucket) that should support the following interface:
+
+ Public typedefs that the bucket should provide:
+ - \p value_type - the type of the item in the bucket
+ - \p iterator - bucket's item iterator
+ - \p const_iterator - bucket's item constant iterator
+ - \p default_resizing_policy - default resizing policy preferable for the container.
+ By default, the library defines cds::container::striped_set::load_factor_resizing<4> for sequential containers like
+ boost::intrusive::list, and cds::container::striped_set::no_resizing for ordered container like boost::intrusive::set.
+
+ <b>Insert value \p val of type \p Q</b>
+ \code template <typename Func> bool insert( value_type& val, Func f ) ; \endcode
+ Inserts \p val into the container and, if inserting is successful, calls functor \p f
+ with \p val.
+
+ The functor signature is:
+ \code
+ struct functor {
+ void operator()( value_type& item );
+ };
+ \endcode
+ where \p item is the item inserted.
+
+ The user-defined functor \p f is called only if the inserting is success.
+ <hr>
+
+ <b>Updates the item in the container</b>
+ \code template <typename Func> std::pair<bool, bool> update( value_type& val, Func f, bool bAllowInsert = true ) \endcode
+ The operation performs inserting or changing data.
+
+ If the \p val key not found in the container, then \p val is inserted iff \p bAllowInsert is \p true.
+ Otherwise, the functor \p f is called with the item found.
+
+ The \p Func functor has the following interface:
+ \code
+ void func( bool bNew, value_type& item, value_type& val );
+ \endcode
+ or like a functor:
+ \code
+ struct functor {
+ void operator()( bool bNew, value_type& item, value_type& val );
+ };
+ \endcode
+
+ where arguments are:
+ - \p bNew - \p true if the item has been inserted, \p false otherwise
+ - \p item - container's item
+ - \p val - argument \p val passed into the \p update() function
+
+ If \p val has been inserted (i.e. <tt>bNew == true</tt>) then \p item and \p val
+ are the same element: <tt>&item == &val</tt>. Otherwise, they are different.
+
+ The functor can change non-key fields of the \p item.
+
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
+ \p second is true if new item has been added or \p false if the item with \p val key
+ already exists.
+ <hr>
+
+ <b>Unlink an item</b>
+ \code bool unlink( value_type& val ) \endcode
+ Unlink \p val from the container if \p val belongs to it.
+ <hr>
+
+ <b>Erase \p key</b>
+ \code template <typename Q, typename Func> bool erase( Q const& key, Func f ) \endcode
+ The function searches an item with key \p key, calls \p f functor
+ and erases the item. If \p key is not found, the functor is not called.
+
+ The functor \p Func interface is:
+ \code
+ struct functor {
+ void operator()(value_type& val);
+ };
+ \endcode
+
+ The type \p Q can differ from \ref value_type of items storing in the container.
+ Therefore, the \p value_type should be comparable with type \p Q.
+
+ Return \p true if key is found and deleted, \p false otherwise
+ <hr>
+
+
+ <b>Find the key \p val </b>
+ \code
+ template <typename Q, typename Func> bool find( Q& val, Func f )
+ template <typename Q, typename Compare, typename Func> bool find( Q& val, Compare cmp, Func f )
+ \endcode
+ The function searches the item with key equal to \p val and calls the functor \p f for item found.
+ The interface of \p Func functor is:
+ \code
+ struct functor {
+ void operator()( value_type& item, Q& val );
+ };
+ \endcode
+ where \p item is the item found, \p val is the <tt>find</tt> function argument.
+
+ The functor can change non-key fields of \p item.
+ The \p val argument may be non-const since it can be used as \p f functor destination i.e., the functor
+ can modify both arguments.
+
+ The type \p Q can differ from \ref value_type of items storing in the container.
+ Therefore, the \p value_type should be comparable with type \p Q.
+
+ The first form uses default \p compare function used for key ordering.
+ The second form allows to point specific \p Compare functor \p cmp
+ that can compare \p value_typwe and \p Q type. The interface of \p Compare is the same as \p std::less.
+
+ The function returns \p true if \p val is found, \p false otherwise.
+ <hr>
+
+ <b>Clears the container</b>
+ \code
+ void clear()
+ template <typename Disposer> void clear( Disposer disposer )
+ \endcode
+ Second form calls \p disposer for each item in the container before clearing.
+ <hr>
+
+ <b>Get size of bucket</b>
+ \code size_t size() const \endcode
+ This function may be required by some resizing policy
+ <hr>
+
+ <b>Iterators</b>
+ \code
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+ \endcode
+ <hr>
+
+ <b>Move item when resizing</b>
+ \code void move_item( adapted_container& from, iterator it ) \endcode
+ This helper function is invented for the set resizing when the item
+ pointed by \p it iterator is copied from old bucket \p from to a new bucket
+ pointed by \p this.
+ <hr>
+
+ */
+ template < typename Container, typename... Options >
+ class adapt
+ {
+ public:
+ typedef Container type ; ///< adapted container type
+ typedef typename type::value_type value_type ; ///< value type stored in the container
+ };
+
+ //@cond
+ struct adapted_sequential_container
+ {
+ typedef striped_set::load_factor_resizing<4> default_resizing_policy;
+ };
+
+ struct adapted_container
+ {
+ typedef striped_set::no_resizing default_resizing_policy;
+ };
+ //@endcond
+
+ //@cond
+ namespace details {
+ template <typename Set>
+ class boost_intrusive_set_adapter: public cds::intrusive::striped_set::adapted_container
+ {
+ public:
+ typedef Set container_type;
+
+ typedef typename container_type::value_type value_type ; ///< value type stored in the container
+ typedef typename container_type::iterator iterator ; ///< container iterator
+ typedef typename container_type::const_iterator const_iterator ; ///< container const iterator
+
+ typedef typename container_type::key_compare key_comparator;
+
+ private:
+ container_type m_Set;
+
+ public:
+ boost_intrusive_set_adapter()
+ {}
+
+ container_type& base_container()
+ {
+ return m_Set;
+ }
+
+ template <typename Func>
+ bool insert( value_type& val, Func f )
+ {
+ std::pair<iterator, bool> res = m_Set.insert( val );
+ if ( res.second )
+ f( val );
+ return res.second;
+ }
+
+ template <typename Func>
+ std::pair<bool, bool> update( value_type& val, Func f, bool bAllowInsert )
+ {
+ if ( bAllowInsert ) {
+ std::pair<iterator, bool> res = m_Set.insert( val );
+ f( res.second, *res.first, val );
+ return std::make_pair( true, res.second );
+ }
+ else {
+ auto it = m_Set.find( val, key_comparator());
+ if ( it == m_Set.end())
+ return std::make_pair( false, false );
+ f( false, *it, val );
+ return std::make_pair( true, false );
+ }
+ }
+
+ bool unlink( value_type& val )
+ {
+ iterator it = m_Set.find( val, key_comparator());
+ if ( it == m_Set.end() || &(*it) != &val )
+ return false;
+ m_Set.erase( it );
+ return true;
+ }
+
+ template <typename Q, typename Func>
+ value_type * erase( Q const& key, Func f )
+ {
+ iterator it = m_Set.find( key, key_comparator());
+ if (it == m_Set.end())
+ return nullptr;
+ value_type& val = *it;
+ f( val );
+ m_Set.erase( it );
+ return &val;
+ }
+
+ template <typename Q, typename Less, typename Func>
+ value_type * erase( Q const& key, Less pred, Func f )
+ {
+ iterator it = m_Set.find( key, pred );
+ if (it == m_Set.end())
+ return nullptr;
+ value_type& val = *it;
+ f( val );
+ m_Set.erase( it );
+ return &val;
+ }
+
+ template <typename Q, typename Func>
+ bool find( Q const& key, Func f )
+ {
+ return find( key, key_comparator(), f );
+ }
+
+ template <typename Q, typename Compare, typename Func>
+ bool find( Q const& key, Compare cmp, Func f )
+ {
+ iterator it = m_Set.find( key, cmp );
+ if ( it == m_Set.end())
+ return false;
+ f( *it, key );
+ return true;
+ }
+
+ void clear()
+ {
+ m_Set.clear();
+ }
+
+ template <typename Disposer>
+ void clear( Disposer disposer )
+ {
+ m_Set.clear_and_dispose( disposer );
+ }
+
+ iterator begin() { return m_Set.begin(); }
+ const_iterator begin() const { return m_Set.begin(); }
+ iterator end() { return m_Set.end(); }
+ const_iterator end() const { return m_Set.end(); }
+
+ size_t size() const
+ {
+ return (size_t) m_Set.size();
+ }
+
+ void move_item( boost_intrusive_set_adapter& from, iterator itWhat )
+ {
+ value_type& val = *itWhat;
+ from.base_container().erase( itWhat );
+ insert( val, []( value_type& ) {} );
+ }
+ };
+ } // namespace details
+ //@endcond
+
+ } // namespace striped_set
+}} // namespace cds::intrusive
+
+#endif // #ifndef CDSLIB_INTRUSIVE_STRIPED_SET_ADAPTER_H