diff --git a/Blob.h b/Blob.h index 987bba1..876cfac 100644 --- a/Blob.h +++ b/Blob.h @@ -2,17 +2,22 @@ static_assert( __cplusplus > 2020'99 ); #pragma once +#include + +#include + #include #include "Buffer.h" #include "swappable.h" -#include "stringify.h" -#include "Exceptions.h" -#include "evaluation_helpers.h" -#include "threading.h" +#include "Exception.h" +//#include "threading.h" #include "error.h" -namespace Alepha::inline Cavorite ::detail:: blob +#include +#include + +namespace Alepha::Hydrogen ::detail:: Blob_m { inline namespace exports { @@ -34,28 +39,29 @@ namespace Alepha::inline Cavorite ::detail:: blob } using std::begin, std::end; + using IOStreams::stringify; class exports::DataCarveTooLargeError - : public virtual OutOfRangeError + : public virtual Buffer_m::OutOfRangeError { public: explicit DataCarveTooLargeError( const void *const location, const std::size_t request, const std::size_t available ) : std::out_of_range( "Tried to carve " + stringify( request ) + " bytes from `Blob` object at location " - + stringify( location ) + " which only has " + stringify( avail ) + " bytes allocated." ), + + stringify( location ) + " which only has " + stringify( available ) + " bytes allocated." ), OutOfRangeError( location, request, available ) {} }; class exports::DataCarveOutOfRangeError - : public virtual OutOfRangeError + : public virtual Buffer_m::OutOfRangeError { public: explicit - DataCarveOutOfRanceError( const void *const location, const std::size_t request, const std::size_t available ) + DataCarveOutOfRangeError( const void *const location, const std::size_t request, const std::size_t available ) : std::out_of_range( "Tried to carve " + stringify( request ) + " bytes from `Blob` object at location " - + stringify( location ) + " which only has " + stringify( avail ) + " bytes allocated." ), + + stringify( location ) + " which only has " + stringify( available ) + " bytes allocated." ), OutOfRangeError( location, request, available ) {} }; @@ -66,25 +72,27 @@ namespace Alepha::inline Cavorite ::detail:: blob private: using IndirectStorage= std::shared_ptr< std::shared_ptr< Blob > >; IndirectStorage storage; // If this is empty, then this `Blob` object doesn't share ownership. This references the shared pool. - Buffer buffer; + Buffer< Mutable > buffer; std::size_t viewLimit= 0; // TODO: Consider allowing for unrooted sub-buffer views? // TODO: Take the `storage` parameter and make it not increment when this ctor is called -- only when the dice roll passes. explicit - Blob( IndirectStorage storage, Buffer buffer ) noexcept - : storage( evaluate <=[storage= std::move( storage )] () -> IndirectBacking + Blob( IndirectStorage storage, Buffer< Mutable > buffer ) noexcept + : storage( Utility::evaluate <=[storage= std::move( storage )] () -> IndirectStorage { - if( fastRandomBits( C::storageSplitRandomBitDepth ) ) return std::move( storage ); - if( C::debugSplitSharing ) error() << "Observed a use count of " << storage.use_count() << " when we failed the dice roll." << std::endl; - auto split= std::make_shared< std::shared_ptr< Blob > >( *storage ); - if( C:: + //if( fastRandomBits( C::storageSplitRandomBitDepth ) ) + return std::move( storage ); + //if( C::debugSplitSharing ) error() << "Observed a use count of " << storage.use_count() << " when we failed the dice roll." << std::endl; + //auto split= std::make_shared< std::shared_ptr< Blob > >( *storage ); + //if( C:: + //return split; }), - buffer( buffer ) + buffer( buffer ), viewLimit( buffer.size() ) {} public: - ~Buffer() { reset(); } + ~Blob() { reset(); } auto swap_lens() noexcept @@ -106,7 +114,7 @@ namespace Alepha::inline Cavorite ::detail:: blob void reset() noexcept { - if( not storage ) delete buffer; + if( not storage ) delete [] buffer.byte_data(); else storage.reset(); buffer= {}; @@ -125,7 +133,7 @@ namespace Alepha::inline Cavorite ::detail:: blob * @note: No data are copied. */ void - reset( const std::size_t ) + reset( const std::size_t size ) { Blob tmp{ size }; swap( tmp, *this ); @@ -133,8 +141,8 @@ namespace Alepha::inline Cavorite ::detail:: blob // Copy deep copies the data. Blob( const Blob © ) - : buffer( new std::byte[ copy.buffer.size() ] ), - viewLimit( copy.viewLimit ) + : buffer( new std::byte[ copy.size() ], copy.size() ), + viewLimit( copy.size() ) { if( C::debugCtors ) error() << "Blob copy invoked." << std::endl; copyData( *this, copy ); @@ -178,13 +186,13 @@ namespace Alepha::inline Cavorite ::detail:: blob explicit Blob( const std::size_t amount ) - : buffer( new std::byte[ amount ]{} ), // The data must be 0'ed upon allocation. + : buffer( new std::byte[ amount ]{}, amount ), // The data must be 0'ed upon allocation. viewLimit( amount ) {} explicit Blob( const Buffer< Const > b ) - : Buffer( b.size() ) + : Blob( b.size() ) { copyData( buffer, b ); } @@ -228,7 +236,7 @@ namespace Alepha::inline Cavorite ::detail:: blob // Now we assume that there's a two-layer scheme, so we operate based upon that. - Blob rv{ storage, Buffer< Mutable >{ buffer, amount } } + Blob rv{ storage, Buffer< Mutable >{ buffer, amount } }; buffer= buffer + amount; viewLimit-= amount; @@ -260,7 +268,7 @@ namespace Alepha::inline Cavorite ::detail:: blob template< typename T > void operator []( T ) const= delete; template< typename T > void operator []( T )= delete; - constexpr std::size_t capacity() const noecept { return buffer.size(); } + constexpr std::size_t capacity() const noexcept { return buffer.size(); } bool isContiguousWith( const Blob &other ) const & noexcept @@ -269,7 +277,7 @@ namespace Alepha::inline Cavorite ::detail:: blob ( storage != nullptr and - *storage == *other.backing + *storage == *other.storage and byte_data() + size() == other.byte_data() ); @@ -331,7 +339,7 @@ namespace Alepha::inline Cavorite ::detail:: blob bool couldConcatenate( const Buffer< Const > buffer ) const noexcept { - return data.size() <= ( capacity() - size() ); + return buffer.size() <= ( capacity() - size() ); } /*! @@ -372,9 +380,9 @@ namespace Alepha::inline Cavorite ::detail:: blob [[nodiscard]] Buffer< constness > concatenate( const Buffer< constness > data ) noexcept { - const auto amount= std::min( capacity - size(), data.size() ); - const DataWindow< const > fitted{ data, amount }; - copyData( buffer, + size(), fitted ); + const auto amount= std::min( capacity() - size(), data.size() ); + const Buffer< Const > fitted{ data, amount }; + copyData( buffer + size(), fitted ); setSize( size() + amount ); return data + amount; } @@ -406,7 +414,7 @@ namespace Alepha::inline Cavorite ::detail:: blob } else { - const auto amount= concatenate( Buffer< Const >{ blob } ).size() + const auto amount= concatenate( Buffer< Const >{ blob } ).size(); const auto rv= blob.carveTail( amount ); blob.reset(); return rv; @@ -482,11 +490,11 @@ namespace Alepha::inline Cavorite ::detail:: blob } }; - static_assert( HasCapability< Blob, swappable > ); - static_assert( detail::swaps::SwapLensable< Blob > ); + //static_assert( Capability< Blob, swappable > ); + //static_assert( detail::swaps::SwapLensable< Blob > ); } -namespace Alepha::Cavorite::inline exports::inline blob +namespace Alepha::Hydrogen::inline exports::inline Blob_m { - using namespace detail::blob::exports; + using namespace detail::Blob_m::exports; } diff --git a/Blob.test/0.cc b/Blob.test/0.cc new file mode 100644 index 0000000..afa887d --- /dev/null +++ b/Blob.test/0.cc @@ -0,0 +1,25 @@ +static_assert( __cplusplus > 2020'99 ); + +#include "../Blob.h" + +#include + +#include + +static auto init= Alepha::Utility::enroll <=[] +{ + using namespace Alepha::Testing::literals::test_literals; + "Simple carve head test"_test <=[] + { + Alepha::Blob b{ 1024 }; + + auto b2= b.carveHead( 256 ); + + assert( b.size() == 768 ); + assert( b2.size() == 256 ); + + std::string h= "Hello world"; + + copyData( b2, Alepha::make_buffer( h ) ); + }; +}; diff --git a/Blob.test/CMakeLists.txt b/Blob.test/CMakeLists.txt new file mode 100644 index 0000000..b099603 --- /dev/null +++ b/Blob.test/CMakeLists.txt @@ -0,0 +1 @@ +unit_test( 0 ) diff --git a/Buffer.h b/Buffer.h index aae3bf6..c3d450d 100644 --- a/Buffer.h +++ b/Buffer.h @@ -2,6 +2,11 @@ static_assert( __cplusplus > 2020'99 ); #pragma once +#include + +#include +#include + #include #include #include @@ -10,19 +15,22 @@ static_assert( __cplusplus > 2020'99 ); #include #include -#include +#include +#include + +#include #include "Concepts.h" #include "assertion.h" #include "Capabilities.h" -#include "lifetime.h" -namespace Alepha::inline Cavorite ::detail:: buffer +namespace Alepha::Hydrogen ::detail:: Buffer_m { inline namespace exports {} using namespace std::literals::string_literals; + using IOStreams::stringify; namespace exports { @@ -42,7 +50,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer : baseAddress( address ), requestedSize( requestedSize ), availableSize( availableSize ) {} - public + public: const void *getAddress() const noexcept { return baseAddress; } const std::size_t getRequestedSize() const noexcept { return requestedSize; } const std::size_t getAvailableSize() const noexcept { return availableSize; } @@ -62,20 +70,20 @@ namespace Alepha::inline Cavorite ::detail:: buffer : std::out_of_range( "Tried to access an object of type "s + type.name() + " which is " + stringify( requestedSize ) + " bytes in size. " + "The request was at location " + stringify( location ) + " which only has " + stringify( availableSize ) + " bytes allocated" ), - OutOfRangeError( location, requestedSIze, availableSize ), + OutOfRangeError( location, requestedSize, availableSize ), typeID( type ) {} }; class OutOfRangeSizeError - : virtual public OutOfRangeException + : virtual public OutOfRangeError { public: explicit - OutOfRangeSizeException( const void *const location, const std::ptrdiff_t requestedOffset, const std::size_t availableSpace ) + OutOfRangeSizeError( const void *const location, const std::ptrdiff_t requestedOffset, const std::size_t availableSpace ) : std::out_of_range( "Tried to view a byte offset of " + stringify( requestedOffset ) + " into location " + stringify( location ) + " which is " + stringify( availableSpace ) + " bytes in size." ), - OutOfRangeException( location, requestedOffset, availableSpace ) + OutOfRangeError( location, requestedOffset, availableSpace ) {} }; @@ -106,26 +114,31 @@ namespace Alepha::inline Cavorite ::detail:: buffer constexpr Buffer( const pointer_type ptr, const std::size_t bytes ) noexcept - : ptr( static_cast< byte_pointer_type >( ptr ), bytes( bytes ) + : ptr( static_cast< byte_pointer_type >( ptr ) ), bytes( bytes ) {} constexpr Buffer( const Buffer< Mutable > © ) noexcept : ptr( copy.byte_data() ), bytes( copy.size() ) {} + template< Constness constness_= constness > + requires( constness_ == Mutable ) constexpr - Buffer( const Buffer< Const > © ) noexcept requires( Constness == Mutable )= delete; + Buffer( const Buffer< Const > © ) noexcept = delete; constexpr byte_pointer_type byte_data() const noexcept { return ptr; } constexpr pointer_type data() const noexcept { return ptr; } - constexpr const_byte_pointer_type byte_data() const noexcept { return ptr; } - constexpr const_pointer_type data() const noexcept { return ptr; } + constexpr const_byte_pointer_type const_byte_data() const noexcept { return ptr; } + constexpr const_pointer_type const_data() const noexcept { return ptr; } constexpr std::size_t size() const noexcept { return bytes; } constexpr bool empty() const noexcept { return size() == 0; } + constexpr byte_pointer_type begin() const noexcept { return byte_data(); } + constexpr byte_pointer_type end() const noexcept { return begin() + size(); } + constexpr const_byte_pointer_type cbegin() const noexcept { return begin(); } constexpr const_byte_pointer_type cend() const noexcept { return end(); } @@ -137,7 +150,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer as( std::nothrow_t ) const noexcept { assertion( sizeof( T ) <= bytes ); - return *start_lifetime_as< std::add_lvalue_reference_t< maybe_const_t< T, constness > > >( ptr ); + return *Alepha::start_lifetime_as< std::add_lvalue_reference_t< maybe_const_t< T, constness > > >( ptr ); } template< typename T > @@ -153,7 +166,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer const_as( std::nothrow_t ) const noexcept { assertion( sizeof( T ) <= bytes ); - return *start_lifetime_as< std::add_const_t< T > >( ptr ); + return *Alepha::start_lifetime_as< std::add_const_t< T > >( ptr ); } template< typename T > @@ -222,7 +235,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer struct BufferModel_capability {}; template< typename T > - concept UndecayedBufferModelable= HasCapability< T, BufferModel_capability >; + concept UndecayedBufferModelable= Capability< T, BufferModel_capability >; template< typename T > concept BufferModelable= UndecayedBufferModelable< std::decay_t< T > >; @@ -234,8 +247,8 @@ namespace Alepha::inline Cavorite ::detail:: buffer constexpr auto &crtp() noexcept { return static_cast< Derived & >( *this ); } constexpr const auto &crtp() const noexcept { return static_cast< const Derived & >( *this ); } - constexpr auto &buffer() { return static_cast< Buffer< Mutable > >( crtp() ); } - constexpr const auto &buffer() const { return static_cast< Buffer< Const > >( crtp() ); } + constexpr auto buffer() { return static_cast< Buffer< Mutable > >( crtp() ); } + constexpr auto buffer() const { return static_cast< Buffer< Const > >( crtp() ); } public: constexpr auto byte_data() { return buffer().byte_data(); } @@ -273,8 +286,8 @@ namespace Alepha::inline Cavorite ::detail:: buffer template< typename T > extern Constness constness_of_v; - template< UndecayedBufferModelble T > - constexpr Constness constness_of_v= std::is_const_v< T >; + template< UndecayedBufferModelable T > + constexpr Constness constness_of_v< T >{ std::is_const_v< T > }; template< Constness constness > constexpr Constness constness_of_v< Buffer< constness > >{ constness }; @@ -283,7 +296,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer constexpr auto operator + ( const Buffer< constness > buffer, const std::size_t offset ) { - if( offset > buffer.size() ) throw OutOfRangeError{ buffer.data(), offset, buffer.size() }; + if( offset > buffer.size() ) throw OutOfRangeSizeError{ buffer.data(), std::ptrdiff_t( offset ), buffer.size() }; return Buffer< constness >{ buffer.byte_data() + offset, buffer.size() - offset }; } @@ -372,23 +385,6 @@ namespace Alepha::inline Cavorite ::detail:: buffer } - template< Concepts::StandardLayout T, std::size_t size > - constexpr Buffer< Mutable > - make_buffer( T array[ size ] ) noexcept - { - // TODO: Do we need to consider overflow here? - return { array, sizeof( array ) }; - } - - template< Concepts::StandardLayout T, std::size_t size > - constexpr Buffer< Const > - make_buffer( const T array[ size ] ) noexcept - { - // TODO: Do we need to consider overflow here? - return { array, sizeof( array ) }; - } - - inline Buffer< Mutable > make_buffer( std::string &string ) noexcept { @@ -407,7 +403,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer { if( source.size() > destination.size() ) throw InsufficientSizeError{ destination.data(), source.size(), destination.size(), typeid( std::byte ) }; - ::memcpy( destination, source, source.size() ); + std::memcpy( destination, source, source.size() ); return { destination, source.size() }; } @@ -419,13 +415,13 @@ namespace Alepha::inline Cavorite ::detail:: buffer namespace exports { - using detail::buffer::make_buffer; + using detail::Buffer_m::make_buffer; } } -namespace Alepha::Cavorite::inline exports::inline buffer +namespace Alepha::Hydrogen::inline exports::inline Buffer_m { - using namespace detail::buffer::exports; + using namespace detail::Buffer_m::exports; } /* @@ -453,8 +449,8 @@ namespace Alepha::Cavorite::inline exports::inline buffer template<> constexpr auto -std::cbegin( const ::Alepha::Cavorite::Buffer< Alepha::Cavorite::Mutable > &range ) -> decltype( range.begin() )= delete; +std::cbegin( const ::Alepha::Hydrogen::Buffer< Alepha::Hydrogen::Mutable > &range ) -> decltype( range.begin() )= delete; template<> constexpr auto -std::cend( const ::Alepha::Cavorite::Buffer< Alepha::Cavorite::Mutable > &range ) -> decltype( range.end() )= delete; +std::cend( const ::Alepha::Hydrogen::Buffer< Alepha::Hydrogen::Mutable > &range ) -> decltype( range.end() )= delete; diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b46b65..e873c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ add_subdirectory( tuplize_args.test ) add_subdirectory( Thread.test ) add_subdirectory( assertion.test ) add_subdirectory( Constness.test ) +add_subdirectory( Blob.test ) # Sample applications add_executable( example example.cc )