forked from Alepha/Alepha
Merge branch 'master' of coruscant:/Sources/Repositories/Alepha
This commit is contained in:
2
Alepha.h
2
Alepha.h
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
193
Atomic/Mailbox.h
Normal file
193
Atomic/Mailbox.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*!
|
||||
* @file Mailbox.h
|
||||
* @brief Class which abstracts a "mailbox" metaphor, for threaded programming
|
||||
*
|
||||
* Copyright (C) 2010 Alepha Library. All rights reserved. <BR>
|
||||
* @author ADAM David Alan Martin
|
||||
*/
|
||||
|
||||
#ifndef ALEPHA_MAILBOX_HEADER
|
||||
#define ALEPHA_MAILBOX_HEADER
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <Alepha/ScopedUsage.h>
|
||||
#include <Alepha/Exceptions.h>
|
||||
|
||||
namespace Alepha
|
||||
{
|
||||
namespace Atomic
|
||||
{
|
||||
/*!
|
||||
* @brief The Mailbox class implements a mailbox metaphor. Just like postal service mailboxes,
|
||||
* the mailbox class lets users add items to the box from a producer thread or group of threads,
|
||||
* and in a (single, for now) consumer thread, take the entire contents of the mailbox out, and
|
||||
* work with them.
|
||||
*
|
||||
* @tparam Item The Item type which is used in the mailbox containers.
|
||||
*
|
||||
* @note Mailboxes, for now, only support one consumer, and any number of producers.
|
||||
*
|
||||
* @invariant Mailboxes give out their contents in the order placed in.
|
||||
*
|
||||
* The Mailbox primitive is implemented as two "containers" which are swapped periodically by the
|
||||
* consumer, and continually filled by the producers. This swapping keeps the identity in principle,
|
||||
* but allows the user to access the contents of the "other side", in practice. The two mailbox
|
||||
* containers are: "preparation" and "filled". The consumer takes a whole "filled" mailbox out, and
|
||||
* replaces his current mailbox into the system for use as the new "preparation" box. The producer
|
||||
* continually inserts mail into the "preparation" mailbox until full. The consumer clears his mailbox
|
||||
* when returning it.
|
||||
*/
|
||||
template< typename Item >
|
||||
class Mailbox
|
||||
{
|
||||
private:
|
||||
/*! @brief The maximum number of "mail" items which can be placed into a "preparation" mailbox */
|
||||
const size_t boxLimit;
|
||||
|
||||
const size_t minSwapFill;
|
||||
|
||||
boost::mutex mailboxAccess;
|
||||
|
||||
boost::condition boxFull;
|
||||
boost::condition boxEmpty;
|
||||
|
||||
std::vector< Item > preparing;
|
||||
std::vector< Item > filled;
|
||||
|
||||
bool finished;
|
||||
bool terminated;
|
||||
|
||||
bool
|
||||
testTerminated() const
|
||||
{
|
||||
if( terminated ) throw Alepha::TerminatedException();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
testFinished() const
|
||||
{
|
||||
if( finished ) throw Alepha::FinishedException();
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit inline
|
||||
Mailbox( const size_t lim, const size_t min= 1 )
|
||||
: boxLimit( lim ), minSwapFill( min ), finished( false ), terminated( false )
|
||||
{
|
||||
this->preparing.reserve( boxLimit );
|
||||
this->filled.reserve( boxLimit );
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function will give back the "now-current" preparation mailbox, and check out the current
|
||||
* mail as the filled mailbox.
|
||||
* @returns A reference to the current filled mailbox.
|
||||
*
|
||||
* @throw ClosureException When a closure event is encountered. (Any ClosureException derived type, see
|
||||
* the ClosureException schedule for why these events get thrown.)
|
||||
*
|
||||
* @pre The mailbox must have some items in it. This is established for you by the internal locking system.
|
||||
* @post The preparing mailbox is cleared, and the filled mailbox has the new mail.
|
||||
* @invariant The filled mailbox will have some items in it, or a Alepha::ClosureException will be thrown.
|
||||
* @invariant This function is not threadsafe in the presence of multiple consumers (fetchers).
|
||||
*/
|
||||
std::vector< Item > &
|
||||
fetchItems()
|
||||
{
|
||||
boost::this_thread::interruption_point();
|
||||
/* Our mailbox is done, so let's empty it. (Don't hold the lock during this, to reduce contention.) */
|
||||
this->filled.clear();
|
||||
|
||||
ALEPHA_TEMPLATE_NAMED_USAGE( lock, this->mailboxAccess )
|
||||
{
|
||||
/* Make sure that there's mail we can get. */
|
||||
while( this->testTerminated() && ( this->preparing.size() < minSwapFill ) )
|
||||
//while( ( this->testTerminated() ) && ( this->preparing.empty() ) )
|
||||
{
|
||||
//this->testFinished();
|
||||
if( this->finished && !this->preparing.empty() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
this->testFinished();
|
||||
this->boxFull.wait( lock );
|
||||
}
|
||||
assert( !this->preparing.empty() );
|
||||
|
||||
/* Exchange our mailbox with the preparation box. And give it back. */
|
||||
std::swap( this->filled, this->preparing );
|
||||
this->boxEmpty.notify_all();
|
||||
}
|
||||
return this->filled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function will add mail to the mailbox.
|
||||
*
|
||||
* @throw ClosureException When a closure event is encountered. (Any ClosureException derived type, see
|
||||
* the ClosureException schedule for why these events get thrown.)
|
||||
*
|
||||
* @pre The mailbox must have room. This is established for you by the internal locking system.
|
||||
* @post The preparing mailbox will have "item" as the last item added to this box.
|
||||
* @invariant The mailbox will not be allowed to become overfull.
|
||||
*/
|
||||
void
|
||||
push_back( const Item &item )
|
||||
{
|
||||
boost::this_thread::interruption_point();
|
||||
ALEPHA_TEMPLATE_NAMED_USAGE( lock, this->mailboxAccess )
|
||||
{
|
||||
/* Make sure we can put the mail in */
|
||||
while( ( this->testTerminated() ) && ( this->preparing.size() == this->boxLimit ) )
|
||||
{
|
||||
this->boxEmpty.wait( lock );
|
||||
}
|
||||
assert( !this->preparing.size() < this->boxLimit );
|
||||
|
||||
/* Put the item into the mailbox. */
|
||||
this->preparing.push_back( item );
|
||||
this->boxFull.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function will close the mailbox to any new mail, and deliver a closure
|
||||
* event to the other side.
|
||||
*
|
||||
* @pre The mailbox must not be finished.
|
||||
* @pre The mailbox will be put into the finished state.
|
||||
*/
|
||||
void
|
||||
close()
|
||||
{
|
||||
ALEPHA_TEMPLATE_SCOPED_USAGE( this->mailboxAccess )
|
||||
{
|
||||
this->finished= true;
|
||||
this->boxFull.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
terminate()
|
||||
{
|
||||
ALEPHA_TEMPLATE_SCOPED_USAGE( this->mailboxAccess )
|
||||
{
|
||||
this->terminated= true;
|
||||
this->boxEmpty.notify_all();
|
||||
this->boxFull.notify_all();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*** ALEPHA_MAILBOX_HEADER ***/
|
||||
|
||||
/*
|
||||
* vim:ts=3:sw=3:sts=3:sta:et:ft=cpp
|
||||
*/
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/AutoRAII.h>
|
||||
|
||||
|
||||
84
Blob.h
84
Blob.h
@ -1,18 +1,23 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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 <Alepha/IOStreams/String.h>
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
25
Blob.test/0.cc
Normal file
25
Blob.test/0.cc
Normal 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 ) );
|
||||
};
|
||||
};
|
||||
84
Buffer.h
84
Buffer.h
@ -1,7 +1,12 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <array>
|
||||
@ -10,19 +15,22 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <Alepha/Constness.h>
|
||||
#include <Alepha/lifetime.h>
|
||||
|
||||
#include <Alepha/IOStreams/String.h>
|
||||
|
||||
#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;
|
||||
|
||||
@ -3,6 +3,7 @@ project( Alepha )
|
||||
|
||||
include( cmake/rules.cmake )
|
||||
|
||||
link_libraries( pthread )
|
||||
|
||||
|
||||
# The core alepha library:
|
||||
@ -31,6 +32,10 @@ add_subdirectory( Exception.test )
|
||||
add_subdirectory( word_wrap.test )
|
||||
add_subdirectory( string_algorithms.test )
|
||||
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 )
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -78,6 +78,7 @@ namespace Alepha::Hydrogen
|
||||
has_cap_in_capability_base( const Left &, Meta::type_value< Cap > cap )
|
||||
{
|
||||
throw "Unevaluated";
|
||||
return false;
|
||||
}
|
||||
|
||||
template< typename Cap, typename ... TParams >
|
||||
@ -100,6 +101,13 @@ namespace Alepha::Hydrogen
|
||||
return has_cap( Meta::Container::vector< TParams... >{}, cap );
|
||||
}
|
||||
|
||||
template< typename Type, typename Cap >
|
||||
consteval bool
|
||||
has_cap( const Meta::type_value< Type > &, Meta::type_value< Cap > )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace exports
|
||||
{
|
||||
template< typename T, typename cap >
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -11,7 +11,7 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include "meta.h"
|
||||
#include "function_traits.h"
|
||||
|
||||
namespace Alepha::Hydrogen ::detail:: core_concepts
|
||||
namespace Alepha::Hydrogen ::detail:: Concepts_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
@ -282,7 +282,7 @@ namespace Alepha::Hydrogen ::detail:: core_concepts
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::inline exports::inline core_concepts
|
||||
namespace Alepha::Hydrogen::inline exports::inline Concepts_m::inline Concepts
|
||||
{
|
||||
using namespace detail::core_concepts::exports;
|
||||
using namespace detail::Concepts_m::exports;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "Console.h"
|
||||
|
||||
@ -13,9 +13,9 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <ext/stdio_filebuf.h>
|
||||
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
#include <Alepha/IOStreams/OutUnixFileBuf.h>
|
||||
|
||||
#include "Enum.h"
|
||||
#include "ProgramOptions.h"
|
||||
@ -348,8 +348,7 @@ namespace Alepha::Hydrogen ::detail:: console_m
|
||||
struct Console::Impl
|
||||
{
|
||||
int fd;
|
||||
// TODO: Do we want to make this not gnu libstdc++ specific?
|
||||
__gnu_cxx::stdio_filebuf< char > filebuf;
|
||||
IOStreams::OutUnixFileBuf filebuf;
|
||||
std::ostream stream;
|
||||
std::stack< std::pair< struct termios, ConsoleMode > > modeStack;
|
||||
ConsoleMode mode= cooked;
|
||||
@ -357,7 +356,7 @@ namespace Alepha::Hydrogen ::detail:: console_m
|
||||
|
||||
explicit
|
||||
Impl( const int fd )
|
||||
: fd( fd ), filebuf( fd, std::ios::out ), stream( &filebuf )
|
||||
: fd( fd ), filebuf( fd ), stream( &filebuf )
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <array>
|
||||
@ -9,9 +11,7 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
namespace Alepha::Cavorite ::detail:: constexpr_string
|
||||
namespace Alepha::Hydrogen ::detail:: ConstexprString_m
|
||||
{
|
||||
namespace C
|
||||
{
|
||||
@ -134,12 +134,12 @@ namespace Alepha::Cavorite ::detail:: constexpr_string
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline constexpr_string
|
||||
namespace Alepha::Hydrogen::inline exports::inline ConstexprString_m
|
||||
{
|
||||
using namespace detail::constexpr_string::exports;
|
||||
using namespace detail::ConstexprString_m::exports;
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline literals::inline constexpr_string_literals
|
||||
namespace Alepha::Hydrogen::inline exports::inline literals::inline constexpr_string_literals
|
||||
{
|
||||
using namespace detail::constexpr_string::exports::literals;
|
||||
using namespace ConstexprString_m::literals;
|
||||
}
|
||||
|
||||
152
Constness.h
Normal file
152
Constness.h
Normal file
@ -0,0 +1,152 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace Alepha::Hydrogen ::detail:: Constness_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
/*!
|
||||
* Conditional constness primitive.
|
||||
*
|
||||
* C++17 and beyond have many conditional attributes on functions. Conditional `noexcept`,
|
||||
* conditional `explicit`, and even conditional instantiation. The `noexcept` and `explicit`
|
||||
* are conditional on a boolean condition. This enum permits making templates which
|
||||
* are conditionally const, depending upon instantiation.
|
||||
*
|
||||
* Simple example:
|
||||
*
|
||||
* ```
|
||||
* template< Constness constness >
|
||||
* struct IntWrapper
|
||||
* {
|
||||
* private:
|
||||
* int variable;
|
||||
*
|
||||
* public:
|
||||
* maybe_const_t< int &, constness > // This is sort of like if one could write `const( constness ) int &`
|
||||
* view() { return variable; }
|
||||
*
|
||||
* const int &
|
||||
* view() const { return variable; }
|
||||
* };
|
||||
*
|
||||
* using MutableIntWrapper= IntWrapper< Mutable >;
|
||||
* using ConstIntWrapper= IntWrapper< Const >;
|
||||
* ```
|
||||
*
|
||||
* Now `Constness< Mutable >` has a member `view` which returns `int &` and `Constness< Const >` has a member
|
||||
* `view` which returns `const int &`. This facility can be useful in implementing pairs of `const`/non-`const`
|
||||
* iterators, and other gadgets.
|
||||
*/
|
||||
enum Constness : bool
|
||||
{
|
||||
Const= true,
|
||||
Mutable= false,
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* Apply the `Constness` requested to the specified type.
|
||||
*
|
||||
* If the type isn't `const`, but `Constness` is set, then
|
||||
* it evaluates to `const T`.
|
||||
*/
|
||||
template< typename Type, Constness > struct maybe_const;
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type, Const >
|
||||
{
|
||||
using type= std::add_const_t< Type >;
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type, Mutable >
|
||||
{
|
||||
using type= Type;
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type &, Const >
|
||||
{
|
||||
using type= std::add_const_t< Type > &;
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
struct maybe_const< Type &, Mutable >
|
||||
{
|
||||
using type= Type &;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Conditionally make `Type` `const`.
|
||||
*/
|
||||
template< typename Type, Constness constness >
|
||||
using maybe_const_t= typename maybe_const< Type, constness >::type;
|
||||
|
||||
/*!
|
||||
* Conditionally make `Type` into `const Type *`.
|
||||
*/
|
||||
template< typename Type, Constness constness >
|
||||
using maybe_const_ptr_t= std::add_pointer_t< maybe_const_t< Type, constness > >;
|
||||
|
||||
/*!
|
||||
* Conditionally call `std::as_const`.
|
||||
*
|
||||
* Sometimes `std::as_const` is appropriate to call, and sometimes it isn't.
|
||||
* In some cases, one might want to have type deduction driven by an expression
|
||||
* where, in a `const` "branch" `std::as_const` is called, but in a non-`const`
|
||||
* branch, it isn't. This facilitates that:
|
||||
*
|
||||
* ```
|
||||
* template< Constness constness >
|
||||
* struct IntWrapper
|
||||
* {
|
||||
* private:
|
||||
* int variable;
|
||||
*
|
||||
* public:
|
||||
* // `std::as_const` will be called when `constness` is true,
|
||||
* // and will be skipped otherwise. This permits the right
|
||||
* // client overload to be called
|
||||
* template< typename Function >
|
||||
* decltype( auto )
|
||||
* apply( Function func )
|
||||
* {
|
||||
* return func( maybe_as_const< constness >( variable ) );
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
template< Constness constness, typename T >
|
||||
constexpr auto &
|
||||
maybe_as_const( T &t ) noexcept
|
||||
{
|
||||
if constexpr( constness ) return std::as_const( t );
|
||||
else return t;
|
||||
}
|
||||
|
||||
template< Constness constness, typename T >
|
||||
constexpr decltype( auto )
|
||||
maybe_as_const( const T &t ) noexcept
|
||||
{
|
||||
if constexpr( constness ) return std::as_const( t );
|
||||
else static_assert( dependent_value< false, T > );
|
||||
}
|
||||
|
||||
template< Constness constness, typename T >
|
||||
void maybe_as_const( T && )= delete;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::inline exports::inline Constness_m
|
||||
{
|
||||
using namespace detail::Constness_m::exports;
|
||||
}
|
||||
3
Constness.test/0.cc
Normal file
3
Constness.test/0.cc
Normal file
@ -0,0 +1,3 @@
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../Constness.h"
|
||||
1
Constness.test/CMakeLists.txt
Normal file
1
Constness.test/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
unit_test( 0 )
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
14
Enum.h
14
Enum.h
@ -1,7 +1,9 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <tuple>
|
||||
@ -17,7 +19,7 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include "ConstexprString.h"
|
||||
#include "meta.h"
|
||||
|
||||
namespace Alepha::inline Cavorite ::detail:: enhanced_enum
|
||||
namespace Alepha::Hydrogen ::detail:: Enum_m
|
||||
{
|
||||
inline namespace exports {}
|
||||
|
||||
@ -246,12 +248,12 @@ namespace Alepha::inline Cavorite ::detail:: enhanced_enum
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline enhanced_enum
|
||||
namespace Alepha::Hydrogen::inline exports::inline Enum_m
|
||||
{
|
||||
using namespace detail::enhanced_enum::exports;
|
||||
using namespace detail::Enum_m::exports;
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline literals::inline enum_literals
|
||||
namespace Alepha::Hydrogen::inline exports::inline literals::inline enum_literals
|
||||
{
|
||||
using namespace detail::enhanced_enum::exports::literals;
|
||||
using namespace Enum_m::literals;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -277,6 +277,8 @@ namespace Alepha::Hydrogen ::detail:: Exception_m
|
||||
|
||||
~Violation() override { if( not active ) abort(); }
|
||||
|
||||
Violation()= default;
|
||||
|
||||
Violation( const Violation © )= delete;
|
||||
Violation( Violation © ) : active( copy.active ) { copy.active= false; }
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Exception.h>
|
||||
|
||||
|
||||
388
Format
Normal file
388
Format
Normal file
@ -0,0 +1,388 @@
|
||||
Basic Code Formatting Rules:
|
||||
|
||||
0) Like most things in Alepha, these rules are "strong guidelines". When in doubt, these rules
|
||||
form a baseline of good current practice. However, there's no substitute for good judgement.
|
||||
Therefore, a large degree of formatting latitude is afforded to code. The primary value
|
||||
being sought is clarity, not consistency. Therefore, new stylistic forms are constantly being
|
||||
adopted for specific cases -- it is cumbersome (at best) to keep track of all of them here.
|
||||
|
||||
Reason: Format should convey meaning. It's fine to invent new conventions. Documenting them is
|
||||
good too, but it shouldn't be cumbersome to do so -- thus this file itself will always be an
|
||||
incomplete representation of the format.
|
||||
|
||||
Exceptions: Certain core guidelines are universally required, like tabs.
|
||||
|
||||
1) Alepha code uses tab character ('\t', ASCII:0x09) for indentation. One tab per indent level. Tabs
|
||||
are not to be used for alignment, except with other tabs. Tabs have no expected set width.
|
||||
|
||||
Reason: Tabs permit customization of code indent level to a reader's taste via the tabwidth settings
|
||||
of editors.
|
||||
|
||||
Exceptions: None. The tab character as _indent only_ permits cooperation amongst those with different
|
||||
visual preferences.
|
||||
|
||||
2) Semicolons on all lines shall appear immediately after the last syntactic character, without a separating space,
|
||||
immediately followed by a newline (or trailing comment). It is permissible put a semicolon on its own line to
|
||||
facilitate a block structure where appropriate for the language.
|
||||
|
||||
Examples:
|
||||
|
||||
++i;
|
||||
f( a, b );
|
||||
|
||||
const bool value= true
|
||||
or a
|
||||
or b
|
||||
;
|
||||
|
||||
3) Declare only one variable per "line".
|
||||
|
||||
Examples:
|
||||
|
||||
int x;
|
||||
float *y;
|
||||
int &xr= x;
|
||||
|
||||
Reason: C++ declaration grammar inherits ambiguities and oddities from C. By declaring one variable per line, we sidestep this issue.
|
||||
|
||||
Exceptions: None.
|
||||
|
||||
|
||||
4) All bracing constructs, "(), {}, [], and <>", must have a space between the opening brace and the first
|
||||
argument, and between the last argument and the closing brace. If there are no arguments then there should
|
||||
be no spaces between the opening and closing brace. No space shall exist between a keyword or an entity name
|
||||
and the following opening bracing construct. A newline character counts as a space for these constructs,
|
||||
thus permitting block-like structure.
|
||||
|
||||
Examples:
|
||||
|
||||
if( someFunction( argument ) ) return 1; // Good. Notice that there is no trailing space after the "if"
|
||||
std::vector< std::map< std::string, std::set< std::string > > > complexDataEntity; // Even for templates
|
||||
complexDataEntity[ 10 ][ "Hello "].find( "Something" ); // Even for array-like operations.
|
||||
std::cout << [](){ return "Hello World!"; }() << std::endl; // For one-lining lambdas and initializers, the rule applies.
|
||||
for( int i= 0; i < 10; ++i ) std::cout << i << std::endl; // Even within a loop construct.
|
||||
|
||||
Reason: Extra space can be visually helpful. Many styles encourage visual cues to code flow.
|
||||
|
||||
|
||||
5) All 2-argument operators that do not modify the left hand side (binary-function operators) must have a space
|
||||
on both sides of the operator, whereas data-modifying equals-based operators like ' =, +=, -=, *=, /=, ^=, |=,
|
||||
&=, ~=, <<=, >>=, %= ' shall have no space to their left, thus binding them to the expression that they modify.
|
||||
Note that ' !=, <=, >= ' are not assignment-like operators, but a comparison operators. Comma "operators"
|
||||
shall also follow left-hand no spacing rules, as this matches their natural use in other circumstances.
|
||||
|
||||
Examples:
|
||||
|
||||
int a= 10;
|
||||
int b= 11, c= 12;
|
||||
c= ( a * b + c ) / ( a * 22 );
|
||||
a%= c / b;
|
||||
if( ( a != b ) or ( c < a ) && ( a= b ) ) return true;
|
||||
|
||||
Reason: Extra visual space helps. Cuddling the assignment operators helps distinguish them from comparison
|
||||
operators. "<=" vs "<<=" and "==" vs "=". By having extra code-intent presented in a side-channel (spacing),
|
||||
it helps prevent accidental typos and bugs.
|
||||
|
||||
Exceptions: `<=` when used as a "left fat arrow" operator may be used with the spacing rules that most
|
||||
make sense for their context. `<=[]` on lambdas, for example. `/` when used as a directory separator
|
||||
between path components from `std::filesystem` should also omit surrounding spaces.
|
||||
|
||||
|
||||
6) All unary operators shall "cuddle" their applied variable. Pointers and references shall be be declared
|
||||
with the "&" or "*" attached to the variable name.
|
||||
|
||||
Examples:
|
||||
|
||||
int a= 10;
|
||||
++a;
|
||||
a--;
|
||||
a= ~a;
|
||||
if( !a ) return false;
|
||||
|
||||
Reason: Somewhat improves readability. For declarations, although "int &" is the type of "int &x;", this
|
||||
does not extend to: "int &x, y". Those are distinct types, but by banning multiple declarations per line,
|
||||
we mostly avoid this issue.
|
||||
|
||||
|
||||
7) Brace placement shall be "Allman/BSD"-like. Opening braces shall be on a new line, closing braces on a
|
||||
new line. Braces shall be indented by the same level as the line of their "control" statement. A braced-block
|
||||
that is not subordinate to a control statement shall be indented as if it had an "if( true )" control statement
|
||||
above it. A do-while loop shall have the while on its own line, after the closing brace, where possible. Note
|
||||
that one-line compaction is permitted, as is omitting braces for fully subsumed blocks.
|
||||
|
||||
Examples:
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int x= 10;
|
||||
int y= 11;
|
||||
if( x < y )
|
||||
{
|
||||
std::vector< int > v;
|
||||
if( y % 2 )
|
||||
{
|
||||
rv.push_back( v );
|
||||
}
|
||||
|
||||
// Note that this if block has no parent, but it is indented like it has one.
|
||||
{
|
||||
std::list< int > l( v.begin(), v.end() );
|
||||
if( x == y ) for( const auto &x: stuff )
|
||||
{
|
||||
std::cout << x << std::endl;
|
||||
}
|
||||
std::cout << l.size() << std::endl;;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
std::cout << v.size() << std::endl;
|
||||
}
|
||||
while( false );
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Exceptions: Very small functions or blocks can be subsumed into one line, for brevity.
|
||||
|
||||
8) Return types shall be placed above the name of the function in definitions, but on the same line for
|
||||
declarations. inline or explicit for ctors, dtors, and conversion functions shall follow this rule as well.
|
||||
|
||||
Example:
|
||||
|
||||
bool is_even( int x );
|
||||
|
||||
bool
|
||||
is_even( int x )
|
||||
{
|
||||
return ~x & 1;
|
||||
}
|
||||
|
||||
|
||||
9) Template clauses for definitions shall be on their own line. For declarations, a separate line is optional.
|
||||
|
||||
Examples:
|
||||
|
||||
template< typename T > bool is_even( T x );
|
||||
|
||||
template< typename T >
|
||||
bool
|
||||
is_even( T x )
|
||||
{
|
||||
return ( x % 2 ) == 0;
|
||||
}
|
||||
|
||||
|
||||
10) In class definitions, public, protected, and private regions shall be indented beyond the access control
|
||||
keywords, which must also be indented. In switch/case blocks, cases shall be similarly single-indented,
|
||||
as too breaks shall remain single indented. All switch statements shall have a break, return, or throw
|
||||
at the end of each case clause or shall use [[fallthrough]] to document fallthrough behavior, where
|
||||
it is used. Default clauses are not mandatory, but are recommended. (Default clauses might be blank,
|
||||
or all cases might be covered, especially when the argument is an enum.)
|
||||
|
||||
Examples:
|
||||
|
||||
class Foobar
|
||||
{
|
||||
private:
|
||||
int x;
|
||||
|
||||
public:
|
||||
void setX( int newx ) { x= newx; }
|
||||
int getX() const { return x }
|
||||
|
||||
void
|
||||
operation( int val )
|
||||
{
|
||||
switch( val )
|
||||
{
|
||||
case 2:
|
||||
x= 11;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
x= 2;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
specialCase();
|
||||
[[fallthrough]];
|
||||
|
||||
default:
|
||||
x= val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Open
|
||||
{
|
||||
int x;
|
||||
};
|
||||
|
||||
|
||||
11) Continued lines shall be indented twice past the main parent's indent. When breaking a line on an operator,
|
||||
the next line should begin with an operator. Spaces may also be used to line up nicely for vertical alignment
|
||||
of operators; however, note that spacing alignment starts from the tab-depth of the previous line. (Never use
|
||||
spaces to align to a specific tab depth.) Control structures which have a single subordinate statement
|
||||
on a separate line shall enclose that line in braces. If wrapping becomes necessary with "one line" control
|
||||
structures, then bracing is required.
|
||||
|
||||
Example:
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
std::cout << "A really long message which "
|
||||
<< "needed to be indented "
|
||||
<< "across multiple lines." << std::endl;
|
||||
|
||||
std::cout << "A really long message which "
|
||||
<< "needed to be indented "
|
||||
<< "across multiple lines. "
|
||||
<< "This message was aligned "
|
||||
<< "on ostream operators."
|
||||
<< std::endl;
|
||||
|
||||
if( condition ) action();
|
||||
|
||||
if( moreComplicatedCondition )
|
||||
{
|
||||
moreComplicatedAction();
|
||||
}
|
||||
}
|
||||
|
||||
Reasons: It is important to know when lines have wrapped. A specific visually distinct
|
||||
style helps make this stand out from other indented scenarios. By avoiding braceless
|
||||
subordinates to control structures we avoid a class of silly maintenance bugs.
|
||||
|
||||
|
||||
12) Initializer lists shall be treated as-if they're part of the ctor body. They get
|
||||
single indented, unless the function is really short.
|
||||
|
||||
Example:
|
||||
|
||||
struct StringWrapper
|
||||
{
|
||||
std::string string;
|
||||
|
||||
explicit
|
||||
StringWrapper( const std::string &s )
|
||||
: string( s ) {}
|
||||
|
||||
explicit StringWrapper() : string( "no value" ) {} // A short ctor or other function can be on one-line.
|
||||
};
|
||||
|
||||
Exceptions: Single line functions and ctors, and the like are sometimes good to conserve space. Trivial
|
||||
implementations should take trivial amounts of space.
|
||||
|
||||
|
||||
13) Private data shall be declared before the functionality of the class is declared or defined. Constructors,
|
||||
copy assignment, and destructors shall be declared (or defined) before other member functions.
|
||||
|
||||
Example:
|
||||
|
||||
template< typename T >
|
||||
class smart_ptr : boost::noncopyable
|
||||
{
|
||||
private:
|
||||
T *ptr;
|
||||
|
||||
public:
|
||||
explicit inline
|
||||
smart_ptr( T *const p )
|
||||
: ptr( p ) {}
|
||||
|
||||
inline ~smart_ptr() { delete p; }
|
||||
|
||||
T &
|
||||
operator *() const
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
T *
|
||||
operator->() const
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
Reasons: It's easier to reason about the correctness of a class's primary invariant mechanism (construction
|
||||
and destruction) when its near the variables and types it manages. Knowing the contents of a class helps to
|
||||
understand about the invariants which must be maintained. Some argue this makes finding the public interfaces
|
||||
harder -- but Hera classes are designed to be perused by doxygen, and thus this documentation shall serve as
|
||||
a primary public usage reference. Within Hera, the only reason to read a header file is to understand more
|
||||
about a particular implementation.
|
||||
|
||||
Exceptions: None.
|
||||
|
||||
|
||||
14) Class parents (inheritance) shall logically be on the same line as the declaration. If on another line,
|
||||
must count as a continuation.
|
||||
|
||||
Reasons: It helps to isolate a class's name from the parent list, which is (when you think about it) part of
|
||||
the class, and needs indentation.
|
||||
|
||||
|
||||
15) Preprocessor nested scopes (which sometimes do happen) shall indent, by requisite spacing, all characters
|
||||
AFTER the leading "#".
|
||||
|
||||
Examples:
|
||||
|
||||
#ifndef SOME_THING
|
||||
# ifndef SOME_OTHER_THING
|
||||
# define NEITHER_THING_IS_AVAILABLE
|
||||
# else
|
||||
# error Must have SOME_THING if SOME_OTHER_THING is around
|
||||
# endif
|
||||
#endif
|
||||
|
||||
Reasons: Because C preprocessor macros also follow logical scope, it helps to trace their nesting by indentation.
|
||||
By indenting after the leading "#", we help distinguish C++ code from C preprocessor code.
|
||||
|
||||
Exceptions: The header guards, being ubiquitous, shall not count as a level of indentation in nested preprocessor
|
||||
construct
|
||||
|
||||
|
||||
16) In declaration of entities, the following order of keywords shall always be followed:
|
||||
|
||||
virtual explicit extern static constexpr consteval constinit inline mutable const volatile <TYPE>
|
||||
|
||||
For integers & double:
|
||||
unsigned long long int
|
||||
signed short int
|
||||
long double
|
||||
|
||||
signed and int are each optional.
|
||||
|
||||
For characters:
|
||||
unsigned char
|
||||
signed char
|
||||
char
|
||||
|
||||
Each of those char types are three distinct types -- signed or unsigned are NOT optional.
|
||||
|
||||
|
||||
Examples:
|
||||
struct Type
|
||||
{
|
||||
virtual inline ~Type() noexcept {} // Yes, this is actually allowed.
|
||||
explicit inline Type() {}
|
||||
static inline const std::string string() { return "String"; }
|
||||
|
||||
// Allowed, but violates the style guide:
|
||||
long const unsigned volatile int virtual long inline *resource() const;
|
||||
|
||||
// The same declaration, following the style guide:
|
||||
virtual inline const volatile unsigned long long int *resource() const;
|
||||
};
|
||||
|
||||
Reasons: C++ is very forgiving in the order of its type-and-qualifiers, but standardizing them makes finding
|
||||
specific things simpler. There are many mutually exclusive keywords above, like static and virtual and explicit,
|
||||
for example. Many may not know it but 'long const unsigned volatile int virtual long inline *' is a valid token
|
||||
sequence for declaring a member function. Standardization gives us: 'virtual inline const volatile unsigned
|
||||
long long int *', which makes the declaration type far less confusing.
|
||||
@ -1,3 +1,10 @@
|
||||
add_subdirectory( IStreamable.test )
|
||||
add_subdirectory( OStreamable.test )
|
||||
add_subdirectory( streamable.test )
|
||||
add_subdirectory( OutUnixFileBuf.test )
|
||||
add_subdirectory( StackableStreambuf.test )
|
||||
|
||||
target_sources( alepha PRIVATE
|
||||
StackableStreambuf.cc
|
||||
)
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../IStreamable.h"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../OStreamable.h"
|
||||
|
||||
|
||||
47
IOStreams/OutUnixFileBuf.h
Normal file
47
IOStreams/OutUnixFileBuf.h
Normal file
@ -0,0 +1,47 @@
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <streambuf>
|
||||
|
||||
namespace Alepha::Hydrogen::IOStreams ::detail:: OutUnixFileBuf_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
class OutUnixFileBuf;
|
||||
}
|
||||
|
||||
class exports::OutUnixFileBuf
|
||||
: virtual public std::streambuf
|
||||
{
|
||||
private:
|
||||
int fd;
|
||||
|
||||
int
|
||||
overflow( const int ch_ ) override
|
||||
{
|
||||
if( ch_ == EOF ) throw std::runtime_error{ "Unexpected EOF" };
|
||||
const char ch= ch_;
|
||||
xsputn( &ch, 1 );
|
||||
return ch_;
|
||||
}
|
||||
|
||||
std::streamsize
|
||||
xsputn( const char *const data, const std::streamsize amt ) override
|
||||
{
|
||||
return ::write( fd, data, amt );
|
||||
}
|
||||
|
||||
public:
|
||||
explicit OutUnixFileBuf( const int fd ) : fd( fd ) {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::IOStreams::inline exports::inline OutUnixFileBuf_m
|
||||
{
|
||||
using namespace detail::OutUnixFileBuf_m::exports;
|
||||
}
|
||||
28
IOStreams/OutUnixFileBuf.test/0.cc
Normal file
28
IOStreams/OutUnixFileBuf.test/0.cc
Normal file
@ -0,0 +1,28 @@
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../OutUnixFileBuf.h"
|
||||
|
||||
#include <Alepha/Testing/test.h>
|
||||
#include <Alepha/AutoRAII.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
|
||||
auto init= Alepha::Utility::enroll <=[]
|
||||
{
|
||||
using namespace Alepha::Testing::exports;
|
||||
|
||||
"Can we write to /dev/null?"_test <=[]
|
||||
{
|
||||
const auto fd= Alepha::AutoRAII
|
||||
{
|
||||
[]{ return open( "/dev/null", O_WRONLY ); },
|
||||
::close
|
||||
};
|
||||
|
||||
Alepha::IOStreams::OutUnixFileBuf buf{ fd };
|
||||
std::ostream file{ &buf };
|
||||
};
|
||||
};
|
||||
1
IOStreams/OutUnixFileBuf.test/CMakeLists.txt
Normal file
1
IOStreams/OutUnixFileBuf.test/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
unit_test( 0 )
|
||||
@ -1,17 +1,25 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "StackableStreambuf.h"
|
||||
|
||||
namespace Alepha::Hydrogen::Utility::detail::stackable_streambuf
|
||||
#include <cassert>
|
||||
|
||||
namespace Alepha::Hydrogen::IOStreams::detail::stackable_streambuf
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const auto index= std::ios::xalloc();
|
||||
|
||||
inline auto &
|
||||
auto *&
|
||||
getStackPtr( std::ios_base &ios )
|
||||
{
|
||||
return reinterpret_cast< std::stack< std::unique_ptr< StackableStreambuf > > *& >( ios.pword( index ) );
|
||||
}
|
||||
|
||||
auto &
|
||||
getStack( std::ios_base &ios )
|
||||
{
|
||||
auto &ownership= reinterpret_cast< std::stack< std::unique_ptr< StackableStreambuf > > *& >( ios.pword( index ) );
|
||||
auto &ownership= getStackPtr( ios );
|
||||
if( not ownership ) ownership= new std::decay_t< decltype( *ownership ) >{};
|
||||
|
||||
return *ownership;
|
||||
@ -24,6 +32,7 @@ namespace Alepha::Hydrogen::Utility::detail::stackable_streambuf
|
||||
{
|
||||
auto &ownership= getStack( ios );
|
||||
|
||||
assert( not ownership.empty() );
|
||||
// Since it's owned, delete happens at scope exit.
|
||||
const std::unique_ptr top= std::move( ownership.top() );
|
||||
ownership.pop();
|
||||
@ -48,9 +57,8 @@ namespace Alepha::Hydrogen::Utility::detail::stackable_streambuf
|
||||
inline void
|
||||
releaseStack( std::ios_base &ios )
|
||||
{
|
||||
auto &os= dynamic_cast< std::ostream & >( ios );
|
||||
|
||||
while( releaseTop( os ) );
|
||||
delete getStackPtr( ios );
|
||||
getStackPtr( ios )= nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -10,7 +10,7 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
|
||||
namespace Alepha::Hydrogen::Utility ::detail:: stackable_streambuf
|
||||
namespace Alepha::Hydrogen::IOStreams ::detail:: stackable_streambuf
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
@ -63,7 +63,7 @@ namespace Alepha::Hydrogen::Utility ::detail:: stackable_streambuf
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::Utility::inline exports::inline stackable_streambuf
|
||||
namespace Alepha::Hydrogen::IOStreams::inline exports::inline stackable_streambuf
|
||||
{
|
||||
using namespace detail::stackable_streambuf::exports;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../StackableStreambuf.h"
|
||||
|
||||
1
IOStreams/StackableStreambuf.test/CMakeLists.txt
Normal file
1
IOStreams/StackableStreambuf.test/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
unit_test( 0 )
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "../streamable.h"
|
||||
|
||||
|
||||
26
LICENSE
26
LICENSE
@ -1,23 +1,3 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
373
MPL-LICENSE.txt
Normal file
373
MPL-LICENSE.txt
Normal file
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -69,6 +69,7 @@ namespace Alepha::Hydrogen::Meta::Container
|
||||
};
|
||||
|
||||
template< typename MetaFunction, typename Arg1, typename First, typename ... Members >
|
||||
requires( sizeof...( Members ) != 0 )
|
||||
constexpr decltype( auto )
|
||||
invoke_call( MetaFunction func, type_value< Arg1 > arg1, dereferenced_iterator< vector< First, Members... > > deref )
|
||||
{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Meta/is_sequence.h>
|
||||
#include <Alepha/Meta/is_streamable.h>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -18,8 +18,8 @@ namespace Alepha::Hydrogen::Meta
|
||||
template< typename T >
|
||||
struct is_optional : std::false_type {};
|
||||
|
||||
template< typename T, typename ... Args >
|
||||
struct is_optional< std::optional< T, Args... > > : std::true_type {};
|
||||
template< typename T >
|
||||
struct is_optional< std::optional< T > > : std::true_type {};
|
||||
|
||||
template< typename T >
|
||||
constexpr bool is_optional_v= is_optional< T >::value;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "ProgramOptions.h"
|
||||
|
||||
@ -10,7 +10,9 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include <Alepha/StaticValue.h>
|
||||
#include <Alepha/error.h>
|
||||
|
||||
namespace Alepha::Cavorite ::detail:: program_options
|
||||
#include <Alepha/System/programName.h>
|
||||
|
||||
namespace Alepha::Hydrogen ::detail:: ProgramOptions_m
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -205,9 +207,7 @@ namespace Alepha::Cavorite ::detail:: program_options
|
||||
|
||||
VariableMap substitutions=
|
||||
{
|
||||
// This uses a GNU extension, but it's fine. We can always make this
|
||||
// portable, later.
|
||||
{ "program-name"s, lambaste<=::program_invocation_short_name },
|
||||
{ "program-name"s, lambaste<=System::programName() },
|
||||
{ "option-name"s, lambaste<=name },
|
||||
{ "default"s, [&defaultBuilder= defaultBuilder, &name= name]
|
||||
{
|
||||
@ -283,8 +283,7 @@ namespace Alepha::Cavorite ::detail:: program_options
|
||||
{
|
||||
VariableMap substitutions
|
||||
{
|
||||
// Another use of the GNUism.
|
||||
{ "program-name"s, lambaste<=::program_invocation_short_name },
|
||||
{ "program-name"s, lambaste<=System::programName() },
|
||||
};
|
||||
|
||||
if( canonicalName.has_value() ) substitutions[ "canonical-name"s ]= lambaste<=canonicalName.value();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -96,7 +96,7 @@ static_assert( __cplusplus > 2020'00 );
|
||||
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
|
||||
namespace Alepha::inline Cavorite ::detail:: program_options
|
||||
namespace Alepha::Hydrogen ::detail:: ProgramOptions_m
|
||||
{
|
||||
inline namespace exports {}
|
||||
|
||||
@ -290,7 +290,7 @@ namespace Alepha::inline Cavorite ::detail:: program_options
|
||||
// TODO: This should steal the impl from the vector form, above, and that should defer to this.
|
||||
|
||||
using parse_type= typename arg_type::value_type;
|
||||
auto handler= [handler, name= name]( std::optional< std::string > argument )
|
||||
auto wrapped= [handler, name= name]( std::optional< std::string > argument )
|
||||
{
|
||||
impl::checkArgument( argument, name );
|
||||
|
||||
@ -311,7 +311,7 @@ namespace Alepha::inline Cavorite ::detail:: program_options
|
||||
};
|
||||
handler( parsed );
|
||||
};
|
||||
return registerHandler( handler );
|
||||
return registerHandler( wrapped );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -392,12 +392,12 @@ namespace Alepha::inline Cavorite ::detail:: program_options
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline program_options
|
||||
namespace Alepha::Hydrogen::inline exports::inline ProgramOptions_m
|
||||
{
|
||||
using namespace detail::program_options::exports;
|
||||
using namespace detail::ProgramOptions_m::exports;
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline literals::inline option_literals
|
||||
namespace Alepha::Hydrogen::inline exports::inline literals::inline option_literals
|
||||
{
|
||||
using namespace detail::program_options::exports::literals;
|
||||
using namespace ProgramOptions_m::literals;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
/*!
|
||||
* @file
|
||||
* @brief The `Attestation` framework permits code which can provide limited compiletime guarantees of conditions.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -72,14 +72,6 @@ namespace Alepha::Hydrogen::Reflection
|
||||
// any initialization method.
|
||||
struct argument { template< typename T > constexpr operator T (); };
|
||||
|
||||
template< typename T >
|
||||
struct checker
|
||||
{
|
||||
using type= typename checker< T >::type;
|
||||
//using type= void;
|
||||
//static_assert( std::is_empty_v< T > );
|
||||
};
|
||||
|
||||
// Any empty-base-class argument.
|
||||
template< typename Aggregate >
|
||||
struct empty_base
|
||||
@ -88,7 +80,6 @@ namespace Alepha::Hydrogen::Reflection
|
||||
requires
|
||||
(
|
||||
true
|
||||
//typename= typename checker< std::decay_t< T > >::type,
|
||||
and EmptyType< std::decay_t< T > >
|
||||
and not SameAs< std::decay_t< T >, Aggregate >
|
||||
and DerivedFrom< Aggregate, std::decay_t< T > >
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Reflection/tuplizeAggregate.h>
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
223
Style
Normal file
223
Style
Normal file
@ -0,0 +1,223 @@
|
||||
Alepha library C++ style Guide
|
||||
|
||||
This guide shall follow the format of "Rule", then "Examples", then "Reasoning", then "Exceptions".
|
||||
Some of these clauses are omitted. No portion of the C++ language itself is off-limits, unless explicit mention
|
||||
is made banning that feature -- which is rare. The Alepha C++ philosophy sees C++ as a whole langauge and
|
||||
does not seek to provide a "safe subset". The few banned features tend to be those which are either deprecated
|
||||
or generally unused.
|
||||
|
||||
Note that this "style guide" covers the style of the code in the sense of how to write the code itself,
|
||||
not the rendering/format. For that guide, please see the "Format" file.
|
||||
|
||||
General Coding and Language Rules:
|
||||
|
||||
0. The Alepha C++ library shall only contain code written for ISO/ANSI C++23, compilation with any other language
|
||||
standard is incidental. Modifying a component of Alepha to compile with a non-compliant compiler (while still
|
||||
remaining compliant to the standard) is sometimes necessary. Deprecated features should be avoided, wherever
|
||||
possible. C++98 code (with precious few exceptions) will work unchanged in C++23.
|
||||
|
||||
Reason: Alepha is a modern C++ library technology.
|
||||
|
||||
Exceptions: None. ("#pragma once" is used, as if it were part of the standard. This is widely supported,
|
||||
and when C++20's modules become more prevalent, the library will move to those.)
|
||||
|
||||
Note: Even among all "compliant" compilers, some quirks prevent perfect, and ideal C++23 code.
|
||||
Even in such cases, the code which does compile is still expected to be C++23 compliant.
|
||||
|
||||
|
||||
1. All names and user-defined tokens shall avoid C89, C99, C11, C++98, C++03, C++11, C++14, C++17, C++20, and C++23
|
||||
implementation reserved names, in all contexts.
|
||||
|
||||
- Names shall not begin with an underscore.
|
||||
- Names shall not contain two consecutive underscores.
|
||||
- User defined names include: functions, macros, classes, constants, and header guards.
|
||||
- Be mindful of C++'s little known reserved words: compl or not and xor bit_and bit_or bit_xor
|
||||
|
||||
Reason: Alepha is a portable C++ library, and thus must be able to compile with any C++23 compiler. The presence
|
||||
of implementation reserved names in code can cause potential issues. Even in a context where the name wouldn't
|
||||
be reserved, consider it to be reserved.
|
||||
|
||||
Exceptions: NONE
|
||||
|
||||
|
||||
2. `#define`s of a keyword to anything else are prohibited.
|
||||
|
||||
Reason: #defining a keyword yields non-portable behavior. On a fully conforming C++23 compiler, all features
|
||||
are present, and useful. Not all compilers behave in the same way, when it comes to violating the standard.
|
||||
|
||||
Exceptions: None. For a while, it was necessary to supplement some compilers with `#define override` or
|
||||
similar hacks, for not-yet-supported C++11 features. By this point in time, the new features in C++20 and
|
||||
C++23 cannot be so easily "hacked in".
|
||||
|
||||
|
||||
3. No C++23 core-language features shall be proscribed from use, with the exception of avoiding the following
|
||||
idioms or features (some are banned outright):
|
||||
|
||||
- digraphs are forbidden (Trigraphs were removed in 17)
|
||||
- prefer `new` over `malloc` (except in implementing `::operator new`)
|
||||
- prefer to use `()` instead of `( void )` in empty parameter functions
|
||||
- avoid `reinterpret_cast` (except in specific hardware-oriented contexts, or where otherwise necessary)
|
||||
- rarely use "old C style" casts. (E.g.: `(char *) variable`) -- this is widely known to be dangerous
|
||||
- never throw from a destructor -- this is not expected by any C++23 libraries
|
||||
- Avoid the use of general `mutable` members. No good can come from changing values behind const, even locks.
|
||||
TOCTIOU bugs abound with observers of threadsafe mechanisms. Properly written Atomics primitives still need
|
||||
to be members of classes as mutable.
|
||||
|
||||
Reason: C++23 is a cohesive, well-reasoned language with many tightly-integrated features. Circumscription of
|
||||
a feature is ill-advised. The above prohibitions are mostly encouraged by choices of the standards committee
|
||||
over the past 20 or more years. Reinterpret cast, in particular, represents a standards-sanctioned form of
|
||||
platform specific behavior. Digraphs and trigraphs were a compatibility feature required by the standard, but
|
||||
are bizarre and unintuitive -- many compilers disabled them unless in strict compatibility modes, and they are
|
||||
removed in C++23.
|
||||
|
||||
Exceptions: Malloc can be used in circumstances where that allocator is necessary. "( void )" parameter lists are
|
||||
usable in specific 'meant to be included in C' headers -- these must be in their own directory. C style casts
|
||||
are dangerous, in general, but '(float) 4 / 2' is more readable than: 'static_cast< float >( 4 ) /
|
||||
static_cast< float >( 2 )' or 'std::divide< float >{}( 4, 2 )' -- prefer function-style casting if possible though.
|
||||
Never cast with typedefs, or pointers. Destructor throwing is banned, because no C++ STL library can recover
|
||||
from it, nor can the exception system itself. Reinterpret_cast has platform dependent behavior, and should
|
||||
only be in platform-dependent code. Digraphs should only exist in obfuscation contests. Assume that
|
||||
destructors that throw always cause undefined behavior.
|
||||
|
||||
|
||||
4. No non-portable, undefined, implementation defined, or optional behaviors, functions and features shall be
|
||||
placed into any non-detail portions of the Alepha library. Detail portions shall push implementation-specifics
|
||||
into isolated files. Only the "Alepha::Windows", "Alepha::Posix", or similar namespaces shall contain any
|
||||
non-portable constructs.
|
||||
|
||||
Reasons: Portability is a top concern for the Alepha library.
|
||||
|
||||
Exceptions: Alepha has namespaces dedicated to specific platforms and systems -- those namespaces are suitable
|
||||
for non-portable code, but no core library portions may rely upon those. (Code must compile with a C++11
|
||||
compiler and be platform agnostic.) For non-portable namespaces, the code should remain compiler agnostic,
|
||||
where possible. Always use macro-guards to prevent accidental compilation of files intended for only one compiler.
|
||||
|
||||
|
||||
5. Avoid "pass-by-non-const-reference" for "out-params". Prefer tuples, pairs and aggregate types for multiple
|
||||
return values, and use exceptions to signal failures.
|
||||
|
||||
Reason: "push-to-argument" style was useful in the 1990s when compilers were very bad at optimizing the
|
||||
class return path. In a post-C++11 world, with both NRV and move semantics, this caveat is no longer pertinent.
|
||||
Further, this out-parameter style was necessary when exceptions were avoided, as returning an aggregate is
|
||||
not conducive to error-checking. Alepha fully embraces the C++ exceptions mindset. Exceptions exist in the
|
||||
language to signal out-of-band errors -- return codes are to be avodied.
|
||||
|
||||
Exceptions: Sometimes arguments have to be passed to be modified, like 'operator <<' on std::ostream. The
|
||||
'operator >>' std::istream operators are also examples of this, but technically fall under the "out-params" rule.
|
||||
Historically these iostream constructs exist, and we shall still support the iostreams idiom -- it's part of
|
||||
the standard.
|
||||
|
||||
|
||||
6. Manage all resources with objects and RAII. Prefer to manage only a single resource per RAII class. Do not
|
||||
ever allow unshepherded or unowned resources to exist. Directly callling "new" is strongly discouraged.
|
||||
|
||||
Reason: It's not just a good idea -- all of C++23 is built around the RAII idiom. It's necessary for exception
|
||||
safety, which is a core part of the Alepha philosophy. An RAII class which has to manage several resources
|
||||
often represents a design bug. Some classes (like ref-counting-pointer constructs) may need to allocate some
|
||||
resources to manage another resource -- this is unavoidable, but the other resources are management metadata.
|
||||
|
||||
Exceptions: None, whatsoever.
|
||||
|
||||
|
||||
7. Unless a class is intended to directly manage a resource, it ought to have a blank destructor, in the
|
||||
ideal situation. Prefer `AutoRAII` as the basis of a class designed to use resource management, in the general
|
||||
case.
|
||||
|
||||
Reason: RAII is most effective when each class that actually manages a resource only manages a single resource,
|
||||
and concept abstraction classes don't have to have any explicit resource management.
|
||||
|
||||
Exceptions: Sometimes a destructor of a class may need to call one of its own functions, like a "cancel"
|
||||
function. A network request, or a thread, for example. This is not entirely an exception, since that class
|
||||
models that concept as a kind of resource. Conversely, those "cancel" functions are merely an exposition of
|
||||
the dtor functionality for early voluntary cleanup.
|
||||
|
||||
|
||||
8. Naked `delete` and other resource release calls outside of destructors are banned. Naked `new` and other
|
||||
resource allocation calls that are assigned to raw unmanaged C types, outside of constructors or constructor
|
||||
parameters are banned. This rule works hand-in-hand with the previous three rules. Prefer scoped_ptr,
|
||||
unique_ptr, shared_ptr, weak_ptr, AutoRAII, vector, list, set, map, and other types over rolling your own
|
||||
resource management types, where possible. Calls to 'new' and 'delete' are bad code smells. Use of raw
|
||||
primitive pointers is also such a code smell. Consider using `single_ptr` or a native reference when working
|
||||
with items held at a distance. Alepha::single_ptr is only constructible from an owned resource, or another
|
||||
single_ptr.
|
||||
|
||||
Reason: C++ RAII is the only safe way to manage resources. By limiting the resource release code to only
|
||||
exist in dtors, it limits the scope of code needed to audit for leak-safety. Even RAII classes should only
|
||||
handle resource release through the dtor path. Resource release outside of this path should be viewed as a
|
||||
glaring bug. Resource acquisition outside of a ctor, or an argument to a ctor should likewise be seen as a bug.
|
||||
Raw C types are unsafe for resource management in the face of changing resources.
|
||||
|
||||
Exceptions: None. Although passing a lambda calling a release function to an AutoRAII object is technically
|
||||
an exception, it should be thought of as writing an inline dtor. Note that std::make_unique and
|
||||
std::make_shared are suitable replacements for new in almost all situations.
|
||||
|
||||
|
||||
9. Avoid the use of #ifdef/else/endif for conditional compilation of code -- prefer to include headers with
|
||||
well defined code for these purposes.
|
||||
|
||||
Reason: Conditional compilation makes code multiply architecturally dependent not independent.
|
||||
|
||||
Exceptions: Some small blocks of code (particularly preprocessor control macros) can be if-else-endif for
|
||||
small specific variances.
|
||||
|
||||
|
||||
|
||||
|
||||
Basic Environment Rules:
|
||||
|
||||
0. Alepha shall compile on any C++23 compliant compilers. At present gcc-13 is a supported minimum,
|
||||
and is also the "reference compiler".
|
||||
|
||||
Exception: Compiler specific code in detail sections need only work with that compiler. Platform specific code,
|
||||
in Alepha::<Platform> namespaces need only work on that target platform, but should be portable across compilers
|
||||
for that platform. Alepha::Posix sections should try to also work in Cygwin, where possible.
|
||||
|
||||
1. Header files shall be named with a trailing ".h". Headers shall be entirely compatible with C++.
|
||||
|
||||
2. Header files which are safe to include from "C" language parsers shall be organized into a specific
|
||||
"c_interface" subdirectory of the appropriate domain. Such headers are rarely expected.
|
||||
|
||||
|
||||
Basic Naming Rules:
|
||||
|
||||
0. Use good judgement in naming things. This cannot be codified as a set of mechanical rules.
|
||||
|
||||
1. Follow this general naming style (there's some room for flexibility within):
|
||||
|
||||
* ClassesAndTypedefsLikeThis
|
||||
* PublicNamespaceAlsoLikeThis
|
||||
* functionsAndVariablesLikeThis
|
||||
* ALEPHA_PATH_TO_MACROS_GET_NAMED_IN_VERY_LONG_STYLE_AND_OBNOXIOUS_WITH_CAPS_AND_UNDERSCORES
|
||||
* meta_programming_things_like_this
|
||||
* TCP_IP_Socket or connectToTCP_IP_Socket-- If the entity name contains abbreviations, separate the abbreviation by `_`,
|
||||
don't case flatten things like TCP to Tcp.
|
||||
* Follow STL and related C++ Standards names, where appropriate (`push_back` not `pushBack`).
|
||||
|
||||
2. Follow the general module-namespace technique defined in the NAMESPACES document.
|
||||
|
||||
3. Name the private module namespace within files as ` ::detail:: FileName_m`, such that `FileName.h`
|
||||
provides the namespace. This provides a simple transform:
|
||||
Alepha/IOStream/String.h -> Alepha::IOStream::String_m
|
||||
|
||||
4. General file naming is case-sensitive. Every major modern operating system supports a case-sensitive
|
||||
filesystem. Use it. Windows' default filesystem is case-preserving. This case-preserving property
|
||||
should suffice for most file naming situations; however, if `foo.h` and `Foo.h` both exist, it might
|
||||
cause a problem. That problem is more easily remedied by using a case-sensitive filesystem than by
|
||||
putting an onus for name mangling onto a project.
|
||||
|
||||
5. Name files after the primary component in them, if the file makes a single component available.
|
||||
|
||||
Example: `class Alepha::Foobar::Quux` should be defined in `Alepha/Foobar/Quux.h`, if defined in a single
|
||||
file. The full public name of that class would be `Alepha::Foobar::exports::Quux_m::Quux`. The private
|
||||
name can be anything, of course, but would typically be `Alepha::Foobar::detail::Quux_m::exports::Quux`.
|
||||
|
||||
6. Name files which provide families of facilities without leading capitals. Those names shouldn't be
|
||||
confused for classes.
|
||||
|
||||
7. Name functions with a verb, where appropriate. Don't name observers with a `get` verb.
|
||||
|
||||
8. Avoid names with `do`, `run`, `compute`, or `execute` in them for functions. Remember functions
|
||||
`do`, they aren't things.
|
||||
|
||||
9. Avoid names with `-er`, `Manager`, `Owner`, or `Holder` in them for classes. Remember that
|
||||
classes don't `do`, they're not functions.
|
||||
46
System/programName.h
Normal file
46
System/programName.h
Normal file
@ -0,0 +1,46 @@
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#if defined( __FreeBSD__ )
|
||||
# include <sys/types.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined( _GNU_SOURCE )
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Alepha::Hydrogen::System ::detail:: programName_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
inline std::string
|
||||
programName()
|
||||
{
|
||||
#if defined( __FreeBSD__ )
|
||||
int mib[]
|
||||
{
|
||||
CTL_KERN,
|
||||
KERN_PROC,
|
||||
KERN_PROC_PATHNAME,
|
||||
-1,
|
||||
};
|
||||
char buf[ 4096 ];
|
||||
std::size_t cb = sizeof( buf );
|
||||
::sysctl( mib, 4, buf, &cb, nullptr, 0);
|
||||
return buf;
|
||||
#elif defined( _GNU_SOURCE )
|
||||
return ::program_invocation_short_name;
|
||||
#else
|
||||
#error "Not supported."
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::System::inline exports::inline programName_m
|
||||
{
|
||||
using namespace detail::programName_m::exports;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -17,80 +17,31 @@ static_assert( __cplusplus > 2020'00 );
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <Alepha/Meta/is_vector.h>
|
||||
#include <Alepha/Meta/is_optional.h>
|
||||
#include <Alepha/Meta/is_streamable.h>
|
||||
#include <Alepha/Meta/is_sequence.h>
|
||||
#include <Alepha/Meta/is_product_type.h>
|
||||
|
||||
#include <Alepha/Meta/product_type_decay.h>
|
||||
#include <Alepha/Meta/sequence_kind.h>
|
||||
|
||||
#include <Alepha/function_traits.h>
|
||||
#include <Alepha/template_for_each.h>
|
||||
|
||||
#include <Alepha/IOStreams/String.h>
|
||||
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
#include <Alepha/Utility/TupleAdapter.h>
|
||||
|
||||
#include <Alepha/Reflection/tuplizeAggregate.h>
|
||||
|
||||
#include <Alepha/TotalOrder.h>
|
||||
#include <Alepha/Console.h>
|
||||
|
||||
#include "colors.h"
|
||||
#include "printDebugging.h"
|
||||
|
||||
namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
enum class OutputMode { All, Relaxed };
|
||||
}
|
||||
inline namespace exports {}
|
||||
|
||||
inline void breakpoint() {}
|
||||
|
||||
namespace C
|
||||
{
|
||||
inline namespace Colors
|
||||
namespace C:: inline Colors
|
||||
{
|
||||
using namespace testing_colors::C::Colors;
|
||||
}
|
||||
}
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
void printDebugging( const T &witness, const T &expected );
|
||||
|
||||
template< Aggregate Agg, TypeListType >
|
||||
struct TupleSneak;
|
||||
|
||||
template< Aggregate Agg >
|
||||
struct TupleSneak< Agg, Nil >
|
||||
: Agg
|
||||
{
|
||||
TupleSneak() { std::cerr << "The inherited default ctor was called." << std::endl; }
|
||||
|
||||
protected:
|
||||
void set( Agg agg ) { static_cast< Agg & >( *this )= agg; }
|
||||
};
|
||||
|
||||
template< Aggregate Agg, typename ... Args >
|
||||
struct TupleSneak< Agg, TypeList< Args... > >
|
||||
: TupleSneak< Agg, cdr_t< TypeList< Args... > > >
|
||||
{
|
||||
using Parent= TupleSneak< Agg, cdr_t< TypeList< Args... > > >;
|
||||
using Parent::Parent;
|
||||
|
||||
TupleSneak( Args ... args )
|
||||
{
|
||||
std::cerr << "I was the ctor called, with " << sizeof...( Args ) << " arguments." << std::endl;
|
||||
tuple_for_each( std::tuple{ args... } ) <=
|
||||
[]( const auto element )
|
||||
{
|
||||
std::cerr << "Element: " << element << std::endl;
|
||||
};
|
||||
this->set( { args... } );
|
||||
}
|
||||
};
|
||||
|
||||
enum class TestResult { Passed, Failed };
|
||||
|
||||
@ -100,7 +51,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
static consteval auto
|
||||
compute_base_f() noexcept
|
||||
{
|
||||
if constexpr ( Aggregate< T > ) return std::type_identity< TupleSneak< T, list_from_tuple_t< Reflection::aggregate_tuple_t< T > > > >{};
|
||||
if constexpr ( Aggregate< T > ) return std::type_identity< Utility::TupleAdapter< T > >{};
|
||||
else if constexpr( std::is_class_v< T > ) return std::type_identity< T >{};
|
||||
else return std::type_identity< BlankBase >{};
|
||||
}
|
||||
@ -109,141 +60,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
using compute_base_t= typename decltype( compute_base_f< std::decay_t< T > >() )::type;
|
||||
|
||||
template< typename return_type, OutputMode outputMode >
|
||||
struct BasicUniversalHandler;
|
||||
|
||||
template< Primitive return_type, OutputMode outputMode >
|
||||
struct BasicUniversalHandler< return_type, outputMode >
|
||||
{
|
||||
using Invoker= std::function< return_type () >;
|
||||
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
||||
|
||||
TestResult
|
||||
operator() ( Invoker invoker, const std::string &comment ) const
|
||||
{
|
||||
return impl( invoker, comment );
|
||||
//if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
||||
}
|
||||
|
||||
#if 1
|
||||
BasicUniversalHandler( const return_type expected )
|
||||
: impl
|
||||
{
|
||||
[expected]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
const auto witness= Utility::evaluate <=[&]() -> std::optional< return_type >
|
||||
{
|
||||
try
|
||||
{
|
||||
return invoker();
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
|
||||
if( result == TestResult::Failed )
|
||||
{
|
||||
if( witness.has_value() )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
printDebugging< outputMode >( witness.value(), expected );
|
||||
}
|
||||
else std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": Unexpected exception in \"" << comment << '"' << std::endl;
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
template< typename ... Args >
|
||||
requires ConstructibleFrom< return_type, std::decay_t< Args >... >
|
||||
BasicUniversalHandler( Args &&... expected_init )
|
||||
: BasicUniversalHandler( return_type{ std::forward< Args >( expected_init )... } )
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
template< typename T >
|
||||
requires( not SameAs< T, void > )
|
||||
BasicUniversalHandler( std::type_identity< T > ) : impl
|
||||
{
|
||||
[]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore= invoker();
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Failed;
|
||||
}
|
||||
catch( const T & )
|
||||
{
|
||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Passed;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< typename T >
|
||||
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
||||
BasicUniversalHandler( T ) : impl
|
||||
{
|
||||
[]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore= invoker();
|
||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Passed;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< DerivedFrom< std::exception > T >
|
||||
BasicUniversalHandler( const T exemplar ) : impl
|
||||
{
|
||||
[expected= std::string{ exemplar.what() }]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"
|
||||
<< typeid( T ).name()
|
||||
<< "` wasn't thrown." << std::endl;
|
||||
return TestResult::Failed;
|
||||
}
|
||||
catch( const T &ex )
|
||||
{
|
||||
const std::string witness= ex.what();
|
||||
const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
if( rv == TestResult::Failed )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected message did not match." << std::endl;
|
||||
printDebugging< outputMode >( witness, expected );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
#endif
|
||||
};
|
||||
|
||||
template< Aggregate return_type, OutputMode outputMode >
|
||||
struct BasicUniversalHandler< return_type, outputMode >
|
||||
struct BasicUniversalHandler
|
||||
: compute_base_t< return_type >
|
||||
{
|
||||
using ComputedBase= compute_base_t< return_type >;
|
||||
@ -253,12 +70,43 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
|
||||
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
||||
|
||||
BasicUniversalHandler( const return_type expected ) : impl
|
||||
{
|
||||
[expected]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
const auto witness= Utility::evaluate <=[&]() -> std::optional< return_type >
|
||||
{
|
||||
try
|
||||
{
|
||||
return invoker();
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
|
||||
if( result == TestResult::Failed )
|
||||
{
|
||||
if( witness.has_value() )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
printDebugging< outputMode >( witness.value(), expected );
|
||||
}
|
||||
else std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": Unexpected exception in \"" << comment << '"' << std::endl;
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
TestResult
|
||||
operator() ( Invoker invoker, const std::string &comment ) const
|
||||
{
|
||||
if( impl != nullptr ) return impl( invoker, comment );
|
||||
//if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
||||
if constexpr( true )
|
||||
if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
||||
{
|
||||
const return_type *const expected_p= this;
|
||||
const auto expected= *expected_p;
|
||||
@ -291,39 +139,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
else throw std::logic_error( "Somehow we didn't setup impl, and it's not an adapted case!" );
|
||||
}
|
||||
|
||||
#if 0
|
||||
template< typename T_= return_type, typename= std::enable_if_t< not std::is_class_v< std::decay_t< T_ > > > >
|
||||
BasicUniversalHandler( const T_ expected )
|
||||
: impl
|
||||
{
|
||||
[expected]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
static_assert( not Aggregate< T_ > );
|
||||
static_assert( not std::is_class_v< T_ > );
|
||||
const return_type witness= invoker();
|
||||
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
|
||||
if( result == TestResult::Failed )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
printDebugging< outputMode >( witness, expected );
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
template< typename ... Args >
|
||||
requires ConstructibleFrom< return_type, std::decay_t< Args >... >
|
||||
BasicUniversalHandler( Args &&... expected_init )
|
||||
: BasicUniversalHandler( return_type{ std::forward< Args >( expected_init )... } )
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
template< typename T >
|
||||
requires( not SameAs< T, void > )
|
||||
BasicUniversalHandler( std::type_identity< T > ) : impl
|
||||
@ -396,167 +211,8 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
}
|
||||
}
|
||||
{}
|
||||
#endif
|
||||
};
|
||||
|
||||
template< typename return_type, OutputMode outputMode >
|
||||
struct BasicUniversalHandler
|
||||
: return_type
|
||||
{
|
||||
using return_type::return_type;
|
||||
|
||||
BasicUniversalHandler( return_type rt ) : return_type( rt ) {}
|
||||
|
||||
using Invoker= std::function< return_type () >;
|
||||
|
||||
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
||||
|
||||
TestResult
|
||||
operator() ( Invoker invoker, const std::string &comment ) const
|
||||
{
|
||||
if( impl != nullptr ) return impl( invoker, comment );
|
||||
//if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
||||
if constexpr( true )
|
||||
{
|
||||
const return_type *const expected_p= this;
|
||||
const auto expected= *expected_p;
|
||||
const auto witness= Utility::evaluate <=[&]() -> std::optional< return_type >
|
||||
{
|
||||
try
|
||||
{
|
||||
return invoker();
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
|
||||
if( result == TestResult::Failed )
|
||||
{
|
||||
if( witness.has_value() )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
printDebugging< outputMode >( witness.value(), expected );
|
||||
}
|
||||
else std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": Unexpected exception in \"" << comment << '"' << std::endl;
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return result;
|
||||
}
|
||||
else throw std::logic_error( "Somehow we didn't setup impl, and it's not an adapted case!" );
|
||||
}
|
||||
|
||||
#if 0
|
||||
template< typename T_= return_type, typename= std::enable_if_t< not std::is_class_v< std::decay_t< T_ > > > >
|
||||
BasicUniversalHandler( const T_ expected )
|
||||
: impl
|
||||
{
|
||||
[expected]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
static_assert( not Aggregate< T_ > );
|
||||
static_assert( not std::is_class_v< T_ > );
|
||||
const return_type witness= invoker();
|
||||
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
|
||||
if( result == TestResult::Failed )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
printDebugging< outputMode >( witness, expected );
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
template< typename ... Args >
|
||||
requires ConstructibleFrom< return_type, std::decay_t< Args >... >
|
||||
BasicUniversalHandler( Args &&... expected_init )
|
||||
: BasicUniversalHandler( return_type{ std::forward< Args >( expected_init )... } )
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
template< typename T >
|
||||
requires( not SameAs< T, void > )
|
||||
BasicUniversalHandler( std::type_identity< T > ) : impl
|
||||
{
|
||||
[]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore= invoker();
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Failed;
|
||||
}
|
||||
catch( const T & )
|
||||
{
|
||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Passed;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< typename T >
|
||||
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
||||
BasicUniversalHandler( T ) : impl
|
||||
{
|
||||
[]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore= invoker();
|
||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Passed;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
return TestResult::Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< DerivedFrom< std::exception > T >
|
||||
BasicUniversalHandler( const T exemplar ) : impl
|
||||
{
|
||||
[expected= std::string{ exemplar.what() }]( Invoker invoker, const std::string &comment )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"
|
||||
<< typeid( T ).name()
|
||||
<< "` wasn't thrown." << std::endl;
|
||||
return TestResult::Failed;
|
||||
}
|
||||
catch( const T &ex )
|
||||
{
|
||||
const std::string witness= ex.what();
|
||||
const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||
if( rv == TestResult::Failed )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected message did not match." << std::endl;
|
||||
printDebugging< outputMode >( witness, expected );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
template< typename F >
|
||||
concept FunctionVariable=
|
||||
requires( const F &f )
|
||||
@ -564,7 +220,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
{ std::function{ f } };
|
||||
};
|
||||
|
||||
|
||||
namespace exports
|
||||
{
|
||||
template< FunctionVariable auto, OutputMode outputMode= OutputMode::All > struct TableTest;
|
||||
@ -578,7 +233,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
|
||||
using std::begin, std::end;
|
||||
using namespace Utility::exports::evaluation_helpers;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
template< template< typename, typename... > class Sequence, typename ... TupleArgs >
|
||||
auto
|
||||
@ -598,151 +252,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
return rv;
|
||||
}
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
std::string
|
||||
stringifyValue( const T &v )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
if constexpr( false ) ; // To keep the rest of the clauses regular
|
||||
else if constexpr( std::is_same_v< std::uint8_t, std::decay_t< T > > )
|
||||
{
|
||||
oss << std::hex << std::setw( 2 ) << std::setfill( '0' ) << int( v );
|
||||
}
|
||||
else if constexpr( std::is_same_v< bool, std::decay_t< T > > )
|
||||
{
|
||||
oss << std::boolalpha << v;
|
||||
}
|
||||
else if constexpr( std::is_same_v< std::string, std::decay_t< T > > )
|
||||
{
|
||||
oss << "(String with " << v.size() << " chars)";
|
||||
oss << '\n' << R"(""")" << '\n';
|
||||
for( const char ch: v )
|
||||
{
|
||||
if( ch == '\n' ) oss << "<EOL>\n";
|
||||
else if( std::isalnum( ch ) or std::ispunct( ch ) or ( ch == ' ' ) ) oss << ch;
|
||||
else oss << "<\\0x" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << unsigned( ch ) << '>';
|
||||
}
|
||||
oss << '\n' << R"(""")";
|
||||
}
|
||||
else if constexpr( Meta::is_ostreamable_v< T > )
|
||||
{
|
||||
return IOStreams::stringify( v );
|
||||
}
|
||||
else if constexpr( Meta::is_optional_v< T > )
|
||||
{
|
||||
return v.has_value() ? stringifyValue< outputMode >( v.value() ) : "<noopt>"s;
|
||||
}
|
||||
else if constexpr( Meta::is_sequence_v< T > )
|
||||
{
|
||||
if constexpr( outputMode == OutputMode::Relaxed and not Meta::is_ostreamable_v< typename T::value_type > )
|
||||
{
|
||||
oss << "<Unstreamable sequence of " << v.size() << " elements.>";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << Meta::sequence_kind_v< T > << "(" << v.size() << " elements):\n{" << std::endl;
|
||||
|
||||
int index= 0;
|
||||
for( const auto &elem: v ) oss << "\t" << index++ << ": " << stringifyValue< outputMode >( elem ) << "," << std::endl;
|
||||
oss << "}" << std::endl;
|
||||
}
|
||||
}
|
||||
else if constexpr( Meta::is_pair_v< T > )
|
||||
{
|
||||
const auto &[ first, second ]= v;
|
||||
return stringifyValue< outputMode >( std::tie( first, second ) );
|
||||
}
|
||||
else if constexpr( Meta::is_tuple_v< T > )
|
||||
{
|
||||
oss << '[';
|
||||
tuple_for_each( v ) <=[&oss, first= true]( const auto &elem ) mutable
|
||||
{
|
||||
if( not first ) oss << ", ";
|
||||
first= false;
|
||||
oss << std::endl << stringifyValue< outputMode >( elem );
|
||||
};
|
||||
oss << std::endl << ']' << std::endl;
|
||||
}
|
||||
else if constexpr( std::is_same_v< T, TotalOrder > )
|
||||
{
|
||||
if( false ) ; // For alignment
|
||||
else if( v == TotalOrder::less ) oss << "less";
|
||||
else if ( v == TotalOrder::equal ) oss << "equal";
|
||||
else if( v == TotalOrder::greater ) oss << "greater";
|
||||
else throw std::logic_error( "Impossible `TotalOrder` condition." );
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert( dependent_value< false, T >, "One of the types used in the testing table does not support stringification." );
|
||||
}
|
||||
return std::move( oss ).str();
|
||||
}
|
||||
|
||||
inline void
|
||||
printDebuggingForStrings( const std::string &witness, const std::string &expected )
|
||||
{
|
||||
const std::size_t amount= std::min( witness.size(), expected.size() );
|
||||
if( witness.size() != expected.size() )
|
||||
{
|
||||
std::cout << "Witness string size did not match the expected string size. Only mismatches found in the first "
|
||||
<< amount << " characters will be printed." << std::endl;
|
||||
}
|
||||
|
||||
for( int i= 0; i < amount; ++i )
|
||||
{
|
||||
if( witness.at( i ) == expected.at( i ) ) continue;
|
||||
std::cout << "Mismatch at index: " << i << std::endl;
|
||||
std::cout << "witness: " << witness.at( i ) << std::endl;
|
||||
std::cout << "expected: " << expected.at( i ) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
void
|
||||
printDebugging( const T &witness, const T &expected )
|
||||
{
|
||||
if constexpr( std::is_same_v< std::string, std::decay_t< T > > )
|
||||
{
|
||||
printDebuggingForStrings( witness, expected );
|
||||
}
|
||||
else if constexpr( Meta::is_sequence_v< T > )
|
||||
{
|
||||
if constexpr( std::is_same_v< std::string, typename T::value_type > )
|
||||
{
|
||||
if( witness.size() == expected.size() ) for( std::size_t i= 0; i < witness.size(); ++i )
|
||||
{
|
||||
if( witness.at( i ) != expected.at( i ) ) printDebuggingForStrings( witness.at( i ), expected.at( i ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( witness.size() != expected.size() )
|
||||
{
|
||||
std::cout << "Witness sequence size of " << witness.size() << " did not match the expected sequence size of "
|
||||
<< expected.size() << std::endl;
|
||||
}
|
||||
|
||||
auto next= std::make_pair( begin( witness ), begin( expected ) );
|
||||
bool first= true;
|
||||
while( next.first != end( witness ) and next.second != end( expected ) )
|
||||
{
|
||||
if( not first )
|
||||
{
|
||||
std::cout << "Mismatch at witness index " << std::distance( begin( witness ), next.first ) << " and "
|
||||
<< "expected index " << std::distance( begin( expected ), next.second ) << std::endl;
|
||||
++next.first; ++next.second;
|
||||
}
|
||||
first= false;
|
||||
next= std::mismatch( next.first, end( witness ), next.second, end( expected ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << std::endl
|
||||
<< "computed: " << stringifyValue< outputMode >( witness ) << std::endl
|
||||
<< "expected: " << stringifyValue< outputMode >( expected ) << std::endl << std::endl;
|
||||
}
|
||||
|
||||
template< FunctionVariable auto function, OutputMode outputMode >
|
||||
struct exports::TableTest
|
||||
{
|
||||
@ -751,175 +260,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
using args_type= Meta::product_type_decay_t< typename function_traits_type::args_type >;
|
||||
using return_type= typename function_traits_type::return_type;
|
||||
|
||||
// The classic table-test engine would only support `Cases` which were run-and-test-value
|
||||
// without the ability to test exceptions. The `ExceptionCases` construct was used to
|
||||
// test throwing cases.
|
||||
//
|
||||
// A unified `Cases` type is forthcoming, and thus `ExecutionCases` exists for backwards
|
||||
// compatibility.
|
||||
struct ExecutionCases
|
||||
{
|
||||
using TestDescription= std::tuple< std::string, args_type, return_type >;
|
||||
|
||||
std::vector< TestDescription > tests;
|
||||
|
||||
explicit
|
||||
ExecutionCases( std::initializer_list< TestDescription > initList )
|
||||
: tests( initList ) {}
|
||||
|
||||
int
|
||||
operator() () const
|
||||
{
|
||||
int failureCount= 0;
|
||||
for( const auto &[ comment, params, expected ]: tests )
|
||||
{
|
||||
if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl;
|
||||
breakpoint();
|
||||
const auto witness= std::apply( function, params );
|
||||
const auto result= witness == expected;
|
||||
if( not result )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
++failureCount;
|
||||
printDebugging< outputMode >( witness, expected );
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
}
|
||||
|
||||
return failureCount;
|
||||
}
|
||||
};
|
||||
|
||||
struct ExceptionCases_real
|
||||
{
|
||||
using Invoker= std::function< void () >;
|
||||
struct ExceptionHandler
|
||||
{
|
||||
std::function< bool ( Invoker ) > impl;
|
||||
|
||||
bool operator() ( Invoker invoker ) const { return impl( invoker ); }
|
||||
|
||||
ExceptionHandler() : impl
|
||||
{
|
||||
[]( Invoker invoker )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
return true;
|
||||
}
|
||||
catch( ... ) { return false; }
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< typename T >
|
||||
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
||||
ExceptionHandler( T ) : impl
|
||||
{
|
||||
[]( Invoker invoker )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
return true;
|
||||
}
|
||||
catch( ... ) { return false; }
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< typename T >
|
||||
requires( not SameAs< T, void > )
|
||||
ExceptionHandler( std::type_identity< T > ) : impl
|
||||
{
|
||||
[]( Invoker invoker )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
return false;
|
||||
}
|
||||
catch( const T & ) { return true; }
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
template< typename T >
|
||||
ExceptionHandler( const T exemplar ) : impl
|
||||
{
|
||||
[expected= std::string{ exemplar.what() }]( Invoker invoker )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
std::cerr << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"<< typeid( T ).name()
|
||||
<< "` wasn't thrown." << std::endl;
|
||||
return false;
|
||||
}
|
||||
catch( const T &ex )
|
||||
{
|
||||
const std::string witness= ex.what();
|
||||
const bool rv= witness == expected;
|
||||
if( not rv )
|
||||
{
|
||||
std::cerr << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"<< typeid( T ).name()
|
||||
<< "` wasn't thrown." << std::endl;
|
||||
printDebugging< outputMode >( witness, expected );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
// This checker is invoked during `catch( ... )`
|
||||
ExceptionHandler( const std::function< bool () > checker ) : impl
|
||||
{
|
||||
[=]( Invoker invoker )
|
||||
{
|
||||
try
|
||||
{
|
||||
invoker();
|
||||
return false;
|
||||
}
|
||||
catch( ... ) { checker(); } // The `checker` can use `throw` to run any complex checks it needs.
|
||||
}
|
||||
}
|
||||
{}
|
||||
};
|
||||
|
||||
using TestDescription= std::tuple< std::string, args_type, ExceptionHandler >;
|
||||
|
||||
std::vector< TestDescription > tests;
|
||||
|
||||
|
||||
explicit
|
||||
ExceptionCases_real( std::initializer_list< TestDescription > initList )
|
||||
: tests( initList ) {}
|
||||
|
||||
int
|
||||
operator() () const
|
||||
{
|
||||
int failureCount= 0;
|
||||
for( const auto &[ comment, params, checker ]: tests )
|
||||
{
|
||||
if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl;
|
||||
breakpoint();
|
||||
auto invoker= [&]{ std::apply( function, params ); };
|
||||
const auto result= checker( invoker );
|
||||
if( not result )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
++failureCount;
|
||||
}
|
||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
}
|
||||
|
||||
return failureCount;
|
||||
}
|
||||
};
|
||||
|
||||
using ComputedBase= compute_base_t< return_type >;
|
||||
|
||||
struct UniversalCases
|
||||
@ -929,21 +269,17 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
|
||||
using UniversalHandler= BasicUniversalHandler< return_type, outputMode >;
|
||||
|
||||
using TestDescription= std::tuple< std::string, args_type, UniversalHandler >;
|
||||
struct TestDescription
|
||||
{
|
||||
std::string comment;
|
||||
args_type args;
|
||||
UniversalHandler handler;
|
||||
};
|
||||
std::vector< TestDescription > tests;
|
||||
|
||||
UniversalCases( std::initializer_list< TestDescription > initList )
|
||||
: tests( initList )
|
||||
{
|
||||
for( const auto &desc: initList )
|
||||
{
|
||||
if constexpr( Aggregate< return_type > )
|
||||
{
|
||||
std::cerr << "Case: " << std::get< 0 >( desc );
|
||||
const return_type &v= std::get< 2 >( desc );
|
||||
std::cerr << " (" << v << ")" << std::endl;
|
||||
tests.push_back( desc );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@ -958,7 +294,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
breakpoint();
|
||||
return std::apply( function, params );
|
||||
};
|
||||
const TestResult result= checker( invoker, comment );
|
||||
const auto result= checker( invoker, comment );
|
||||
if( result == TestResult::Failed )
|
||||
{
|
||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||
@ -980,58 +316,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||
//using ExceptionCases= ExceptionCases_real;
|
||||
using ExceptionCases= UniversalCases;
|
||||
};
|
||||
|
||||
#ifdef DISABLED
|
||||
template< typename RetVal, typename ... Args, RetVal (*function)( Args... ) >
|
||||
struct TableTest< function >::VectorCases
|
||||
{
|
||||
static_assert( sizeof...( Args ) == 1 );
|
||||
static_assert( Meta::is_vector_v< RetVal > );
|
||||
static_assert( Meta::is_vector_v< std::tuple_element_t< 0, std::tuple< Args... > > > );
|
||||
|
||||
using TestDescription= std::tuple< std::string,
|
||||
std::vector< std::pair< typename std::tuple_element_t< 0, std::tuple< Args... > >::value_type, typename RetVal::value_type > > >;
|
||||
|
||||
std::vector< TestDescription > tests;
|
||||
|
||||
explicit
|
||||
VectorCases( std::initializer_list< TestDescription > initList )
|
||||
: tests( initList ) {}
|
||||
|
||||
int
|
||||
operator() () const
|
||||
{
|
||||
int failureCount= 0;
|
||||
for( const auto &[ comment, productions ]: tests )
|
||||
{
|
||||
const auto expected= evaluate <=[&]
|
||||
{
|
||||
std::vector< RetVal > rv;
|
||||
std::transform( begin( productions ), end( productions ), back_inserter( rv ),
|
||||
[]( const auto &prod ) { return prod.second; } );
|
||||
return rv;
|
||||
};
|
||||
|
||||
const auto params= evaluate <=[&]
|
||||
{
|
||||
std::vector< RetVal > rv;
|
||||
std::transform( begin( productions ), end( productions ), back_inserter( rv ),
|
||||
[]( const auto &prod ) { return prod.first; } );
|
||||
return rv;
|
||||
};
|
||||
|
||||
if( std::apply( function, std::tuple{ params } ) != expected )
|
||||
{
|
||||
std::cout << " FAILURE: " << comment << std::endl;
|
||||
++failureCount;
|
||||
}
|
||||
else std::cout << " SUCCESS: " << comment << std::endl;
|
||||
}
|
||||
|
||||
return failureCount;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::Testing::inline exports::inline table_test
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Testing/test.h>
|
||||
#include <Alepha/Testing/TableTest.h>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Testing/TableTest.h>
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
207
Testing/printDebugging.h
Normal file
207
Testing/printDebugging.h
Normal file
@ -0,0 +1,207 @@
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <Alepha/TotalOrder.h>
|
||||
#include <Alepha/Console.h>
|
||||
|
||||
#include <Alepha/IOStreams/String.h>
|
||||
|
||||
#include <Alepha/Meta/product_type_decay.h>
|
||||
#include <Alepha/Meta/sequence_kind.h>
|
||||
|
||||
#include <Alepha/Meta/is_vector.h>
|
||||
#include <Alepha/Meta/is_optional.h>
|
||||
#include <Alepha/Meta/is_streamable.h>
|
||||
#include <Alepha/Meta/is_sequence.h>
|
||||
#include <Alepha/Meta/is_product_type.h>
|
||||
|
||||
namespace Alepha::Hydrogen::Testing ::detail:: printDebugging_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
enum class OutputMode { All, Relaxed };
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
void printDebugging( const T &witness, const T &expected );
|
||||
}
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
void
|
||||
streamValue( const T &v, std::ostream &oss )
|
||||
{
|
||||
if constexpr( false ) ; // To keep the rest of the clauses regular
|
||||
else if constexpr( std::is_same_v< std::uint8_t, std::decay_t< T > > )
|
||||
{
|
||||
oss << std::hex << std::setw( 2 ) << std::setfill( '0' ) << int( v );
|
||||
}
|
||||
else if constexpr( std::is_same_v< bool, std::decay_t< T > > )
|
||||
{
|
||||
oss << std::boolalpha << v;
|
||||
}
|
||||
else if constexpr( std::is_same_v< std::string, std::decay_t< T > > )
|
||||
{
|
||||
oss << "(String with " << v.size() << " chars)";
|
||||
oss << '\n' << R"(""")" << '\n';
|
||||
for( const char ch: v )
|
||||
{
|
||||
if( ch == '\n' ) oss << "<EOL>\n";
|
||||
else if( std::isalnum( ch ) or std::ispunct( ch ) or ( ch == ' ' ) ) oss << ch;
|
||||
else oss << "<\\0x" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << unsigned( ch ) << '>';
|
||||
}
|
||||
oss << '\n' << R"(""")";
|
||||
}
|
||||
else if constexpr( Meta::is_ostreamable_v< T > )
|
||||
{
|
||||
oss << v;
|
||||
}
|
||||
else if constexpr( Meta::is_optional_v< T > )
|
||||
{
|
||||
if( not v.has_value() ) oss << "<noopt>";
|
||||
else streamValue< outputMode >( v.value(), oss );
|
||||
}
|
||||
else if constexpr( Meta::is_sequence_v< T > )
|
||||
{
|
||||
if constexpr( outputMode == OutputMode::Relaxed and not Meta::is_ostreamable_v< typename T::value_type > )
|
||||
{
|
||||
oss << "<Unstreamable sequence of " << v.size() << " elements.>";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << Meta::sequence_kind_v< T > << "(" << v.size() << " elements):\n{" << std::endl;
|
||||
|
||||
int index= 0;
|
||||
for( const auto &elem: v )
|
||||
{
|
||||
oss << "\t" << index++ << ": ";
|
||||
streamValue< outputMode >( elem, oss );
|
||||
oss << "," << std::endl;
|
||||
}
|
||||
oss << "}" << std::endl;
|
||||
}
|
||||
}
|
||||
else if constexpr( Meta::is_pair_v< T > )
|
||||
{
|
||||
const auto &[ first, second ]= v;
|
||||
streamValue< outputMode >( std::tie( first, second ), oss );
|
||||
}
|
||||
else if constexpr( Meta::is_tuple_v< T > )
|
||||
{
|
||||
oss << '[';
|
||||
tuple_for_each( v ) <=[&oss, first= true]( const auto &elem ) mutable
|
||||
{
|
||||
if( not first ) oss << ", ";
|
||||
first= false;
|
||||
oss << std::endl;
|
||||
streamValue< outputMode >( elem, oss );
|
||||
};
|
||||
oss << std::endl << ']' << std::endl;
|
||||
}
|
||||
else if constexpr( std::is_same_v< T, TotalOrder > )
|
||||
{
|
||||
if( false ) ; // For alignment
|
||||
else if( v == TotalOrder::less ) oss << "less";
|
||||
else if( v == TotalOrder::equal ) oss << "equal";
|
||||
else if( v == TotalOrder::greater ) oss << "greater";
|
||||
else throw std::logic_error( "Impossible `TotalOrder` condition." );
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert( dependent_value< false, T >, "One of the types used in the testing table does not support stringification." );
|
||||
}
|
||||
}
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
std::string
|
||||
stringifyValue( const T &v )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
streamValue< outputMode >( v, oss );
|
||||
return std::move( oss ).str();
|
||||
}
|
||||
|
||||
inline void
|
||||
printDebuggingForStrings( const std::string &witness, const std::string &expected )
|
||||
{
|
||||
const std::size_t amount= std::min( witness.size(), expected.size() );
|
||||
if( witness.size() != expected.size() )
|
||||
{
|
||||
std::cout << "Witness string size did not match the expected string size. Only mismatches found in the first "
|
||||
<< amount << " characters will be printed." << std::endl;
|
||||
}
|
||||
|
||||
for( int i= 0; i < amount; ++i )
|
||||
{
|
||||
if( witness.at( i ) == expected.at( i ) ) continue;
|
||||
std::cout << "Mismatch at index: " << i << std::endl;
|
||||
std::cout << "witness: " << witness.at( i ) << std::endl;
|
||||
std::cout << "expected: " << expected.at( i ) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template< OutputMode outputMode, typename T >
|
||||
void
|
||||
exports::printDebugging( const T &witness, const T &expected )
|
||||
{
|
||||
if constexpr( std::is_same_v< std::string, std::decay_t< T > > )
|
||||
{
|
||||
printDebuggingForStrings( witness, expected );
|
||||
}
|
||||
else if constexpr( Meta::is_sequence_v< T > )
|
||||
{
|
||||
if constexpr( std::is_same_v< std::string, typename T::value_type > )
|
||||
{
|
||||
if( witness.size() == expected.size() ) for( std::size_t i= 0; i < witness.size(); ++i )
|
||||
{
|
||||
if( witness.at( i ) != expected.at( i ) ) printDebuggingForStrings( witness.at( i ), expected.at( i ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( witness.size() != expected.size() )
|
||||
{
|
||||
std::cout << "Witness sequence size of " << witness.size() << " did not match the expected sequence size of "
|
||||
<< expected.size() << std::endl;
|
||||
}
|
||||
|
||||
auto next= std::make_pair( begin( witness ), begin( expected ) );
|
||||
bool first= true;
|
||||
while( next.first != end( witness ) and next.second != end( expected ) )
|
||||
{
|
||||
if( not first )
|
||||
{
|
||||
std::cout << "Mismatch at witness index " << std::distance( begin( witness ), next.first ) << " and "
|
||||
<< "expected index " << std::distance( begin( expected ), next.second ) << std::endl;
|
||||
++next.first; ++next.second;
|
||||
}
|
||||
first= false;
|
||||
next= std::mismatch( next.first, end( witness ), next.second, end( expected ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << std::endl
|
||||
<< "computed: " << stringifyValue< outputMode >( witness ) << std::endl
|
||||
<< "expected: " << stringifyValue< outputMode >( expected ) << std::endl << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::Testing::inline exports::inline printDebugging_m
|
||||
{
|
||||
using namespace detail::printDebugging_m::exports;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include "test.h"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Testing/test.h>
|
||||
#include <Alepha/ProgramOptions.h>
|
||||
|
||||
30
Thread.h
30
Thread.h
@ -1,12 +1,12 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <Alepha/boost_path/thread.hpp>
|
||||
#include <Alepha/boost_path/thread/mutex.hpp>
|
||||
#include <Alepha/boost_path/thread/condition_variable.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
#include <Alepha/Exception.h>
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Alepha::Hydrogen
|
||||
{
|
||||
callable();
|
||||
}
|
||||
catch( const boost_ns::thread_interrupted & )
|
||||
catch( const boost::thread_interrupted & )
|
||||
{
|
||||
std::lock_guard lock( access );
|
||||
if( not notification ) throw;
|
||||
@ -63,7 +63,7 @@ namespace Alepha::Hydrogen
|
||||
namespace exports
|
||||
{
|
||||
class ConditionVariable
|
||||
: private boost_ns::condition_variable
|
||||
: private boost::condition_variable
|
||||
{
|
||||
public:
|
||||
using condition_variable::notify_all;
|
||||
@ -89,17 +89,17 @@ namespace Alepha::Hydrogen
|
||||
{
|
||||
template< typename Clock, typename Duration >
|
||||
void
|
||||
sleep_until( const boost_ns::chrono::time_point< Clock, Duration > &abs_time )
|
||||
sleep_until( const boost::chrono::time_point< Clock, Duration > &abs_time )
|
||||
{
|
||||
notification.check_interrupt( [&]{ boost_ns::this_thread::sleep_until( abs_time ); } );
|
||||
notification.check_interrupt( [&]{ boost::this_thread::sleep_until( abs_time ); } );
|
||||
}
|
||||
|
||||
#if 0
|
||||
template< typename Rep, typename Period >
|
||||
void
|
||||
sleep_for( const boost_ns::chrono::duration< Rep, Period > &rel_time )
|
||||
sleep_for( const boost::chrono::duration< Rep, Period > &rel_time )
|
||||
{
|
||||
notification.check_interrupt( [&]( boost_ns::this_thread::sleep_until( rel_time ); } );
|
||||
notification.check_interrupt( [&]( boost::this_thread::sleep_until( rel_time ); } );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -113,7 +113,7 @@ namespace Alepha::Hydrogen
|
||||
namespace exports
|
||||
{
|
||||
class Thread
|
||||
: ThreadNotification, boost_ns::thread
|
||||
: ThreadNotification, boost::thread
|
||||
{
|
||||
public:
|
||||
template< typename Callable >
|
||||
@ -153,10 +153,10 @@ namespace Alepha::Hydrogen
|
||||
}
|
||||
};
|
||||
|
||||
using Mutex= boost_ns::mutex;
|
||||
using boost_ns::mutex;
|
||||
using boost_ns::unique_lock;
|
||||
using boost_ns::lock_guard;
|
||||
using Mutex= boost::mutex;
|
||||
using boost::mutex;
|
||||
using boost::unique_lock;
|
||||
using boost::lock_guard;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
Thread.test/CMakeLists.txt
Normal file
3
Thread.test/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
link_libraries( boost_thread )
|
||||
|
||||
unit_test( thread )
|
||||
@ -1,10 +0,0 @@
|
||||
CXXFLAGS+= -std=c++2a -I ../
|
||||
CXXFLAGS+= -g -O0
|
||||
CXX=clang++-12
|
||||
|
||||
CXXFLAGS+= -Wno-inline-namespace-reopened-noninline
|
||||
CXXFLAGS+= -Wno-unused-comparison
|
||||
|
||||
LDLIBS+= -lboost_thread -lpthread
|
||||
|
||||
all: thread
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Thread.h>
|
||||
|
||||
@ -6,7 +6,7 @@ static_assert( __cplusplus > 2020'00 );
|
||||
|
||||
#include <Alepha/Testing/test.h>
|
||||
#include <Alepha/Testing/TableTest.h>
|
||||
#include <Alepha/Utility/evaluation.h>
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -36,7 +36,7 @@ namespace
|
||||
}
|
||||
catch( const boost::thread_interrupted & )
|
||||
{
|
||||
std::cerr << "SHIT! We didn't get intercepted!" << std::endl;
|
||||
std::cerr << "OOPS! We didn't get intercepted!" << std::endl;
|
||||
throw;
|
||||
}
|
||||
catch( const MyNotification &n )
|
||||
|
||||
10
TotalOrder.h
10
TotalOrder.h
@ -1,12 +1,14 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <compare>
|
||||
|
||||
#include "Concepts.h"
|
||||
|
||||
namespace Alepha::inline Cavorite ::detail:: total_order
|
||||
namespace Alepha::Hydrogen ::detail:: TotalOrder_m
|
||||
{
|
||||
inline namespace exports
|
||||
{
|
||||
@ -21,7 +23,7 @@ namespace Alepha::inline Cavorite ::detail:: total_order
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Cavorite::inline exports::inline total_order
|
||||
namespace Alepha::Hydrogen::inline exports::inline TotalOrder_m
|
||||
{
|
||||
using namespace detail::total_order::exports;
|
||||
using namespace detail::TotalOrder_m::exports;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
static_assert( __cplusplus > 2020'00 );
|
||||
static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user