From 322bf65400aa205d1ce89e0775df8fc2832ba8e4 Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Thu, 8 Aug 2024 17:16:37 -0400 Subject: [PATCH] Invariant gadget. --- CMakeLists.txt | 1 + Invariant.h | 44 ++++++++++++++++++++++++ Invariant.test/0.cc | 64 +++++++++++++++++++++++++++++++++++ Invariant.test/CMakeLists.txt | 1 + 4 files changed, 110 insertions(+) create mode 100644 Invariant.h create mode 100644 Invariant.test/0.cc create mode 100644 Invariant.test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index cd8d722..97ff2d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ add_subdirectory( Exception.test ) add_subdirectory( word_wrap.test ) add_subdirectory( string_algorithms.test ) add_subdirectory( template_for.test ) +add_subdirectory( Invariant.test ) add_subdirectory( tuplize_args.test ) add_subdirectory( Thread.test ) add_subdirectory( assertion.test ) diff --git a/Invariant.h b/Invariant.h new file mode 100644 index 0000000..dade8d3 --- /dev/null +++ b/Invariant.h @@ -0,0 +1,44 @@ +static_assert( __cplusplus > 2023'00 ); + +#pragma once + +#include + +#include + +namespace Alepha::Hydrogen ::detail:: Invariant_m +{ + inline namespace exports + { + template< typename T > + class Invariant + { + private: + const T *this_; + + void + check() const + { + assert( this_->invariant() ); + } + + public: + ~Invariant() + { + check(); + } + + explicit + Invariant( const T *const this_ ) + : this_( this_ ) + { + check(); + } + }; + } +} + +namespace Alepha::Hydrogen::inline exports::inline Invariant_m +{ + using namespace detail::Invariant_m::exports; +} diff --git a/Invariant.test/0.cc b/Invariant.test/0.cc new file mode 100644 index 0000000..187565b --- /dev/null +++ b/Invariant.test/0.cc @@ -0,0 +1,64 @@ +static_assert( __cplusplus > 2023'00 ); + +#include "../Invariant.h" + +#include +#include + +static auto init= Alepha::Utility::enroll <=[] +{ + using namespace Alepha::Testing::exports; + + "Invariant basic test"_test <=[] + { + struct ItIsFine {}; + + struct FakeVector + { + int size= 0; + int capacity= 0; + int *data= nullptr; + + bool + invariant() const + { + return true + and ( capacity >= size ) + and ( capacity < 10 ) + and ( capacity == 0 or data != nullptr ) + ; + } + + void + push_back( const int x ) + { + Alepha::Invariant inv{ this }; + + if( size == capacity ) + { + // Not fully exception safe, but just + // ignore that... + const int newCapacity= capacity * 2 + 1; + int *const data2= new int [ newCapacity ]; + if( capacity > 8 ) throw ItIsFine{}; + + std::copy( data, data + size, data2 ); + capacity= newCapacity; + delete [] data; + data= data2; + } + assert( size < capacity ); + data[ size++ ]= x; + } + }; + + FakeVector v; + + for( int i= 0; i < 4; ++i ) try + { + v.push_back( i ); + } + catch( const ItIsFine & ) {} // It's fine! + }; +}; + diff --git a/Invariant.test/CMakeLists.txt b/Invariant.test/CMakeLists.txt new file mode 100644 index 0000000..b099603 --- /dev/null +++ b/Invariant.test/CMakeLists.txt @@ -0,0 +1 @@ +unit_test( 0 )