1
0
forked from Alepha/Alepha

Get Blob and Buffer building and a bit tested

This commit is contained in:
2023-11-10 23:29:20 -05:00
parent 3458c6af9a
commit c78237e844
5 changed files with 111 additions and 80 deletions

82
Blob.h
View File

@ -2,17 +2,22 @@ static_assert( __cplusplus > 2020'99 );
#pragma once #pragma once
#include <Alepha/Alepha.h>
#include <cassert>
#include <memory> #include <memory>
#include "Buffer.h" #include "Buffer.h"
#include "swappable.h" #include "swappable.h"
#include "stringify.h" #include "Exception.h"
#include "Exceptions.h" //#include "threading.h"
#include "evaluation_helpers.h"
#include "threading.h"
#include "error.h" #include "error.h"
namespace Alepha::inline Cavorite ::detail:: blob #include <Alepha/IOStreams/String.h>
#include <Alepha/Utility/evaluation_helpers.h>
namespace Alepha::Hydrogen ::detail:: Blob_m
{ {
inline namespace exports inline namespace exports
{ {
@ -34,28 +39,29 @@ namespace Alepha::inline Cavorite ::detail:: blob
} }
using std::begin, std::end; using std::begin, std::end;
using IOStreams::stringify;
class exports::DataCarveTooLargeError class exports::DataCarveTooLargeError
: public virtual OutOfRangeError : public virtual Buffer_m::OutOfRangeError
{ {
public: public:
explicit explicit
DataCarveTooLargeError( const void *const location, const std::size_t request, const std::size_t available ) 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 " : 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 ) OutOfRangeError( location, request, available )
{} {}
}; };
class exports::DataCarveOutOfRangeError class exports::DataCarveOutOfRangeError
: public virtual OutOfRangeError : public virtual Buffer_m::OutOfRangeError
{ {
public: public:
explicit 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 " : 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 ) OutOfRangeError( location, request, available )
{} {}
}; };
@ -66,25 +72,27 @@ namespace Alepha::inline Cavorite ::detail:: blob
private: private:
using IndirectStorage= std::shared_ptr< std::shared_ptr< Blob > >; 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. 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? 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. // TODO: Take the `storage` parameter and make it not increment when this ctor is called -- only when the dice roll passes.
explicit explicit
Blob( IndirectStorage storage, Buffer buffer ) noexcept Blob( IndirectStorage storage, Buffer< Mutable > buffer ) noexcept
: storage( evaluate <=[storage= std::move( storage )] () -> IndirectBacking : storage( Utility::evaluate <=[storage= std::move( storage )] () -> IndirectStorage
{ {
if( fastRandomBits( C::storageSplitRandomBitDepth ) ) return std::move( storage ); //if( fastRandomBits( C::storageSplitRandomBitDepth ) )
if( C::debugSplitSharing ) error() << "Observed a use count of " << storage.use_count() << " when we failed the dice roll." << std::endl; return std::move( storage );
auto split= std::make_shared< std::shared_ptr< Blob > >( *storage ); //if( C::debugSplitSharing ) error() << "Observed a use count of " << storage.use_count() << " when we failed the dice roll." << std::endl;
if( C:: //auto split= std::make_shared< std::shared_ptr< Blob > >( *storage );
//if( C::
//return split;
}), }),
buffer( buffer ) buffer( buffer ),
viewLimit( buffer.size() ) viewLimit( buffer.size() )
{} {}
public: public:
~Buffer() { reset(); } ~Blob() { reset(); }
auto auto
swap_lens() noexcept swap_lens() noexcept
@ -106,7 +114,7 @@ namespace Alepha::inline Cavorite ::detail:: blob
void void
reset() noexcept reset() noexcept
{ {
if( not storage ) delete buffer; if( not storage ) delete [] buffer.byte_data();
else storage.reset(); else storage.reset();
buffer= {}; buffer= {};
@ -125,7 +133,7 @@ namespace Alepha::inline Cavorite ::detail:: blob
* @note: No data are copied. * @note: No data are copied.
*/ */
void void
reset( const std::size_t ) reset( const std::size_t size )
{ {
Blob tmp{ size }; Blob tmp{ size };
swap( tmp, *this ); swap( tmp, *this );
@ -133,8 +141,8 @@ namespace Alepha::inline Cavorite ::detail:: blob
// Copy deep copies the data. // Copy deep copies the data.
Blob( const Blob &copy ) Blob( const Blob &copy )
: buffer( new std::byte[ copy.buffer.size() ] ), : buffer( new std::byte[ copy.size() ], copy.size() ),
viewLimit( copy.viewLimit ) viewLimit( copy.size() )
{ {
if( C::debugCtors ) error() << "Blob copy invoked." << std::endl; if( C::debugCtors ) error() << "Blob copy invoked." << std::endl;
copyData( *this, copy ); copyData( *this, copy );
@ -178,13 +186,13 @@ namespace Alepha::inline Cavorite ::detail:: blob
explicit explicit
Blob( const std::size_t amount ) 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 ) viewLimit( amount )
{} {}
explicit explicit
Blob( const Buffer< Const > b ) Blob( const Buffer< Const > b )
: Buffer( b.size() ) : Blob( b.size() )
{ {
copyData( buffer, b ); 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. // 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; buffer= buffer + amount;
viewLimit-= 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 ) const= delete;
template< typename T > void operator []( T )= 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 bool
isContiguousWith( const Blob &other ) const & noexcept isContiguousWith( const Blob &other ) const & noexcept
@ -269,7 +277,7 @@ namespace Alepha::inline Cavorite ::detail:: blob
( (
storage != nullptr storage != nullptr
and and
*storage == *other.backing *storage == *other.storage
and and
byte_data() + size() == other.byte_data() byte_data() + size() == other.byte_data()
); );
@ -331,7 +339,7 @@ namespace Alepha::inline Cavorite ::detail:: blob
bool bool
couldConcatenate( const Buffer< Const > buffer ) const noexcept 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 > [[nodiscard]] Buffer< constness >
concatenate( const Buffer< constness > data ) noexcept concatenate( const Buffer< constness > data ) noexcept
{ {
const auto amount= std::min( capacity - size(), data.size() ); const auto amount= std::min( capacity() - size(), data.size() );
const DataWindow< const > fitted{ data, amount }; const Buffer< Const > fitted{ data, amount };
copyData( buffer, + size(), fitted ); copyData( buffer + size(), fitted );
setSize( size() + amount ); setSize( size() + amount );
return data + amount; return data + amount;
} }
@ -406,7 +414,7 @@ namespace Alepha::inline Cavorite ::detail:: blob
} }
else else
{ {
const auto amount= concatenate( Buffer< Const >{ blob } ).size() const auto amount= concatenate( Buffer< Const >{ blob } ).size();
const auto rv= blob.carveTail( amount ); const auto rv= blob.carveTail( amount );
blob.reset(); blob.reset();
return rv; return rv;
@ -482,11 +490,11 @@ namespace Alepha::inline Cavorite ::detail:: blob
} }
}; };
static_assert( HasCapability< Blob, swappable > ); //static_assert( Capability< Blob, swappable > );
static_assert( detail::swaps::SwapLensable< Blob > ); //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;
} }

25
Blob.test/0.cc Normal file
View File

@ -0,0 +1,25 @@
static_assert( __cplusplus > 2020'99 );
#include "../Blob.h"
#include <Alepha/Testing/test.h>
#include <Alepha/Utility/evaluation_helpers.h>
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 ) );
};
};

1
Blob.test/CMakeLists.txt Normal file
View File

@ -0,0 +1 @@
unit_test( 0 )

View File

@ -2,6 +2,11 @@ static_assert( __cplusplus > 2020'99 );
#pragma once #pragma once
#include <Alepha.h>
#include <cstddef>
#include <cstring>
#include <vector> #include <vector>
#include <string> #include <string>
#include <array> #include <array>
@ -10,19 +15,22 @@ static_assert( __cplusplus > 2020'99 );
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
#include <boost/lexical_cast.hpp> #include <Alepha/Constness.h>
#include <Alepha/lifetime.h>
#include <Alepha/IOStreams/String.h>
#include "Concepts.h" #include "Concepts.h"
#include "assertion.h" #include "assertion.h"
#include "Capabilities.h" #include "Capabilities.h"
#include "lifetime.h"
namespace Alepha::inline Cavorite ::detail:: buffer namespace Alepha::Hydrogen ::detail:: Buffer_m
{ {
inline namespace exports {} inline namespace exports {}
using namespace std::literals::string_literals; using namespace std::literals::string_literals;
using IOStreams::stringify;
namespace exports namespace exports
{ {
@ -42,7 +50,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer
: baseAddress( address ), requestedSize( requestedSize ), availableSize( availableSize ) : baseAddress( address ), requestedSize( requestedSize ), availableSize( availableSize )
{} {}
public public:
const void *getAddress() const noexcept { return baseAddress; } const void *getAddress() const noexcept { return baseAddress; }
const std::size_t getRequestedSize() const noexcept { return requestedSize; } const std::size_t getRequestedSize() const noexcept { return requestedSize; }
const std::size_t getAvailableSize() const noexcept { return availableSize; } 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. " : 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 ) + "The request was at location " + stringify( location ) + " which only has " + stringify( availableSize )
+ " bytes allocated" ), + " bytes allocated" ),
OutOfRangeError( location, requestedSIze, availableSize ), OutOfRangeError( location, requestedSize, availableSize ),
typeID( type ) typeID( type )
{} {}
}; };
class OutOfRangeSizeError class OutOfRangeSizeError
: virtual public OutOfRangeException : virtual public OutOfRangeError
{ {
public: public:
explicit 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 ) : std::out_of_range( "Tried to view a byte offset of " + stringify( requestedOffset ) + " into location " + stringify( location )
+ " which is " + stringify( availableSpace ) + " bytes in size." ), + " 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 constexpr
Buffer( const pointer_type ptr, const std::size_t bytes ) noexcept 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 constexpr
Buffer( const Buffer< Mutable > &copy ) noexcept Buffer( const Buffer< Mutable > &copy ) noexcept
: ptr( copy.byte_data() ), bytes( copy.size() ) {} : ptr( copy.byte_data() ), bytes( copy.size() ) {}
template< Constness constness_= constness >
requires( constness_ == Mutable )
constexpr constexpr
Buffer( const Buffer< Const > &copy ) noexcept requires( Constness == Mutable )= delete; Buffer( const Buffer< Const > &copy ) noexcept = delete;
constexpr byte_pointer_type byte_data() const noexcept { return ptr; } constexpr byte_pointer_type byte_data() const noexcept { return ptr; }
constexpr pointer_type 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_byte_pointer_type const_byte_data() const noexcept { return ptr; }
constexpr const_pointer_type 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 std::size_t size() const noexcept { return bytes; }
constexpr bool empty() const noexcept { return size() == 0; } 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 cbegin() const noexcept { return begin(); }
constexpr const_byte_pointer_type cend() const noexcept { return end(); } 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 as( std::nothrow_t ) const noexcept
{ {
assertion( sizeof( T ) <= bytes ); 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 > template< typename T >
@ -153,7 +166,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer
const_as( std::nothrow_t ) const noexcept const_as( std::nothrow_t ) const noexcept
{ {
assertion( sizeof( T ) <= bytes ); 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 > template< typename T >
@ -222,7 +235,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer
struct BufferModel_capability {}; struct BufferModel_capability {};
template< typename T > template< typename T >
concept UndecayedBufferModelable= HasCapability< T, BufferModel_capability >; concept UndecayedBufferModelable= Capability< T, BufferModel_capability >;
template< typename T > template< typename T >
concept BufferModelable= UndecayedBufferModelable< std::decay_t< 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 auto &crtp() noexcept { return static_cast< Derived & >( *this ); }
constexpr const auto &crtp() const noexcept { return static_cast< const Derived & >( *this ); } constexpr const auto &crtp() const noexcept { return static_cast< const Derived & >( *this ); }
constexpr auto &buffer() { return static_cast< Buffer< Mutable > >( crtp() ); } constexpr auto buffer() { return static_cast< Buffer< Mutable > >( crtp() ); }
constexpr const auto &buffer() const { return static_cast< Buffer< Const > >( crtp() ); } constexpr auto buffer() const { return static_cast< Buffer< Const > >( crtp() ); }
public: public:
constexpr auto byte_data() { return buffer().byte_data(); } constexpr auto byte_data() { return buffer().byte_data(); }
@ -273,8 +286,8 @@ namespace Alepha::inline Cavorite ::detail:: buffer
template< typename T > template< typename T >
extern Constness constness_of_v; extern Constness constness_of_v;
template< UndecayedBufferModelble T > template< UndecayedBufferModelable T >
constexpr Constness constness_of_v= std::is_const_v< T >; constexpr Constness constness_of_v< T >{ std::is_const_v< T > };
template< Constness constness > template< Constness constness >
constexpr Constness constness_of_v< Buffer< constness > >{ constness }; constexpr Constness constness_of_v< Buffer< constness > >{ constness };
@ -283,7 +296,7 @@ namespace Alepha::inline Cavorite ::detail:: buffer
constexpr auto constexpr auto
operator + ( const Buffer< constness > buffer, const std::size_t offset ) 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 }; 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 > inline Buffer< Mutable >
make_buffer( std::string &string ) noexcept 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 ) }; 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() }; return { destination, source.size() };
} }
@ -419,13 +415,13 @@ namespace Alepha::inline Cavorite ::detail:: buffer
namespace exports 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<> template<>
constexpr auto 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<> template<>
constexpr auto 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;

View File

@ -34,6 +34,7 @@ add_subdirectory( tuplize_args.test )
add_subdirectory( Thread.test ) add_subdirectory( Thread.test )
add_subdirectory( assertion.test ) add_subdirectory( assertion.test )
add_subdirectory( Constness.test ) add_subdirectory( Constness.test )
add_subdirectory( Blob.test )
# Sample applications # Sample applications
add_executable( example example.cc ) add_executable( example example.cc )