aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/jau/cow_darray.hpp101
-rw-r--r--include/jau/cow_iterator.hpp339
-rw-r--r--include/jau/cow_vector.hpp42
-rw-r--r--test/test_cow_darray_01.cpp34
-rw-r--r--test/test_cow_darray_perf01.cpp50
-rw-r--r--test/test_cow_iterator_01.cpp125
-rw-r--r--test/test_hashset_perf01.cpp47
7 files changed, 457 insertions, 281 deletions
diff --git a/include/jau/cow_darray.hpp b/include/jau/cow_darray.hpp
index e9926af..44582da 100644
--- a/include/jau/cow_darray.hpp
+++ b/include/jau/cow_darray.hpp
@@ -93,16 +93,29 @@ namespace jau {
* jau::cow_darray::get_write_mutex(), jau::cow_darray::copy_store() and jau::cow_darray::set_store().<br>
* See example in jau::cow_darray::set_store()
* </p>
- *
+ * <p>
+ * To allow data-race free operations using iterators from a potentially mutated CoW,
+ * only one cow_darray::begin() const_iterator or iterator should be retrieved from this CoW
+ * and all further operations shall use its
+ * jau::cow_ro_iterator::size(), jau::cow_ro_iterator::begin() and jau::cow_ro_iterator::end()
+ * - or its respective variant from jau::cow_rw_iterator.
* </p>
* See also:
* <pre>
* - Sequentially Consistent (SC) ordering or SC-DRF (data race free) <https://en.cppreference.com/w/cpp/atomic/memory_order#Sequentially-consistent_ordering>
* - std::memory_order <https://en.cppreference.com/w/cpp/atomic/memory_order>
* </pre>
+ * @see jau::cow_darray::cbegin()
* @see jau::cow_ro_iterator
+ * @see jau::cow_ro_iterator::size()
+ * @see jau::cow_ro_iterator::begin()
+ * @see jau::cow_ro_iterator::end()
* @see jau::for_each_fidelity
+ * @see jau::cow_darray::begin()
* @see jau::cow_rw_iterator
+ * @see jau::cow_rw_iterator::size()
+ * @see jau::cow_rw_iterator::begin()
+ * @see jau::cow_rw_iterator::end()
*/
template <typename Value_type, typename Alloc_type = callocator<Value_type>, typename Size_type = jau::nsize_t>
class cow_darray
@@ -125,6 +138,8 @@ namespace jau {
typedef darray<value_type, allocator_type, size_type> storage_t;
typedef std::shared_ptr<storage_t> storage_ref_t;
+ typedef cow_darray<value_type, allocator_type, size_type> cow_container_t;
+
/**
* Immutable, read-only const_iterator, lock-free,
* holding the current shared store reference until destruction.
@@ -138,10 +153,13 @@ namespace jau {
* Also see jau::for_each_fidelity to iterate through in this good faith fashion.
* </p>
* @see jau::cow_ro_iterator
+ * @see jau::cow_ro_iterator::size()
+ * @see jau::cow_ro_iterator::begin()
+ * @see jau::cow_ro_iterator::end()
* @see jau::for_each_fidelity
* @see jau::cow_rw_iterator
*/
- typedef cow_ro_iterator<storage_t, storage_ref_t, cow_darray> const_iterator;
+ typedef cow_ro_iterator<storage_t, storage_ref_t, cow_container_t> const_iterator;
/**
* Mutable, read-write iterator, holding the write-lock and a store copy until destruction.
@@ -154,11 +172,13 @@ namespace jau {
* consider using jau::cow_rw_iterator if elements won't get mutated
* or any changes can be discarded.
* </p>
- * @see jau::cow_ro_iterator
- * @see jau::for_each_fidelity
* @see jau::cow_rw_iterator
+ * @see jau::cow_rw_iterator::size()
+ * @see jau::cow_rw_iterator::begin()
+ * @see jau::cow_rw_iterator::end()
+ * @see jau::cow_ro_iterator
*/
- typedef cow_rw_iterator<storage_t, storage_ref_t, cow_darray> iterator;
+ typedef cow_rw_iterator<storage_t, storage_ref_t, cow_container_t> iterator;
// typedef std::reverse_iterator<iterator> reverse_iterator;
// typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
@@ -410,86 +430,49 @@ namespace jau {
// const_iterator, non mutable, read-only
- /**
- * Returns a jau::cow_darray::const_iterator of type jau::cow_ro_iterator.
- * <p>
- * This method variant is only chosen if the container is const.
- * </p>
- * @return jau::cow_darray::const_iterator of type jau::cow_ro_iterator
- * @see jau::cow_ro_iterator
- * @see jau::for_each_fidelity
- */
- constexpr const_iterator begin() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cbegin());
- }
+ // Removed for clarity: "constexpr const_iterator begin() const noexcept"
/**
- * Returns a jau::cow_darray::const_iterator of type jau::cow_ro_iterator.
+ * Returns an jau::cow_ro_iterator to the first element of this CoW storage.
* <p>
* This method is the preferred choice if the use case allows,
* read remarks in jau::cow_ro_iterator.
* </p>
- * @return jau::cow_darray::const_iterator of type jau::cow_ro_iterator
- * @see jau::cow_ro_iterator
- * @see jau::for_each_fidelity
- */
- constexpr const_iterator cbegin() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cbegin());
- }
-
- /**
- * Returns a jau::cow_darray::const_iterator of type jau::cow_ro_iterator.
- * <p>
- * This method variant is only chosen if the container is const.
- * </p>
- * @return jau::cow_darray::const_iterator of type jau::cow_ro_iterator
- * @see jau::cow_ro_iterator
- * @see jau::for_each_fidelity
- */
- constexpr const_iterator end() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cend());
- }
-
- /**
- * Returns a jau::cow_darray::const_iterator of type jau::cow_ro_iterator.
* <p>
- * This method is the preferred choice if the use case allows,
- * read remarks in jau::cow_ro_iterator.
+ * Use jau::cow_ro_iterator::end() on this returned const_iterator
+ * to retrieve the end const_iterator in a data-race free fashion.
* </p>
* @return jau::cow_darray::const_iterator of type jau::cow_ro_iterator
* @see jau::cow_ro_iterator
+ * @see jau::cow_ro_iterator::size()
+ * @see jau::cow_ro_iterator::begin()
+ * @see jau::cow_ro_iterator::end()
* @see jau::for_each_fidelity
*/
- constexpr const_iterator cend() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cend());
+ constexpr const_iterator cbegin() const noexcept {
+ return const_iterator(get_snapshot(), store_ref->cbegin());
}
// iterator, mutable, read-write
/**
- * Returns a jau::cow_darray::iterator of type jau::cow_rw_iterator.
+ * Returns an jau::cow_rw_iterator to the first element of this CoW storage.
* <p>
* Acquiring this mutable iterator has considerable costs attached,
* read remarks in jau::cow_rw_iterator.
* </p>
- * @return jau::cow_darray::iterator of type jau::cow_rw_iterator
- * @see jau::cow_rw_iterator
- */
- constexpr iterator begin() noexcept {
- return iterator(*this, [](storage_ref_t& new_store) -> typename storage_t::iterator { return new_store->begin(); } );
- }
-
- /**
- * Returns a jau::cow_darray::iterator of type jau::cow_rw_iterator.
* <p>
- * Acquiring this mutable iterator has considerable costs attached,
- * read remarks in jau::cow_rw_iterator.
+ * Use jau::cow_rw_iterator::end() on this returned iterator
+ * to retrieve the end iterator in a data-race free fashion.
* </p>
* @return jau::cow_darray::iterator of type jau::cow_rw_iterator
* @see jau::cow_rw_iterator
+ * @see jau::cow_rw_iterator::size()
+ * @see jau::cow_rw_iterator::begin()
+ * @see jau::cow_rw_iterator::end()
*/
- constexpr iterator end() noexcept {
- return iterator(*this, [](storage_ref_t& new_store) -> typename storage_t::iterator { return new_store->end(); } );
+ constexpr iterator begin() noexcept {
+ return iterator(*this, [](storage_ref_t& new_store) -> typename storage_t::iterator { return new_store->begin(); } );
}
// read access
diff --git a/include/jau/cow_iterator.hpp b/include/jau/cow_iterator.hpp
index 23e5a64..bc5e9a8 100644
--- a/include/jau/cow_iterator.hpp
+++ b/include/jau/cow_iterator.hpp
@@ -44,13 +44,11 @@ namespace jau {
template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
class cow_rw_iterator;
+ /****************************************************************************************
+ ****************************************************************************************/
+
/**
* iterator_type -> std::string conversion
- * <p>
- * TODO: Test whether 'base()' method actually exists,
- * however - this is good enough for stl iterator_type
- * having implemented the inner native iterator (a pointer).
- * </p>
* @tparam iterator_type the iterator type
* @param iter the iterator
* @param if iterator_type is a class
@@ -59,9 +57,9 @@ namespace jau {
template< class iterator_type >
std::string to_string(const iterator_type & iter,
typename std::enable_if<
- std::is_class<iterator_type>::value
- >::type* = 0
- ) {
+ !std::is_pointer<iterator_type>::value
+ >::type* = 0 )
+ {
return aptrHexString( (void*) ( iter.base() ) );
}
@@ -75,16 +73,21 @@ namespace jau {
template< class iterator_type >
std::string to_string(const iterator_type & iter,
typename std::enable_if<
- !std::is_class<iterator_type>::value
- >::type* = 0
- ) {
+ std::is_pointer<iterator_type>::value
+ >::type* = 0 )
+ {
return aptrHexString((void*)iter);
}
+ /****************************************************************************************
+ ****************************************************************************************/
+
/**
* Implementation of a Copy-On-Write (CoW) read-write iterator for mutable value_type.<br>
- * Instance holds the 'shared value_type reference', Storage_ref_type,
- * of the current CoW storage until destruction.
+ * Instance holds a copy of the CoW's value_type storage until destruction.
+ * <p>
+ * Implementation complies with Type Traits iterator_category 'random_access_iterator_tag'
+ * </p>
* <p>
* This iterator wraps the native iterator of type 'iterator_type'
* and manages the CoW related resource lifecycle.
@@ -98,35 +101,57 @@ namespace jau {
* consider using jau::cow_rw_iterator if elements won't get mutated
* or any changes can be discarded.
* </p>
+ * <p>
+ * To allow data-race free operations on this iterator's data copy from a potentially mutated CoW,
+ * only one begin iterator should be retrieved from CoW and all further operations shall use
+ * jau::cow_rw_iterator::size(), jau::cow_rw_iterator::begin() and jau::cow_rw_iterator::end().
+ * </p>
+ * @see jau::cow_rw_iterator::size()
+ * @see jau::cow_rw_iterator::begin()
+ * @see jau::cow_rw_iterator::end()
+ * @see jau::for_each_fidelity
* @see jau::cow_darray
*/
template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
class cow_rw_iterator {
friend cow_ro_iterator<Storage_type, Storage_ref_type, CoW_container>;
+ template<typename, typename, typename> friend class cow_darray;
+ template<typename, typename> friend class cow_vector;
public:
+ typedef Storage_type storage_t;
+ typedef Storage_ref_type storage_ref_t;
+ typedef CoW_container cow_container_t;
+
/** Actual iterator type of the contained native iterator, probably a simple pointer. */
- typedef typename Storage_type::iterator iterator_type;
+ typedef typename storage_t::iterator iterator_type;
private:
typedef std::iterator_traits<iterator_type> sub_traits_t;
- CoW_container& cow_parent_;
+ cow_container_t& cow_parent_;
std::lock_guard<std::recursive_mutex> lock_;
- Storage_ref_type store_ref_;
- iterator_type iterator_;
+ storage_ref_t store_ref_;
+ iterator_type iterator_;
+ iterator_type iterator_begin;
+
+ constexpr explicit cow_rw_iterator(cow_container_t& cow_parent, const storage_ref_t& store, iterator_type iter) noexcept
+ : cow_parent_(cow_parent), lock_(cow_parent.get_write_mutex()), store_ref_(store),
+ iterator_(iter), iterator_begin(iter) {}
+
+ constexpr cow_rw_iterator(cow_container_t& cow_parent, iterator_type (*get_begin)(storage_ref_t&))
+ : cow_parent_(cow_parent), lock_(cow_parent.get_write_mutex()),
+ store_ref_(cow_parent.copy_store()), iterator_(get_begin(store_ref_)), iterator_begin(iterator_) {}
- constexpr explicit cow_rw_iterator(CoW_container& cow_parent, const Storage_ref_type& store, iterator_type iter) noexcept
- : cow_parent_(cow_parent), lock_(cow_parent.get_write_mutex()), store_ref_(store), iterator_(iter) {}
public:
typedef typename sub_traits_t::iterator_category iterator_category; // random_access_iterator_tag
- typedef typename Storage_type::size_type size_type; // using our template overload Size_type
- typedef typename Storage_type::difference_type difference_type; // derived from our Size_type
- // typedef typename Storage_type::value_type value_type; // OK
- // typedef typename Storage_type::reference reference; //
- // typedef typename Storage_type::pointer pointer; //
+ typedef typename storage_t::size_type size_type; // using our template overload Size_type
+ typedef typename storage_t::difference_type difference_type; // derived from our Size_type
+ // typedef typename storage_t::value_type value_type; // OK
+ // typedef typename storage_t::reference reference; //
+ // typedef typename storage_t::pointer pointer; //
typedef typename sub_traits_t::value_type value_type; // OK
typedef typename sub_traits_t::reference reference; // 'value_type &'
typedef typename sub_traits_t::pointer pointer; // 'value_type *'
@@ -137,16 +162,6 @@ namespace jau {
public:
- constexpr cow_rw_iterator(CoW_container& cow_parent, iterator_type (*get_iterator)(Storage_ref_type&))
- : cow_parent_(cow_parent), lock_(cow_parent.get_write_mutex()),
- store_ref_(cow_parent.copy_store()), iterator_(get_iterator(store_ref_)) {}
-
-#if 0
- constexpr cow_rw_iterator(CoW_container& cow_parent, iterator_type iter)
- : cow_parent_(cow_parent), lock_(cow_parent.get_write_mutex()),
- store_ref_(cow_parent.copy_store()), iterator_(iter) {}
-#endif
-
#if __cplusplus > 201703L
constexpr ~cow_rw_iterator() noexcept
#else
@@ -159,7 +174,7 @@ namespace jau {
// C++ named requirements: LegacyIterator: CopyConstructible
constexpr cow_rw_iterator(const cow_rw_iterator& o) noexcept
: cow_parent_(o.cow_parent_), lock_(cow_parent_.get_write_mutex()),
- store_ref_(o.store_ref_), iterator_(o.iterator_) {}
+ store_ref_(o.store_ref_), iterator_(o.iterator_), iterator_begin(o.iterator_begin) {}
// C++ named requirements: LegacyIterator: CopyAssignable
constexpr cow_rw_iterator& operator=(const cow_rw_iterator& o) noexcept {
@@ -167,16 +182,18 @@ namespace jau {
lock_ = cow_parent_.get_write_mutex();
store_ref_ = o.store_ref_;
iterator_ = o.iterator_;
+ iterator_begin = o.iterator_begin;
return *this;
}
// C++ named requirements: LegacyIterator: MoveConstructable
constexpr cow_rw_iterator(cow_rw_iterator && o) noexcept
: cow_parent_(std::move(o.cow_parent_)), lock_(cow_parent_.get_write_mutex()),
- store_ref_(std::move(o.store_ref_)), iterator_(std::move(o.iterator_)) {
+ store_ref_(std::move(o.store_ref_)), iterator_(std::move(o.iterator_)), iterator_begin(std::move(o.iterator_begin)) {
o.lock_ = nullptr; // ???
o.store_ref_ = nullptr;
// o.iterator_ = nullptr;
+ // o.iterator_begin = nullptr;
}
// C++ named requirements: LegacyIterator: MoveAssignable
@@ -185,8 +202,10 @@ namespace jau {
lock_ = cow_parent_.get_write_mutex();
store_ref_ = std::move(o.store_ref_);
iterator_ = std::move(o.iterator_);
+ iterator_begin = std::move(o.iterator_begin);
o.store_ref_ = nullptr;
// o.iterator_ = nullptr;
+ // o.iterator_begin = nullptr;
return *this;
}
@@ -196,9 +215,45 @@ namespace jau {
// std::swap( lock_, o.lock_); // lock stays in each
std::swap( store_ref_, o.store_ref_);
std::swap( iterator_, o.iterator_);
+ std::swap( iterator_begin, o.iterator_begin);
}
/**
+ * Return the size of the underlying value_type store.
+ * <p>
+ * This is an addition API entry, allowing data-race free arithmetic on
+ * this iterator's data snapshot from a potentially mutated CoW.
+ * </p>
+ * @see begin()
+ * @see end()
+ */
+ constexpr size_type size() const noexcept { return store_ref_->size(); }
+
+ /**
+ * Returns a new iterator pointing to the first element, aka begin.
+ * <p>
+ * This is an addition API entry, allowing data-race free operations on
+ * this iterator's data snapshot from a potentially mutated CoW.
+ * </p>
+ * @see size()
+ * @see end()
+ */
+ constexpr cow_rw_iterator begin() const noexcept
+ { return cow_rw_iterator( cow_parent_, store_ref_, iterator_begin ); }
+
+ /**
+ * Returns a new iterator pointing to the <i>element following the last element</i>, aka end.<br>
+ * <p>
+ * This is an addition API entry, allowing data-race free operations on
+ * this iterator's data snapshot from a potentially mutated CoW.
+ * </p>
+ * @see size()
+ * @see begin()
+ */
+ constexpr cow_rw_iterator end() const noexcept
+ { return cow_rw_iterator( cow_parent_, store_ref_, iterator_begin + store_ref_->size() ); }
+
+ /**
* Returns a copy of the underlying storage iterator.
*/
constexpr iterator_type base() const noexcept { return iterator_; };
@@ -324,10 +379,12 @@ namespace jau {
/**
* Implementation of a Copy-On-Write (CoW) read-only iterator for immutable value_type.<br>
- * Instance holds the 'shared value_type reference', Storage_ref_type,
- * of the current CoW storage until destruction.
+ * Instance holds a 'shared value_type' snapshot of the current CoW storage until destruction.
+ * <p>
+ * Implementation complies with Type Traits iterator_category 'random_access_iterator_tag'
+ * </p>
* <p>
- * This iterator simply wraps the native iterator of type 'iterator_type'
+ * Implementation simply wraps the native iterator of type 'iterator_type'
* and manages the CoW related resource lifecycle.
* </p>
* <p>
@@ -337,31 +394,47 @@ namespace jau {
* Also see jau::for_each_fidelity to iterate through in this good faith fashion.
* </p>
* <p>
- * Implementation complies with iterator_category 'random_access_iterator_tag'
+ * To allow data-race free operations on this iterator's data snapshot from a potentially mutated CoW,
+ * only one begin iterator should be retrieved from CoW and all further operations shall use
+ * jau::cow_ro_iterator::size(), jau::cow_ro_iterator::begin() and jau::cow_ro_iterator::end().
* </p>
+ * @see jau::cow_ro_iterator::size()
+ * @see jau::cow_ro_iterator::begin()
+ * @see jau::cow_ro_iterator::end()
* @see jau::for_each_fidelity
* @see jau::cow_darray
*/
template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
class cow_ro_iterator {
+ template<typename, typename, typename> friend class cow_darray;
+ template<typename, typename> friend class cow_vector;
+
public:
+ typedef Storage_type storage_t;
+ typedef Storage_ref_type storage_ref_t;
+ typedef CoW_container cow_container_t;
+
/** Actual const iterator type of the contained native iterator, probably a simple pointer. */
- typedef typename Storage_type::const_iterator iterator_type;
+ typedef typename storage_t::const_iterator iterator_type;
private:
typedef std::iterator_traits<iterator_type> sub_traits_t;
- Storage_ref_type store_ref_;
- iterator_type iterator_;
+ storage_ref_t store_ref_;
+ iterator_type iterator_;
+ iterator_type iterator_begin;
+
+ constexpr cow_ro_iterator(storage_ref_t store, iterator_type begin) noexcept
+ : store_ref_(store), iterator_(begin), iterator_begin(begin) { }
public:
typedef typename sub_traits_t::iterator_category iterator_category; // random_access_iterator_tag
- typedef typename Storage_type::size_type size_type; // using our template overload Size_type
- typedef typename Storage_type::difference_type difference_type; // derived from our Size_type
- // typedef typename Storage_type::value_type value_type; // OK
- // typedef typename Storage_type::reference reference; // Storage_type is not 'const'
- // typedef typename Storage_type::pointer pointer; // Storage_type is not 'const'
+ typedef typename storage_t::size_type size_type; // using our template overload Size_type
+ typedef typename storage_t::difference_type difference_type; // derived from our Size_type
+ // typedef typename storage_t::value_type value_type; // OK
+ // typedef typename storage_t::reference reference; // storage_t is not 'const'
+ // typedef typename storage_t::pointer pointer; // storage_t is not 'const'
typedef typename sub_traits_t::value_type value_type; // OK
typedef typename sub_traits_t::reference reference; // 'const value_type &'
typedef typename sub_traits_t::pointer pointer; // 'const value_type *'
@@ -372,10 +445,7 @@ namespace jau {
public:
constexpr cow_ro_iterator() noexcept
- : store_ref_(nullptr), iterator_() { }
-
- constexpr cow_ro_iterator(Storage_ref_type store, iterator_type iter) noexcept
- : store_ref_(store), iterator_(iter) { }
+ : store_ref_(nullptr), iterator_(), iterator_begin() { }
/**
* Conversion constructor: cow_rw_iterator -> cow_ro_iterator
@@ -384,39 +454,44 @@ namespace jau {
* using a temporary cow_rw_iterator instance involving storage copy etc.
* </p>
*/
- constexpr explicit cow_ro_iterator(const cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container>& o) noexcept
- : store_ref_(o.store_ref_), iterator_(o.iterator_) {}
+ constexpr explicit cow_ro_iterator(const cow_rw_iterator<storage_t, storage_ref_t, cow_container_t>& o) noexcept
+ : store_ref_(o.store_ref_), iterator_(o.iterator_), iterator_begin(o.iterator_begin) {}
// C++ named requirements: LegacyIterator: CopyConstructible
constexpr cow_ro_iterator(const cow_ro_iterator& o) noexcept
- : store_ref_(o.store_ref_), iterator_(o.iterator_) {}
+ : store_ref_(o.store_ref_), iterator_(o.iterator_), iterator_begin(o.iterator_begin) {}
// C++ named requirements: LegacyIterator: CopyAssignable
constexpr cow_ro_iterator& operator=(const cow_ro_iterator& o) noexcept {
store_ref_ = o.store_ref_;
iterator_ = o.iterator_;
+ iterator_begin = o.iterator_begin;
return *this;
}
- constexpr cow_ro_iterator& operator=(const cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container>& o) noexcept {
+ constexpr cow_ro_iterator& operator=(const cow_rw_iterator<storage_t, storage_ref_t, cow_container_t>& o) noexcept {
store_ref_ = o.store_ref_;
iterator_ = o.iterator_;
+ iterator_begin = o.iterator_begin;
return *this;
}
// C++ named requirements: LegacyIterator: MoveConstructable
constexpr cow_ro_iterator(cow_ro_iterator && o) noexcept
- : store_ref_(std::move(o.store_ref_)), iterator_(std::move(o.iterator_)) {
+ : store_ref_(std::move(o.store_ref_)), iterator_(std::move(o.iterator_)), iterator_begin(std::move(o.iterator_begin)) {
o.store_ref_ = nullptr;
// o.iterator_ = nullptr;
+ // o.iterator_begin = nullptr;
}
// C++ named requirements: LegacyIterator: MoveAssignable
constexpr cow_ro_iterator& operator=(cow_ro_iterator&& o) noexcept {
store_ref_ = std::move(o.store_ref_);
iterator_ = std::move(o.iterator_);
+ iterator_begin = std::move(o.iterator_begin);
o.store_ref_ = nullptr;
// o.iterator_ = nullptr;
+ // o.iterator_begin = nullptr;
return *this;
}
@@ -424,10 +499,49 @@ namespace jau {
void swap(cow_ro_iterator& o) noexcept {
std::swap( store_ref_, o.store_ref_);
std::swap( iterator_, o.iterator_);
+ std::swap( iterator_begin, o.iterator_begin);
}
/**
+ * Return the size of the underlying value_type store.
+ * <p>
+ * This is an addition API entry, allowing data-race free arithmetic on
+ * this iterator's data snapshot from a potentially mutated CoW.
+ * </p>
+ * @see begin()
+ * @see end()
+ */
+ constexpr size_type size() const noexcept { return store_ref_->size(); }
+
+ /**
+ * Returns a new const_iterator pointing to the first element, aka begin.
+ * <p>
+ * This is an addition API entry, allowing data-race free operations on
+ * this iterator's data snapshot from a potentially mutated CoW.
+ * </p>
+ * @see size()
+ * @see end()
+ */
+ constexpr cow_ro_iterator begin() const noexcept
+ { return cow_ro_iterator( store_ref_, iterator_begin ); }
+
+ /**
+ * Returns a new const_iterator pointing to the <i>element following the last element</i>, aka end.<br>
+ * <p>
+ * This is an addition API entry, allowing data-race free operations on
+ * this iterator's data snapshot from a potentially mutated CoW.
+ * </p>
+ * @see size()
+ * @see begin()
+ */
+ constexpr cow_ro_iterator end() const noexcept
+ { return cow_ro_iterator( store_ref_, iterator_begin + store_ref_->size() ); }
+
+ /**
* Returns a copy of the underlying storage const_iterator.
+ * <p>
+ * This is an addition API entry, inspired by the STL std::normal_iterator.
+ * </p>
*/
constexpr iterator_type base() const noexcept { return iterator_; };
@@ -448,7 +562,7 @@ namespace jau {
: ( iterator_ < rhs.iterator_ ? -1 : 1);
}
- constexpr int compare(const cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container>& rhs) const noexcept {
+ constexpr int compare(const cow_rw_iterator<storage_t, storage_ref_t, cow_container_t>& rhs) const noexcept {
return store_ref_ == rhs.store_ref_ && iterator_ == rhs.iterator_ ? 0
: ( iterator_ < rhs.iterator_ ? -1 : 1);
}
@@ -533,7 +647,7 @@ namespace jau {
constexpr difference_type operator-(const cow_ro_iterator& rhs) const noexcept
{ return iterator_ - rhs.iterator_; }
- constexpr difference_type distance(const cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container>& rhs) const noexcept
+ constexpr difference_type distance(const cow_rw_iterator<storage_t, storage_ref_t, cow_container_t>& rhs) const noexcept
{ return iterator_ - rhs.iterator_; }
__constexpr_cxx20_ std::string toString() const noexcept {
@@ -546,6 +660,9 @@ namespace jau {
#endif
};
+ /****************************************************************************************
+ ****************************************************************************************/
+
template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
std::ostream & operator << (std::ostream &out, const cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container> &c) {
out << c.toString();
@@ -558,6 +675,9 @@ namespace jau {
return out;
}
+ /****************************************************************************************
+ ****************************************************************************************/
+
template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
constexpr bool operator==(const cow_ro_iterator<Storage_type, Storage_ref_type, CoW_container>& lhs,
const cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container>& rhs) noexcept
@@ -630,6 +750,107 @@ namespace jau {
const cow_ro_iterator<Storage_type, Storage_ref_type, CoW_container>& rhs) noexcept
{ return rhs.distance(lhs) * -1; }
+ /****************************************************************************************
+ ****************************************************************************************/
+
+ /**
+ * <code>template< class T > is_cow_type<T>::value</code> compile-time Type Trait,
+ * determining whether the given template class is a CoW type, e.g. jau::cow_darray,
+ * jau::cow_vector or any of their iterator.
+ */
+ template< class, class = void >
+ struct is_cow_type : std::false_type { };
+
+ /**
+ * <code>template< class T > is_cow_type<T>::value</code> compile-time Type Trait,
+ * determining whether the given template class is a CoW type, e.g. jau::cow_darray,
+ * jau::cow_vector or any of their iterator.
+ */
+ template< class T >
+ struct is_cow_type<T, std::void_t<typename T::cow_container_t>> : std::true_type { };
+
+ template<class T>
+ const typename T::value_type * find_const(T& data, typename T::value_type const & elem,
+ std::enable_if_t< is_cow_type<T>::value, bool> = true ) noexcept
+ {
+ typename T::const_iterator begin = data.cbegin();
+ typename T::const_iterator end = begin.end();
+ auto it = jau::find( begin, end, elem);
+ if( it != end ) {
+ return &(*it);
+ }
+ return nullptr;
+ }
+ template<class T>
+ const typename T::value_type * find_const(T& data, typename T::value_type const & elem,
+ std::enable_if_t< !is_cow_type<T>::value, bool> = true ) noexcept
+ {
+ typename T::const_iterator end = data.cend();
+ auto it = jau::find( data.cbegin(), end, elem);
+ if( it != end ) {
+ return &(*it);
+ }
+ return nullptr;
+ }
+
+ /****************************************************************************************
+ ****************************************************************************************/
+
+ template<class T, class UnaryFunction>
+ constexpr UnaryFunction for_each_const(T& data, UnaryFunction f,
+ std::enable_if_t< is_cow_type<T>::value, bool> = true ) noexcept
+ {
+ typename T::const_iterator first = data.cbegin();
+ typename T::const_iterator last = first.end();
+ for (; first != last; ++first) {
+ f(*first);
+ }
+ return f; // implicit move since C++11
+ }
+ template<class T, class UnaryFunction>
+ constexpr UnaryFunction for_each_const(T& data, UnaryFunction f,
+ std::enable_if_t< !is_cow_type<T>::value, bool> = true ) noexcept
+ {
+ typename T::const_iterator first = data.cbegin();
+ typename T::const_iterator last = data.cend();
+ for (; first != last; ++first) {
+ f(*first);
+ }
+ return f; // implicit move since C++11
+ }
+
+ /****************************************************************************************
+ ****************************************************************************************/
+
+ /**
+ * See jau::for_each_fidelity()
+ */
+ template<class T, class UnaryFunction>
+ constexpr UnaryFunction for_each_fidelity(T& data, UnaryFunction f,
+ std::enable_if_t< is_cow_type<T>::value, bool> = true ) noexcept
+ {
+ typename T::const_iterator first = data.cbegin();
+ typename T::const_iterator last = first.end();
+ for (; first != last; ++first) {
+ f( *const_cast<typename T::value_type*>( & (*first) ) );
+ }
+ return f; // implicit move since C++11
+ }
+ /**
+ * See jau::for_each_fidelity()
+ */
+ template<class T, class UnaryFunction>
+ constexpr UnaryFunction for_each_fidelity(T& data, UnaryFunction f,
+ std::enable_if_t< !is_cow_type<T>::value, bool> = true ) noexcept
+ {
+ typename T::const_iterator first = data.cbegin();
+ typename T::const_iterator last = data.cend();
+ for (; first != last; ++first) {
+ f( *const_cast<typename T::value_type*>( & (*first) ) );
+ }
+ return f; // implicit move since C++11
+ }
+
} /* namespace jau */
diff --git a/include/jau/cow_vector.hpp b/include/jau/cow_vector.hpp
index 5223f82..365d776 100644
--- a/include/jau/cow_vector.hpp
+++ b/include/jau/cow_vector.hpp
@@ -117,23 +117,19 @@ namespace jau {
typedef std::vector<value_type, allocator_type> storage_t;
typedef std::shared_ptr<storage_t> storage_ref_t;
+ typedef cow_vector<value_type, allocator_type> cow_container_t;
+
/**
- * Immutable, read-only const_iterator, lock-free,
- * holding the current shared store reference until destruction.
- * <p>
- * Using jau::cow_vector::get_snapshot() at construction.
- * </p>
+ * @see jau::cow_darray::const_iterator
+ * @see jau::cow_ro_iterator
*/
- typedef cow_ro_iterator<storage_t, storage_ref_t, cow_vector> const_iterator;
+ typedef cow_ro_iterator<storage_t, storage_ref_t, cow_container_t> const_iterator;
/**
- * Mutable, read-write iterator, holding the write-lock and a store copy until destruction.
- * <p>
- * Using jau::cow_vector::get_write_mutex(), jau::cow_vector::copy_store() at construction<br>
- * and jau::cow_vector::set_store() at destruction.
- * </p>
+ * @see jau::cow_darray::iterator
+ * @see jau::cow_rw_iterator
*/
- typedef cow_rw_iterator<storage_t, storage_ref_t, cow_vector> iterator;
+ typedef cow_rw_iterator<storage_t, storage_ref_t, cow_container_t> iterator;
private:
static constexpr size_type DIFF_MAX = std::numeric_limits<difference_type>::max();
@@ -278,32 +274,24 @@ namespace jau {
// const_iterator, non mutable, read-only
- constexpr const_iterator begin() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cbegin());
- }
+ // Removed for clarity: "constexpr const_iterator begin() const noexcept"
+ /**
+ * See description in jau::cow_darray::cbegin()
+ */
constexpr const_iterator cbegin() const noexcept {
return const_iterator(get_snapshot(), store_ref->cbegin());
}
- constexpr const_iterator end() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cend());
- }
-
- constexpr const_iterator cend() const noexcept {
- return const_iterator(get_snapshot(), store_ref->cend());
- }
-
// iterator, mutable, read-write
+ /**
+ * See description in jau::cow_darray::begin()
+ */
constexpr iterator begin() noexcept {
return iterator(*this, [](storage_ref_t& new_store) -> typename storage_t::iterator { return new_store->begin(); } );
}
- constexpr iterator end() noexcept {
- return iterator(*this, [](storage_ref_t& new_store) -> typename storage_t::iterator { return new_store->end(); } );
- }
-
// read access
allocator_type get_allocator() const noexcept {
diff --git a/test/test_cow_darray_01.cpp b/test/test_cow_darray_01.cpp
index 7b7f87a..1ae6fb8 100644
--- a/test/test_cow_darray_01.cpp
+++ b/test/test_cow_darray_01.cpp
@@ -35,6 +35,7 @@
#include "test_datatype01.hpp"
+#include <jau/basic_algos.hpp>
#include <jau/basic_types.hpp>
#include <jau/darray.hpp>
#include <jau/cow_darray.hpp>
@@ -72,17 +73,6 @@ DataType01 * findDataSet01_idx(T& data, DataType01 const & elem) noexcept {
}
return nullptr;
}
-template<class T>
-const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept {
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(; iter != end ; ++iter) {
- if( elem == *iter ) {
- return &(*iter);
- }
- }
- return nullptr;
-}
template<class T>
static void test_00_list_idx(T& data, const bool show) {
@@ -98,18 +88,20 @@ static void test_00_list_idx(T& data, const bool show) {
}
}
template<class T>
-static void test_00_list_itr(T& data, const bool show) {
+static int test_00_list_itr(T& data, const bool show) {
Addr48Bit a0(start_addr);
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(std::size_t i = 0; iter != end && a0.next(); ++iter, ++i) {
- const DataType01 & e = *iter;
- e.nop();
+ int some_number = 0, i=0; // add some validated work, avoiding any 'optimization away'
+ jau::for_each_const(data, [&some_number, &a0, &i, show](const DataType01 & e) {
+ some_number += e.nop();
if( show ) {
- printf("data[%zu]: %s\n", i, e.toString().c_str());
+ printf("data[%d]: %s\n", i, e.toString().c_str());
}
+ REQUIRE( a0.next() );
REQUIRE(e.address == a0);
- }
+ ++i;
+ } );
+ REQUIRE(some_number > 0);
+ return some_number;
}
template<class T>
@@ -136,7 +128,7 @@ static void test_00_seq_find_itr(T& data) {
for(; i<size && a0.next(); i++) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01 *found = findDataSet01_itr(data, elem);
+ const DataType01 *found = jau::find_const(data, elem);
if( nullptr != found ) {
fi++;
found->nop();
@@ -191,7 +183,7 @@ static void test_00_seq_fill_unique_itr(T& data, const std::size_t size) {
for(; i<size && a0.next(); i++) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01* exist = findDataSet01_itr(data, elem);
+ const DataType01* exist = jau::find_const(data, elem);
if( nullptr == exist ) {
data.push_back( std::move(elem) );
fi++;
diff --git a/test/test_cow_darray_perf01.cpp b/test/test_cow_darray_perf01.cpp
index c4c519b..70e3a47 100644
--- a/test/test_cow_darray_perf01.cpp
+++ b/test/test_cow_darray_perf01.cpp
@@ -52,9 +52,6 @@ using namespace jau;
static uint8_t start_addr_b[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static Addr48Bit start_addr(start_addr_b);
-// #define USE_STD_ITER_ALGO 1
-#define USE_JAU_ITER_ALGO 1
-
/****************************************************************************************
****************************************************************************************/
@@ -70,34 +67,6 @@ DataType01 * findDataSet01_idx(T& data, DataType01 const & elem) noexcept {
return nullptr;
}
-template<class T>
-const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept {
-#if defined(USE_STD_ITER_ALGO)
- // much slower, approx 3x over 1000 * 1000, why?
- typename T::const_iterator end = data.cend();
- auto it = std::find( data.cbegin(), end, elem);
- if( it != end ) {
- return &(*it);
- }
-#elif defined (USE_JAU_ITER_ALGO)
- // same logic, much faster
- typename T::const_iterator end = data.cend();
- auto it = jau::find( data.cbegin(), end, elem);
- if( it != end ) {
- return &(*it);
- }
-#else
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(; iter != end ; ++iter) {
- if( elem == *iter ) {
- return &(*iter);
- }
- }
-#endif
- return nullptr;
-}
-
template<class T, typename Size_type>
static int test_00_list_idx(T& data) {
int some_number = 0; // add some validated work, avoiding any 'optimization away'
@@ -113,20 +82,9 @@ static int test_00_list_idx(T& data) {
template<class T>
static int test_00_list_itr(T& data) {
int some_number = 0; // add some validated work, avoiding any 'optimization away'
-#if defined(USE_STD_ITER_ALGO)
- // slower, why?
- std::for_each(data.cbegin(), data.cend(), [&some_number](const DataType01 & e) { some_number += e.nop(); });
-#elif defined (USE_JAU_ITER_ALGO)
- // same logic, faster
- jau::for_each(data.cbegin(), data.cend(), [&some_number](const DataType01 & e) { some_number += e.nop(); });
-#else
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(; iter != end ; ++iter) {
- const DataType01 & e = *iter;
+ jau::for_each_const(data, [&some_number](const DataType01 & e) {
some_number += e.nop();
- }
-#endif
+ } );
REQUIRE(some_number > 0);
return some_number;
}
@@ -156,7 +114,7 @@ static void test_00_seq_find_itr(T& data) {
for(; i<size && a0.next(); ++i) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01 *found = findDataSet01_itr<T>(data, elem);
+ const DataType01 *found = jau::find_const<T>(data, elem);
if( nullptr != found ) {
++fi;
found->nop();
@@ -199,7 +157,7 @@ static void test_00_seq_fill_unique_itr(T& data, const Size_type size) {
for(; i<size && a0.next(); ++i) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01* exist = findDataSet01_itr<T>(data, elem);
+ const DataType01* exist = jau::find_const<T>(data, elem);
if( nullptr == exist ) {
data.push_back( std::move( elem ) );
++fi;
diff --git a/test/test_cow_iterator_01.cpp b/test/test_cow_iterator_01.cpp
index 737d870..834a4c7 100644
--- a/test/test_cow_iterator_01.cpp
+++ b/test/test_cow_iterator_01.cpp
@@ -36,6 +36,7 @@
#include "test_datatype01.hpp"
+#include <jau/basic_algos.hpp>
#include <jau/basic_types.hpp>
#include <jau/darray.hpp>
#include <jau/cow_darray.hpp>
@@ -67,30 +68,20 @@ JAU_TYPENAME_CUE_ALL(jau_cow_vector_DataType01)
JAU_TYPENAME_CUE_ALL(jau_cow_darray_DataType01)
template<class T>
-const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept {
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(; iter != end ; ++iter) {
- if( elem == *iter ) {
- return &(*iter);
- }
- }
- return nullptr;
-}
-
-template<class T>
-static void test_00_list_itr(T& data, const bool show) {
+static int test_00_list_itr(T& data, const bool show) {
Addr48Bit a0(start_addr);
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(std::size_t i = 0; iter != end && a0.next(); ++iter, ++i) {
- const DataType01 & e = *iter;
- e.nop();
+ int some_number = 0, i=0; // add some validated work, avoiding any 'optimization away'
+ jau::for_each_const(data, [&some_number, &a0, &i, show](const DataType01 & e) {
+ some_number += e.nop();
if( show ) {
- printf("data[%zu]: %s\n", i, e.toString().c_str());
+ printf("data[%d]: %s\n", i, e.toString().c_str());
}
+ REQUIRE( a0.next() );
REQUIRE(e.address == a0);
- }
+ ++i;
+ } );
+ REQUIRE(some_number > 0);
+ return some_number;
}
template<class T>
@@ -101,7 +92,7 @@ static void test_00_seq_find_itr(T& data) {
for(; i<size && a0.next(); i++) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01 *found = findDataSet01_itr(data, elem);
+ const DataType01 *found = jau::find_const(data, elem);
if( nullptr != found ) {
fi++;
found->nop();
@@ -419,11 +410,56 @@ static void test_iterator_arithmetic(const typename T::size_type size,
}
template<class T>
-static bool test_const_iterator_ops(const std::string& type_id, T& data) {
- printf("**** test_const_iterator_ops: %s\n", type_id.c_str());
+static bool test_const_iterator_ops(const std::string& type_id, T& data,
+ std::enable_if_t< is_cow_type<T>::value, bool> = true )
+{
+ printf("**** test_const_iterator_ops(CoW): %s\n", type_id.c_str());
+ {
+ typename T::const_iterator begin = data.cbegin(); // immutable new_store non-const iterator, gets held until destruction
+ typename T::const_iterator end = begin.end(); // no new store iterator, on same store as begin, obtained from begin
+ typename T::difference_type data_size = static_cast<typename T::difference_type>(data.size());
+ typename T::difference_type begin_size = static_cast<typename T::difference_type>(begin.size());
+ typename T::difference_type end_size = static_cast<typename T::difference_type>(end.size());
+ REQUIRE( begin_size == data_size );
+ REQUIRE( end_size == data_size );
+ REQUIRE( end - begin == data_size );
+ REQUIRE( end - end_size == begin );
+ REQUIRE( begin + begin_size == end );
+ REQUIRE( *( end - end_size ) == *begin );
+ REQUIRE( *( begin + begin_size ) == *end );
+ test_iterator_dereference<T, typename T::const_iterator>(begin.size(), begin, end);
+ }
+
{
typename T::const_iterator begin = data.cbegin(); // no new store const_iterator
- typename T::const_iterator end = data.cend(); // no new store const_iterator, on same store as begin
+ typename T::const_iterator end = begin.end(); // no new store const_iterator, on same store as begin, obtained from begin
+ test_iterator_arithmetic<T, typename T::const_iterator>(data.size(), begin, end);
+ }
+#if 0
+ {
+ // INTENIONAL FAILURES, checking behavior of error values etc
+ typename T::const_iterator begin = data.cbegin(); // no new store const_iterator
+ typename T::const_iterator iter = begin + 1;
+ CHECK( *begin == *iter );
+ CHECK( begin == iter );
+ }
+#endif
+ return true;
+}
+template<class T>
+static bool test_const_iterator_ops(const std::string& type_id, T& data,
+ std::enable_if_t< !is_cow_type<T>::value, bool> = true )
+{
+ printf("**** test_const_iterator_ops: %s\n", type_id.c_str());
+ {
+ typename T::const_iterator begin = data.cbegin(); // mutable new_store non-const iterator, gets held until destruction
+ typename T::const_iterator end = data.cend(); // no new store iterator, on same store as begin and from begin
+ typename T::difference_type data_size = static_cast<typename T::difference_type>(data.size());
+ REQUIRE( end - begin == data_size );
+ REQUIRE( end - data_size == begin );
+ REQUIRE( begin + data_size == end );
+ REQUIRE( *( end - data_size ) == *begin );
+ REQUIRE( *( begin + data_size ) == *end );
test_iterator_dereference<T, typename T::const_iterator>(data.size(), begin, end);
}
@@ -445,11 +481,48 @@ static bool test_const_iterator_ops(const std::string& type_id, T& data) {
}
template<class T>
-static bool test_mutable_iterator_ops(const std::string& type_id, T& data) {
- printf("**** test_mutable_iterator_ops: %s\n", type_id.c_str());
+static bool test_mutable_iterator_ops(const std::string& type_id, T& data,
+ std::enable_if_t< is_cow_type<T>::value, bool> = true )
+{
+ printf("**** test_mutable_iterator_ops(CoW): %s\n", type_id.c_str());
+ {
+ typename T::iterator begin = data.begin(); // mutable new_store non-const iterator, gets held until destruction
+ typename T::iterator end = begin.end(); // no new store iterator, on same store as begin and from begin
+ typename T::difference_type data_size = static_cast<typename T::difference_type>(data.size());
+ typename T::difference_type begin_size = static_cast<typename T::difference_type>(begin.size());
+ typename T::difference_type end_size = static_cast<typename T::difference_type>(end.size());
+ REQUIRE( begin_size == data_size );
+ REQUIRE( end_size == data_size );
+ REQUIRE( end - begin == data_size );
+ REQUIRE( end - end_size == begin );
+ REQUIRE( begin + begin_size == end );
+ REQUIRE( *( end - end_size ) == *begin );
+ REQUIRE( *( begin + begin_size ) == *end );
+ test_iterator_dereference<T, typename T::iterator>(begin.size(), begin, end);
+ }
+
{
typename T::iterator begin = data.begin(); // mutable new_store non-const iterator, gets held until destruction
typename T::iterator end = begin + data.size(); // hence use iterator artihmetic to have end pointer
+ test_iterator_arithmetic<T, typename T::iterator>(data.size(), begin, end);
+ }
+ return true;
+}
+
+template<class T>
+static bool test_mutable_iterator_ops(const std::string& type_id, T& data,
+ std::enable_if_t< !is_cow_type<T>::value, bool> = true )
+{
+ printf("**** test_mutable_iterator_ops(___): %s\n", type_id.c_str());
+ {
+ typename T::iterator begin = data.begin(); // mutable new_store non-const iterator, gets held until destruction
+ typename T::iterator end = data.end(); // no new store iterator, on same store as begin and from begin
+ typename T::difference_type data_size = static_cast<typename T::difference_type>(data.size());
+ REQUIRE( end - begin == data_size );
+ REQUIRE( end - data_size == begin );
+ REQUIRE( begin + data_size == end );
+ REQUIRE( *( end - data_size ) == *begin );
+ REQUIRE( *( begin + data_size ) == *end );
test_iterator_dereference<T, typename T::iterator>(data.size(), begin, end);
}
diff --git a/test/test_hashset_perf01.cpp b/test/test_hashset_perf01.cpp
index ff8c8d2..223c05d 100644
--- a/test/test_hashset_perf01.cpp
+++ b/test/test_hashset_perf01.cpp
@@ -54,34 +54,6 @@ static Addr48Bit start_addr(start_addr_b);
#define USE_JAU_ITER_ALGO 1
template<class T>
-const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept {
-#if defined(USE_STD_ITER_ALGO)
- // much slower, approx 3x over 1000 * 1000, why?
- typename T::const_iterator end = data.cend();
- auto it = std::find( data.cbegin(), end, elem);
- if( it != end ) {
- return &(*it);
- }
-#elif defined (USE_JAU_ITER_ALGO)
- // same logic, much faster
- typename T::const_iterator end = data.cend();
- auto it = jau::find( data.cbegin(), end, elem);
- if( it != end ) {
- return &(*it);
- }
-#else
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(; iter != end ; ++iter) {
- if( elem == *iter ) {
- return &(*iter);
- }
- }
-#endif
- return nullptr;
-}
-
-template<class T>
const DataType01 * findDataSet01_hash(T& data, DataType01 const & elem) noexcept {
auto search = data.find(elem);
if( search != data.end() ) {
@@ -93,20 +65,9 @@ const DataType01 * findDataSet01_hash(T& data, DataType01 const & elem) noexcept
template<class T>
static int test_00_list_itr(T& data) {
int some_number = 0; // add some validated work, avoiding any 'optimization away'
-#if defined(USE_STD_ITER_ALGO)
- // slower, why?
- std::for_each(data.cbegin(), data.cend(), [&some_number](const DataType01 & e) { some_number += e.nop(); });
-#elif defined (USE_JAU_ITER_ALGO)
- // same logic, faster
- jau::for_each(data.cbegin(), data.cend(), [&some_number](const DataType01 & e) { some_number += e.nop(); });
-#else
- typename T::const_iterator iter = data.cbegin();
- typename T::const_iterator end = data.cend();
- for(; iter != end ; ++iter) {
- const DataType01 & e = *iter;
+ jau::for_each_const(data, [&some_number](const DataType01 & e) {
some_number += e.nop();
- }
-#endif
+ } );
REQUIRE(some_number > 0);
return some_number;
}
@@ -119,7 +80,7 @@ static void test_00_seq_find_itr(T& data) {
for(; i<size && a0.next(); ++i) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01 *found = findDataSet01_itr<T>(data, elem);
+ const DataType01 *found = jau::find_const<T>(data, elem);
if( nullptr != found ) {
++fi;
found->nop();
@@ -163,7 +124,7 @@ static void test_00_seq_fill_unique_itr(T& data, const Size_type size) {
for(; i<size && a0.next(); ++i) {
DataType01 elem(a0, static_cast<uint8_t>(1));
- const DataType01* exist = findDataSet01_itr<T>(data, elem);
+ const DataType01* exist = jau::find_const<T>(data, elem);
if( nullptr == exist ) {
data.push_back( std::move( elem ) );
++fi;