diff --git a/include/etl/memory.h b/include/etl/memory.h index 5b59ce90..39ea6bbb 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -36,6 +36,7 @@ SOFTWARE. #include "type_traits.h" #include "iterator.h" #include "utility.h" +#include "nullptr.h" #include @@ -1232,44 +1233,52 @@ namespace etl typedef T* pointer; typedef T& reference; - ETL_CONSTEXPR unique_ptr() + //********************************* + ETL_CONSTEXPR unique_ptr() ETL_NOEXCEPT : p(nullptr) { } - ETL_CONSTEXPR explicit unique_ptr(pointer p_) + //********************************* + ETL_CONSTEXPR explicit unique_ptr(pointer p_) ETL_NOEXCEPT : p(p_) { } #if ETL_CPP11_SUPPORTED - unique_ptr(unique_ptr&& p_) + //********************************* + unique_ptr(unique_ptr&& p_) ETL_NOEXCEPT : p(p_.release()) { } #endif + //********************************* ~unique_ptr() { deleter(p); } - ETL_CONSTEXPR pointer get() const + //********************************* + ETL_CONSTEXPR pointer get() const ETL_NOEXCEPT { return p; } - TDeleter& get_deleter() + //********************************* + TDeleter& get_deleter() ETL_NOEXCEPT { return deleter; } - const TDeleter& get_deleter() const + //********************************* + const TDeleter& get_deleter() const ETL_NOEXCEPT { return deleter; } - pointer release() + //********************************* + pointer release() ETL_NOEXCEPT { pointer value = p; p = nullptr; @@ -1277,7 +1286,8 @@ namespace etl return value; } - void reset(pointer p_ = pointer()) + //********************************* + void reset(pointer p_ = pointer()) ETL_NOEXCEPT { assert(p_ != p); @@ -1286,25 +1296,31 @@ namespace etl deleter(value); } - void swap(unique_ptr& value) + //********************************* + void swap(unique_ptr& value) ETL_NOEXCEPT { + using ETL_OR_STD::swap; + swap(p, value.p); } - ETL_CONSTEXPR operator bool() const + //********************************* + ETL_CONSTEXPR operator bool() const ETL_NOEXCEPT { return (p != nullptr); } - unique_ptr& operator =(pointer p_) + //********************************* + unique_ptr& operator =(std::nullptr_t) ETL_NOEXCEPT { - reset(p_); + reset(nullptr); return *this; } #if ETL_CPP11_SUPPORTED - unique_ptr& operator =(unique_ptr&& p_) + //********************************* + unique_ptr& operator =(unique_ptr&& p_) ETL_NOEXCEPT { reset(p_.release()); @@ -1312,41 +1328,29 @@ namespace etl } #endif + //********************************* ETL_CONSTEXPR reference operator *() const { return *get(); } - ETL_CONSTEXPR pointer operator ->() const + //********************************* + ETL_CONSTEXPR pointer operator ->() const ETL_NOEXCEPT { return get(); } + //********************************* ETL_CONSTEXPR reference operator [](size_t i) const { - return get()[i]; - } - - ETL_CONSTEXPR bool operator== (const pointer p_) const - { - return p == p_; - } - - ETL_CONSTEXPR bool operator== (const unique_ptr& p_) const - { - return p == p_.p; - } - - ETL_CONSTEXPR bool operator< (const unique_ptr& p_) const - { - return p < p_.p; + return p[i]; } private: // Deleted. - unique_ptr(const unique_ptr&); - unique_ptr& operator =(const unique_ptr&); + unique_ptr(const unique_ptr&) ETL_DELETE; + unique_ptr& operator =(const unique_ptr&) ETL_DELETE; TDeleter deleter; @@ -1368,51 +1372,60 @@ namespace etl typedef T* pointer; typedef T& reference; - ETL_CONSTEXPR unique_ptr() + //********************************* + ETL_CONSTEXPR unique_ptr() ETL_NOEXCEPT : p(nullptr) { } - ETL_CONSTEXPR explicit unique_ptr(pointer p_) + //********************************* + ETL_CONSTEXPR explicit unique_ptr(pointer p_) ETL_NOEXCEPT : p(p_) { } #if ETL_CPP11_SUPPORTED - unique_ptr(unique_ptr&& p_) + //********************************* + unique_ptr(unique_ptr&& p_) ETL_NOEXCEPT : p(p_.release()) { } #endif + //********************************* ~unique_ptr() { deleter(p); } - ETL_CONSTEXPR pointer get() const + //********************************* + ETL_CONSTEXPR pointer get() const ETL_NOEXCEPT { return p; } - TDeleter& get_deleter() + //********************************* + TDeleter& get_deleter() ETL_NOEXCEPT { return deleter; } - const TDeleter& get_deleter() const + //********************************* + const TDeleter& get_deleter() const ETL_NOEXCEPT { return deleter; } - pointer release() + //********************************* + pointer release() ETL_NOEXCEPT { pointer value = p; p = nullptr; return value; } - void reset(pointer p_) + //********************************* + void reset(pointer p_) ETL_NOEXCEPT { assert(p_ != p); @@ -1421,25 +1434,23 @@ namespace etl delete[] value; } - void swap(unique_ptr& v) + //********************************* + void swap(unique_ptr& v) ETL_NOEXCEPT { + using ETL_OR_STD::swap; + swap(p, v.p); } - ETL_CONSTEXPR operator bool() const + //********************************* + ETL_CONSTEXPR operator bool() const ETL_NOEXCEPT { return (p != nullptr); } - unique_ptr& operator =(pointer p_) - { - reset(p_); - - return *this; - } - #if ETL_CPP11_SUPPORTED - unique_ptr& operator =(unique_ptr&& p_) + //********************************* + unique_ptr& operator =(unique_ptr&& p_) ETL_NOEXCEPT { reset(p_.release()); @@ -1447,41 +1458,29 @@ namespace etl } #endif + //********************************* ETL_CONSTEXPR reference operator *() const { return *p; } - ETL_CONSTEXPR pointer operator ->() const + //********************************* + ETL_CONSTEXPR pointer operator ->() const ETL_NOEXCEPT { return p; } + //********************************* ETL_CONSTEXPR reference operator [](size_t i) const { return p[i]; } - ETL_CONSTEXPR bool operator ==(const pointer p_) const - { - return (p == p_); - } - - ETL_CONSTEXPR bool operator ==(const unique_ptr& p_) const - { - return (p == p_.p); - } - - ETL_CONSTEXPR bool operator <(const unique_ptr& p_) const - { - return (p < p_.p); - } - private: // Deleted. - unique_ptr(const unique_ptr&); - unique_ptr& operator =(const unique_ptr&); + unique_ptr(const unique_ptr&) ETL_DELETE; + unique_ptr& operator =(const unique_ptr&) ETL_DELETE; TDeleter deleter; @@ -1489,6 +1488,113 @@ namespace etl }; } +//***************************************************************************** +// Global functions for unique_ptr +//***************************************************************************** +template +bool operator ==(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +{ + return lhs.get() == rhs.get(); +} + +//********************************* +template +bool operator <(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +{ + return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); +} + +//********************************* +template +bool operator <=(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +{ + return !(rhs < lhs); +} + +//********************************* +template +bool operator >(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +{ + return (rhs < lhs); +} + +//********************************* +template +bool operator >=(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +{ + return !(lhs < rhs); +} + +//********************************* +template +bool operator ==(const etl::unique_ptr&lhs, std::nullptr_t) +{ + return !lhs; +} + +//********************************* +template +bool operator ==(std::nullptr_t, const etl::unique_ptr&rhs) +{ + return !rhs; +} + +//********************************* +template +bool operator <(const etl::unique_ptr&lhs, std::nullptr_t) +{ + return etl::less::pointer>()(lhs.get(), nullptr); +} + +//********************************* +template +bool operator <(std::nullptr_t, const etl::unique_ptr& rhs) +{ + return etl::less::pointer>()(nullptr, rhs.get()); +} + +//********************************* +template +bool operator <=(const etl::unique_ptr&lhs, std::nullptr_t) +{ + return !(nullptr < lhs); +} + +//********************************* +template +bool operator <=(std::nullptr_t, const etl::unique_ptr& rhs) +{ + return !(rhs < nullptr); +} + +//********************************* +template +bool operator >(const etl::unique_ptr&lhs, std::nullptr_t) +{ + return nullptr < lhs; +} + +//********************************* +template +bool operator >(std::nullptr_t, const etl::unique_ptr& rhs) +{ + return rhs < nullptr; +} + +//********************************* +template +bool operator >=(const etl::unique_ptr&lhs, std::nullptr_t) +{ + return !(lhs < nullptr); +} + +//********************************* +template +bool operator >=(std::nullptr_t, const etl::unique_ptr& rhs) +{ + return !(nullptr < rhs); +} + namespace etl { //***************************************************************************** diff --git a/include/etl/platform.h b/include/etl/platform.h index 66291bd4..a00a434a 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -71,16 +71,21 @@ SOFTWARE. #define ETL_CONSTEXPR constexpr #define ETL_CONST_OR_CONSTEXPR constexpr #define ETL_DELETE = delete - #define ETL_NOEXCEPT noexcept - #define ETL_NOEXCEPT_EXPR(expression) noexcept(expression) #define ETL_EXPLICIT explicit + #if defined(ETL_EXCEPTIONS_DISABLED) + #define ETL_NOEXCEPT + #define ETL_NOEXCEPT_EXPR(expression) + #else + #define ETL_NOEXCEPT noexcept + #define ETL_NOEXCEPT_EXPR(expression) noexcept(expression) + #endif #else #define ETL_CONSTEXPR #define ETL_CONST_OR_CONSTEXPR const #define ETL_DELETE + #define ETL_EXPLICIT #define ETL_NOEXCEPT #define ETL_NOEXCEPT_EXPR(expression) - #define ETL_EXPLICIT #endif // C++14 diff --git a/include/etl/utility.h b/include/etl/utility.h index fa5f2d72..c736493b 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -46,20 +46,20 @@ namespace etl #if ETL_CPP11_SUPPORTED //****************************************************************************** template - constexpr typename etl::remove_reference::type&& move(T&& t) noexcept + constexpr typename etl::remove_reference::type&& move(T&& t) ETL_NOEXCEPT { return static_cast::type&&>(t); } //****************************************************************************** template - constexpr T&& forward(typename etl::remove_reference::type& t) noexcept + constexpr T&& forward(typename etl::remove_reference::type& t) ETL_NOEXCEPT { return static_cast(t); } template - constexpr T&& forward(typename etl::remove_reference::type&& t) noexcept + constexpr T&& forward(typename etl::remove_reference::type&& t) ETL_NOEXCEPT { return static_cast(t); } @@ -273,7 +273,7 @@ namespace etl object = new_value; return old_value; } - + template T exchange(T& object, const U& new_value) { diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 2b156022..2aabf552 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -37,6 +37,7 @@ SOFTWARE. #include #include #include +#include #include #include @@ -80,6 +81,33 @@ namespace return nullptr; } }; + + //*********************************** + template + struct NoDelete + { + NoDelete() + { + } + + void operator()(T* p) const + { + } + }; + + //*********************************** + template + struct NoDelete + { + NoDelete() + { + } + + template + void operator()(U* p) const + { + } + }; } namespace @@ -344,15 +372,15 @@ namespace } is_equal = (output_moveable[0] == moveable_t(0)) && - (output_moveable[1] == moveable_t(1)) && - (output_moveable[2] == moveable_t(2)) && - (output_moveable[3] == moveable_t(3)) && - (output_moveable[4] == moveable_t(4)) && - (output_moveable[5] == moveable_t(5)) && - (output_moveable[6] == moveable_t(6)) && - (output_moveable[7] == moveable_t(7)) && - (output_moveable[8] == moveable_t(8)) && - (output_moveable[9] == moveable_t(9)); + (output_moveable[1] == moveable_t(1)) && + (output_moveable[2] == moveable_t(2)) && + (output_moveable[3] == moveable_t(3)) && + (output_moveable[4] == moveable_t(4)) && + (output_moveable[5] == moveable_t(5)) && + (output_moveable[6] == moveable_t(6)) && + (output_moveable[7] == moveable_t(7)) && + (output_moveable[8] == moveable_t(8)) && + (output_moveable[9] == moveable_t(9)); CHECK(is_equal); etl::destroy(p, p + SIZE); @@ -372,15 +400,15 @@ namespace } is_equal = (output_moveable[0] == moveable_t(0)) && - (output_moveable[1] == moveable_t(1)) && - (output_moveable[2] == moveable_t(2)) && - (output_moveable[3] == moveable_t(3)) && - (output_moveable[4] == moveable_t(4)) && - (output_moveable[5] == moveable_t(5)) && - (output_moveable[6] == moveable_t(6)) && - (output_moveable[7] == moveable_t(7)) && - (output_moveable[8] == moveable_t(8)) && - (output_moveable[9] == moveable_t(9)); + (output_moveable[1] == moveable_t(1)) && + (output_moveable[2] == moveable_t(2)) && + (output_moveable[3] == moveable_t(3)) && + (output_moveable[4] == moveable_t(4)) && + (output_moveable[5] == moveable_t(5)) && + (output_moveable[6] == moveable_t(6)) && + (output_moveable[7] == moveable_t(7)) && + (output_moveable[8] == moveable_t(8)) && + (output_moveable[9] == moveable_t(9)); CHECK(is_equal); CHECK_EQUAL(SIZE, count); @@ -409,15 +437,15 @@ namespace } is_equal = (output_moveable[0] == moveable_t(0)) && - (output_moveable[1] == moveable_t(1)) && - (output_moveable[2] == moveable_t(2)) && - (output_moveable[3] == moveable_t(3)) && - (output_moveable[4] == moveable_t(4)) && - (output_moveable[5] == moveable_t(5)) && - (output_moveable[6] == moveable_t(6)) && - (output_moveable[7] == moveable_t(7)) && - (output_moveable[8] == moveable_t(8)) && - (output_moveable[9] == moveable_t(9)); + (output_moveable[1] == moveable_t(1)) && + (output_moveable[2] == moveable_t(2)) && + (output_moveable[3] == moveable_t(3)) && + (output_moveable[4] == moveable_t(4)) && + (output_moveable[5] == moveable_t(5)) && + (output_moveable[6] == moveable_t(6)) && + (output_moveable[7] == moveable_t(7)) && + (output_moveable[8] == moveable_t(8)) && + (output_moveable[9] == moveable_t(9)); CHECK(is_equal); etl::destroy(p, p + SIZE); @@ -437,15 +465,15 @@ namespace } is_equal = (output_moveable[0] == moveable_t(0)) && - (output_moveable[1] == moveable_t(1)) && - (output_moveable[2] == moveable_t(2)) && - (output_moveable[3] == moveable_t(3)) && - (output_moveable[4] == moveable_t(4)) && - (output_moveable[5] == moveable_t(5)) && - (output_moveable[6] == moveable_t(6)) && - (output_moveable[7] == moveable_t(7)) && - (output_moveable[8] == moveable_t(8)) && - (output_moveable[9] == moveable_t(9)); + (output_moveable[1] == moveable_t(1)) && + (output_moveable[2] == moveable_t(2)) && + (output_moveable[3] == moveable_t(3)) && + (output_moveable[4] == moveable_t(4)) && + (output_moveable[5] == moveable_t(5)) && + (output_moveable[6] == moveable_t(6)) && + (output_moveable[7] == moveable_t(7)) && + (output_moveable[8] == moveable_t(8)) && + (output_moveable[9] == moveable_t(9)); CHECK(is_equal); CHECK_EQUAL(SIZE, count); @@ -678,7 +706,7 @@ namespace etl::memory_clear(data); CHECK_EQUAL(0x00000000, data.d1); - CHECK_EQUAL(0x00, data.d2); + CHECK_EQUAL(0x00, data.d2); } //************************************************************************* @@ -741,7 +769,7 @@ namespace etl::memory_set(data, 0x5A); CHECK_EQUAL(0x5A5A5A5A, data.d1); - CHECK_EQUAL(0x5A, data.d2); + CHECK_EQUAL(0x5A, data.d2); } //************************************************************************* @@ -789,5 +817,230 @@ namespace CHECK_EQUAL(0x5A5A5A5A, data[2].d1); CHECK_EQUAL(0x5A, data[2].d2); } + + //************************************************************************* + TEST(test_unique_ptr_default_construction) + { + etl::unique_ptr up; + + CHECK(up.get() == nullptr); + CHECK(!bool(up)); + } + + //************************************************************************* + TEST(test_unique_ptr_from_pointer_construction) + { + etl::unique_ptr up(new int(1)); + + CHECK(up.get() != nullptr); + CHECK(bool(up)); + CHECK_EQUAL(1, *up); + } + + //************************************************************************* + TEST(test_unique_ptr_move_construction) + { + etl::unique_ptr up1(new int(1)); + etl::unique_ptr up2(std::move(up1)); + + CHECK(up1.get() == nullptr); + CHECK(!bool(up1)); + CHECK(up2.get() != nullptr); + CHECK(bool(up2)); + CHECK_EQUAL(1, *up2); + } + + //************************************************************************* + TEST(test_unique_ptr_release) + { + etl::unique_ptr up(new int); + + CHECK(up.release() != nullptr); + CHECK(!bool(up)); + } + + //************************************************************************* + TEST(test_unique_ptr_reset) + { + etl::unique_ptr up(new int(1)); + int* p = new int(2); + + CHECK_EQUAL(1, *up); + up.reset(p); + CHECK_EQUAL(2, *up); + } + + //************************************************************************* + TEST(test_unique_ptr_swap) + { + etl::unique_ptr up1(new int(1)); + etl::unique_ptr up2(new int(2)); + + up1.swap(up2); + + CHECK_EQUAL(2, *up1); + CHECK_EQUAL(1, *up2); + } + + //************************************************************************* + TEST(test_unique_ptr_from_nullptr_assignment) + { + etl::unique_ptr up(new int); + + int* p = new int(1); + up = nullptr; + + CHECK(up.get() == nullptr); + CHECK(!bool(up)); + } + + //************************************************************************* + TEST(test_unique_ptr_move_assignment) + { + etl::unique_ptr up1(new int(1)); + etl::unique_ptr up2(new int(2)); + + up1 = std::move(up2); + + CHECK(!bool(up2)); + CHECK_EQUAL(2, *up1); + } + + //************************************************************************* + TEST(test_unique_ptr_comparison_tests) + { + int* p1 = (int*)1U; + int* p2 = (int*)2U; + + etl::unique_ptr> up1(p1); + etl::unique_ptr> up2(p1); + etl::unique_ptr> up3(p2); + + CHECK(up1 == up2); + CHECK(!(up1 == up3)); + CHECK(!(up1 < up2)); + CHECK(up1 < up3); + CHECK(!(up3 <= up1)); + CHECK(up1 <= up2); + CHECK(up1 <= up3); + CHECK(!(up1 > up2)); + CHECK(up3 > up1); + CHECK(!(up1 >= up3)); + CHECK(up2 >= up1); + CHECK(up3 >= up1); + } + + //************************************************************************* + TEST(test_unique_ptr_from_array_pointer_construction) + { + etl::unique_ptr up(new int[4]); + std::iota(&up[0], &up[4], 0); + + CHECK(up.get() != nullptr); + CHECK(bool(up)); + CHECK_EQUAL(0, up[0]); + CHECK_EQUAL(1, up[1]); + CHECK_EQUAL(2, up[2]); + CHECK_EQUAL(3, up[3]); + } + + //************************************************************************* + TEST(test_unique_ptr_move_array_construction) + { + etl::unique_ptr up1(new int[4]); + std::iota(&up1[0], &up1[4], 0); + etl::unique_ptr up2(std::move(up1)); + + CHECK(up1.get() == nullptr); + CHECK(!bool(up1)); + CHECK(up2.get() != nullptr); + CHECK(bool(up2)); + CHECK_EQUAL(0, up2[0]); + CHECK_EQUAL(1, up2[1]); + CHECK_EQUAL(2, up2[2]); + CHECK_EQUAL(3, up2[3]); + } + + //************************************************************************* + TEST(test_unique_ptr_array_release) + { + etl::unique_ptr up(new int[4]); + std::iota(&up[0], &up[4], 0); + + CHECK(up.release() != nullptr); + CHECK(!bool(up)); + } + + //************************************************************************* + TEST(test_unique_ptr_array_reset) + { + etl::unique_ptr up(new int[4]); + std::iota(&up[0], &up[4], 0); + + int* p = new int[4]; + std::iota(p, p + 4, 4); + + CHECK_EQUAL(0, up[0]); + CHECK_EQUAL(1, up[1]); + CHECK_EQUAL(2, up[2]); + CHECK_EQUAL(3, up[3]); + up.reset(p); + CHECK_EQUAL(4, up[0]); + CHECK_EQUAL(5, up[1]); + CHECK_EQUAL(6, up[2]); + CHECK_EQUAL(7, up[3]); + } + + //************************************************************************* + TEST(test_unique_ptr_array_swap) + { + etl::unique_ptr up1(new int[4]); + std::iota(&up1[0], &up1[4], 0); + + etl::unique_ptr up2(new int[4]); + std::iota(&up2[0], &up2[4], 4); + + up1.swap(up2); + + CHECK_EQUAL(4, up1[0]); + CHECK_EQUAL(5, up1[1]); + CHECK_EQUAL(6, up1[2]); + CHECK_EQUAL(7, up1[3]); + + CHECK_EQUAL(0, up2[0]); + CHECK_EQUAL(1, up2[1]); + CHECK_EQUAL(2, up2[2]); + CHECK_EQUAL(3, up2[3]); + } + + //************************************************************************* + TEST(test_unique_ptr_array_from_nullptr_assignment) + { + etl::unique_ptr up(new int[4]); + + int* p = new int[4]; + up = nullptr; + + CHECK(up.get() == nullptr); + CHECK(!bool(up)); + } + + //************************************************************************* + TEST(test_unique_ptr_array_move_assignment) + { + etl::unique_ptr up1(new int[4]); + std::iota(&up1[0], &up1[4], 0); + + etl::unique_ptr up2(new int[4]); + std::iota(&up2[0], &up2[4], 4); + + up1 = std::move(up2); + + CHECK(!bool(up2)); + CHECK_EQUAL(4, up1[0]); + CHECK_EQUAL(5, up1[1]); + CHECK_EQUAL(6, up1[2]); + CHECK_EQUAL(7, up1[3]); + } }; }