diff --git a/AutoRAII.h b/AutoRAII.h new file mode 100644 index 0000000..7c381a3 --- /dev/null +++ b/AutoRAII.h @@ -0,0 +1,91 @@ +static_assert( __cplusplus > 201700, "C++17 Required" ); + +#pragma once + +#include + +#include +#include + +#include + +namespace Alepha::Hydrogen +{ + inline namespace exports { inline namespace auto_raii {} } + + namespace detail::auto_raii + { + inline namespace exports + { + template< typename T, typename Dtor= std::function< void ( T ) > > + class AutoRAII : boost::noncopyable + { + private: + Dtor dtor; + T value; + + public: + ~AutoRAII() + { + if constexpr( std::is_same_v< Dtor, std::function< void ( T ) > > ) + { + if( dtor == nullptr ) return; + } + dtor( value ); + } + + template + < + typename AutoRAII_= AutoRAII, + typename= std::enable_if_t< std::is_same_v< AutoRAII_, AutoRAII > >, + typename= std::enable_if_t< std::is_function_v< decltype( AutoRAII_::dtor ) > > + > + AutoRAII( AutoRAII &&move ) + : value() + { + std::swap( move.dtor, this->dtor ); + std::swap( move.value, this->value ); + } + + template< typename Ctor > + explicit AutoRAII( Ctor ctor, Dtor dtor ) : dtor( std::move( dtor ) ), value( ctor() ) {} + + template + < + typename AutoRAII_= AutoRAII, + typename= std::enable_if_t< std::is_same_v< AutoRAII_, AutoRAII > >, + typename= std::enable_if_t< std::is_function_v< decltype( AutoRAII_::dtor ) > > + > + AutoRAII &operator= ( AutoRAII_ &&move ) + { + std::swap( move.dtor, this->dtor ); + std::swap( move.value, this->value ); + } + + operator const T &() const { return value; } + + template + < + typename T_= T, + typename= std::enable_if_t< std::is_pointer_v< T_ > > + > + decltype( auto ) operator *() const { return *value; } + + template + < + typename T_= T, + typename= std::enable_if_t< std::is_pointer_v< T_ > > + > + decltype( auto ) operator->() const { return value; } + }; + + template< typename Ctor, typename Dtor > + explicit AutoRAII( Ctor ctor, Dtor ) -> AutoRAII< decltype( ctor() ), Dtor >; + } + } + + namespace exports::auto_raii + { + using namespace detail::auto_raii::exports; + } +} diff --git a/AutoRAII.test/0.cc b/AutoRAII.test/0.cc new file mode 100644 index 0000000..ccf42d5 --- /dev/null +++ b/AutoRAII.test/0.cc @@ -0,0 +1,43 @@ +static_assert( __cplusplus > 201700, "C++17 Required" ); + +#include + +#include +#include + +int +main( const int argcnt, const char *const argvec[] ) +{ + return Alepha::Testing::runAllTests( argcnt, argvec ); +} + +namespace +{ + using namespace Alepha::exports::auto_raii; + + using namespace Alepha::Utility::exports::evaluation; + using namespace Alepha::Testing::exports::literals; + using Alepha::Testing::exports::TestState; + + auto tests= enroll <=[] + { + "basic.syntax"_test <=[]( TestState test ) + { + AutoRAII managed{ []{ return 42; }, []( auto ){} }; + test.expect( managed == 42 ); + }; + + "basic.functionality"_test <=[]( TestState test ) + { + bool initialized= false; + bool destroyed= false; + { + AutoRAII managed{ [&]{ initialized= true; return 0; }, [&]( auto ) { initialized= false; destroyed= true; } }; + test.expect( initialized ); + test.expect( not destroyed ); + } + test.expect( not initialized ); + test.expect( destroyed ); + }; + }; +} diff --git a/AutoRAII.test/Makefile b/AutoRAII.test/Makefile new file mode 100644 index 0000000..b76123d --- /dev/null +++ b/AutoRAII.test/Makefile @@ -0,0 +1,3 @@ +CXXFLAGS+= -std=c++17 -I ../ + +all: 0