Initial implementation

This commit is contained in:
John Wellbelove 2025-08-15 17:18:15 +01:00
parent f6fd44a096
commit 28d90aa80c
5 changed files with 491 additions and 69 deletions

View File

@ -34,8 +34,8 @@ SOFTWARE.
#include "platform.h"
#include "error_handler.h"
#include "exception.h"
#include "ETL_STATIC_ASSERT.h"
#include "unique_ptr.h"
#include "static_assert.h"
#include "memory.h"
#include "type_traits.h"
namespace etl
@ -61,128 +61,216 @@ namespace etl
public:
not_null_contains_null(string_type file_name_, numeric_type line_number_)
: delegate_exception(ETL_ERROR_TEXT("not_null:contains null", ETL_NOT_NULL_FILE_ID"A"), file_name_, line_number_)
: not_null_exception(ETL_ERROR_TEXT("not_null:contains null", ETL_NOT_NULL_FILE_ID"A"), file_name_, line_number_)
{
}
};
//***************************************************************************
// not_null
// Primary template
//***************************************************************************
template <typename T>
class not_null;
//***************************************************************************
// Specialisation for T*
// A container for pointers that are not allowed to be null.
//***************************************************************************
template <typename T>
class not_null<T*>
{
public:
//*********************************
/// Constructs a not_null from a pointer.
/// Asserts if the pointer is null.
//*********************************
explicit not_null(T* ptr_)
: ptr(ptr_)
{
ETL_ASSERT(ptr != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
ETL_ASSERT(ptr_ != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
}
not_null(const etl::not_null& other)
//*********************************
/// Copy constructor from a not_null pointer.
//*********************************
not_null(const etl::not_null<T*>& other)
: ptr(other.get())
{
}
not_null& operator =(const etl::not_null& other)
//*********************************
/// Assignment from a not_null.
//*********************************
not_null& operator =(const etl::not_null<T*>& rhs)
{
ptr = other.get();
ptr = rhs.get();
return *this;
}
not_null& operator =(T* ptr_)
//*********************************
/// Assignment from a pointer.
/// Asserts if the pointer is null.
//*********************************
not_null& operator =(T* rhs)
{
ETL_ASSERT(ptr_ != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
ETL_ASSERT_OR_RETURN_VALUE(rhs != ETL_NULLPTR, ETL_ERROR(not_null_contains_null), *this);
ptr = ptr_;
ptr = rhs;
return *this;
}
//*********************************
/// Gets the underlying pointer.
//*********************************
T* get() const
{
return ptr;
}
//*********************************
/// Implicit conversion to T*.
//*********************************
operator T*() const
{
return ptr;
}
typename etl::remove_pointer<T*>::type& operator*() const
{
return *ptr;
}
T operator->() const
{
return ptr;
}
private:
T* ptr;
};
// Partial specialisation for etl::unique_ptr
template <typename T, typename TDeleter>
class not_null<etl::unique_ptr<T, TDeleter>>
{
public:
explicit not_null(etl::unique_ptr<T, TDeleter>&& ptr_)
: ptr(etl::move(ptr_))
{
ETL_ASSERT(ptr != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
}
#if ETL_USING_CPP11
not_null& operator =(etl::unique_ptr<T, TDeleter>&& ptr_)
{
ETL_ASSERT(ptr_ != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
ptr = etl::move(ptr_);
return *this;
}
#endif
T* get() const
{
return ptr.get();
}
operator T*() const
{
return ptr.get();
}
//*********************************
/// Dereference operator.
//*********************************
T& operator*() const
{
return *ptr;
}
//*********************************
/// Arrow operator.
//*********************************
T* operator->() const
{
return ptr.get();
}
etl::unique_ptr<T, TDeleter>& unique()
{
return ptr;
}
const etl::unique_ptr<T, TDeleter>& unique() const
{
return ptr;
}
private:
/// The underlying pointer.
T* ptr;
};
//***************************************************************************
// Partial specialisation for etl::unique_ptr
// A container for unique_ptr that are not allowed to be null.
//***************************************************************************
template <typename T, typename TDeleter>
class not_null<etl::unique_ptr<T, TDeleter>>
{
private:
// The unique_ptr type.
typedef etl::unique_ptr<T, TDeleter> unique_ptr_type;
public:
//*********************************
/// Constructs a not_null from a unique_ptr.
/// Asserts if the unique_ptr is null.
//*********************************
explicit not_null(unique_ptr_type&& u_ptr_)
: u_ptr(etl::move(u_ptr_))
{
ETL_ASSERT(u_ptr.get() != ETL_NULLPTR, ETL_ERROR(not_null_contains_null));
}
#if ETL_USING_CPP11
//*********************************
/// Constructs a not_null from a unique_ptr.
//*********************************
not_null(etl::not_null<unique_ptr_type>&& other)
: u_ptr(etl::move(other.u_ptr))
{
}
//*********************************
/// Assign from a unique_ptr.
/// Asserts if the unique_ptr is null.
//*********************************
not_null& operator =(unique_ptr_type&& rhs)
{
ETL_ASSERT_OR_RETURN_VALUE(rhs.get() != ETL_NULLPTR, ETL_ERROR(not_null_contains_null), *this);
u_ptr = etl::move(rhs);
return *this;
}
//*********************************
/// Assign from a not_null.
//*********************************
not_null& operator =(etl::not_null<unique_ptr_type>&& rhs)
{
u_ptr = etl::move(rhs.u_ptr);
return *this;
}
#endif
//*********************************
/// Gets the underlying unique_ptr.
//*********************************
T* get() const
{
return u_ptr.get();
}
//*********************************
/// Implicit conversion to T*.
//*********************************
operator T*() const
{
return u_ptr.get();
}
etl::unique_ptr<T, TDeleter> ptr;
//*********************************
/// Dereference operator.
//*********************************
T& operator*() const
{
return *u_ptr;
}
//*********************************
/// Arrow operator.
//*********************************
T* operator->() const
{
return u_ptr.get();
}
//*********************************
/// Gets the underlying unique_ptr.
//*********************************
unique_ptr_type& unique()
{
return u_ptr;
}
//*********************************
/// Gets the underlying unique_ptr.
//*********************************
const unique_ptr_type& unique() const
{
return u_ptr;
}
private:
/// The underlying unique_ptr.
unique_ptr_type u_ptr;
};
}
#endif

View File

@ -0,0 +1,152 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
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 "unit_test_framework.h"
#include "etl/not_null.h"
namespace
{
SUITE(test_not_null_pointer)
{
//*************************************************************************
TEST(test_construct_from_non_null_pointer)
{
int value = 42;
etl::not_null<int*> nn(&value);
CHECK_EQUAL(&value, nn.get());
CHECK_EQUAL(42, *nn);
}
//*************************************************************************
TEST(test_copy_construct)
{
int value = 123;
etl::not_null<int*> nn1(&value);
etl::not_null<int*> nn2(nn1); // Copy constructor
CHECK_EQUAL(&value, nn2.get());
CHECK_EQUAL(123, *nn2);
}
//*************************************************************************
TEST(test_assign_from_pointer)
{
int value1 = 123;
etl::not_null<int*> nn1(&value1);
int value2 = 456;
nn1 = &value2;
CHECK_EQUAL(&value2, nn1.get());
CHECK_EQUAL(456, *nn1);
}
//*************************************************************************
TEST(test_assign_from_not_null)
{
int value1 = 123;
etl::not_null<int*> nn1(&value1);
int value2 = 456;
etl::not_null<int*> nn2(&value2);
nn1 = nn2;
CHECK_EQUAL(&value2, nn2.get());
CHECK_EQUAL(456, *nn2);
}
//*************************************************************************
TEST(test_implicit_conversion)
{
struct S
{
int x;
};
S s{77};
etl::not_null<S*> nn(&s);
S* raw = nn;
CHECK_EQUAL(&s, raw);
}
//*************************************************************************
TEST(test_arrow_operator)
{
struct S
{
int x;
int get() const
{
return x;
}
};
S s{77};
etl::not_null<S*> nn(&s);
CHECK_EQUAL(s.x, nn->x);
CHECK_EQUAL(s.get(), nn->get());
}
//*************************************************************************
TEST(test_dereference_operator)
{
struct S
{
int x;
int get() const
{
return x;
}
};
S s{77};
etl::not_null<S*> nn(&s);
CHECK_EQUAL(s.x, (*nn).x);
CHECK_EQUAL(s.get(), (*nn).get());
}
//*************************************************************************
TEST(test_construct_from_null_pointer_asserts)
{
CHECK_THROW(etl::not_null<int*> nn(nullptr), etl::not_null_contains_null);
}
//*************************************************************************
TEST(test_assign_null_pointer_asserts)
{
int value = 1;
etl::not_null<int*> nn(&value);
CHECK_THROW(nn = nullptr, etl::not_null_contains_null);
}
};
}

View File

@ -0,0 +1,174 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
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 "unit_test_framework.h"
#include "etl/not_null.h"
namespace
{
struct S
{
int x;
int get() const
{
return x;
}
};
SUITE(test_not_null_unique_pointer)
{
//*************************************************************************
TEST(test_construct_from_non_null_unique_ptr)
{
using up_t = etl::unique_ptr<int>;
up_t up(new int{ 123 });
etl::not_null<up_t> nn(etl::move(up));
CHECK_EQUAL(123, *nn);
CHECK_EQUAL(123, *nn.get());
}
//*************************************************************************
TEST(test_unique)
{
using up_t = etl::unique_ptr<int>;
up_t up1(new int{ 123 });
etl::not_null<up_t> nn(etl::move(up1));
up_t up2 = etl::move(nn.unique());
CHECK_EQUAL(123, *up2.get());
}
//*************************************************************************
TEST(test_unique_const)
{
using up_t = etl::unique_ptr<int>;
up_t up1(new int{ 123 });
const etl::not_null<up_t> nn(etl::move(up1));
const up_t& up2 = nn.unique();
CHECK_EQUAL(123, *up2.get());
}
//*************************************************************************
TEST(test_move_construct)
{
using up_t = etl::unique_ptr<int>;
up_t up(new int{ 123 });
etl::not_null<up_t> nn1(etl::move(up));
etl::not_null<up_t> nn2(etl::move(nn1)); // Move constructor
CHECK_TRUE(nn1.get() == nullptr);
CHECK_EQUAL(123, *nn2.get());
CHECK_EQUAL(123, *nn2);
}
//*************************************************************************
TEST(test_assign_from_unique_ptr)
{
using up_t = etl::unique_ptr<int>;
up_t up1(new int{ 123 });
etl::not_null<up_t> nn1(etl::move(up1));
using up_t = etl::unique_ptr<int>;
up_t up2(new int);
*up2 = 456;
nn1 = etl::move(up2);
CHECK_EQUAL(456, *nn1.get());
}
//*************************************************************************
TEST(test_assign_from_not_null)
{
using up_t = etl::unique_ptr<int>;
up_t up1(new int{ 123 });
etl::not_null<up_t> nn1(etl::move(up1));
up_t up2(new int{ 456 });
etl::not_null<up_t> nn2(etl::move(up2));
nn1 = etl::move(nn2);
CHECK_TRUE(nn2.get() == nullptr);
CHECK_EQUAL(456, *nn1.get());
}
//*************************************************************************
TEST(test_implicit_conversion)
{
using up_t = etl::unique_ptr<S>;
up_t up1(new S{ 123 });
etl::not_null<up_t> nn1(etl::move(up1));
S s = *nn1;
CHECK_EQUAL(123, s.x);
}
//*************************************************************************
TEST(test_arrow_operator)
{
S s{ 123 };
using up_t = etl::unique_ptr<S>;
up_t up1(new S{ 123 });
etl::not_null<up_t> nn1(etl::move(up1));
CHECK_EQUAL(s.x, nn1->x);
CHECK_EQUAL(s.get(), nn1->get());
}
//*************************************************************************
TEST(test_dereference_operator)
{
S s{ 123 };
using up_t = etl::unique_ptr<S>;
up_t up1(new S{ 123 });
etl::not_null<up_t> nn1(etl::move(up1));
CHECK_EQUAL(s.x, (*nn1).x);
CHECK_EQUAL(s.get(), (*nn1).get());
}
//*************************************************************************
TEST(test_construct_from_null_pointer_asserts)
{
using up_t = etl::unique_ptr<int>;
up_t up1(nullptr);
CHECK_THROW(etl::not_null<up_t> nn1(etl::move(up1)), etl::not_null_contains_null);
}
}
}

View File

@ -9472,6 +9472,8 @@
<ClCompile Include="..\test_math_functions.cpp" />
<ClCompile Include="..\test_message.cpp" />
<ClCompile Include="..\test_message_broker.cpp" />
<ClCompile Include="..\test_not_null_pointer.cpp" />
<ClCompile Include="..\test_not_null_unique_pointer.cpp" />
<ClCompile Include="..\test_poly_span_dynamic_extent.cpp" />
<ClCompile Include="..\test_poly_span_fixed_extent.cpp" />
<ClCompile Include="..\test_pseudo_moving_average.cpp" />

View File

@ -3701,6 +3701,12 @@
<ClCompile Include="..\test_rounded_integral_division.cpp">
<Filter>Tests\Maths</Filter>
</ClCompile>
<ClCompile Include="..\test_not_null_pointer.cpp">
<Filter>Tests\Misc</Filter>
</ClCompile>
<ClCompile Include="..\test_not_null_unique_pointer.cpp">
<Filter>Tests\Misc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">