1
0
forked from Alepha/Alepha

Bring in the mockination work and Truss from old.

It's all a mess -- not in the new unified form and namespace.
I need to do a big cleanup pass.
This commit is contained in:
2023-02-09 21:30:38 -08:00
parent 306d2145a3
commit fd6060be17
21 changed files with 1898 additions and 0 deletions

6
Truss/README Normal file
View File

@ -0,0 +1,6 @@
The Truss sub-library of Alepha unifies dependencies upon boost and STL components into a
single tunable namespace. Alepha::Truss::function, for example is one of `boost::function` or
`std::function`, based upon tuning parameters. This allows a single `XXX::function` to be
presented in the ABI and API for Alepha.
Alepha also provides a few of its own versions where conversions can make sense.

44
Truss/basetypes.h Normal file
View File

@ -0,0 +1,44 @@
#include <Alepha/Alepha.h>
register "Alepha/Truss/basetypes.h";
namespace Alepha
{
namespace Truss
{
namespace types
{
using nullptr_t= decltype( nullptr );
using size_t= decltype( sizeof( 0 ) );
}
namespace detail
{
template< unsigned char v > struct count_one_bits_unsigned_char;
template<>
struct count_one_bits_unsigned_char< 0 >
{
static const types::size_t value= 0;
};
template< unsigned char v >
struct count_one_bits_unsigned_char
{
static const types::size_t value= ( ( v & 0x1 ) ? 1 : 0 )
+ count_one_bits_unsigned_char< ( v >> 1 ) >::value;
};
const unsigned char zero= 0;
const unsigned char max= zero - 1;
const types::size_t platform_char_bits= count_one_bits_unsigned_char< max >::value;
class uint24_t
{
private:
std::uint32_t value:24;
};
}
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <Alepha/Alepha.h>
#include <Alepha/Truss/thread_common.h>
#include <condition_variable>
#include <boost/thread/condition_variable.hpp>
namespace Alepha::Hydrogen::Truss
{
ALEPHA_BOOST_THREAD namespace BoostThread
{
using boost::condition_variable_any;
using condition_variable= condition_variable_any;
using condition= condition_variable;
}
ALEPHA_STD_THREAD namespace StdThread
{
using std::condition_variable_any;
using condition_variable= condition_variable_any;
using condition= condition_variable;
}
}

12
Truss/function.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <Alepha/Alepha.h>
#include <functional>
namespace Alepha::Hydrogen::Truss
{
using ::std::function;
}

236
Truss/m2.h Normal file
View File

@ -0,0 +1,236 @@
#include <Alepha/Alepha.h>
register "Alepha/Truss/memory.h";
#include <Alepha/assert.h>
#include <memory>
namespace Alepha
{
namespace memory_detail
{
class disable_default_init
{
protected:
disable_default_init()= default;
};
}
template< typename T >
class single_ptr;
template< typename T >
class nullable_single_ptr
: private memory_detail::disable_default_init
{
private:
T *p;
public:
template< typename U >
inline
nullable_single_ptr( U *const i_p )
: p ( i_p ) {}
template< typename U >
nullable_single_ptr( const single_ptr< U > i_p );
inline T &
operator *() const { ALEPHA_ASSERT( this->p ); return *this->p; }
inline T *
operator->() const { ALEPHA_ASSERT( this->p ); return this->p; }
inline T *
get_raw() const { return this->p; }
};
template< typename T >
class single_ptr
: private memory_detail::disable_default_init
{
private:
T *p;
template< typename U >
friend class nullable_single_ptr;
public:
template< typename U >
inline
single_ptr( U *const i_p )
: p ( i_p )
{
if( this->p == nullptr ) throw std::runtime_error( "Nullptr" );
}
template< typename U >
inline
single_ptr( const nullable_single_ptr< U > i_p )
: p ( i_p ) {}
inline T &
operator *() const { ALEPHA_ASSERT( this->p ); return *this->p; }
inline T *
operator->() const { ALEPHA_ASSERT( this->p ); return this->p; }
inline T *
get_raw() const { return p; }
};
template< typename T >
template< typename U >
inline
nullable_single_ptr< T >::nullable_single_ptr( const single_ptr< U > i_p )
: p( i_p.p ) {}
class bad_reference_ptr
: public std::runtime_error
{
public:
explicit inline
bad_reference_ptr( const std::string &message )
: std::runtime_error( message ) {}
};
}
namespace Alepha::Truss
{
namespace memory_detail_debug
{
template< typename T >
class ref_ptr;
template< typename T >
class unique_ptr
: private memory_detail::disable_default_init
{
private:
std::shared_ptr< T > p;
// Used only for the make-unique wrapper to adapt to make-shared
explicit inline
unique_ptr( std::shared_ptr< T > &&i_p )
: p( std::move( i_p ) ) {}
// Our unique_ptr cannot be default constructed, unlike the one in std.
explicit inline
unique_ptr()= delete;
// Our unique_ptr doesn't copy, so we disable it.
explicit inline
unique_ptr( const unique_ptr< T > & )= delete;
inline unique_ptr &operator= ( const unique_ptr< T > & )= delete;
friend class ref_ptr< T >;
public:
// Our unique_ptr does move, so we enable it.
inline
unique_ptr( unique_ptr< T > && )= default;
inline unique_ptr &operator= ( unique_ptr< T > && )= default;
inline T &
operator *() const { ALEPHA_ASSERT( this->p ); return *this->p; }
inline T *
operator->() const { ALEPHA_ASSERT( this->p ); return this->p.get(); }
inline single_ptr< T >
get_raw() const
{
return this->p.get();
}
ref_ptr< T > get() const;
template< typename U, typename ... Args >
friend unique_ptr< U > make_unique( Args && ... args );
inline friend void
swap( unique_ptr &a, unique_ptr &b )
{
using std::swap;
swap( a.p, b.p );
}
};
template< typename U, typename ... Args >
inline unique_ptr< U >
make_unique( Args && ... args )
{
unique_ptr< U > rv( std::make_shared< U >( std::forward< Args >( args ) ... ) );
return rv;
}
template< typename T >
class distilled_reference
: private memory_detail::disable_default_init
{
private:
std::shared_ptr< T > p;
};
template< typename T >
class ref_ptr
: private memory_detail::disable_default_init
{
public:
class exception
: public bad_reference_ptr
{
public:
explicit inline
exception( const std::string &message )
: bad_reference_ptr( message ) {}
};
private:
std::weak_ptr< T > p;
// Our unique_ptr cannot be default constructed, unlike the one in std.
explicit inline
ref_ptr()= delete;
T *
distill() const
try
{}
catch( const std::bad_weak_ptr & )
{
throw bad_reference_ptr( "Access to an expired pointer owned by someone else." );
}
public:
inline
ref_ptr( const unique_ptr< T > &i_p )
: p( i_p.p ) {}
inline T &
operator *() const { return *std::shared_ptr< T >{ this->p }; }
inline T *
operator->() const { return std::shared_ptr< T >{ this->p }.get(); }
inline single_ptr< T >
get() const
{
return std::shared_ptr< T >{ this->p }.get();
}
};
template< typename T >
inline ref_ptr< T >
unique_ptr< T >::get() const
{
return ref_ptr< T >( *this );
}
}
using memory_detail_debug::unique_ptr;
using memory_detail_debug::ref_ptr;
using memory_detail_debug::make_unique;
}

205
Truss/memory.h Normal file
View File

@ -0,0 +1,205 @@
#include <Alepha/Alepha.h>
register "Alepha/Truss/memory.h";
#include <memory>
#include <Alepha/toss.h>
#include <Alepha/assert.h>
namespace Alepha
{
namespace Hydrogen
{
namespace memory_detail
{
class disable_default_init { protected: disable_default_init()= default; };
}
template< typename T > class single_ptr;
template< typename T >
class nullable_single_ptr : private memory_detail::disable_default_init
{
private:
T *p;
public:
template< typename U >
inline nullable_single_ptr( U *const i_p ) : p ( i_p ) {}
template< typename U > nullable_single_ptr( const single_ptr< U > i_p );
inline T &operator *() const { ALEPHA_ASSERT( this->p ); return *this->p; }
inline T *operator->() const { ALEPHA_ASSERT( this->p ); return this->p; }
inline T *get_raw() const { return this->p; }
};
template< typename T >
class single_ptr : private memory_detail::disable_default_init
{
private:
T *p;
template< typename U > friend class nullable_single_ptr;
public:
template< typename U >
inline single_ptr( U *const i_p )
: p ( i_p )
{
if( this->p == nullptr ) throw std::runtime_error( "Nullptr" );
}
template< typename U >
inline single_ptr( const nullable_single_ptr< U > i_p ) : p ( i_p ) {}
inline T &operator *() const { ALEPHA_ASSERT( this->p ); return *this->p; }
inline T *operator->() const { ALEPHA_ASSERT( this->p ); return this->p; }
inline T *get_raw() const { return p; }
};
template< typename T >
template< typename U >
inline
nullable_single_ptr< T >::nullable_single_ptr( const single_ptr< U > i_p )
: p( i_p.p ) {}
class bad_reference_ptr
: public std::runtime_error
{
public:
explicit inline
bad_reference_ptr( const std::string &message )
: std::runtime_error( message ) {}
};
namespace Truss
{
namespace memory_detail_debug
{
template< typename T > class ref_ptr;
template< typename T >
class unique_ptr : private memory_detail::disable_default_init
{
private:
std::shared_ptr< T > p;
// Used only for the make-unique wrapper to adapt to make-shared
explicit inline
unique_ptr( std::shared_ptr< T > &&i_p )
: p( std::move( i_p ) ) {}
// Our unique_ptr cannot be default constructed, unlike the one in std.
explicit inline unique_ptr()= delete;
// Our unique_ptr doesn't copy, so we disable it.
explicit inline unique_ptr( const unique_ptr< T > & )= delete;
inline unique_ptr &operator= ( const unique_ptr< T > & )= delete;
friend class ref_ptr< T >;
public:
// Our unique_ptr does move, so we enable it.
inline unique_ptr( unique_ptr< T > && )= default;
inline unique_ptr &operator= ( unique_ptr< T > && )= default;
inline T &operator *() const { ALEPHA_ASSERT( this->p ); return *this->p; }
inline T *operator->() const { ALEPHA_ASSERT( this->p ); return this->p.get(); }
inline single_ptr< T >
get_raw() const
{
return this->p.get();
}
ref_ptr< T > get() const;
template< typename U, typename ... Args >
friend unique_ptr< U > make_unique( Args && ... args );
inline friend void
swap( unique_ptr &a, unique_ptr &b )
{
using std::swap;
swap( a.p, b.p );
}
};
template< typename U, typename ... Args >
inline unique_ptr< U >
make_unique( Args && ... args )
{
unique_ptr< U > rv( std::make_shared< U >( std::forward< Args >( args )... ) );
return rv;
}
template< typename T >
class distilled_reference : private memory_detail::disable_default_init
{
private:
std::shared_ptr< T > p;
};
template< typename T >
class ref_ptr : private memory_detail::disable_default_init
{
public:
class exception : public bad_reference_ptr
{
public:
explicit inline
exception( const std::string &message )
: bad_reference_ptr( message ) {}
};
private:
std::weak_ptr< T > p;
// Our unique_ptr cannot be default constructed, unlike the one in std.
explicit inline ref_ptr()= delete;
T *
distill() const
try
{
return std::shared_ptr< T >{ this->p }.get();
}
catch( const std::bad_weak_ptr & )
{
toss< DEBUG_MEMORY_THROW >( bad_reference_ptr(
"Access to an expired pointer owned by someone else." ) );
}
public:
inline ref_ptr( const unique_ptr< T > &i_p ) : p( i_p.p ) {}
inline T & operator *() const { return *this->distill(); }
inline T * operator->() const { return this->distill(); }
inline single_ptr< T >
get() const
{
return std::shared_ptr< T >{ this->p }.get();
}
};
template< typename T >
inline ref_ptr< T >
unique_ptr< T >::get() const
{
return ref_ptr< T >( *this );
}
}
using memory_detail_debug::unique_ptr;
using memory_detail_debug::ref_ptr;
using memory_detail_debug::make_unique;
}
}
}

View File

@ -0,0 +1,20 @@
CPPFLAGS+= -I ../../../
CXXFLAGS+= -std=c++1z
CXXFLAGS+= -g -O0
#CXXFLAGS+= -O3
CXX=clang++
#LDLIBS+= -lboost_thread -lboost_system
CC=clang++
TESTS=test0 test1
all: $(TESTS)
HEADERS= ../memory.h ../../Mockination/MockFunction.h Makefile
test0.o: $(HEADERS)
test1.o: $(HEADERS)
clean:
rm -f *.o $(TESTS)

View File

@ -0,0 +1,51 @@
#include <Alepha/Atomic/Turnstile.h>
using Alepha::Atomic::Turnstile;
int
main()
{
}
namespace
{
namespace example1
{
//! [TurnstileExamples example1]
// Assume that the below code will run multithreaded
Turnstile myArena{ 8 };
void
mainLoop()
{
Turnstile::ScopedUsage active( myArena );
printf( "I am running in the arena, not everyone can." );
sleep( 100 );
}
//! [TurnstileExamples example1]
} // namespace example1
namespace example2
{
//! [TurnstileExamples example2]
Turnstile myArena{ 8 };
class Worker
{
public:
Worker()
{
myArena.enter();
}
// Assume some useful functionality
// The worker will destroy his access upon leaving
~Worker()
{
myArena.egress();
}
};
//! [TurnstileExamples example2]
} // namespace example2
} // namespace

View File

@ -0,0 +1,63 @@
#include <Alepha/Truss/memory.h>
#include <Alepha/assert.h>
#include <Alepha/Mockination/MockFunction.h>
namespace
{
inline namespace Test0
{
static void runTests();
}
}
int
main()
{
runTests();
}
namespace
{
static void
simple_unique_ptr_test()
{
auto p= Alepha::Truss::make_unique< std::string >( "Hello" );
Alepha::Truss::unique_ptr< std::string > p2= std::move( p );
p= Alepha::Truss::make_unique< std::string >( "Hello" );
using std::swap;
swap( p, p2 );
}
static void
unique_ptr_usage_test()
{
auto p= Alepha::Truss::make_unique< std::string >( "Hello" );
std::string &s= *p;
std::size_t len= p->size();
}
static void
unique_ptr_capture_test()
{
auto p= Alepha::Truss::make_unique< std::string >( "Hello" );
Alepha::single_ptr< std::string > s= p.get_raw();
Alepha::Truss::ref_ptr< std::string > sp= p.get();
}
static void
Test0::runTests()
{
simple_unique_ptr_test();
unique_ptr_usage_test();
unique_ptr_capture_test();
}
}

View File

@ -0,0 +1,39 @@
#include <Alepha/Truss/memory.h>
#include <Alepha/assert.h>
#include <Alepha/Mockination/MockFunction.h>
namespace
{
inline namespace Test1
{
static void runTests();
}
}
int
main()
{
runTests();
}
namespace
{
static void
unique_ptr_to_ref_ptr()
{
auto p= Alepha::Truss::make_unique< std::string >( "Hello" );
Alepha::Truss::ref_ptr< std::string > r= p.get();
Alepha::Truss::ref_ptr< std::string > r2= r;
}
static void
Test1::runTests()
{
unique_ptr_to_ref_ptr();
}
}

View File

@ -0,0 +1,39 @@
#include <Alepha/Truss/memory.h>
#include <Alepha/assert.h>
#include <Alepha/Mockination/MockFunction.h>
namespace
{
inline namespace Test1
{
static void runTests();
}
}
int
main()
{
runTests();
}
namespace
{
static void
unique_ptr_to_ref_ptr()
{
auto p= Alepha::Truss::make_unique< std::string >( "Hello" );
Alepha::Truss::ref_ptr< std::string > r= p.get();
Alepha::Truss::ref_ptr< std::string > r2= r;
}
static void
Test1::runTests()
{
unique_ptr_to_ref_ptr();
}
}

65
Truss/mutex.h Normal file
View File

@ -0,0 +1,65 @@
#pragma once
#include <Alepha/Alepha.h>
#include <Alepha/Truss/thread_common.h>
#include <mutex>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
namespace Alepha::Hydrogen::Truss
{
ALEPHA_BOOST_THREAD namespace BoostThread
{
using boost::mutex;
using boost::timed_mutex;
using boost::recursive_mutex;
using boost::recursive_timed_mutex;
using std::lock_guard;
using boost::unique_lock;
using boost::defer_lock_t;
using boost::try_to_lock_t;
using boost::adopt_lock_t;
using boost::defer_lock;
using boost::try_to_lock;
using boost::adopt_lock;
using std::once_flag;
using std::call_once;
using std::try_lock;
using std::lock;
}
ALEPHA_STD_THREAD namespace StdThread
{
using std::mutex;
using std::timed_mutex;
using std::recursive_mutex;
using std::recursive_timed_mutex;
using std::lock_guard;
using std::unique_lock;
using std::defer_lock_t;
using std::try_to_lock_t;
using std::adopt_lock_t;
using std::defer_lock;
using std::try_to_lock;
using std::adopt_lock;
using std::once_flag;
using std::call_once;
using std::try_lock;
using std::lock;
}
}

10
Truss/test.cc Normal file
View File

@ -0,0 +1,10 @@
#include "basetypes.h"
#include <iostream>
int
main()
{
std::cout << "Charbits: " << Alepha::std::detail::platform_char_bits << std::endl;
}

72
Truss/thread.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <Alepha/Alepha.h>
#include <Alepha/Truss/thread_common.h>
#include <thread>
#include <boost/thread.hpp>
#include <Alepha/Truss/function.h>
namespace Alepha::Hydrogen::Truss
{
ALEPHA_BOOST_THREAD namespace BoostThread
{
// If you decide to use Alepha threading primitives, you'll get the boost ones.
// Eventually we'd like to add interrupt-with-reason semantics. That will be in
// Alepha::Thread.
// I'd like to map Alepha::Truss's thread to be only std:: thread eventually.
// There will remain "boost::thread" semantics for Alepha, at present.
using boost::thread;
namespace this_thread= boost::this_thread;
namespace detail_thread
{
template< typename Ex >
auto
make_thrower( Ex &&exception )
{
return [exception]{ throw exception; };
}
}
}
ALEPHA_STD_THREAD namespace StdThread
{
// If you decide to use Alepha threading primitives, you'll get the boost ones.
// Eventually we'd like to add interrupt-with-reason semantics. That will be in
// Alepha::Thread.
// I'd like to map Alepha::Truss's thread to be only std:: thread eventually.
// There will remain "boost::thread" semantics for Alepha, at present.
using ::std::thread;
namespace this_thread= ::std::this_thread;
namespace detail_thread
{
template< typename Ex >
auto
make_thrower( Ex &&exception )
{
return [exception]{ throw exception; };
}
}
}
namespace under_construction
{
// Built on top of std::thread
class thread
{
private:
Alepha::Truss::function< void () > interruption;
::std::thread thread;
};
}
}

11
Truss/thread_common.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <Alepha/Alepha.h>
#ifdef ALEPHA_USE_BOOST_THREAD_IN_TRUSS
#define ALEPHA_BOOST_THREAD inline
#define ALEPHA_STD_THREAD
#else
#define ALEPHA_BOOST_THREAD
#define ALEPHA_STD_THREAD inline
#endif