From 5972c64ce8ee47a2bb32b0dbc35c7d687f839d0b Mon Sep 17 00:00:00 2001 From: Vadim Faber Date: Wed, 23 Jan 2019 20:44:53 +0300 Subject: [PATCH 1/3] nogc Ellen Non-blocking Binary Search Trees --- cds/.DS_Store | Bin 0 -> 6148 bytes cds/container/ellen_bintree_map_nogc.h | 220 ++++++ cds/intrusive/ellen_bintree_nogc.h | 642 ++++++++++++++++++ test/.DS_Store | Bin 0 -> 6148 bytes test/stress/.DS_Store | Bin 0 -> 6148 bytes test/stress/map/.DS_Store | Bin 0 -> 6148 bytes .../find_string/map_find_string_ellentree.cpp | 34 +- test/stress/map/map_type_ellen_bintree.h | 69 +- test/unit/.DS_Store | Bin 0 -> 8196 bytes test/unit/tree/CMakeLists.txt | 4 +- .../tree/intrusive_ellen_bintree_nogc.cpp | 38 ++ test/unit/tree/test_intrusive_tree_nogc.h | 139 ++++ 12 files changed, 1132 insertions(+), 14 deletions(-) create mode 100644 cds/.DS_Store create mode 100644 cds/container/ellen_bintree_map_nogc.h create mode 100644 cds/intrusive/ellen_bintree_nogc.h create mode 100644 test/.DS_Store create mode 100644 test/stress/.DS_Store create mode 100644 test/stress/map/.DS_Store create mode 100644 test/unit/.DS_Store create mode 100644 test/unit/tree/intrusive_ellen_bintree_nogc.cpp create mode 100644 test/unit/tree/test_intrusive_tree_nogc.h diff --git a/cds/.DS_Store b/cds/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..afb0c07d142f902d53f538ee859fa48d9fd1e3a1 GIT binary patch literal 6148 zcmeHK%}N6?5T4koyNcL@px$!v)x^o@K0 zU&omwmDbjiAW||g`6fS;Fdrn70RUF*wH$yF09dGm#T9I32+fmD$$}m!A~Ly$2O&fd zK-=ynzgpafDezy}QX{GYP77E41rDe;uEql$n zt+z#1PrbC4RK56G_QF=+Yx_co&X?`^mtl}KN*gC4O1&@&;<4p7S7Fo=Syl9+RwDN~ z_tG}{%7YrE?ZIHLvRmfPfio=gfm3mg%6#8B91bmObH_P8Yd$imUf zA~FmZ27bu^y$>9f(AAhLlurjXvIIb+Z-f-Isg@uguF=()E5sQTrd$z~E7K(gQ|>s< z^*UE$u28uH)5QnVCo^54FnK!e&*gGpu0qoq1`Gp}3=~wiMEU>p=lXxr$@B~ZhJm?a zfE8=?S`|amxpgWy%C#J|iAqB2a)r_b8=a1&L8*8PRSM2=G7w#jxk4O4F&_a*gJ}!{ Hf6Blo#5|g{ literal 0 HcmV?d00001 diff --git a/cds/container/ellen_bintree_map_nogc.h b/cds/container/ellen_bintree_map_nogc.h new file mode 100644 index 000000000..623d3de5f --- /dev/null +++ b/cds/container/ellen_bintree_map_nogc.h @@ -0,0 +1,220 @@ +#ifndef CDS_ELLEN_BINTREE_MAP_NOGC_H +#define CDS_ELLEN_BINTREE_MAP_NOGC_H +#include +#include + +namespace cds { namespace container { + + template < + typename Key, + typename T, +#ifdef CDS_DOXYGEN_INVOKED + class Traits = ellen_bintree::traits +#else + class Traits +#endif + > + class EllenBinTreeMap + : public ellen_bintree::details::make_ellen_bintree_map< gc::nogc, Key, T, Traits >::type + { + typedef ellen_bintree::details::make_ellen_bintree_map< gc::nogc,Key, T, Traits > maker; + typedef typename maker::type base_class; + //@endcond + + public: + typedef cds::gc::nogc gc; ///< Garbage collector + typedef Key key_type; ///< type of a key to be stored in internal nodes; key is a part of \p value_type + typedef T value_type; ///< type of value to be stored in the binary tree + typedef Traits traits; ///< Traits template parameter + +# ifdef CDS_DOXYGEN_INVOKED + typedef implementation_defined key_comparator ; ///< key compare functor based on opt::compare and opt::less option setter. +# else + typedef typename maker::intrusive_traits::compare key_comparator; +# endif + typedef typename base_class::item_counter item_counter; ///< Item counting policy used + typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option + typedef typename traits::key_extractor key_extractor; ///< key extracting functor + typedef typename traits::back_off back_off; ///< Back-off strategy + + typedef typename traits::allocator allocator_type; ///< Allocator for leaf nodes + typedef typename base_class::node_allocator node_allocator; ///< Internal node allocator + typedef typename base_class::update_desc_allocator update_desc_allocator; ///< Update descriptor allocator + + protected: + //@cond + + typedef typename maker::cxx_leaf_node_allocator cxx_leaf_node_allocator; + typedef typename base_class::value_type leaf_node; + typedef typename base_class::internal_node internal_node; + + typedef std::unique_ptr< leaf_node, typename maker::leaf_deallocator > scoped_node_ptr; + + public: + /// Default constructor + EllenBinTreeMap() + : base_class() + {} + + /// Clears the map + ~EllenBinTreeMap() + {} + + /// Inserts new node with key and default value + template + bool insert( K const& key ) + { + return insert_with( key, [](value_type&){} ); + } + + /// Inserts new node + template + bool insert( K const& key, V const& val ) + { + scoped_node_ptr pNode( cxx_leaf_node_allocator().New( key, val )); + if ( base_class::insert( *pNode )) + { + pNode.release(); + return true; + } + return false; + } + + // Inserts new node and initialize it by a functor + template + bool insert_with( K const& key, Func func ) + { + scoped_node_ptr pNode( cxx_leaf_node_allocator().New( key )); + if ( base_class::insert( *pNode, [&func]( leaf_node& item ) { func( item.m_Value ); } )) { + pNode.release(); + return true; + } + return false; + } + + /// For key \p key inserts data of type \p value_type created in-place from \p args + template + bool emplace( K&& key, Args&&... args ) + { + scoped_node_ptr pNode( cxx_leaf_node_allocator().MoveNew( key_type( std::forward(key)), mapped_type( std::forward(args)... ))); + if ( base_class::insert( *pNode )) { + pNode.release(); + return true; + } + return false; + } + + /// Updates the node + template + std::pair update( K const& key, Func func, bool bAllowInsert = true ) + { + scoped_node_ptr pNode( cxx_leaf_node_allocator().New( key )); + std::pair res = base_class::update( *pNode, + [&func](bool bNew, leaf_node& item, leaf_node const& ){ func( bNew, item.m_Value ); }, + bAllowInsert + ); + if ( res.first && res.second ) + pNode.release(); + return res; + } + //@cond + template + CDS_DEPRECATED("ensure() is deprecated, use update()") + std::pair ensure( K const& key, Func func ) + { + return update( key, func, true ); + } + //@endcond + + /// Delete \p key from the map + template + bool find( K const& key, Func f ) + { + return base_class::find( key, [&f](leaf_node& item, K const& ) { f( item.m_Value );}); + } + + /// Finds the key \p val using \p pred predicate for searching + template + bool find_with( K const& key, Less pred, Func f ) + { + CDS_UNUSED( pred ); + return base_class::find_with( key, cds::details::predicate_wrapper< leaf_node, Less, typename maker::key_accessor >(), + [&f](leaf_node& item, K const& ) { f( item.m_Value );}); + } + + /// Clears the map + void clear() + { + base_class::clear(); + } + + /// Checks whether the map contains \p key + template + bool contains( K const& key ) + { + return base_class::contains( key ); + } + //@cond + template + CDS_DEPRECATED("deprecated, use contains()") + bool find( K const& key ) + { + return contains( key ); + } + //@endcond + + /// Checks whether the map contains \p key using \p pred predicate for searching + template + bool contains( K const& key, Less pred ) + { + CDS_UNUSED( pred ); + return base_class::contains( key, cds::details::predicate_wrapper< leaf_node, Less, typename maker::key_accessor >()); + } + //@cond + template + CDS_DEPRECATED("deprecated, use contains()") + bool find_with( K const& key, Less pred ) + { + return contains( key, pred ); + } + //@endcond + + /// Finds \p key and return the item found + template + value_type * get( Q const& key ) const + { + leaf_node * pNode = base_class::get( key ); + return pNode ? &pNode->m_Value : nullptr; + } + + /// Finds \p key with \p pred predicate and return the item found + template + value_type * get_with( Q const& key, Less pred ) const + { + CDS_UNUSED( pred ); + leaf_node * pNode = base_class::get_with( key, + cds::details::predicate_wrapper< leaf_node, Less, typename maker::key_accessor >()); + return pNode ? &pNode->m_Value : nullptr; + } + + /// Checks if the map is empty + bool empty() const + { + return base_class::empty(); + } + + /// Returns item count in the map + size_t size() const + { + return base_class::size(); + } + + + + + }; + } +} + + +#endif //CDS_ELLEN_BINTREE_MAP_NOGC_H diff --git a/cds/intrusive/ellen_bintree_nogc.h b/cds/intrusive/ellen_bintree_nogc.h new file mode 100644 index 000000000..96da9350c --- /dev/null +++ b/cds/intrusive/ellen_bintree_nogc.h @@ -0,0 +1,642 @@ +#ifndef CDSLIB_INTRUSIVE_ELLEN_BINTREE_NOGC_H +#define CDSLIB_INTRUSIVE_ELLEN_BINTREE_NOGC_H +#include +#include +#include +namespace cds +{ +namespace intrusive +{ +template +class EllenBinTree +{ + public: + typedef gc::nogc gc; ///< Garbage collector + typedef Key key_type; ///< type of a key to be stored in internal nodes; key is a part of \p value_type + typedef T value_type; ///< type of value stored in the binary tree + typedef Traits traits; ///< Traits template parameter + + typedef typename traits::hook hook; ///< hook type + typedef typename hook::node_type node_type; ///< node type + typedef typename traits::disposer disposer; ///< leaf node disposer + typedef typename traits::back_off back_off; ///< back-off strategy + protected: + typedef ellen_bintree::base_node tree_node; + typedef node_type leaf_node; + typedef ellen_bintree::node_types node_factory; + typedef typename node_factory::internal_node_type internal_node; + typedef ellen_bintree::update_desc update_desc; + typedef typename update_desc::update_ptr update_ptr; + + public: +#ifdef CDS_DOXYGEN_INVOKED + typedef implementation_defined key_comparator; ///< key compare functor based on \p Traits::compare and \p Traits::less + typedef typename get_node_traits::type node_traits; ///< Node traits +#else + typedef typename opt::details::make_comparator::type key_comparator; + struct node_traits : public get_node_traits::type + { + static internal_node const &to_internal_node(tree_node const &n) + { + assert(n.is_internal()); + return static_cast(n); + } + + static leaf_node const &to_leaf_node(tree_node const &n) + { + assert(n.is_leaf()); + return static_cast(n); + } + }; +#endif + + typedef typename traits::node_allocator node_allocator; + typedef typename traits::item_counter item_counter; + typedef typename traits::memory_model memory_model; + typedef typename traits::stat stat; ///< internal statistics type + typedef typename traits::key_extractor key_extractor; + typedef typename traits::update_desc_allocator update_desc_allocator; + + protected: + typedef ellen_bintree::details::compare node_compare; + + typedef cds::details::Allocator cxx_node_allocator; + typedef cds::details::Allocator cxx_update_desc_allocator; + struct search_result + { + internal_node *pParent; + leaf_node *pLeaf; + bool bRightLeaf; + update_ptr updParent; + + search_result() + : pParent(nullptr), pLeaf(nullptr), bRightLeaf(false) + { + } + }; + + protected: + //@cond + internal_node m_Root; ///< Tree root node (key= Infinite2) + leaf_node m_LeafInf1; ///< Infinite leaf 1 (key= Infinite1) + leaf_node m_LeafInf2; ///< Infinite leaf 2 (key= Infinite2) + + item_counter m_ItemCounter; + mutable stat m_Stat; ///< internal statistics + + protected: + static void free_leaf_node(void *p) + { + disposer()(reinterpret_cast(p)); + } + + static void free_internal_node(void *pNode) + { + cxx_node_allocator().Delete(reinterpret_cast(pNode)); + } + + struct internal_node_deleter + { + void operator()(internal_node *p) const + { + cxx_node_allocator().Delete(p); + } + }; + + typedef std::unique_ptr unique_internal_node_ptr; + + internal_node *alloc_internal_node() const + { + m_Stat.onInternalNodeCreated(); + internal_node *pNode = cxx_node_allocator().New(); + return pNode; + } + update_desc *alloc_update_desc() const + { + m_Stat.onUpdateDescCreated(); + return cxx_update_desc_allocator().New(); + } + + static void free_update_desc(void *pDesc) + { + cxx_update_desc_allocator().Delete(reinterpret_cast(pDesc)); + } + + public: + EllenBinTree() + { + make_empty_tree(); + } + + ~EllenBinTree() + { + clear(); + } + + /// Inserts new node + /** + The function inserts \p val in the tree if it does not contain + an item with key equal to \p val. + + Returns \p true if \p val is placed into the tree, \p false otherwise. + */ + bool insert(value_type &val) + { + return insert(val, [](value_type &) {}); + } + + /// Inserts new node + /** + This function is intended for derived non-intrusive containers. + + The function allows to split creating of new item into two part: + - create item with key only + - insert new item into the tree + - if inserting is success, calls \p f functor to initialize value-field of \p val. + + The functor signature is: + \code + void func( value_type& val ); + \endcode + where \p val is the item inserted. User-defined functor \p f should guarantee that during changing + \p val no any other changes could be made on this tree's item by concurrent threads. + The user-defined functor is called only if the inserting is success. + */ + template + bool insert(value_type &val, Func f) + { + search_result res; + back_off bkoff; + unique_internal_node_ptr pNewInternal; + + while (true) + { + if (search(res, val, node_compare())) + { + m_Stat.onInsertFailed(); + return false; // uniq value + } + + if (res.updParent.bits() == update_desc::Clean) + { + if (!pNewInternal.get()) + { + pNewInternal.reset(alloc_internal_node()); + } + + if (try_insert(val, pNewInternal.get(), res)) + { + f(val); + pNewInternal.release(); + break; + } + } + bkoff(); + m_Stat.onInsertRetry(); + } + ++m_ItemCounter; + m_Stat.onInsertSuccess(); + return true; + } + + /// Updates the node + /** + The operation performs inserting or changing data with lock-free manner. + + If the item \p val is not found in the set, then \p val is inserted into the set + iff \p bAllowInsert is \p true. + Otherwise, the functor \p func is called with item found. + The functor \p func signature is: + \code + void func( bool bNew, value_type& item, value_type& val ); + \endcode + with arguments: + - \p bNew - \p true if the item has been inserted, \p false otherwise + - \p item - item of the set + - \p val - argument \p val passed into the \p %update() function + If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments + refer to the same thing. + + The functor can change non-key fields of the \p item; however, \p func must guarantee + that during changing no any other modifications could be made on this item by concurrent threads. + + Returns std::pair where \p first is \p true if operation is successful, + i.e. the node has been inserted or updated, + \p second is \p true if new item has been added or \p false if the item with \p key + already exists. + + @warning See \ref cds_intrusive_item_creating "insert item troubleshooting" + */ + template + std::pair update(value_type &val, Func func, bool bAllowInsert = true) + { + + unique_internal_node_ptr pNewInternal; + search_result res; + back_off bkoff; + + for (;;) + { + if (search(res, val, node_compare())) + { + func(false, *node_traits::to_value_ptr(res.pLeaf), val); + m_Stat.onUpdateExist(); + return std::make_pair(true, false); + } + + if (res.updParent.bits() == update_desc::Clean) + { + if (!bAllowInsert) + return std::make_pair(false, false); + + if (!pNewInternal.get()) + pNewInternal.reset(alloc_internal_node()); + + if (try_insert(val, pNewInternal.get(), res)) + { + func(true, val, val); + pNewInternal.release(); // internal node has been linked into the tree and should not be deleted + break; + } + } + bkoff(); + m_Stat.onUpdateRetry(); + } + + ++m_ItemCounter; + m_Stat.onUpdateNew(); + return std::make_pair(true, true); + } + + /// Checks whether the set contains \p key + /** + The function searches the item with key equal to \p key + and returns \p true if it is found, and \p false otherwise. + */ + template + bool contains(Q const &key) const + { + search_result res; + if (search(res, key, node_compare())) + { + m_Stat.onFindSuccess(); + return true; + } + m_Stat.onFindFailed(); + return false; + } + + //@cond + template + CDS_DEPRECATED("deprecated, use contains()") + bool find(Q const &key) + { + return contains(key); + } + //@endcond + + /// Checks whether the set contains \p key using \p pred predicate for searching + /** + The function is similar to contains( key ) but \p pred is used for key comparing. + \p Less functor has the interface like \p std::less. + \p Less must imply the same element order as the comparator used for building the set. + */ + template + bool contains(Q const &key, Less pred) const + { + typedef ellen_bintree::details::compare< + key_type, + value_type, + opt::details::make_comparator_from_less, + node_traits> + compare_functor; + + search_result res; + if (search(res, key, compare_functor())) + { + m_Stat.onFindSuccess(); + return true; + } + m_Stat.onFindFailed(); + return false; + } + //@cond + template + CDS_DEPRECATED("deprecated, use contains()") + bool find_with(Q const &key, Less pred) const + { + return contains(key, pred); + } + //@endcond + + /// Finds the key \p key + /** @anchor cds_intrusive_EllenBinTree_find_func + The function searches the item with key equal to \p key 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& key ); + }; + \endcode + where \p item is the item found, \p key is the find function argument. + + The functor can change non-key fields of \p item. Note that the functor is only guarantee + that \p item cannot be disposed during functor is executing. + The functor does not serialize simultaneous access to the tree \p item. If such access is + possible you must provide your own synchronization schema on item level to exclude unsafe item modifications. + + The function returns \p true if \p key is found, \p false otherwise. + */ + template + bool find(Q &key, Func f) const + { + return find_(key, f); + } + //@cond + template + bool find(Q const &key, Func f) const + { + return find_(key, f); + } + //@endcond + /// Finds the key \p key with comparing functor \p pred + /** + The function is an analog of \ref cds_intrusive_EllenBinTree_find_func "find(Q&, Func)" + but \p pred is used for key comparison. + \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less + "Predicate requirements". + \p pred must imply the same element order as the comparator used for building the tree. + */ + //@cond + template + bool find_with(Q const &key, Less pred, Func f) const + { + return find_with_(key, pred, f); + } + //@endcond + + /// Checks if the tree is empty + bool empty() const + { + return m_Root.m_pLeft.load(memory_model::memory_order_relaxed)->is_leaf(); + } + + /// Clears the tree + void clear() + { + while (true) + { + internal_node *pParent = nullptr; + internal_node *pGrandParent = nullptr; + tree_node *pLeaf = const_cast(&m_Root); + + // Get leftmost leaf + while (pLeaf->is_internal()) + { + pGrandParent = pParent; + pParent = static_cast(pLeaf); + pLeaf = pParent->m_pLeft.load(memory_model::memory_order_relaxed); + } + + if (pLeaf->infinite_key()) + { + m_ItemCounter.reset(); + return; + } + + // Remove leftmost leaf and its parent node + assert(pGrandParent); + assert(pParent); + assert(pLeaf->is_leaf()); + + pGrandParent->m_pLeft.store(pParent->m_pRight.load(memory_model::memory_order_relaxed), memory_model::memory_order_relaxed); + free_leaf_node(node_traits::to_value_ptr(static_cast(pLeaf))); + free_internal_node(pParent); + m_ItemCounter--; + } + } + + /// Returns item count in the tree + /** + Only leaf nodes containing user data are counted. + + The value returned depends on item counter type provided by \p Traits template parameter. + If it is \p atomicity::empty_item_counter this function always returns 0. + The function is not suitable for checking the tree emptiness, use \p empty() + member function for this purpose. + */ + size_t size() const + { + return m_ItemCounter; + } + + /// Returns const reference to internal statistics + stat const &statistics() const + { + return m_Stat; + } + + /// Checks internal consistency (not atomic, not thread-safe) + /** + The debugging function to check internal consistency of the tree. + */ + bool check_consistency() const + { + return check_consistency(&m_Root); + } + + protected: + //@cond + + bool check_consistency(internal_node const *pRoot) const + { + tree_node *pLeft = pRoot->m_pLeft.load(atomics::memory_order_relaxed); + tree_node *pRight = pRoot->m_pRight.load(atomics::memory_order_relaxed); + assert(pLeft); + assert(pRight); + + if (node_compare()(*pLeft, *pRoot) < 0 && node_compare()(*pRoot, *pRight) <= 0 && node_compare()(*pLeft, *pRight) < 0) + { + bool bRet = true; + if (pLeft->is_internal()) + bRet = check_consistency(static_cast(pLeft)); + assert(bRet); + + if (bRet && pRight->is_internal()) + bRet = bRet && check_consistency(static_cast(pRight)); + assert(bRet); + + return bRet; + } + return false; + } + + template + bool search(search_result &res, KeyValue const &key, Compare cmp) const + { + internal_node *pParent; + tree_node *pLeaf; + update_ptr updParent; + + bool bRightLeaf; + bool bRightParent = false; + + int nCmp = 0; + + pParent = nullptr; + pLeaf = const_cast(&m_Root); + updParent = nullptr; + bRightLeaf = false; + while (pLeaf->is_internal()) + { + pParent = static_cast(pLeaf); + bRightParent = bRightLeaf; + updParent = pParent->m_pUpdate.load(memory_model::memory_order_acquire); + nCmp = cmp(key, *pParent); + bRightLeaf = nCmp >= 0; + pLeaf = pParent->get_child(nCmp >= 0, memory_model::memory_order_acquire); + }; + assert(pLeaf->is_leaf()); + + leaf_node *keyValue = static_cast(pLeaf); + nCmp = cmp(key, *static_cast(pLeaf)); + + res.pParent = pParent; + res.pLeaf = static_cast(pLeaf); + res.updParent = updParent; + res.bRightLeaf = bRightLeaf; + return nCmp == 0; + } + + void help_insert(update_desc *pOp) + { + tree_node *pLeaf = static_cast(pOp->iInfo.pLeaf); + if (pOp->iInfo.bRightLeaf) + { + pOp->iInfo.pParent->m_pRight.compare_exchange_strong(pLeaf, static_cast(pOp->iInfo.pNew), + memory_model::memory_order_release, atomics::memory_order_relaxed); + } + else + { + pOp->iInfo.pParent->m_pLeft.compare_exchange_strong(pLeaf, static_cast(pOp->iInfo.pNew), + memory_model::memory_order_release, atomics::memory_order_relaxed); + } + + // Unflag parent + update_ptr cur(pOp, update_desc::IFlag); + CDS_VERIFY(pOp->iInfo.pParent->m_pUpdate.compare_exchange_strong(cur, pOp->iInfo.pParent->null_update_desc(), + memory_model::memory_order_release, atomics::memory_order_relaxed)); + } + + bool try_insert(value_type &val, internal_node *pNewInternal, search_result &res) + { + assert(res.updParent.bits() == update_desc::Clean); + assert(res.pLeaf->is_leaf()); + + if (static_cast(res.pParent->get_child(res.bRightLeaf, memory_model::memory_order_relaxed)) == res.pLeaf) + { + leaf_node *pNewLeaf = node_traits::to_node_ptr(val); + + int nCmp = node_compare()(val, *res.pLeaf); + if (nCmp < 0) + { + if (res.pLeaf->infinite_key()) + { + pNewInternal->infinite_key(1); + } + else + { + pNewInternal->infinite_key(0); + key_extractor()(pNewInternal->m_Key, *node_traits::to_value_ptr(res.pLeaf)); + } + pNewInternal->m_pLeft.store(static_cast(pNewLeaf), memory_model::memory_order_relaxed); + pNewInternal->m_pRight.store(static_cast(res.pLeaf), memory_model::memory_order_relaxed); + } + else + { + pNewInternal->infinite_key(0); + key_extractor()(pNewInternal->m_Key, val); + pNewInternal->m_pLeft.store(static_cast(res.pLeaf), memory_model::memory_order_relaxed); + pNewInternal->m_pRight.store(static_cast(pNewLeaf), memory_model::memory_order_relaxed); + } + update_desc *pOp = alloc_update_desc(); + + pOp->iInfo.pParent = res.pParent; + pOp->iInfo.pNew = pNewInternal; + pOp->iInfo.pLeaf = res.pLeaf; + pOp->iInfo.bRightLeaf = res.bRightLeaf; + + update_ptr updCur(res.updParent.ptr()); + + if (res.pParent->m_pUpdate.compare_exchange_strong(updCur, update_ptr(pOp, update_desc::IFlag), + memory_model::memory_order_acq_rel, atomics::memory_order_acquire)) + { + + // do insert + help_insert(pOp); + return true; + } + else + { + free_update_desc(pOp); + } + } + return false; + } + + template + bool find_with(Q &key, Less pred, Func f) const + { + return find_with_(key, pred, f); + } + + template + bool find_with_(Q &val, Less pred, Func f) const + { + typedef ellen_bintree::details::compare< + key_type, + value_type, + opt::details::make_comparator_from_less, + node_traits> + compare_functor; + + search_result res; + if (search(res, val, compare_functor())) + { + assert(res.pLeaf); + f(*node_traits::to_value_ptr(res.pLeaf), val); + m_Stat.onFindSuccess(); + return true; + } + m_Stat.onFindFailed(); + return false; + } + + template + bool find_(Q &val, Func f) const + { + search_result res; + if (search(res, val, node_compare())) + { + f(*node_traits::to_value_ptr(res.pLeaf), val); + m_Stat.onFindSuccess(); + return true; + } + m_Stat.onFindFailed(); + return false; + } + + void make_empty_tree() + { + m_Root.infinite_key(2); + m_LeafInf1.infinite_key(1); + m_LeafInf2.infinite_key(2); + m_Root.m_pLeft.store(&m_LeafInf1, memory_model::memory_order_relaxed); + m_Root.m_pRight.store(&m_LeafInf2, memory_model::memory_order_release); + } +}; +} // namespace intrusive +} // namespace cds +#endif diff --git a/test/.DS_Store b/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ac71503736b3cec2534fd5f40509d6f7a25a85c7 GIT binary patch literal 6148 zcmeHK%}T>S5T3QMri$2upx*Z4t%rna#e)!HJ$Mr;dQfQ-5^NwQB}pwBD|rrmBVWMR zarURBwTcHpirs&a74giUGyIyfMJ;ZW&U@AORn7^8UWLy)Z~K!+0l4C2hI9qE{+l%R zbFzMFJINLA1)lFp`#g@rvF*4Qfj?+hH;>~ebArfECYE1c29XyJ?6@C!Dc|SJ$-3yv z4{BF;@_f&z*QnVrhc%j;hIv?{`{u!LsOww1=Fw^A?%^?i8a}@WS_!^FTs9<*;1!Lj zDDPWI6vojljx!$(`Vc_?*~IHL57E~fJo?7(qaR23De@6R3Kx$7d0X_g#S2|UtQb%X z{J;QvA1EqAOJX6AKONZc5&)5XBeS5Z<*_Q$)-`P;Yzj)Ykq-vgvAnQS{TBv336ve)?R~PP~ zJFbhub=>2+IB<`~W6Rpwbx+RQ{l}-`dHnLK3Fg4Rk`03scmu`M_uvncSSI%{GKro< z5fTH$05L!eED{6e6tLD7sc5Q|7$63I!~pIO0ve)cu+*rw4(RaujQ%Pj3h4NjKokZ& zgQZ6BfN-4(s8hLlVsM=fMHANjK>WDx_zz&~SvSDSvb0Y#a!^;>y()(U8CXebz0q5=Z?%q0K}+()*R eQ~L$#5a$^zHR3EduF?VNBA^JNju`j_20j6O=1=Va literal 0 HcmV?d00001 diff --git a/test/stress/map/.DS_Store b/test/stress/map/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1f668dd340f58c525a5bf8111b66f579d3388bbd GIT binary patch literal 6148 zcmeHK%}T>S5T0$TrWCOULA~w8TMrHX;Xw$s9=r(=J*cz^scoPp(xeuxl{|;OkuTuu zIJ3JgEwwihDKjwp&Cbs3vfqZCEC7gFKd=GH0AQgK=8D+-AT&-oCpqIG6l#tJB#=T6 zLWt&~+3_D4ptCE%y*jY~rq8eK50Xc}8~YgX=|6VEB&}AzL@r-gSzWV=MXR`O-MO83 z;HF;MPikK8M)ks=X4mWW(SX zKG0aO-zT>hb>paw5##J}79%sj3@`)B#elixtkQCAi+95eFay890NoD~mC!MmX;fDS zHuU>Q;{`$zwCOEDC=EIWGmSWcB6KREP8H^fA#^(WrHOM4W*T)m2(>cKV^$XCg(B4I z=$9%SgrkvLW`G%(WgxG+Wvc&Yi{JmVN!()wn1Q8YKosh3y@p#dwRLWDRBI(_6P1MG nGL4fIG*l_ZSSrQas7lZ;$v|`rW*X6h!ao9v25y*vKV{$>_|8=$ literal 0 HcmV?d00001 diff --git a/test/stress/map/find_string/map_find_string_ellentree.cpp b/test/stress/map/find_string/map_find_string_ellentree.cpp index 0792c86cc..43e5371b2 100644 --- a/test/stress/map/find_string/map_find_string_ellentree.cpp +++ b/test/stress/map/find_string/map_find_string_ellentree.cpp @@ -1,7 +1,32 @@ -// Copyright (c) 2006-2018 Maxim Khizhinsky -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +/* + 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. +*/ #include "map_find_string.h" #include "map_type_ellen_bintree.h" @@ -9,5 +34,6 @@ namespace map { CDSSTRESS_EllenBinTreeMap( Map_find_string, run_test, std::string, Map_find_string::value_type ) + CDSSTRESS_EllenBinTreeMapNOGC( Map_find_string, run_test, std::string, Map_find_string::value_type ) } // namespace map diff --git a/test/stress/map/map_type_ellen_bintree.h b/test/stress/map/map_type_ellen_bintree.h index c926fab38..da55f1724 100644 --- a/test/stress/map/map_type_ellen_bintree.h +++ b/test/stress/map/map_type_ellen_bintree.h @@ -1,7 +1,32 @@ -// Copyright (c) 2006-2018 Maxim Khizhinsky -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +/* + 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 CDSUNIT_MAP_TYPE_ELLEN_BINTREE_H #define CDSUNIT_MAP_TYPE_ELLEN_BINTREE_H @@ -11,6 +36,7 @@ #include #include #include +#include #include #include "framework/ellen_bintree_update_desc_pool.h" @@ -24,7 +50,7 @@ namespace map { public: template EllenBinTreeMap( Config const& /*cfg*/) - : base_class() + : base_class() {} std::pair extract_min_key() @@ -84,6 +110,12 @@ namespace map { typedef cc::ellen_bintree::internal_node< Key, leaf_node > internal_node; typedef cc::ellen_bintree::update_desc< leaf_node, internal_node > update_desc; }; + + struct no_gc { + typedef cc::ellen_bintree::map_node leaf_node; + typedef cc::ellen_bintree::internal_node< Key, leaf_node > internal_node; + typedef cc::ellen_bintree::update_desc< leaf_node, internal_node > update_desc; + }; #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED struct shb { typedef cc::ellen_bintree::map_node leaf_node; @@ -97,7 +129,7 @@ namespace map { co::less< less > ,co::node_allocator< ellen_bintree_pool::internal_node_allocator< int > > ,co::item_counter< cds::atomicity::cache_friendly_item_counter > - >::type + >::type {}; struct traits_EllenBinTreeMap_hp : traits_EllenBinTreeMap { typedef cds::memory::pool_allocator< typename ellen_bintree_props::hp_gc::update_desc, ellen_bintree_pool::update_desc_pool_accessor > update_desc_allocator; @@ -124,6 +156,11 @@ namespace map { }; typedef EllenBinTreeMap< rcu_gpt, Key, Value, traits_EllenBinTreeMap_gpt > EllenBinTreeMap_rcu_gpt; + struct traits_EllenBinTreeMap_nogc : traits_EllenBinTreeMap { + typedef cds::memory::pool_allocator< typename ellen_bintree_props::no_gc::update_desc, ellen_bintree_pool::update_desc_pool_accessor > update_desc_allocator; + }; + typedef EllenBinTreeMap EllenBinTreeMap_nogc; + #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED struct traits_EllenBinTreeMap_shb : traits_EllenBinTreeMap { typedef cds::memory::pool_allocator< typename ellen_bintree_props::shb::update_desc, ellen_bintree_pool::update_desc_pool_accessor > update_desc_allocator; @@ -154,12 +191,12 @@ namespace map { struct traits_EllenBinTreeMap_stat: public cc::ellen_bintree::make_set_traits< co::less< less > ,cc::ellen_bintree::update_desc_allocator< - cds::memory::pool_allocator< typename ellen_bintree_props::hp_gc::update_desc, ellen_bintree_pool::update_desc_pool_accessor > + cds::memory::pool_allocator< typename ellen_bintree_props::hp_gc::update_desc, ellen_bintree_pool::update_desc_pool_accessor > > ,co::node_allocator< ellen_bintree_pool::internal_node_allocator< int > > ,co::stat< cc::ellen_bintree::stat<> > ,co::item_counter< cds::atomicity::cache_friendly_item_counter > - >::type + >::type {}; struct traits_EllenBinTreeMap_stat_hp : public traits_EllenBinTreeMap_stat @@ -192,6 +229,13 @@ namespace map { }; typedef EllenBinTreeMap< rcu_gpt, Key, Value, traits_EllenBinTreeMap_stat_gpt > EllenBinTreeMap_rcu_gpt_stat; + struct traits_EllenBinTreeMap_stat_nogc : public traits_EllenBinTreeMap_stat + { + typedef cds::memory::pool_allocator< typename ellen_bintree_props::no_gc::update_desc, ellen_bintree_pool::update_desc_pool_accessor > update_desc_allocator; + }; + typedef EllenBinTreeMap< cds::gc::nogc, Key, Value, traits_EllenBinTreeMap_stat_nogc > EllenBinTreeMap_nogc_stat; + + #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED struct traits_EllenBinTreeMap_stat_shb : public traits_EllenBinTreeMap_stat { @@ -200,7 +244,6 @@ namespace map { typedef EllenBinTreeMap< rcu_shb, Key, Value, traits_EllenBinTreeMap_stat_shb > EllenBinTreeMap_rcu_shb_stat; #endif }; - template static inline void print_stat( cds_test::property_stream& o, EllenBinTreeMap const& s ) { @@ -242,6 +285,7 @@ namespace map { { EXPECT_TRUE( m.check_consistency()); } + } // namespace map @@ -292,8 +336,15 @@ namespace map { CDSSTRESS_EllenBinTreeMap_case( fixture, test_case, EllenBinTreeMap_rcu_gpt_stat, key_type, value_type ) \ CDSSTRESS_EllenBinTreeMap_RCU_1( fixture, test_case, key_type, value_type ) \ +#define CDSSTRESS_EllenBinTreeMap_NOGC( fixture, test_case, key_type, value_type ) \ + CDSSTRESS_EllenBinTreeMap_case( fixture, test_case, EllenBinTreeMap_nogc, key_type, value_type ) \ + + #define CDSSTRESS_EllenBinTreeMap( fixture, test_case, key_type, value_type ) \ CDSSTRESS_EllenBinTreeMap_HP( fixture, test_case, key_type, value_type ) \ CDSSTRESS_EllenBinTreeMap_RCU( fixture, test_case, key_type, value_type ) \ +#define CDSSTRESS_EllenBinTreeMapNOGC( fixture, test_case, key_type, value_type ) \ + CDSSTRESS_EllenBinTreeMap_NOGC( fixture, test_case, key_type, value_type ) \ + #endif // ifndef CDSUNIT_MAP_TYPE_ELLEN_BINTREE_H diff --git a/test/unit/.DS_Store b/test/unit/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d8cf8fa8ec6555718f7ead29f979d98b5530f2c8 GIT binary patch literal 8196 zcmeHMTWl3Y7@qI6&|SN0w+K=yl>-gXlnOnR7D@z8PY;$-kcPIj+&tZLc7=`G-EwwM zFVtc+niwNIdI5bfF-Ap=CL%_C@Ie!W=o17li7&?Z3W>fLAN*%$Pc5x|GMXmrBs1U4 z{Qp0ff4`Dd5P2Z-z(Vi*fYW#3WDCL{dl0x zkQ5lDkq06V%=G}@KBdfOd1f+m=KVc8Y+Ih+*mwi6lF~(s%OqKrWK}xebJ88{@pZr8 zrS$yKpkx_lHq7_Bu05UCvxh8mG@~tTcO75195X*d{aC-{8187wEjWf3w9~EoC&@PG zD5I^Im}qKgYKSLVS|%If6N$z|YeT#_v2}7%l9sPc?C2aE8b3Yp_~e=MVp0e{46I_- zBrnXIq3w;dix-O6Tg4gvFg?S&$`$qQJ)L`2?^QC|k`WsGfnncr9q*8t_Xsmug-6rx z%(+f?-sJL(R+-c7T*20Tv(2`9tkb5~pL6ZPkmGUfT;8?qZr8JTGlvI!bIj*Db3_A2 zJU8#R2ZjR{wJ)@^f@dBysc~z>Oj8%023fjTQB|{M-G;{I?Yq*~w8|y-D9e=P{UerV zWo@%>)H3{&hjlM!I)>$(I6{l#_|~JAnU^bLm2$7651E0LTCJ{>v|4GPkhM+~EPq_I zwMtzrYnP;B26eaJHMpfA^jE2CCFv-yZ_k^QifW}!t(P@j>h)+|qKOBTO|s_6y^qlf z3)9WY7D+SYK3mV4wy4^wv`Si++&>~*D=HsUc1o3KkOy+^&=8H=6V+{MyQF<3J;M9m zr+fZ^Vbl40R2`CZm`mCW!!&A(t6!U}6WQ8iqsYi~#MH3OEX@YkAQ66oonb zBX*g6%)VgXu-Y)3;-(m0tVrN} z#VH8HEyC$7N(2s{*kb4AA#lf@j>^u3OyKV;IBSUH%So3`ypO)vPYHNK68 zGr1SgP4Fq;S&>JA-z%!`TUm3zqV^F3&9T{gqPSPIGR`&W8rNP^tEw6&nJAX8R~6a? zavY@! zud-|GXX5Ce05Ma+QsU+s)L|pGA&C@r;~{jQ8wb&gJ{%%u>c}DoJ7DK9#xa3OoWT=# z7SG{%V(2+y=*z^=SMVy{z?*m*7x4}*;W9qKr}zwC;#=I9#nP@>Ed6dKOGkS0j_o=p zsIJKB+ts7e0`NeI7(*4m|L>mv{eJ> base_item_type; + typedef typename base_class::member_int_item> member_item_type; + + struct generic_traits : public ci::ellen_bintree::traits + { + typedef base_class::key_extractor key_extractor; + typedef mock_disposer disposer; + }; +}; + +TEST_F(IntrusiveEllenBinTreeNogc, base_cmp) +{ + typedef ci::EllenBinTree, ci::opt::hook>>, ci::opt::compare>>::type> + tree_type; + + tree_type t; + test(t); +} + +} // namespace + +#endif + diff --git a/test/unit/tree/test_intrusive_tree_nogc.h b/test/unit/tree/test_intrusive_tree_nogc.h new file mode 100644 index 000000000..c150d8f5d --- /dev/null +++ b/test/unit/tree/test_intrusive_tree_nogc.h @@ -0,0 +1,139 @@ +#ifndef CDSUNIT_TREE_TEST_INTRUSIVE_TREE_NOGC_H +#define CDSUNIT_TREE_TEST_INTRUSIVE_TREE_NOGC_H + +#include "test_intrusive_tree.h" +#include "cds_test/fixture.h" +#include +namespace cds +{ +namespace intrusive +{ +} +} // namespace cds + +namespace cds_test +{ + +namespace ci = cds::intrusive; + +class intrusive_tree_nogc : public intrusive_tree +{ + typedef intrusive_tree base_class; + + protected: + template + void test(Tree &t) + { + ASSERT_TRUE(t.empty()); + ASSERT_CONTAINER_SIZE(t, 0); + size_t const nTreeSize = kSize; + + typedef typename Tree::value_type value_type; + + std::vector data; + std::vector indices; + + data.reserve(kSize); + indices.reserve(kSize); + for (size_t key = 0; key < kSize; ++key) + { + data.push_back(value_type(static_cast(key))); + indices.push_back(key); + } + shuffle(indices.begin(), indices.end()); + // insert/find + for (auto idx : indices) + { + auto &i = data[idx]; + + ASSERT_FALSE(t.contains(i.nKey)); + ASSERT_FALSE(t.contains(i)); + ASSERT_FALSE(t.contains(other_item(i.key()), other_less())); + ASSERT_FALSE(t.find(i.nKey, [](value_type &, int) {})); + ASSERT_FALSE(t.find_with(other_item(i.key()), other_less(), [](value_type &, other_item const &) {})); + + std::pair updResult; + + updResult = t.update(i, [](bool, value_type &, value_type &) { + ASSERT_TRUE(false); + }, + false); + EXPECT_FALSE(updResult.first); + EXPECT_FALSE(updResult.second); + + switch (i.key() % 3) + { + case 0: + ASSERT_TRUE(t.insert(i)); + ASSERT_FALSE(t.insert(i)); + updResult = t.update(i, [](bool bNew, value_type &val, value_type &arg) { + EXPECT_FALSE(bNew); + EXPECT_EQ(&val, &arg); + }, + false); + EXPECT_TRUE(updResult.first); + EXPECT_FALSE(updResult.second); + break; + case 1: + EXPECT_EQ(i.nUpdateNewCount, 0u); + ASSERT_TRUE(t.insert(i, [](value_type &v) { ++v.nUpdateNewCount; })); + EXPECT_EQ(i.nUpdateNewCount, 1u); + ASSERT_FALSE(t.insert(i, [](value_type &v) { ++v.nUpdateNewCount; })); + EXPECT_EQ(i.nUpdateNewCount, 1u); + i.nUpdateNewCount = 0; + break; + case 2: + updResult = t.update(i, [](bool, value_type &, value_type &) { + EXPECT_TRUE(false); + }, + false); + EXPECT_FALSE(updResult.first); + EXPECT_FALSE(updResult.second); + + EXPECT_EQ(i.nUpdateNewCount, 0u); + updResult = t.update(i, [](bool bNew, value_type &val, value_type &arg) { + EXPECT_TRUE(bNew); + EXPECT_EQ(&val, &arg); + ++val.nUpdateNewCount; + }); + EXPECT_TRUE(updResult.first); + EXPECT_TRUE(updResult.second); + EXPECT_EQ(i.nUpdateNewCount, 1u); + i.nUpdateNewCount = 0; + + EXPECT_EQ(i.nUpdateCount, 0u); + updResult = t.update(i, [](bool bNew, value_type &val, value_type &arg) { + EXPECT_FALSE(bNew); + EXPECT_EQ(&val, &arg); + ++val.nUpdateCount; + }, + false); + EXPECT_TRUE(updResult.first); + EXPECT_FALSE(updResult.second); + EXPECT_EQ(i.nUpdateCount, 1u); + i.nUpdateCount = 0; + + break; + } + + ASSERT_TRUE(t.contains(i.nKey)); + ASSERT_TRUE(t.contains(i)); + ASSERT_TRUE(t.contains(other_item(i.key()), other_less())); + EXPECT_EQ(i.nFindCount, 0u); + ASSERT_TRUE(t.find(i.nKey, [](value_type &v, int) { ++v.nFindCount; })); + EXPECT_EQ(i.nFindCount, 1u); + ASSERT_TRUE(t.find_with(other_item(i.key()), other_less(), [](value_type &v, other_item const &) { ++v.nFindCount; })); + EXPECT_EQ(i.nFindCount, 2u); + ASSERT_TRUE(t.find(i, [](value_type &v, value_type &) { ++v.nFindCount; })); + EXPECT_EQ(i.nFindCount, 3u); + } + + ASSERT_FALSE(t.empty()); + ASSERT_CONTAINER_SIZE(t, nTreeSize); + + std::for_each(data.begin(), data.end(), [](value_type &v) { v.clear_stat(); }); + } +}; +} // namespace cds_test + +#endif From 6d8124351e43f0985e1b2f5367302771cfcc7e92 Mon Sep 17 00:00:00 2001 From: Vadim Faber Date: Wed, 23 Jan 2019 20:49:21 +0300 Subject: [PATCH 2/3] .DS_Store banished! --- .gitignore | 1 + cds/.DS_Store | Bin 6148 -> 0 bytes test/.DS_Store | Bin 6148 -> 0 bytes test/stress/.DS_Store | Bin 6148 -> 0 bytes test/stress/map/.DS_Store | Bin 6148 -> 0 bytes test/unit/.DS_Store | Bin 8196 -> 0 bytes 6 files changed, 1 insertion(+) delete mode 100644 cds/.DS_Store delete mode 100644 test/.DS_Store delete mode 100644 test/stress/.DS_Store delete mode 100644 test/stress/map/.DS_Store delete mode 100644 test/unit/.DS_Store diff --git a/.gitignore b/.gitignore index a4086f135..2287e4fc4 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ /.cproject /.settings/ /tools/change_license.pl +.DS_Store diff --git a/cds/.DS_Store b/cds/.DS_Store deleted file mode 100644 index afb0c07d142f902d53f538ee859fa48d9fd1e3a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}N6?5T4koyNcL@px$!v)x^o@K0 zU&omwmDbjiAW||g`6fS;Fdrn70RUF*wH$yF09dGm#T9I32+fmD$$}m!A~Ly$2O&fd zK-=ynzgpafDezy}QX{GYP77E41rDe;uEql$n zt+z#1PrbC4RK56G_QF=+Yx_co&X?`^mtl}KN*gC4O1&@&;<4p7S7Fo=Syl9+RwDN~ z_tG}{%7YrE?ZIHLvRmfPfio=gfm3mg%6#8B91bmObH_P8Yd$imUf zA~FmZ27bu^y$>9f(AAhLlurjXvIIb+Z-f-Isg@uguF=()E5sQTrd$z~E7K(gQ|>s< z^*UE$u28uH)5QnVCo^54FnK!e&*gGpu0qoq1`Gp}3=~wiMEU>p=lXxr$@B~ZhJm?a zfE8=?S`|amxpgWy%C#J|iAqB2a)r_b8=a1&L8*8PRSM2=G7w#jxk4O4F&_a*gJ}!{ Hf6Blo#5|g{ diff --git a/test/.DS_Store b/test/.DS_Store deleted file mode 100644 index ac71503736b3cec2534fd5f40509d6f7a25a85c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5T3QMri$2upx*Z4t%rna#e)!HJ$Mr;dQfQ-5^NwQB}pwBD|rrmBVWMR zarURBwTcHpirs&a74giUGyIyfMJ;ZW&U@AORn7^8UWLy)Z~K!+0l4C2hI9qE{+l%R zbFzMFJINLA1)lFp`#g@rvF*4Qfj?+hH;>~ebArfECYE1c29XyJ?6@C!Dc|SJ$-3yv z4{BF;@_f&z*QnVrhc%j;hIv?{`{u!LsOww1=Fw^A?%^?i8a}@WS_!^FTs9<*;1!Lj zDDPWI6vojljx!$(`Vc_?*~IHL57E~fJo?7(qaR23De@6R3Kx$7d0X_g#S2|UtQb%X z{J;QvA1EqAOJX6AKONZc5&)5XBeS5Z<*_Q$)-`P;Yzj)Ykq-vgvAnQS{TBv336ve)?R~PP~ zJFbhub=>2+IB<`~W6Rpwbx+RQ{l}-`dHnLK3Fg4Rk`03scmu`M_uvncSSI%{GKro< z5fTH$05L!eED{6e6tLD7sc5Q|7$63I!~pIO0ve)cu+*rw4(RaujQ%Pj3h4NjKokZ& zgQZ6BfN-4(s8hLlVsM=fMHANjK>WDx_zz&~SvSDSvb0Y#a!^;>y()(U8CXebz0q5=Z?%q0K}+()*R eQ~L$#5a$^zHR3EduF?VNBA^JNju`j_20j6O=1=Va diff --git a/test/stress/map/.DS_Store b/test/stress/map/.DS_Store deleted file mode 100644 index 1f668dd340f58c525a5bf8111b66f579d3388bbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5T0$TrWCOULA~w8TMrHX;Xw$s9=r(=J*cz^scoPp(xeuxl{|;OkuTuu zIJ3JgEwwihDKjwp&Cbs3vfqZCEC7gFKd=GH0AQgK=8D+-AT&-oCpqIG6l#tJB#=T6 zLWt&~+3_D4ptCE%y*jY~rq8eK50Xc}8~YgX=|6VEB&}AzL@r-gSzWV=MXR`O-MO83 z;HF;MPikK8M)ks=X4mWW(SX zKG0aO-zT>hb>paw5##J}79%sj3@`)B#elixtkQCAi+95eFay890NoD~mC!MmX;fDS zHuU>Q;{`$zwCOEDC=EIWGmSWcB6KREP8H^fA#^(WrHOM4W*T)m2(>cKV^$XCg(B4I z=$9%SgrkvLW`G%(WgxG+Wvc&Yi{JmVN!()wn1Q8YKosh3y@p#dwRLWDRBI(_6P1MG nGL4fIG*l_ZSSrQas7lZ;$v|`rW*X6h!ao9v25y*vKV{$>_|8=$ diff --git a/test/unit/.DS_Store b/test/unit/.DS_Store deleted file mode 100644 index d8cf8fa8ec6555718f7ead29f979d98b5530f2c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMTWl3Y7@qI6&|SN0w+K=yl>-gXlnOnR7D@z8PY;$-kcPIj+&tZLc7=`G-EwwM zFVtc+niwNIdI5bfF-Ap=CL%_C@Ie!W=o17li7&?Z3W>fLAN*%$Pc5x|GMXmrBs1U4 z{Qp0ff4`Dd5P2Z-z(Vi*fYW#3WDCL{dl0x zkQ5lDkq06V%=G}@KBdfOd1f+m=KVc8Y+Ih+*mwi6lF~(s%OqKrWK}xebJ88{@pZr8 zrS$yKpkx_lHq7_Bu05UCvxh8mG@~tTcO75195X*d{aC-{8187wEjWf3w9~EoC&@PG zD5I^Im}qKgYKSLVS|%If6N$z|YeT#_v2}7%l9sPc?C2aE8b3Yp_~e=MVp0e{46I_- zBrnXIq3w;dix-O6Tg4gvFg?S&$`$qQJ)L`2?^QC|k`WsGfnncr9q*8t_Xsmug-6rx z%(+f?-sJL(R+-c7T*20Tv(2`9tkb5~pL6ZPkmGUfT;8?qZr8JTGlvI!bIj*Db3_A2 zJU8#R2ZjR{wJ)@^f@dBysc~z>Oj8%023fjTQB|{M-G;{I?Yq*~w8|y-D9e=P{UerV zWo@%>)H3{&hjlM!I)>$(I6{l#_|~JAnU^bLm2$7651E0LTCJ{>v|4GPkhM+~EPq_I zwMtzrYnP;B26eaJHMpfA^jE2CCFv-yZ_k^QifW}!t(P@j>h)+|qKOBTO|s_6y^qlf z3)9WY7D+SYK3mV4wy4^wv`Si++&>~*D=HsUc1o3KkOy+^&=8H=6V+{MyQF<3J;M9m zr+fZ^Vbl40R2`CZm`mCW!!&A(t6!U}6WQ8iqsYi~#MH3OEX@YkAQ66oonb zBX*g6%)VgXu-Y)3;-(m0tVrN} z#VH8HEyC$7N(2s{*kb4AA#lf@j>^u3OyKV;IBSUH%So3`ypO)vPYHNK68 zGr1SgP4Fq;S&>JA-z%!`TUm3zqV^F3&9T{gqPSPIGR`&W8rNP^tEw6&nJAX8R~6a? zavY@! zud-|GXX5Ce05Ma+QsU+s)L|pGA&C@r;~{jQ8wb&gJ{%%u>c}DoJ7DK9#xa3OoWT=# z7SG{%V(2+y=*z^=SMVy{z?*m*7x4}*;W9qKr}zwC;#=I9#nP@>Ed6dKOGkS0j_o=p zsIJKB+ts7e0`NeI7(*4m|L>mv{eJ Date: Sat, 26 Jan 2019 14:01:33 +0300 Subject: [PATCH 3/3] Typo fix --- test/unit/tree/intrusive_ellen_bintree_nogc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/tree/intrusive_ellen_bintree_nogc.cpp b/test/unit/tree/intrusive_ellen_bintree_nogc.cpp index f5d92ebf9..c3354941a 100644 --- a/test/unit/tree/intrusive_ellen_bintree_nogc.cpp +++ b/test/unit/tree/intrusive_ellen_bintree_nogc.cpp @@ -34,5 +34,4 @@ TEST_F(IntrusiveEllenBinTreeNogc, base_cmp) } // namespace -#endif