aboutsummaryrefslogtreecommitdiffstats
path: root/include/jau/cow_darray.hpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-10-24 03:36:13 +0200
committerSven Gothel <[email protected]>2021-10-24 03:36:13 +0200
commit89b5af2eade2b52e02bade6cbe888c3f54884999 (patch)
treed7d52e0b8bfa7c7f2c55f702563d6445214d3176 /include/jau/cow_darray.hpp
parentc770479d4ce702ec2151f7b88d34b916ad61c53a (diff)
Add darray and cow_darray construction with initializer list using move-semantics, instead of copy-semantics (std::initializer_list)
Using the `std::initializer_list` requires to *copy* the given value_type objects into this darray. This is due to `std::initializer_list` exposing its iterator as `const`. Initially I hacked the `std::initializer_list` ctor to cast away 'const', which practically worked. However, this is not as design and `std::initializer_list` storage has been produced by the compiler, stealing it may lead to undefinded behavior (UB). Hence we require to use a self-made construct, like std::make_shared<>(..). Inspired by Tristan Brindle's <https://tristanbrindle.com/posts/beware-copies-initializer-list>, I added similar more enhanced functionality to darray and cow_array: 'template <typename... Args> constexpr void push_back_list(Args&&... args)' push_back_list() moves the whole argument list into our array as an atomic operation. The latter is more important for cow_darray of course. Storage space for all elements is adjusted and all elements are added. The outter template 'make_[cow_]darray<..>(..)' simply creates the array instance with the desired size and passes the argument list to push_back_list(). Since we can't properly have the array's Value_type deduced if uses as a template type argument, this template passes the First and all Next arguments (pack) in a dedicated fashion. After constraining the template to having the same type for all arguments, we use the First type for the array definition. This version can only handle argument lists of size 2 or greater. Hence a complement template for one argument only has been added. Features used here: - C++11 template pack - C++17 fold expression Tested with Direct-BT.
Diffstat (limited to 'include/jau/cow_darray.hpp')
-rw-r--r--include/jau/cow_darray.hpp124
1 files changed, 123 insertions, 1 deletions
diff --git a/include/jau/cow_darray.hpp b/include/jau/cow_darray.hpp
index 8da0399..e1486cd 100644
--- a/include/jau/cow_darray.hpp
+++ b/include/jau/cow_darray.hpp
@@ -492,10 +492,14 @@ namespace jau {
}
/**
- * Create a new instance from an initializer list.
+ * Using the `std::initializer_list` requires to *copy* the given value_type objects into this cow_darray.
+ *
+ * To utilize more efficient move semantics, see push_back_list() and jau::make_cow_darray().
*
* @param initlist initializer_list.
* @param alloc allocator
+ * @see push_back_list()
+ * @see jau::make_cow_darray()
*/
constexpr cow_darray(std::initializer_list<value_type> initlist, const allocator_type& alloc = allocator_type())
: store_ref(std::make_shared<storage_t>(initlist, alloc)), sync_atomic(false)
@@ -912,6 +916,73 @@ namespace jau {
}
/**
+ * Like push_back(), but for more multiple const r-value to copy.
+ * <p>
+ * This write operation uses a mutex lock and is blocking this instances' write operations only.
+ * </p>
+ *
+ * @tparam Args
+ * @param args r-value references to copy into this storage
+ */
+ template <typename... Args>
+ constexpr_atomic void push_back_list(const Args&... args)
+ {
+ std::lock_guard<std::recursive_mutex> lock(mtx_write);
+ const size_type new_size_ = store_ref->size() + sizeof...(Args);
+
+ if( new_size_ > store_ref->capacity() ) {
+ // grow and swap all refs
+ storage_ref_t new_store_ref = std::make_shared<storage_t>( *store_ref, new_size_,
+ store_ref->growth_factor(),
+ store_ref->get_allocator_ref() );
+ // C++17 fold expression on above C++11 template pack args
+ ( new_store_ref->push_back( args ), ... ); // @suppress("Syntax error")
+ {
+ sc_atomic_critical sync(sync_atomic);
+ store_ref = std::move(new_store_ref);
+ }
+ } else {
+ // just append ..
+ // C++17 fold expression on above C++11 template pack args
+ ( store_ref->push_back( args ), ... ); // @suppress("Syntax error")
+ }
+ }
+
+ /**
+ * Like push_back(), but for more multiple r-value references to move.
+ * <p>
+ * This write operation uses a mutex lock and is blocking this instances' write operations only.
+ * </p>
+ *
+ * @tparam Args
+ * @param args r-value references to move into this storage
+ * @see jau::make_cow_darray()
+ */
+ template <typename... Args>
+ constexpr_atomic void push_back_list(Args&&... args)
+ {
+ std::lock_guard<std::recursive_mutex> lock(mtx_write);
+ const size_type new_size_ = store_ref->size() + sizeof...(Args);
+
+ if( new_size_ > store_ref->capacity() ) {
+ // grow and swap all refs
+ storage_ref_t new_store_ref = std::make_shared<storage_t>( *store_ref, new_size_,
+ store_ref->growth_factor(),
+ store_ref->get_allocator_ref() );
+ // C++17 fold expression on above C++11 template pack args
+ ( new_store_ref->push_back( std::move(args) ), ... ); // @suppress("Syntax error")
+ {
+ sc_atomic_critical sync(sync_atomic);
+ store_ref = std::move(new_store_ref);
+ }
+ } else {
+ // just append ..
+ // C++17 fold expression on above C++11 template pack args
+ ( store_ref->push_back( std::move(args) ), ... ); // @suppress("Syntax error")
+ }
+ }
+
+ /**
* Generic value_type equal comparator to be user defined for e.g. jau::cow_darray::push_back_unique().
* @param a one element of the equality test.
* @param b the other element of the equality test.
@@ -1021,6 +1092,57 @@ namespace jau {
}
};
+ /**
+ * Construct a cow_darray<T> instance, initialized by move semantics from the variadic (template pack) argument list.
+ *
+ * std::initializer_list<T> enforces to copy the created instances into the container,
+ * since its iterator references to `const` value_type.
+ *
+ * This alternative template passes the r-value argument references to cow_darray::push_back_list(),
+ * hence using `std::move` without copying semantics.
+ *
+ * All argument types must be of same type, i.e. std::is_same.
+ * The deduced darray<T> instance also uses same type as its Value_type.
+ *
+ * @tparam First the first argument type, must be same
+ * @tparam Next all other argument types, must be same
+ * @tparam
+ * @param arg1 the first r-value
+ * @param argsN the other r-values
+ * @return the new `cow_darray`
+ * @see cow_darray::push_back_list()
+ * @see make_cow_darray()
+ */
+ template <typename First, typename... Next,
+ // std::enable_if_t< ( std::is_same<First, Next>::value && ... ), bool> = true>
+ std::enable_if_t< std::conjunction_v<std::is_same<First, Next>... >, bool> = true>
+ constexpr cow_darray< First > make_cow_darray(First&& arg1, Next&&... argsN)
+ {
+ cow_darray< First > d(1 + sizeof...(Next));
+ // C++17 fold expression on above C++11 template pack arg1 and argsN
+ // d.push_back_list( std::forward<First>(arg1), ( std::forward<Next>(argsN), ... ) ); // @suppress("Syntax error")
+ d.push_back_list( arg1, argsN... ); // @suppress("Syntax error")
+ return d;
+ }
+
+ /**
+ * Complement constructor for cow_darray<T> instance, move semantics initializer for one argument.
+ * @tparam First
+ * @tparam Next
+ * @param arg1
+ * @return
+ * @see cow_darray::push_back()
+ * @see cow_darray::push_back_list()
+ * @see make_cow_darray()
+ */
+ template <typename First, typename... Next>
+ constexpr cow_darray< First > make_cow_darray(First&& arg1)
+ {
+ cow_darray< First > d(1);
+ d.push_back( std::forward<First>(arg1) );
+ return d;
+ }
+
/****************************************************************************************
****************************************************************************************/