From 1e6fc88ab92f476000bf59b1e9603a7c88421922 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 23 Feb 2017 23:12:48 +0000 Subject: [PATCH] memory algorithm updates --- src/memory.h | 74 +++---- test/test_memory.cpp | 449 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 480 insertions(+), 43 deletions(-) create mode 100644 test/test_memory.cpp diff --git a/src/memory.h b/src/memory.h index bf6b5185..1e05579e 100644 --- a/src/memory.h +++ b/src/memory.h @@ -91,9 +91,10 @@ namespace etl typename etl::enable_if::value_type>::value, TOutputIterator>::type uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count) { - std::fill(o_begin, o_end, value); count += std::distance(o_begin, o_end); + std::fill(o_begin, o_end, value); + return o_end; } @@ -108,13 +109,7 @@ namespace etl { count += std::distance(o_begin, o_end); - typedef typename std::iterator_traits::value_type value_type; - - while (o_begin != o_end) - { - ::new (static_cast(etl::addressof(*o_begin))) value_type(value); - ++o_begin; - } + etl::uninitialized_fill(o_begin, o_end, value); return o_end; } @@ -199,16 +194,7 @@ namespace etl typename etl::enable_if::value_type>::value, TOutputIterator>::type uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) { - typedef typename std::iterator_traits::value_type value_type; - - TOutputIterator o_end = o_begin; - - while (i_begin != i_end) - { - ::new (static_cast(etl::addressof(*o_end))) value_type(*i_begin); - ++i_begin; - ++o_end; - } + TOutputIterator o_end = etl::uninitialized_copy(i_begin, i_end, o_begin); count += std::distance(o_begin, o_end); @@ -244,7 +230,7 @@ namespace etl //***************************************************************************** template typename etl::enable_if::value, void>::type - construct_default_at(T* /*p*/) + create_default_at(T* /*p*/) { } @@ -254,7 +240,7 @@ namespace etl //***************************************************************************** template typename etl::enable_if::value, void>::type - construct_default_at(T* /*p*/, TCounter& count) + create_default_at(T* /*p*/, TCounter& count) { ++count; } @@ -265,7 +251,7 @@ namespace etl //***************************************************************************** template typename etl::enable_if::value, void>::type - construct_default_at(T* p) + create_default_at(T* p) { ::new (p) T; } @@ -276,7 +262,7 @@ namespace etl //***************************************************************************** template typename etl::enable_if::value, void>::type - construct_default_at(T* p, TCounter& count) + create_default_at(T* p, TCounter& count) { ::new (p) T; ++count; @@ -332,13 +318,7 @@ namespace etl { count += std::distance(o_begin, o_end); - typedef typename std::iterator_traits::value_type value_type; - - while (o_begin != o_end) - { - ::new (static_cast(etl::addressof(*o_begin))) value_type; - ++o_begin; - } + etl::uninitialized_default_construct(o_begin, o_end); } //***************************************************************************** @@ -408,7 +388,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - inline void construct_value_at(T* p) + inline void create_value_at(T* p) { ::new (p) T(); } @@ -418,7 +398,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - inline void construct_value_at(T* p, TCounter& count) + inline void create_value_at(T* p, TCounter& count) { ::new (p) T(); ++count; @@ -429,7 +409,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - inline void construct_copy_at(T* p, const T& value) + inline void create_copy_at(T* p, const T& value) { ::new (p) T(value); } @@ -439,7 +419,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - inline void construct_copy_at(T* p, const T& value, TCounter& count) + inline void create_copy_at(T* p, const T& value, TCounter& count) { ::new (p) T(value); ++count; @@ -450,7 +430,21 @@ namespace etl ///\ingroup memory //***************************************************************************** template - void uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) + typename etl::enable_if::value_type>::value, void>::type + uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) + { + typedef typename std::iterator_traits::value_type value_type; + + std::fill(o_begin, o_end, value_type()); + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template + typename etl::enable_if::value_type>::value, void>::type + uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) { typedef typename std::iterator_traits::value_type value_type; @@ -471,13 +465,7 @@ namespace etl { count += std::distance(o_begin, o_end); - typedef typename std::iterator_traits::value_type value_type; - - while (o_begin != o_end) - { - ::new (static_cast(etl::addressof(*o_begin))) value_type(); - ++o_begin; - } + etl::uninitialized_value_construct(o_begin, o_end); } //***************************************************************************** @@ -603,13 +591,13 @@ namespace etl typename etl::enable_if::value_type>::value, void>::type destroy(TIterator i_begin, TIterator i_end, TCounter& count) { + count -= std::distance(i_begin, i_end); + while (i_begin != i_end) { etl::destroy_at(etl::addressof(*i_begin)); ++i_begin; } - - count -= std::distance(i_begin, i_end); } //***************************************************************************** diff --git a/test/test_memory.cpp b/test/test_memory.cpp new file mode 100644 index 00000000..6cc2ee0d --- /dev/null +++ b/test/test_memory.cpp @@ -0,0 +1,449 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include + +#include "../src/memory.h" +#include "../src/debug_count.h" + +#include +#include +#include +#include +#include + +#include + +namespace +{ + typedef std::string non_trivial_t; + typedef uint32_t trivial_t; + + const size_t SIZE = 10; + + std::array test_data_non_trivial = + { + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "ten" + }; + + std::array test_data_trivial = + { + 0x11223344, 0x22334455, 0x33445566, 0x44556677, 0x55667788, + 0x66778899, 0x778899AA, 0x8899AABB, 0x99AABBCC, 0xAABBCCDD + }; + + non_trivial_t test_item_non_trivial("eleven"); + non_trivial_t test_item_non_trivial_null(""); + trivial_t test_item_trivial(0xBBCCDDEE); + + char buffer_non_trivial[sizeof(non_trivial_t) * SIZE]; + char buffer_trivial[sizeof(trivial_t) * SIZE]; + + non_trivial_t* output_non_trivial = reinterpret_cast(buffer_non_trivial); + trivial_t* output_trivial = reinterpret_cast(buffer_trivial); + + struct overloaded + { + overloaded* operator&() + { + return nullptr; + } + }; +} + +namespace +{ + SUITE(test_memory) + { + //************************************************************************* + TEST(test_addressof) + { + int i; + CHECK(&i == etl::addressof(i)); + + overloaded ol; + CHECK(&ol != etl::addressof(ol)); + CHECK(reinterpret_cast(&reinterpret_cast(ol)) == etl::addressof(ol)); + } + + //************************************************************************* + TEST(test_create_destroy_trivial) + { + char n[sizeof(trivial_t)]; + trivial_t* pn = reinterpret_cast(n); + + // Non count. + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_default_at(pn); + CHECK_EQUAL(0xFFFFFFFF, *pn); + etl::destroy_at(pn); + CHECK_EQUAL(0xFFFFFFFF, *pn); + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_value_at(pn); + CHECK_EQUAL(0x0000000, *pn); + etl::destroy_at(pn); + CHECK_EQUAL(0x0000000, *pn); + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_copy_at(pn, test_item_trivial); + CHECK_EQUAL(test_item_trivial, *pn); + etl::destroy_at(pn); + CHECK_EQUAL(test_item_trivial, *pn); + + // Count. + size_t count = 0; + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_default_at(pn, count); + CHECK_EQUAL(0xFFFFFFFF, *pn); + CHECK_EQUAL(1, count); + etl::destroy_at(pn, count); + CHECK_EQUAL(0xFFFFFFFF, *pn); + CHECK_EQUAL(0, count); + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_value_at(pn, count); + CHECK_EQUAL(0x0000000, *pn); + CHECK_EQUAL(1, count); + etl::destroy_at(pn, count); + CHECK_EQUAL(0x0000000, *pn); + CHECK_EQUAL(0, count); + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_copy_at(pn, test_item_trivial, count); + CHECK_EQUAL(test_item_trivial, *pn); + CHECK_EQUAL(1, count); + etl::destroy_at(pn, count); + CHECK_EQUAL(test_item_trivial, *pn); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_create_destroy_non_trivial) + { + char n[sizeof(non_trivial_t)]; + non_trivial_t* pn = reinterpret_cast(n); + + // Non count. + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_default_at(pn); + CHECK_EQUAL(test_item_non_trivial_null, *pn); + etl::destroy_at(pn); + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_value_at(pn); + CHECK_EQUAL(test_item_non_trivial_null, *pn); + etl::destroy_at(pn); + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_copy_at(pn, test_item_non_trivial); + CHECK_EQUAL(test_item_non_trivial, *pn); + etl::destroy_at(pn); + + // Count. + size_t count = 0; + + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_default_at(pn, count); + CHECK_EQUAL(test_item_non_trivial_null, *pn); + CHECK_EQUAL(1, count); + etl::destroy_at(pn, count); + CHECK_EQUAL(0, count); + + count = 0; + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_value_at(pn, count); + CHECK_EQUAL(test_item_non_trivial_null, *pn); + CHECK_EQUAL(1, count); + etl::destroy_at(pn, count); + CHECK_EQUAL(0, count); + + count = 0; + std::fill(std::begin(n), std::end(n), 0xFF); + etl::create_copy_at(pn, test_item_non_trivial, count); + CHECK_EQUAL(test_item_non_trivial, *pn); + CHECK_EQUAL(1, count); + etl::destroy_at(pn, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_fill_n_trivial) + { + // Also tests uninitialized_fill. + + // Non count. + trivial_t* p = reinterpret_cast(buffer_trivial); + + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0); + etl::uninitialized_fill_n(p, SIZE, test_item_trivial); + + trivial_t* result; + + result = std::find_if_not(output_trivial, output_trivial + SIZE, [](trivial_t i) { return i == test_item_trivial; }); + + CHECK(result == output_trivial + SIZE); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0); + etl::uninitialized_fill_n(p, SIZE, test_item_trivial, count); + + result = std::find_if_not(output_trivial, output_trivial + SIZE, [](trivial_t i) { return i == test_item_trivial; }); + + CHECK(result == output_trivial + SIZE); + CHECK_EQUAL(SIZE, count); + + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_fill_n_non_trivial) + { + // Also tests uninitialized_fill. + + // Non count. + non_trivial_t* p = reinterpret_cast(buffer_non_trivial); + + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0); + etl::uninitialized_fill_n(p, SIZE, test_item_non_trivial); + + non_trivial_t* result; + + result = std::find_if_not(output_non_trivial, output_non_trivial + SIZE, [](const non_trivial_t& i) { return i == test_item_non_trivial; }); + + CHECK(result == output_non_trivial + SIZE); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0); + etl::uninitialized_fill_n(p, SIZE, test_item_non_trivial, count); + + result = std::find_if_not(output_non_trivial, + output_non_trivial + SIZE, + [](non_trivial_t i) { return i == test_item_non_trivial; }); + + CHECK(result == output_non_trivial + SIZE); + CHECK_EQUAL(SIZE, count); + + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_copy_n_trivial) + { + // Also tests uninitialized_copy. + + bool is_equal; + + // Non count. + trivial_t* p = reinterpret_cast(buffer_trivial); + + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0); + etl::uninitialized_copy_n(test_data_trivial.begin(), SIZE, p); + + is_equal = std::equal(output_trivial, output_trivial + SIZE, test_data_trivial.begin()); + CHECK(is_equal); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0); + etl::uninitialized_copy_n(test_data_trivial.begin(), SIZE, p, count); + + is_equal = std::equal(output_trivial, output_trivial + SIZE, test_data_trivial.begin()); + CHECK(is_equal); + CHECK_EQUAL(SIZE, count); + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_copy_n_non_trivial) + { + // Also tests uninitialized_copy. + + bool is_equal; + + // Non count. + non_trivial_t* p = reinterpret_cast(buffer_non_trivial); + + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0); + etl::uninitialized_copy_n(test_data_non_trivial.begin(), SIZE, p); + + is_equal = std::equal(output_non_trivial, output_non_trivial + SIZE, test_data_non_trivial.begin()); + CHECK(is_equal); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0); + etl::uninitialized_copy_n(test_data_non_trivial.begin(), SIZE, p, count); + + is_equal = std::equal(output_non_trivial, output_non_trivial + SIZE, test_data_non_trivial.begin()); + CHECK(is_equal); + CHECK_EQUAL(SIZE, count); + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_default_construct_n_trivial) + { + // Also tests uninitialized_default_construct. + + // Non count. + trivial_t* p = reinterpret_cast(buffer_trivial); + + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0xFF); + etl::uninitialized_default_construct_n(p, SIZE); + + trivial_t* result; + + result = std::find_if_not(output_trivial, output_trivial + SIZE, [](trivial_t i) { return i == 0xFFFFFFFF; }); + + CHECK(result == output_trivial + SIZE); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0xFF); + etl::uninitialized_default_construct_n(p, SIZE, count); + + result = std::find_if_not(output_trivial, output_trivial + SIZE, [](trivial_t i) { return i == 0xFFFFFFFF; }); + + CHECK(result == output_trivial + SIZE); + CHECK_EQUAL(SIZE, count); + + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_default_construct_n_non_trivial) + { + // Also tests uninitialized_default_construct. + + // Non count. + non_trivial_t* p = reinterpret_cast(buffer_non_trivial); + + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0xFF); + etl::uninitialized_default_construct_n(p, SIZE); + + non_trivial_t* result; + + result = std::find_if_not(output_non_trivial, output_non_trivial + SIZE, [](non_trivial_t i) { return i == test_item_non_trivial_null; }); + + CHECK(result == output_non_trivial + SIZE); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0xFF); + etl::uninitialized_default_construct_n(p, SIZE, count); + + result = std::find_if_not(output_non_trivial, output_non_trivial + SIZE, [](non_trivial_t i) { return i == test_item_non_trivial_null; }); + + CHECK(result == output_non_trivial + SIZE); + CHECK_EQUAL(SIZE, count); + + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_value_construct_n_trivial) + { + // Also tests uninitialized_default_construct. + + // Non count. + trivial_t* p = reinterpret_cast(buffer_trivial); + + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0xFF); + etl::uninitialized_value_construct_n(p, SIZE); + + trivial_t* result; + + result = std::find_if_not(output_trivial, output_trivial + SIZE, [](trivial_t i) { return i == trivial_t(); }); + + CHECK(result == output_trivial + SIZE); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_trivial), std::end(buffer_trivial), 0xFF); + etl::uninitialized_value_construct_n(p, SIZE, count); + + result = std::find_if_not(output_trivial, output_trivial + SIZE, [](trivial_t i) { return i == trivial_t(); }); + + CHECK(result == output_trivial + SIZE); + CHECK_EQUAL(SIZE, count); + + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + + //************************************************************************* + TEST(test_uninitialized_value_construct_n_non_trivial) + { + // Also tests uninitialized_default_construct. + + // Non count. + non_trivial_t* p = reinterpret_cast(buffer_non_trivial); + + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0xFF); + etl::uninitialized_value_construct_n(p, SIZE); + + non_trivial_t* result; + + result = std::find_if_not(output_non_trivial, output_non_trivial + SIZE, [](non_trivial_t i) { return i == non_trivial_t(); }); + + CHECK(result == output_non_trivial + SIZE); + etl::destroy(p, p + SIZE); + + // Count. + size_t count = 0; + std::fill(std::begin(buffer_non_trivial), std::end(buffer_non_trivial), 0xFF); + etl::uninitialized_value_construct_n(p, SIZE, count); + + result = std::find_if_not(output_non_trivial, output_non_trivial + SIZE, [](non_trivial_t i) { return i == non_trivial_t(); }); + + CHECK(result == output_non_trivial + SIZE); + CHECK_EQUAL(SIZE, count); + + etl::destroy(p, p + SIZE, count); + CHECK_EQUAL(0, count); + } + }; +}