aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-10-23 06:26:09 +0200
committerSven Gothel <[email protected]>2021-10-23 06:26:09 +0200
commitaca6d33271b327b0a282f8059182ed80448d766d (patch)
treeeab9b06150cd872632b78126e859beefcdee0c4d
parent1827dfe59d6bb179bc40e426de3ca4b42eb28eb4 (diff)
darray<> Non-Type Template Parameter: Remove use_realloc (fully deducted), sec_mem -> use_secmem; Add Value_type traits for uses_memmove and use_secmem.
Change also applied on cow_darray<>. Added full API doc for these Non-Type Template Parameter (NTTP). Since `use_realloc` has been removed, all use cases must be validated for changed template parameter. User can now add the following typedef's to not use the NTTP: - typedef std::true_type container_memmove_compliant; - typedef std::true_type enforce_secmem; ^^ these will be queried via compile time traits and set default values of the NTTP. +++ darray::grow_storage_move(Size_type) now returns the maximum of growth * old_capacity and new_capacity, i.e. not dropping the `golder rule` growth factor. Clearing a darray instance (e.g. from std::move), only the iterator and hence heap pointer is being nulled - not the allocator (was a bug). Added darray::shrink_to_fit()
-rw-r--r--include/jau/cow_darray.hpp33
-rw-r--r--include/jau/cow_iterator.hpp4
-rw-r--r--include/jau/darray.hpp116
-rw-r--r--include/jau/type_traits_queries.hpp41
-rw-r--r--test/test_cow_darray_perf01.cpp39
-rw-r--r--test/test_darray_01.cpp8
-rw-r--r--test/test_datatype01.hpp79
7 files changed, 249 insertions, 71 deletions
diff --git a/include/jau/cow_darray.hpp b/include/jau/cow_darray.hpp
index a5d6924..7b2df44 100644
--- a/include/jau/cow_darray.hpp
+++ b/include/jau/cow_darray.hpp
@@ -101,30 +101,29 @@ namespace jau {
* 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>
- * <p>
- * Non-Type Template Parameter <code>use_memmove</code> can be overriden by the user
- * and has its default value <code>std::is_trivially_copyable_v<Value_type></code>.<br>
- * The default value has been chosen with care, see C++ Standard section 6.9 Types <i>trivially copyable</i>.<br>
- * However, one can set <code>use_memmove</code> to true even without the value_type being <i>trivially copyable</i>,
- * as long certain memory side-effects can be excluded (TBD).
- * </p>
+ *
+ * @anchor cow_darray_ntt_params
+ * ### Non-Type Template Parameter controlling Value_type memory
+ * See @ref darray_ntt_params.
+ * #### `use_memmove`
+ * `use_memmove` see @ref darray_memmove.
+ * #### `use_secmem`
+ * `use_secmem` see @ref darray_secmem.
+ *
* 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::darray
+ * @see @ref darray_ntt_params
* @see jau::cow_ro_iterator
* @see jau::for_each_fidelity
* @see jau::cow_rw_iterator
* @see jau::cow_rw_iterator::write_back()
*/
template <typename Value_type, typename Alloc_type = jau::callocator<Value_type>, typename Size_type = jau::nsize_t,
- bool use_memmove = std::is_trivially_copyable_v<Value_type>,
- bool use_realloc = std::is_base_of_v<jau::callocator<Value_type>, Alloc_type>,
- bool sec_mem = false
+ bool use_memmove = std::is_trivially_copyable_v<Value_type> || is_container_memmove_compliant_v<Value_type>,
+ bool use_secmem = is_enforcing_secmem_v<Value_type>
>
class cow_darray
{
@@ -133,8 +132,8 @@ namespace jau {
constexpr static const float DEFAULT_GROWTH_FACTOR = 1.618f;
constexpr static const bool uses_memmove = use_memmove;
- constexpr static const bool uses_realloc = use_realloc && use_memmove;
- constexpr static const bool uses_secmem = sec_mem;
+ constexpr static const bool uses_secmem = use_secmem;
+ constexpr static const bool uses_realloc = use_memmove && std::is_base_of_v<jau::callocator<Value_type>, Alloc_type>;
// typedefs' for C++ named requirements: Container
@@ -149,7 +148,7 @@ namespace jau {
typedef darray<value_type, allocator_type,
size_type,
- use_memmove, use_realloc, sec_mem> storage_t;
+ use_memmove, use_secmem> storage_t;
typedef std::shared_ptr<storage_t> storage_ref_t;
/** Used to determine whether this type is a darray or has a darray, see ::is_darray_type<T> */
@@ -157,7 +156,7 @@ namespace jau {
typedef cow_darray<value_type, allocator_type,
size_type, use_memmove,
- use_realloc, sec_mem> cow_container_t;
+ use_secmem> cow_container_t;
/**
* Immutable, read-only const_iterator, lock-free,
diff --git a/include/jau/cow_iterator.hpp b/include/jau/cow_iterator.hpp
index ebc60af..ed09a61 100644
--- a/include/jau/cow_iterator.hpp
+++ b/include/jau/cow_iterator.hpp
@@ -82,7 +82,7 @@ namespace jau {
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, bool, bool, bool> friend class cow_darray;
+ template<typename, typename, typename, bool, bool> friend class cow_darray;
template<typename, typename> friend class cow_vector;
public:
@@ -649,7 +649,7 @@ namespace jau {
template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
class cow_ro_iterator {
friend cow_rw_iterator<Storage_type, Storage_ref_type, CoW_container>;
- template<typename, typename, typename, bool, bool, bool> friend class cow_darray;
+ template<typename, typename, typename, bool, bool> friend class cow_darray;
template<typename, typename> friend class cow_vector;
public:
diff --git a/include/jau/darray.hpp b/include/jau/darray.hpp
index 7c85ae1..6cddd93 100644
--- a/include/jau/darray.hpp
+++ b/include/jau/darray.hpp
@@ -85,18 +85,51 @@ namespace jau {
* <li>Constructs and destructs value_type via <i>placement new</i> within the pre-allocated array capacity. Latter is managed via allocator_type.</li>
* </ul>
* </p>
- * <p>
- * Non-Type Template Parameter <code>use_memmove</code> can be overriden by the user
- * and has its default value <code>std::is_trivially_copyable_v<Value_type></code>.<br>
- * The default value has been chosen with care, see C++ Standard section 6.9 Types <i>trivially copyable</i>.<br>
- * However, one can set <code>use_memmove</code> to true even without the value_type being <i>trivially copyable</i>,
- * as long certain memory side-effects can be excluded (TBD).
- * </p>
+ *
+ * @anchor darray_ntt_params
+ * ### Non-Type Template Parameter controlling Value_type memory
+ * @anchor darray_memmove
+ * #### `use_memmove`
+ * `use_memmove` can be overriden and defaults to `std::is_trivially_copyable_v<Value_type>`.
+ *
+ * The default value has been chosen with care, see C++ Standard section 6.9 Types *trivially copyable*.
+ * However, since the destructor is not being called when using `memmove` within this container,
+ * the requirements are more relaxed, see below.
+ *
+ * `memmove` will be used only to move an object in memory,
+ * where this container controls the creation and destruction.
+ * - We can't `memmove` one or more object into this container, even with an `rvalue` reference.
+ * The `rvalue`'s destructor will be called and potential acquired resources were lost.
+ * - We can move it around within this container, i.e. when growing or shrinking the array,
+ * or when earsing an object in the middle or even when moving out to the user.
+ *
+ * Relaxed requirements for `use_memmove` are:
+ * - Not using inner class pointer to inner class fields or methods (like launching a thread).
+ * - TBD ???
+ *
+ * Since element pointer and iterator are always invalidated for container after storage mutation,
+ * above constraints are not really anything novel and go along with normal std::vector.
+ *
+ * Users may include `typedef container_memmove_compliant` in their Value_type class
+ * to enforce `use_memmove` as follows:
+ * - `typedef std::true_type container_memmove_compliant;`
+ *
+ * @anchor darray_secmem
+ * #### `use_secmem`
+ * `use_secmem` can be overriden and defaults to `false`.
+ *
+ * `use_secmem`, if enabled, ensures that the underlying memory will be zeroed out
+ * after use and element erasure.
+ *
+ * Users may include `typedef enforce_secmem` in their Value_type class
+ * to enforce `use_secmem` as follows:
+ * - `typedef std::true_type enforce_secmem;`
+ *
+ * @see cow_darray
*/
template <typename Value_type, typename Alloc_type = jau::callocator<Value_type>, typename Size_type = jau::nsize_t,
- bool use_memmove = std::is_trivially_copyable_v<Value_type>,
- bool use_realloc = std::is_base_of_v<jau::callocator<Value_type>, Alloc_type>,
- bool sec_mem = false
+ bool use_memmove = std::is_trivially_copyable_v<Value_type> || is_container_memmove_compliant_v<Value_type>,
+ bool use_secmem = is_enforcing_secmem_v<Value_type>
>
class darray
{
@@ -105,8 +138,8 @@ namespace jau {
constexpr static const float DEFAULT_GROWTH_FACTOR = 1.618f;
constexpr static const bool uses_memmove = use_memmove;
- constexpr static const bool uses_realloc = use_realloc && use_memmove;
- constexpr static const bool uses_secmem = sec_mem;
+ constexpr static const bool uses_secmem = use_secmem;
+ constexpr static const bool uses_realloc = use_memmove && std::is_base_of_v<jau::callocator<Value_type>, Alloc_type>;
// typedefs' for C++ named requirements: Container
@@ -212,6 +245,11 @@ namespace jau {
}
}
+ constexpr void clear_iterator() noexcept {
+ begin_ = nullptr;
+ end_ = nullptr;
+ storage_end_ = nullptr;
+ }
constexpr void set_iterator(pointer new_storage_, difference_type size_, difference_type capacity_) noexcept {
begin_ = new_storage_;
@@ -302,7 +340,7 @@ namespace jau {
return dest;
}
- constexpr void grow_storage_move(const size_type new_capacity) {
+ constexpr void realloc_storage_move(const size_type new_capacity) {
if constexpr ( !uses_memmove ) {
pointer new_storage = allocStore(new_capacity);
{
@@ -320,15 +358,27 @@ namespace jau {
set_iterator(new_storage, size(), new_capacity);
} else {
pointer new_storage = allocStore(new_capacity);
- memcpy(reinterpret_cast<void*>(const_cast<pointer_mutable>(new_storage)),
- reinterpret_cast<const void*>(begin_), (uint8_t*)end_-(uint8_t*)begin_); // we can simply copy the memory over, also no overlap
-
+ memmove(reinterpret_cast<void*>(const_cast<pointer_mutable>(new_storage)),
+ reinterpret_cast<const void*>(begin_), (uint8_t*)end_-(uint8_t*)begin_); // we can simply copy the memory over, also no overlap
freeStore();
set_iterator(new_storage, size(), new_capacity);
}
}
+ constexpr void grow_storage_move(const size_type new_capacity) {
+ /**
+ * Determine a grown_capacity, which is at least
+ * - MIN_SIZE_AT_GROW
+ * - old_capacity * growth_factor ..
+ */
+ const size_type old_capacity = capacity();
+ const size_type grown_capacity = std::max<size_type>(
+ std::max<size_type>( MIN_SIZE_AT_GROW, new_capacity ),
+ std::max<size_type>( new_capacity, static_cast<size_type>(old_capacity * growth_factor_ + 0.5f) )
+ );
+ realloc_storage_move( grown_capacity );
+ }
constexpr void grow_storage_move() {
- grow_storage_move( get_grown_capacity() );
+ realloc_storage_move( get_grown_capacity() );
}
constexpr void move_elements(iterator dest, const_iterator first, const difference_type count) noexcept {
@@ -478,7 +528,7 @@ namespace jau {
DARRAY_PRINTF("ctor move0: this %s\n", get_info().c_str());
DARRAY_PRINTF("ctor move0: x %s\n", x.get_info().c_str());
// Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!
- explicit_bzero((void*)&x, sizeof(x));
+ x.clear_iterator();
}
constexpr explicit darray(darray && x, const float growth_factor, const allocator_type& alloc) noexcept
@@ -488,14 +538,7 @@ namespace jau {
DARRAY_PRINTF("ctor move1: this %s\n", get_info().c_str());
DARRAY_PRINTF("ctor move1: x %s\n", x.get_info().c_str());
// Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!
-#if 1
- explicit_bzero((void*)&x, sizeof(x));
-#else
- x.begin_ = nullptr;
- x.end_ = nullptr;
- x.storage_end_ = nullptr;
- x.growth_factor_ = 0.0;
-#endif
+ x.clear_iterator();
}
/**
@@ -513,7 +556,7 @@ namespace jau {
growth_factor_ = std::move( x.growth_factor_ );
// Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!
- explicit_bzero((void*)&x, sizeof(x));
+ x.clear_iterator();
}
DARRAY_PRINTF("assignment move.X: this %s\n", get_info().c_str());
DARRAY_PRINTF("assignment move.X: x %s\n", x.get_info().c_str());
@@ -753,7 +796,20 @@ namespace jau {
grow_storage_move(new_capacity);
}
}
-
+
+ /**
+ * Like std::vector::shrink_to_fit(), but ensured `constexpr`.
+ *
+ * If capacity() > size(), reallocate storage to size().
+ */
+ constexpr void shrink_to_fit() {
+ const size_type size_ = size();
+ const size_type capacity_ = capacity();
+ if( capacity_ > size_ ) {
+ realloc_storage_move(size_);
+ }
+ }
+
/**
* Like std::vector::assign()
* @tparam InputIt foreign input-iterator to range of value_type [first, last)
@@ -1142,10 +1198,10 @@ namespace jau {
difference_type cap_ = (storage_end_-begin_);
difference_type size_ = (end_-begin_);
std::string res("darray[this "+jau::to_hexstring(this)+
- ", size "+std::to_string(size_)+"/"+std::to_string(cap_)+
+ ", size "+std::to_string(size_)+" / "+std::to_string(cap_)+
", growth "+std::to_string(growth_factor_)+
", uses[mmm "+std::to_string(uses_memmove)+
- ", ralloc "+std::to_string(uses_realloc)+
+ ", realloc "+std::to_string(uses_realloc)+
", smem "+std::to_string(uses_secmem)+
"], begin "+jau::to_hexstring(begin_)+
", end "+jau::to_hexstring(end_)+
diff --git a/include/jau/type_traits_queries.hpp b/include/jau/type_traits_queries.hpp
index d2db3db..010e3f2 100644
--- a/include/jau/type_traits_queries.hpp
+++ b/include/jau/type_traits_queries.hpp
@@ -228,6 +228,47 @@ namespace jau {
// *************************************************
*/
+ // Author: Sven Gothel
+
+ /**
+ * <code>template< class T > is_container_memmove_compliant<T>::value</code> compile-time Type Trait,
+ * determining whether the given template class claims to be container memmove compliant, see @Ref darray_memmove.
+ */
+ template< class, class = void >
+ struct is_container_memmove_compliant : std::false_type { };
+
+ /**
+ * <code>template< class T > is_container_memmove_compliant<T>::value</code> compile-time Type Trait,
+ * determining whether the given template class claims to be container memmove compliant, see @Ref darray_memmove.
+ */
+ template< class T >
+ struct is_container_memmove_compliant<T, std::void_t<typename T::container_memmove_compliant>> : T::container_memmove_compliant { };
+
+ template <typename T> inline constexpr bool is_container_memmove_compliant_v = is_container_memmove_compliant<T>::value;
+
+ /**
+ * <code>template< class T > is_enforcing_secmem<T>::value</code> compile-time Type Trait,
+ * determining whether the given template class enforces secmem, see @Ref darray_secmem.
+ */
+ template< class, class = void >
+ struct is_enforcing_secmem : std::false_type { };
+
+ /**
+ * <code>template< class T > is_enforcing_secmem<T>::value</code> compile-time Type Trait,
+ * determining whether the given template class enforces secmem, see @Ref darray_secmem.
+ */
+ template< class T >
+ struct is_enforcing_secmem<T, std::void_t<typename T::enforce_secmem>> : T::enforce_secmem { };
+
+ template <typename T> inline constexpr bool is_enforcing_secmem_v = is_enforcing_secmem<T>::value;
+
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
// Author: firda @ stackoverflow (posted the following there)
// Location: https://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions/25448020#25448020
#if 0
diff --git a/test/test_cow_darray_perf01.cpp b/test/test_cow_darray_perf01.cpp
index ca121e5..81e5743 100644
--- a/test/test_cow_darray_perf01.cpp
+++ b/test/test_cow_darray_perf01.cpp
@@ -59,12 +59,13 @@ template< class Cont >
static void print_container_info(const std::string& type_id, const Cont &c,
std::enable_if_t< jau::is_darray_type<Cont>::value, bool> = true )
{
- printf("\nContainer Type %s (a darray, a cow %d):\n - Uses memcpy %d (trivially_copyable %d); realloc %d; base_of jau::callocator %d; size %d bytes\n",
+ printf("\nContainer Type %s (a darray, a cow %d):\n - Uses memmove %d (trivially_copyable %d); realloc %d; base_of jau::callocator %d; secmem %d; size %d bytes\n",
type_id.c_str(), jau::is_cow_type<Cont>::value,
Cont::uses_memmove,
std::is_trivially_copyable<typename Cont::value_type>::value,
Cont::uses_realloc,
std::is_base_of<jau::callocator<typename Cont::value_type>, typename Cont::allocator_type>::value,
+ Cont::uses_secmem,
(int)sizeof(c));
}
@@ -608,18 +609,18 @@ TEST_CASE( "Memory Footprint 01 - Fill Sequential and List", "[datatype][footpri
}
footprint_fillseq_list_itr< std::vector<DataType01, counting_allocator<DataType01>>, std::size_t>("stdvec_def_empty_", false);
footprint_fillseq_list_itr< jau::darray<DataType01, counting_callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("darray_def_empty_", false);
- footprint_fillseq_list_itr< jau::darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("darray_mmm_empty_", false);
+ footprint_fillseq_list_itr< jau::darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("darray_mmm_empty_", false);
footprint_fillseq_list_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t>("cowstdvec_def_empty_", false);
footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("cowdarray_def_empty_", false);
- footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("cowdarray_mmm_empty_", false);
+ footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("cowdarray_mmm_empty_", false);
#if RUN_RESERVE_BENCHMARK
footprint_fillseq_list_itr< std::vector<DataType01, counting_allocator<DataType01>>, std::size_t>("stdvec_def_rserv", true);
footprint_fillseq_list_itr< jau::darray<DataType01, counting_callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("darray_def_rserv", true);
- footprint_fillseq_list_itr< jau::darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("darray_mmm_rserv", true);
+ footprint_fillseq_list_itr< jau::darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("darray_mmm_rserv", true);
footprint_fillseq_list_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t>("cowstdvec_def_rserv", true);
footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("cowdarray_def_rserv", true);
- footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("cowdarray_mmm_rserv", true);
+ footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("cowdarray_mmm_rserv", true);
#endif
}
@@ -629,11 +630,11 @@ TEST_CASE( "Perf Test 01 - Fill Sequential and List, empty and reserve", "[datat
// benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_empty_itr", "darray_empty_", false);
benchmark_fillseq_list_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_def_empty_itr", "stdvec_empty_", false);
benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_empty_itr", "darray_empty_", false);
- benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_empty_itr", "darray_empty_", false);
+ benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_empty_itr", "darray_empty_", false);
#if RUN_RESERVE_BENCHMARK
benchmark_fillseq_list_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_def_rserv_itr", "stdvec_rserv", true);
benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_rserv_itr", "darray_rserv", true);
- benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_rserv_itr", "darray_rserv", true);
+ benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_rserv_itr", "darray_rserv", true);
#endif
return;
}
@@ -641,22 +642,22 @@ TEST_CASE( "Perf Test 01 - Fill Sequential and List, empty and reserve", "[datat
benchmark_fillseq_list_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_def_empty_itr", "stdvec_empty_", false);
benchmark_fillseq_list_idx< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_empty_idx", "darray_empty_", false);
- benchmark_fillseq_list_idx< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_empty_idx", "darray_empty_", false);
+ benchmark_fillseq_list_idx< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_empty_idx", "darray_empty_", false);
benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_empty_itr", "darray_empty_", false);
- benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_empty_itr", "darray_empty_", false);
+ benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_empty_itr", "darray_empty_", false);
benchmark_fillseq_list_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_def_empty_itr", "cowstdvec_empty_", false);
benchmark_fillseq_list_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("COW_DArray_def_empty_itr", "cowdarray_empty_", false);
- benchmark_fillseq_list_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("COW_DArray_mmm_empty_itr", "cowdarray_empty_", false);
+ benchmark_fillseq_list_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("COW_DArray_mmm_empty_itr", "cowdarray_empty_", false);
#if RUN_RESERVE_BENCHMARK
benchmark_fillseq_list_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_def_rserv_itr", "stdvec_rserv", true);
benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_rserv_itr", "darray_rserv", true);
- benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_rserv_itr", "darray_rserv", true);
+ benchmark_fillseq_list_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_rserv_itr", "darray_rserv", true);
benchmark_fillseq_list_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_def_rserv_itr", "cowstdvec_rserv", true);
benchmark_fillseq_list_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, std::size_t>("COW_DArray_def_rserv_itr", "cowdarray_rserv", true);
- benchmark_fillseq_list_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, std::size_t>("COW_DArray_mmm_rserv_itr", "cowdarray_rserv", true);
+ benchmark_fillseq_list_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, std::size_t>("COW_DArray_mmm_rserv_itr", "cowdarray_rserv", true);
#endif
}
@@ -664,11 +665,11 @@ TEST_CASE( "Perf Test 02 - Fill Unique and List, empty and reserve", "[datatype]
if( catch_perf_analysis ) {
benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_def_empty_itr", "cowstdvec_empty_", false);
benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("COW_DArray_def_empty_itr", "cowdarray_empty_", false);
- benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("COW_DArray_mmm_empty_itr", "cowdarray_empty_", false);
+ benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("COW_DArray_mmm_empty_itr", "cowdarray_empty_", false);
#if RUN_RESERVE_BENCHMARK
benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_def_rserv_itr", "cowstdvec_rserv", true);
benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("COW_DArray_def_rserv_itr", "cowdarray_rserv", true);
- benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("COW_DArray_mmm_rserv_itr", "cowdarray_rserv", true);
+ benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("COW_DArray_mmm_rserv_itr", "cowdarray_rserv", true);
#endif
return;
}
@@ -676,22 +677,22 @@ TEST_CASE( "Perf Test 02 - Fill Unique and List, empty and reserve", "[datatype]
benchmark_fillunique_find_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_def_empty_itr", "stdvec_empty_", false);
benchmark_fillunique_find_idx< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_empty_idx", "darray_empty_", false);
- benchmark_fillunique_find_idx< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_empty_idx", "darray_empty_", false);
+ benchmark_fillunique_find_idx< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_empty_idx", "darray_empty_", false);
benchmark_fillunique_find_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_empty_itr", "darray_empty_", false);
- benchmark_fillunique_find_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_empty_itr", "darray_empty_", false);
+ benchmark_fillunique_find_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_empty_itr", "darray_empty_", false);
benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_def_empty_itr", "cowstdvec_empty_", false);
benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("COW_DArray_def_empty_itr", "cowdarray_empty_", false);
- benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("COW_DArray_mmm_empty_itr", "cowdarray_empty_", false);
+ benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("COW_DArray_mmm_empty_itr", "cowdarray_empty_", false);
#if RUN_RESERVE_BENCHMARK
benchmark_fillunique_find_itr< std::vector<DataType01, std::allocator<DataType01>>, std::size_t>("STD_Vector_def_rserv_itr", "stdvec_rserv", true);
benchmark_fillunique_find_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("JAU_DArray_def_rserv_itr", "darray_rserv", true);
- benchmark_fillunique_find_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("JAU_DArray_mmm_rserv_itr", "darray_rserv", true);
+ benchmark_fillunique_find_itr< jau::darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("JAU_DArray_mmm_rserv_itr", "darray_rserv", true);
benchmark_fillunique_find_itr< jau::cow_vector<DataType01, std::allocator<DataType01>>, std::size_t>("COW_Vector_def_rserv_itr", "cowstdvec_rserv", true);
benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t>, jau::nsize_t>("COW_DArray_def_rserv_itr", "cowdarray_rserv", true);
- benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true, true>, jau::nsize_t>("COW_DArray_mmm_rserv_itr", "cowdarray_rserv", true);
+ benchmark_fillunique_find_itr< jau::cow_darray<DataType01, jau::callocator<DataType01>, jau::nsize_t, true /* memmove */>, jau::nsize_t>("COW_DArray_mmm_rserv_itr", "cowdarray_rserv", true);
#endif
}
diff --git a/test/test_darray_01.cpp b/test/test_darray_01.cpp
index 3ba4af3..cfba683 100644
--- a/test/test_darray_01.cpp
+++ b/test/test_darray_01.cpp
@@ -122,7 +122,7 @@ TEST_CASE( "JAU DArray Test 02 - jau::darray immutable type (const)", "[const][j
/**********************************************************************************************************************************************/
template<class Payload>
-using SharedPayloadListMemMove = jau::darray<std::shared_ptr<Payload>, jau::callocator<std::shared_ptr<Payload>>, jau::nsize_t, true /* use_memmove */, true /* use_realloc */>;
+using SharedPayloadListMemMove = jau::darray<std::shared_ptr<Payload>, jau::callocator<std::shared_ptr<Payload>>, jau::nsize_t, true /* use_memmove */>;
// JAU_TYPENAME_CUE_ALL(SharedPayloadListMemMove)
template<class Payload>
@@ -172,7 +172,7 @@ struct NamedSharedPayloadListMemMove {
// JAU_TYPENAME_CUE_ALL(NamedSharedPayloadListMemMove)
template<class Payload>
-using PayloadListMemMove = jau::darray<Payload, jau::callocator<Payload>, jau::nsize_t, true /* use_memmove */, true /* use_realloc */>;
+using PayloadListMemMove = jau::darray<Payload, jau::callocator<Payload>, jau::nsize_t, true /* use_memmove */>;
// JAU_TYPENAME_CUE_ALL(PayloadListMemMove)
template<class Payload>
@@ -301,12 +301,13 @@ template< class Cont >
static void print_container_info(const std::string& type_id, const Cont &c,
std::enable_if_t< jau::is_darray_type<Cont>::value, bool> = true )
{
- printf("\nContainer Type %s (a darray, a cow %d):\n - Uses memcpy %d (trivially_copyable %d); realloc %d; base_of jau::callocator %d; size %d bytes\n",
+ printf("\nContainer Type %s (a darray, a cow %d):\n - Uses memmove %d (trivially_copyable %d); realloc %d; base_of jau::callocator %d; secmem %d; size %d bytes\n",
type_id.c_str(), jau::is_cow_type<Cont>::value,
Cont::uses_memmove,
std::is_trivially_copyable<typename Cont::value_type>::value,
Cont::uses_realloc,
std::is_base_of<jau::callocator<typename Cont::value_type>, typename Cont::allocator_type>::value,
+ Cont::uses_secmem,
(int)sizeof(c));
}
@@ -482,6 +483,7 @@ TEST_CASE( "JAU DArray Test 10 - jau::darray value_type behavior (type traits)",
testDArrayValueType<uint64_t>("uint64_t");
testDArrayValueType<Addr48Bit>("Addr48Bit");
testDArrayValueType<DataType01>("DataType01");
+ testDArrayValueType<DataType02_Memmove_Secmem>("DataType02");
testDArrayGattServiceCharacteristic();
}
diff --git a/test/test_datatype01.hpp b/test/test_datatype01.hpp
index 7ca34c1..f098e90 100644
--- a/test/test_datatype01.hpp
+++ b/test/test_datatype01.hpp
@@ -214,6 +214,85 @@ inline bool operator==(const DataType01& lhs, const DataType01& rhs) noexcept {
inline bool operator!=(const DataType01& lhs, const DataType01& rhs) noexcept
{ return !(lhs == rhs); }
+class DataType02_Memmove_Secmem {
+ public:
+ typedef std::true_type container_memmove_compliant;
+ typedef std::true_type enforce_secmem;
+
+ Addr48Bit address;
+ uint8_t type;
+
+ private:
+ jau::relaxed_atomic_size_t hash = 0; // default 0, cache
+
+ public:
+ DataType02_Memmove_Secmem(const Addr48Bit & address_, uint8_t type_)
+ : address(address_), type(type_) {}
+
+ DataType02_Memmove_Secmem(const uint64_t encoded) noexcept
+ : address(encoded), type(0) { }
+
+ constexpr DataType02_Memmove_Secmem() noexcept : address(), type{0} { }
+ DataType02_Memmove_Secmem(const DataType02_Memmove_Secmem &o) noexcept : address(o.address), type(o.type) { }
+ DataType02_Memmove_Secmem(DataType02_Memmove_Secmem &&o) noexcept {
+ address = std::move(o.address);
+ type = std::move(o.type);
+ }
+ constexpr DataType02_Memmove_Secmem& operator=(const DataType02_Memmove_Secmem &o) noexcept {
+ address = o.address;
+ type = o.type;
+ return *this;
+ }
+ DataType02_Memmove_Secmem& operator=(DataType02_Memmove_Secmem &&o) noexcept {
+ address = std::move(o.address);
+ type = std::move(o.type);
+ return *this;
+ }
+
+ int nop() const noexcept { return address.b[0]+1; }
+
+ std::size_t hash_code() const noexcept {
+ std::size_t h = hash;
+ if( 0 == h ) {
+ // 31 * x == (x << 5) - x
+ h = 31 + address.hash_code();
+ h = ((h << 5) - h) + type;
+ const_cast<DataType02_Memmove_Secmem *>(this)->hash = h;
+ // printf("hash.dataSet01 new %zu\n", h);
+ } else {
+ // printf("hash.dataSet01 *cache* %zu\n", h);
+ }
+ return h;
+ }
+
+ void clearHash() { hash = 0; }
+
+ constexpr_cxx20 std::string toString() const noexcept {
+ return "["+address.toString()+", "+std::to_string(type)+"]";
+ }
+#if 0
+ constexpr_cxx20 operator std::string() const noexcept {
+ return toString();
+ }
+#endif
+};
+JAU_TYPENAME_CUE_ALL(DataType02_Memmove_Secmem)
+
+std::ostream & operator << (std::ostream &out, const DataType02_Memmove_Secmem &a) {
+ out << a.toString();
+ return out;
+}
+
+inline bool operator==(const DataType02_Memmove_Secmem& lhs, const DataType02_Memmove_Secmem& rhs) noexcept {
+ if( &lhs == &rhs ) {
+ return true;
+ }
+ return lhs.address == rhs.address &&
+ lhs.type == rhs.type;
+}
+inline bool operator!=(const DataType02_Memmove_Secmem& lhs, const DataType02_Memmove_Secmem& rhs) noexcept
+{ return !(lhs == rhs); }
+
// injecting specialization of std::hash to namespace std of our types above
namespace std
{