diff options
author | Sven Gothel <[email protected]> | 2021-10-23 06:26:09 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-10-23 06:26:09 +0200 |
commit | aca6d33271b327b0a282f8059182ed80448d766d (patch) | |
tree | eab9b06150cd872632b78126e859beefcdee0c4d | |
parent | 1827dfe59d6bb179bc40e426de3ca4b42eb28eb4 (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.hpp | 33 | ||||
-rw-r--r-- | include/jau/cow_iterator.hpp | 4 | ||||
-rw-r--r-- | include/jau/darray.hpp | 116 | ||||
-rw-r--r-- | include/jau/type_traits_queries.hpp | 41 | ||||
-rw-r--r-- | test/test_cow_darray_perf01.cpp | 39 | ||||
-rw-r--r-- | test/test_darray_01.cpp | 8 | ||||
-rw-r--r-- | test/test_datatype01.hpp | 79 |
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 { |