//#define _GNU_SOURCE
# include <cstdlib>
# include <cstring>
# include <cstdio>
# include <unistd.h>
# include "../include/opaque.hh"
static void s_puts ( const auto & string )
{
std : : string_view str { string } ;
# ifdef DIRECT_WRITE
write ( 1 , str . data ( ) , str . size ( ) ) ;
# else
printf ( " %.*s " , ( int ) str . size ( ) , str . data ( ) ) ;
# endif
}
static void print_view ( std : : string_view ptr )
{
//std::string_view ptr{string};
size_t sz ;
# ifdef DIRECT_WRITE
// Bypass all caching of the output and immediately invoke `write()` for everything
if ( __builtin_expect ( ( sz = ptr . size ( ) ) > 0 , true ) ) {
write ( 1 , " > " , 2 ) ;
write ( 1 , ptr . data ( ) , sz ) ;
} else write ( 1 , " ! <null> \n " , 8 ) ;
write ( 1 , " \n " , 1 ) ;
# else
// All the output from the program is cached and `write()` is only called once at the end.
if ( __builtin_expect ( ( sz = ptr . size ( ) ) > 0 , true ) ) {
printf ( " > %.*s \n " , ( int ) sz , ptr . data ( ) ) ;
} else puts ( " ! <null> \n " ) ;
# endif
}
static inline void print ( const std : : string & string )
{
std : : string_view sv { string } ;
return print_view ( sv ) ;
}
enum class moh_hck {
Template ,
Ref ,
Owned ,
} ;
/// Example using `make_opaque_handle`, like would be done for a C interface
template < moh_hck Create = moh_hck : : Owned >
static void use_moh ( )
{
std : : string * str = new std : : string ( __PRETTY_FUNCTION__ ) ;
constexpr auto v_print = [ ] ( const opaque_handle & v ) {
print ( * v ) ;
{
auto copied = v ;
s_puts ( " (copied) " ) ;
print ( * copied ) ;
s_puts ( " (moved) " ) ;
print ( * std : : move ( copied ) ) ;
}
} ;
if constexpr ( Create ! = moh_hck : : Owned ) {
constexpr auto _h = [ ] ( std : : string * ptr , auto op ) noexcept {
if ( ptr ) {
switch ( op ) {
case opaque_handle_operation : : Clone : return new std : : string ( std : : as_const ( * ptr ) ) ;
case opaque_handle_operation : : Delete : delete ptr ; break ;
}
}
return static_cast < std : : string * > ( nullptr ) ;
} ;
if constexpr ( Create = = moh_hck : : Template ) {
const opaque_handle v { make_opaque_handle < std : : string , _h > ( str ) } ;
v_print ( v ) ;
} else /*if constexpr(Create == moh_hck::Ref)*/ {
const opaque_handle v { make_opaque_handle < std : : string > ( str , _h ) } ;
v_print ( v ) ;
}
} else {
const opaque_handle v { make_opaque_handle < std : : string > ( str , [ ] ( std : : string * ptr , auto op ) noexcept {
if ( ptr ) {
switch ( op ) {
case opaque_handle_operation : : Clone : return new std : : string ( std : : as_const ( * ptr ) ) ;
case opaque_handle_operation : : Delete : delete ptr ; break ;
}
}
return static_cast < std : : string * > ( nullptr ) ;
} ) } ;
v_print ( v ) ;
}
s_puts ( " --- \n " ) ;
}
// Testing a hypothetical C interface
extern " C " {
struct c_struct_example ;
struct opaque ;
void black_box ( const opaque * __restrict__ ) { }
c_struct_example * cs_create ( const c_struct_example * __restrict__ from ) ;
void cs_free ( c_struct_example * p ) ;
void cs_print ( const c_struct_example * p ) ;
}
static void use_c_struct ( )
{
using type = c_struct_example ;
auto * allocp = cs_create ( nullptr ) ;
opaque_handle impossible { make_opaque_handle < opaque > ( nullptr , [ ] ( auto * , auto ) noexcept { return static_cast < opaque * > ( nullptr ) ; } ) } ;
black_box ( impossible ) ;
const opaque_handle v { make_opaque_handle < type > ( allocp , [ ] ( auto * ptr , auto op ) noexcept {
if ( ptr ) {
switch ( op ) {
case opaque_handle_operation : : Clone : return cs_create ( ptr ) ;
case opaque_handle_operation : : Delete : cs_free ( ptr ) ; break ;
}
}
return static_cast < type * > ( nullptr ) ;
} ) } ;
s_puts ( " > " ) ;
cs_print ( v ) ;
{
auto copied = v ;
s_puts ( " (copied)> " ) ;
cs_print ( copied ) ;
s_puts ( " (moved)> " ) ;
cs_print ( std : : move ( copied ) ) ;
}
}
int main ( )
{
const
opaque_handle v { make_opaque_object_handle ( std : : string { " Hello world " } ) } ;
puts ( " Auto-downcasting to `const std::string&`: " ) ;
print ( * v ) ;
# if 1
s_puts ( " \n Attempting invalid safe cast... " ) ;
try {
print_view ( * v ) ; // Try to cast to std::string_view, not the correct type...
s_puts ( " FAILED \n " ) ;
return 1 ;
} catch ( opaque_bad_cast & ) { // Expected this exception to be thrown
s_puts ( " OK \n " ) ;
} catch ( opaque_exception & other ) {
s_puts ( " UNEXPECTED ( " ) ;
s_puts ( other . what ( ) ) ;
s_puts ( " ) \n " ) ;
return 2 ;
}
# endif
puts ( " \n Converting view directly: " ) ;
print_view ( std : : string_view { v . cast < std : : string , opaque_handle : : CAST_UNSAFE /* SAFETY: We know this is the type of `v`'s pointee, so we don't need the type check. */ > ( ) } ) ; // Explicit cast needed, *v will choose the wrong type if not.
puts ( " \n Using opaque_make_handle(): " ) ;
use_moh < moh_hck : : Template > ( ) ;
use_moh < moh_hck : : Ref > ( ) ;
use_moh < moh_hck : : Owned > ( ) ;
puts ( " \n Using a C interface struct: " ) ;
use_c_struct ( ) ;
return 0 ;
}
extern " C " {
struct c_struct_example {
int i , j ;
size_t sz ;
char buf [ 256 ] ;
} ;
c_struct_example * cs_create ( const c_struct_example * __restrict__ from )
{
auto * ptr = reinterpret_cast < c_struct_example * > ( aligned_alloc ( alignof ( c_struct_example ) , sizeof ( c_struct_example ) ) ) ;
//memset(ptr, 0, sizeof(c_struct_example);
if ( ! from ) {
ptr - > i = 10 ;
ptr - > j = 11 ;
snprintf ( ptr - > buf , 256 , " Hello from C interface " ) ;
} else {
//memcpy(ptr, from, sizeof(c_struct_example));
* ptr = * from ;
ptr - > i + = 1 ;
ptr - > j - = 1 ;
snprintf ( ptr - > buf , 256 , " Hello from copied C interface (from %p) " , from ) ;
}
return ptr ;
}
void cs_print ( const c_struct_example * p )
{
# ifdef DIRECT_WRITE
char ibuf [ 512 ] ;
size_t n = snprintf ( ibuf , 512 , " %s: (%d, %d) " , p - > buf , p - > i , p - > j ) ;
write ( 1 , ibuf , n < sizeof ( ibuf ) ? n : 511 ) ;
write ( 1 , " \n " , 1 ) ;
# else
printf ( " %s: (%d, %d) \n " , p - > buf , p - > i , p - > j ) ;
# endif
}
void cs_free ( c_struct_example * p )
{
free ( p ) ;
}
}