Compare commits
34 Commits
master
...
heck-rewor
Author | SHA1 | Date |
---|---|---|
![]() |
7e823516d4 | 3 years ago |
![]() |
342986dc06 | 3 years ago |
![]() |
bc4873b286 | 3 years ago |
![]() |
a7bba8210e | 3 years ago |
![]() |
90685f41e5 | 3 years ago |
![]() |
d3f2e1b279 | 3 years ago |
![]() |
b463d27c5d | 3 years ago |
![]() |
4bee3b821a | 3 years ago |
![]() |
c363bd7924 | 3 years ago |
![]() |
0a641597d4 | 3 years ago |
![]() |
224c52b96c | 3 years ago |
![]() |
26e0848fa1 | 3 years ago |
![]() |
6b0ab94595 | 3 years ago |
![]() |
ba0857c930 | 3 years ago |
![]() |
33b898fa23 | 3 years ago |
![]() |
7e5d39f28b | 3 years ago |
![]() |
3f2f9ee3b3 | 3 years ago |
![]() |
41fff66a0c | 3 years ago |
![]() |
79a3dfecf8 | 3 years ago |
![]() |
c25c114082 | 3 years ago |
![]() |
8d9a1272b8 | 3 years ago |
![]() |
fafde0f22a | 3 years ago |
![]() |
9ab1fe5d75 | 3 years ago |
![]() |
d7c3e61322 | 3 years ago |
![]() |
47a1ea9e4c | 3 years ago |
![]() |
1df9c84511 | 3 years ago |
![]() |
e0634523a6 | 3 years ago |
![]() |
82d64f8c58 | 3 years ago |
![]() |
20075f1167 | 3 years ago |
![]() |
e49c88052d | 3 years ago |
![]() |
0853bea66c | 3 years ago |
![]() |
eed57ef631 | 3 years ago |
![]() |
3b556c2e99 | 3 years ago |
![]() |
3737da708d | 3 years ago |
38 changed files with 3533 additions and 23 deletions
@ -0,0 +1,204 @@ |
|||||
|
#include "libc99.h" |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
C99_C* c99_C_new() |
||||
|
{ |
||||
|
C99_C* ret = calloc(1, sizeof(C99_C)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void c99_C_free(C99_C* c) |
||||
|
{ |
||||
|
if (c) { |
||||
|
free(c->pi); |
||||
|
free(c); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
C99_B* c99_B_new() |
||||
|
{ |
||||
|
C99_B* result = calloc(1, sizeof(C99_B)); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
void c99_B_free(C99_B* b) |
||||
|
{ |
||||
|
if (b) { |
||||
|
c99_C_free(b->c); |
||||
|
free(b); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
C99_A* c99_A_new() |
||||
|
{ |
||||
|
C99_A* result = calloc(1, sizeof(C99_A)); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
void c99_A_free(C99_A* a) |
||||
|
{ |
||||
|
if (a) { |
||||
|
c99_B_free(a->b); |
||||
|
c99_A_free(a); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// -------------------------------------------------------------------------------------------------
|
||||
|
// USE
|
||||
|
// ---
|
||||
|
// dont do anything
|
||||
|
C99_Status c99_use_basic(int basic) |
||||
|
{ |
||||
|
return OK; |
||||
|
} |
||||
|
C99_Status c99_use_struct(const C99_A* a) |
||||
|
{ |
||||
|
if (!a) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
return OK; |
||||
|
} |
||||
|
C99_Status c99_use_string(const char* c_str) |
||||
|
{ |
||||
|
if (!c_str) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// SUPPLY
|
||||
|
// ------
|
||||
|
// modify value
|
||||
|
C99_Status c99_supply_basic(int* basic) |
||||
|
{ |
||||
|
if (!basic) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
|
||||
|
*basic *= 2; |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// modify struct elem
|
||||
|
// Replace object in a struct
|
||||
|
C99_Status c99_supply_struct(C99_A* a) |
||||
|
{ |
||||
|
// validate input
|
||||
|
if (!a) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
if (!a->b) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
if (!a->b->c) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
if (!a->b->c->pi) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
|
||||
|
// get current value
|
||||
|
int curr_val = *(a->b->c->pi); |
||||
|
// calculate new value
|
||||
|
int new_val = curr_val * 2; |
||||
|
|
||||
|
// replace with new object
|
||||
|
c99_B_free(a->b); |
||||
|
a->b = c99_B_new(); |
||||
|
a->b->c = c99_C_new(); |
||||
|
a->b->c->pi = calloc(1, sizeof(int)); |
||||
|
*a->b->c->pi = new_val; |
||||
|
|
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// prepend pEp
|
||||
|
C99_Status c99_supply_string(char** c_str) |
||||
|
{ |
||||
|
if (!c_str) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
if (!*c_str) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
|
||||
|
char pEp[] = "pEp"; |
||||
|
size_t pEp_len = strlen(pEp); |
||||
|
size_t c_str_len = strlen(*c_str); |
||||
|
char* new_str = (char*)malloc(c_str_len + pEp_len); |
||||
|
memcpy(new_str, pEp, pEp_len); |
||||
|
memcpy(new_str + pEp_len, *c_str, c_str_len); |
||||
|
free(*c_str); |
||||
|
c_str = &new_str; |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// PROVIDE
|
||||
|
// -------
|
||||
|
// dont do anything
|
||||
|
C99_Status c99_provide_basic(int basic) |
||||
|
{ |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// use and free the struct
|
||||
|
C99_Status c99_provide_struct(C99_A* a) |
||||
|
{ |
||||
|
if (!a) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
c99_A_free(a); |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// use and free the string
|
||||
|
C99_Status c99_provide_string(char* c_str) |
||||
|
{ |
||||
|
if (!c_str) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
free(c_str); |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// RETURN
|
||||
|
// ------
|
||||
|
// create a new instance and return it
|
||||
|
C99_Status c99_return_basic(int** basic) |
||||
|
{ |
||||
|
if (!basic) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
*basic = NULL; |
||||
|
int* new_basic = calloc(1, sizeof(int)); |
||||
|
*basic = new_basic; |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// create a new instance and return it
|
||||
|
C99_Status c99_return_struct(C99_A** a) |
||||
|
{ |
||||
|
if (!a) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
*a = NULL; |
||||
|
C99_A* new_a = c99_A_new(); |
||||
|
*a = new_a; |
||||
|
return OK; |
||||
|
} |
||||
|
|
||||
|
// create a new instance and return it
|
||||
|
C99_Status c99_return_string(char** c_str) |
||||
|
{ |
||||
|
if (!c_str) { |
||||
|
return ERROR; |
||||
|
} |
||||
|
|
||||
|
*c_str = NULL; |
||||
|
char* new_str = strdup("pEp"); |
||||
|
*c_str = new_str; |
||||
|
return OK; |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
// We are testing wrappers for the c-datatypes:
|
||||
|
// * integral e.g (int) here
|
||||
|
// * enum
|
||||
|
// * c-string
|
||||
|
// * struct
|
||||
|
// Those are all considered POD-types
|
||||
|
#ifndef LIBPEPDATATYPES_LIBC99_H |
||||
|
#define LIBPEPDATATYPES_LIBC99_H |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
typedef enum |
||||
|
{ |
||||
|
OK, |
||||
|
ERROR |
||||
|
} C99_Status; |
||||
|
|
||||
|
typedef enum |
||||
|
{ |
||||
|
ONE, |
||||
|
TWO, |
||||
|
THREE |
||||
|
} C99_Enum; |
||||
|
|
||||
|
|
||||
|
typedef struct { |
||||
|
int i; |
||||
|
int* pi; |
||||
|
} C99_C; |
||||
|
C99_C* c99_C_new(); |
||||
|
void c99_C_free(C99_C* c); |
||||
|
|
||||
|
typedef struct { |
||||
|
C99_C* c; |
||||
|
} C99_B; |
||||
|
C99_B* c99_B_new(); |
||||
|
void c99_B_free(C99_B* b); |
||||
|
|
||||
|
|
||||
|
typedef struct { |
||||
|
C99_B* b; |
||||
|
} C99_A; |
||||
|
C99_A* c99_A_new(); |
||||
|
void c99_A_free(C99_A* a); |
||||
|
|
||||
|
|
||||
|
// calling conventions
|
||||
|
// -------------------
|
||||
|
// use
|
||||
|
// readonly in parm, ownership remains with caller
|
||||
|
// create/own a full instance -> operator const T*()
|
||||
|
// const T* / T
|
||||
|
C99_Status c99_use_basic(int basic); |
||||
|
C99_Status c99_use_struct(const C99_A* a); |
||||
|
C99_Status c99_use_string(const char* c_str); |
||||
|
|
||||
|
// supply
|
||||
|
// inout parm, ownership remains with caller
|
||||
|
// the function changes the value of the object, but not the object itself
|
||||
|
// create/own a full instance -> operator T*
|
||||
|
// T*
|
||||
|
C99_Status c99_supply_basic(int* basic); |
||||
|
C99_Status c99_supply_struct(C99_A* a); |
||||
|
// Not valid
|
||||
|
// C99_Status c99_supply_string(char** c_str);
|
||||
|
|
||||
|
// provide
|
||||
|
// in parm, ownership goes to callee
|
||||
|
// same as 'use', but ownership goes to callee
|
||||
|
// create/own a full instance -> release ownership -> operator T*
|
||||
|
// T / T* (release ownership)
|
||||
|
C99_Status c99_provide_basic(int basic); |
||||
|
C99_Status c99_provide_struct(C99_A* a); |
||||
|
C99_Status c99_provide_string(char* c_str); |
||||
|
|
||||
|
// return
|
||||
|
// out parm, ownership goes to caller
|
||||
|
// T** will not be freed by the function,
|
||||
|
// create/own an empty instance -> operator T**
|
||||
|
// T** (must not point to mem which has to be freed first)
|
||||
|
C99_Status c99_return_basic(int** basic); |
||||
|
C99_Status c99_return_struct(C99_A** a); |
||||
|
C99_Status c99_return_string(char** c_str); |
||||
|
|
||||
|
// create
|
||||
|
// factory delivers this, ownership goes to caller
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
@ -0,0 +1,27 @@ |
|||||
|
LIB_STATIC=libc99.a |
||||
|
LIB_DYN=libc99.so |
||||
|
|
||||
|
CFLAGS+=-std=c99 -g -UNDEBUG |
||||
|
|
||||
|
SRCS+=$(wildcard *.c) |
||||
|
OBJS_C+=$(SRCS:.c=.o) |
||||
|
|
||||
|
.PHONY: all lib_static lib_dyn clean |
||||
|
|
||||
|
all: lib_static lib_dyn |
||||
|
|
||||
|
lib_static: $(LIB_STATIC) |
||||
|
|
||||
|
lib_dyn: $(LIB_DYN) |
||||
|
|
||||
|
$(LIB_STATIC): $(OBJS_C) |
||||
|
$(AR) -rc $@ $^ |
||||
|
|
||||
|
$(LIB_DYN): $(OBJS_C) |
||||
|
$(CC) $(CFLAGS) -shared -o $@ $^ |
||||
|
|
||||
|
clean: |
||||
|
rm -f $(LIB_STATIC) |
||||
|
rm -f $(LIB_DYN) |
||||
|
rm -f $(OBJS_C) |
||||
|
|
@ -0,0 +1,897 @@ |
|||||
|
#include <iostream> |
||||
|
#include <cctype> |
||||
|
#include <utility> |
||||
|
#include <pEp/utils.hh> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
#include <pEp/inspect.hh> |
||||
|
#include <type_traits> |
||||
|
#include <map> |
||||
|
#include <optional> |
||||
|
#include "../examples/libc99/libc99.h" |
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_POTS_HH |
||||
|
#define LIBPEPADAPTER_POTS_HH |
||||
|
|
||||
|
// TODO: this needs to go
|
||||
|
using namespace pEp; |
||||
|
|
||||
|
|
||||
|
// Python Overlay Type System
|
||||
|
|
||||
|
|
||||
|
namespace POTS { |
||||
|
class BasicSleeve; |
||||
|
bool operator==(const BasicSleeve& a, const BasicSleeve& b); |
||||
|
bool operator!=(const BasicSleeve& a, const BasicSleeve& b); |
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
class BasicSleeve { |
||||
|
public: |
||||
|
BasicSleeve() = default; |
||||
|
|
||||
|
// Create as a member
|
||||
|
BasicSleeve(const std::string& name, BasicSleeve& parent) : _name{ name }, _parent{ parent } |
||||
|
{ |
||||
|
_parent.value().get().add_member(*this); |
||||
|
} |
||||
|
|
||||
|
BasicSleeve(const BasicSleeve& rhs, BasicSleeve& parent) : |
||||
|
_name{ rhs._name }, |
||||
|
_parent(parent) |
||||
|
{ |
||||
|
_parent.value().get().add_member(*this); |
||||
|
} |
||||
|
|
||||
|
BasicSleeve(const BasicSleeve& rhs) : _name{ rhs._name } {} |
||||
|
|
||||
|
// Add a member
|
||||
|
void add_member(BasicSleeve& member) |
||||
|
{ |
||||
|
try { |
||||
|
_members.insert( |
||||
|
std::pair<std::string, BasicSleeve&>(member.get_name().value(), member)); |
||||
|
} catch (const std::bad_optional_access& e) { |
||||
|
throw std::runtime_error("cant add member without a name"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// leave parent
|
||||
|
void remove_member(BasicSleeve& member) |
||||
|
{ |
||||
|
try { |
||||
|
_members.erase(_members.find(member.get_name().value())); |
||||
|
} catch (const std::bad_optional_access& e) { |
||||
|
throw std::runtime_error("remove_member - cant remove member without a name"); |
||||
|
} catch (...) { |
||||
|
throw std::runtime_error("remove_member - unknown error"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual BasicSleeve& operator=(const BasicSleeve& rhs) |
||||
|
{ |
||||
|
pEpLog("called"); |
||||
|
if (_members.empty()) { |
||||
|
throw std::runtime_error("struct has no members"); |
||||
|
} |
||||
|
|
||||
|
for (std::pair<std::string, BasicSleeve&> member : _members) { |
||||
|
try { |
||||
|
BasicSleeve& other = rhs._members.at(member.first); |
||||
|
member.second = other; |
||||
|
} catch (const std::out_of_range& e) { |
||||
|
throw std::runtime_error("ASSFSD"); |
||||
|
} |
||||
|
} |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
virtual bool cmp(const BasicSleeve& rhs) const |
||||
|
{ |
||||
|
if (_members.empty()) { |
||||
|
throw std::runtime_error("struct has no members"); |
||||
|
} |
||||
|
|
||||
|
for (std::pair<std::string, BasicSleeve&> member : _members) { |
||||
|
try { |
||||
|
BasicSleeve& other = rhs._members.at(member.first); |
||||
|
if (other != member.second) { |
||||
|
return false; |
||||
|
} |
||||
|
} catch (const std::out_of_range& e) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
virtual void leave_ownership_recurse() |
||||
|
{ |
||||
|
for (std::pair<std::string, BasicSleeve&> member : _members) { |
||||
|
member.second.leave_ownership_recurse(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual void rebind() |
||||
|
{ |
||||
|
for (std::pair<std::string, BasicSleeve&> member : _members) { |
||||
|
member.second.rebind(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual std::string to_string(int indent = 0) const |
||||
|
{ |
||||
|
std::stringstream ss{}; |
||||
|
for (std::pair<std::string, BasicSleeve&> member : _members) { |
||||
|
ss << member.second.to_string(indent); |
||||
|
} |
||||
|
return ss.str(); |
||||
|
} |
||||
|
|
||||
|
virtual std::string repr(int indent = 0) const |
||||
|
{ |
||||
|
std::stringstream ss{}; |
||||
|
for (std::pair<std::string, BasicSleeve&> member : _members) { |
||||
|
ss << member.second.repr(indent); |
||||
|
} |
||||
|
return ss.str(); |
||||
|
} |
||||
|
|
||||
|
std::optional<std::string> get_name() |
||||
|
{ |
||||
|
return _name; |
||||
|
} |
||||
|
|
||||
|
virtual ~BasicSleeve() |
||||
|
{ |
||||
|
try { |
||||
|
if (_parent) { |
||||
|
_parent.value().get().remove_member(*this); |
||||
|
} |
||||
|
} catch (...) { |
||||
|
//TODO:
|
||||
|
// haha sth went wrong and you have no idea....
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected: |
||||
|
std::optional<std::string> _name{}; |
||||
|
std::optional<std::reference_wrapper<BasicSleeve>> _parent{}; |
||||
|
std::map<std::string, BasicSleeve&> _members{}; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// template<typename T, class Enable = void>
|
||||
|
// class Sleeve;
|
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
// VALUE
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
template<typename T> |
||||
|
class Sleeve { |
||||
|
// class Sleeve<T, typename std::enable_if<std::is_fundamental<T>::value || std::is_enum<T>::value || std::is_class<T>::value>::type>
|
||||
|
// : public BasicSleeve {
|
||||
|
|
||||
|
public: |
||||
|
using ResolverFunc = std::function<T*()>; |
||||
|
// Creation
|
||||
|
// --------
|
||||
|
Sleeve() = delete; |
||||
|
|
||||
|
// Create a hosting sleeve
|
||||
|
explicit Sleeve(const T& val) : |
||||
|
_target_resolver{ [this]() { return &_hosted_obj; } }, |
||||
|
_hosted_obj(val) |
||||
|
{ |
||||
|
pEpLogClass("hosting sleeve"); |
||||
|
} |
||||
|
|
||||
|
// // create a static sleeve
|
||||
|
// // using static binding to an existing object
|
||||
|
// explicit Sleeve(T* target) : _effective_resolver{ [target]() { return target; } }
|
||||
|
// {
|
||||
|
// pEpLogClass("static sleeve");
|
||||
|
// }
|
||||
|
|
||||
|
// create a dynamic sleeve
|
||||
|
// using dynamic binding (to a per-access determined object using the custom resolver)
|
||||
|
explicit Sleeve(ResolverFunc target_resolver) : |
||||
|
_target_resolver{ std::move(target_resolver) } |
||||
|
{ |
||||
|
pEpLogClass("dynamic sleeve"); |
||||
|
} |
||||
|
|
||||
|
// create a dynamic sleeve
|
||||
|
// using dynamic binding (to a per-access determined object using the custom target_resolver)
|
||||
|
// explicit Sleeve(BasicSleeve& parent, ResolverFunc target_resolver) :
|
||||
|
// BasicSleeve(parent),
|
||||
|
// _effective_resolver{ std::move(target_resolver) }
|
||||
|
// {
|
||||
|
// pEpLogClass("dynamic sleeve");
|
||||
|
// }
|
||||
|
|
||||
|
// copy
|
||||
|
// copy constructor will always create a hosting sleeve
|
||||
|
explicit Sleeve(const Sleeve<T>& rhs) : |
||||
|
_target_resolver{ [this]() { return &_hosted_obj; } }, |
||||
|
_hosted_obj{ rhs.obj() } |
||||
|
{ |
||||
|
pEpLogClass("copy ctor"); |
||||
|
} |
||||
|
|
||||
|
// Assignment
|
||||
|
// ----------
|
||||
|
// takes a copy
|
||||
|
Sleeve<T>& operator=(const Sleeve<T>& rhs) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
*target() = const_cast<Sleeve<T>&>(rhs).obj(); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// takes a copy
|
||||
|
Sleeve<T>& operator=(const T& rhs) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
*target() = rhs; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// Comparison
|
||||
|
// ----------
|
||||
|
// value comparison
|
||||
|
|
||||
|
// virtual bool operator==(const BasicSleeve& rhs) const override
|
||||
|
bool operator==(const Sleeve<T>& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return _this()->obj() == const_cast<Sleeve<T>&>(rhs).obj(); |
||||
|
} |
||||
|
|
||||
|
bool operator==(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return _this()->obj() == rhs; |
||||
|
} |
||||
|
|
||||
|
bool operator!=(const Sleeve<T>& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return !operator==(rhs); |
||||
|
} |
||||
|
|
||||
|
bool operator!=(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return !operator==(rhs); |
||||
|
} |
||||
|
|
||||
|
// object comparison
|
||||
|
bool is(const Sleeve<T>& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return id() == rhs.id(); |
||||
|
} |
||||
|
|
||||
|
bool is(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return _this()->target() == &rhs; |
||||
|
} |
||||
|
|
||||
|
// Accessors
|
||||
|
// ---------
|
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
operator T() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return obj(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
T obj() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *(_this()->target()); |
||||
|
} |
||||
|
|
||||
|
// Access the object pointer r/w
|
||||
|
T* target() |
||||
|
{ |
||||
|
// pEpLogClass("called");
|
||||
|
return _target_resolver(); |
||||
|
} |
||||
|
|
||||
|
// Misc
|
||||
|
// ----
|
||||
|
// obj_pointer as id
|
||||
|
uintptr_t id() const |
||||
|
{ |
||||
|
return reinterpret_cast<uintptr_t>(_this()->target()); |
||||
|
} |
||||
|
|
||||
|
std::string to_string() const //override
|
||||
|
{ |
||||
|
int indent = 0; |
||||
|
std::stringstream builder; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t') << "{" << std::endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "this : " << CXX::Inspect::all(_this()) |
||||
|
<< std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "target : " << CXX::Inspect::all(_this()->target()) << std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "_hosted_obj: " << CXX::Inspect::all(_this()->obj()) << std::endl; |
||||
|
|
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
// static bool log_enabled;
|
||||
|
Adapter::pEpLog::pEpLogger logger{ typeid(T).name(), true }; |
||||
|
|
||||
|
protected: |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
|
||||
|
ResolverFunc _target_resolver; |
||||
|
T _hosted_obj; |
||||
|
|
||||
|
private: |
||||
|
Sleeve<T>* _this() const |
||||
|
{ |
||||
|
return const_cast<Sleeve<T>*>(this); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
// POINTER
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
template<typename T> |
||||
|
class Sleeve<T*> |
||||
|
// class Sleeve<T*, typename std::enable_if<std::is_fundamental<T>::value || std::is_enum<T>::value || std::is_class<T>::value>::type>
|
||||
|
: public BasicSleeve { |
||||
|
protected: |
||||
|
//TODO simply use T
|
||||
|
using SharedPtr = std::shared_ptr<typename std::remove_pointer<T*>::type>; |
||||
|
|
||||
|
using AllocFunc = std::function<T*()>; |
||||
|
using FreeFunc = std::function<void(T*)>; |
||||
|
|
||||
|
const std::function<void(void*)> _deleter_bypass = [](void*) {}; |
||||
|
|
||||
|
public: |
||||
|
using ResolverFunc = std::function<T**()>; |
||||
|
|
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------
|
||||
|
// Creation
|
||||
|
|
||||
|
|
||||
|
// Hosting Sleeve Constructor - Create a hosting sleeve
|
||||
|
// unitialized
|
||||
|
explicit Sleeve() : |
||||
|
_target_resolver{ [this]() { return &_hosted_obj; } }, |
||||
|
_hosted_obj{ _effective_alloc() }, |
||||
|
_sptr{ obj(), _deleter_bypass } |
||||
|
{ |
||||
|
pEpLogClass("hosting sleeve"); |
||||
|
} |
||||
|
|
||||
|
// Hosting Sleeve Constructor - Create a hosting sleeve
|
||||
|
// initialized
|
||||
|
// explicit Sleeve(const T& val) : Sleeve()
|
||||
|
// {
|
||||
|
// pEpLogClass("hosting sleeve (initialized)");
|
||||
|
// this->operator=(val);
|
||||
|
// }
|
||||
|
|
||||
|
// create a static sleeve
|
||||
|
// using static binding to object pointer
|
||||
|
// explicit Sleeve(T** target) :
|
||||
|
// _target_resolver{ [target]() { return target; } },
|
||||
|
// _hosted_obj{ nullptr },
|
||||
|
// _sptr{ obj(), _deleter_bypass }
|
||||
|
// {
|
||||
|
// pEpLogClass("static sleeve");
|
||||
|
// }
|
||||
|
|
||||
|
// Binding Sleeve Constructor - create a dynamic sleeve
|
||||
|
// using dynamic binding (to a per-access determined object pointer using the custom target resolver)
|
||||
|
explicit Sleeve(ResolverFunc target_resolver) : |
||||
|
_target_resolver{ std::move(target_resolver) }, |
||||
|
_hosted_obj{ nullptr }, |
||||
|
_sptr{ obj(), _deleter_bypass } |
||||
|
{ |
||||
|
pEpLogClass("binding sleeve"); |
||||
|
} |
||||
|
|
||||
|
// Member Binding Sleeve Constructor - create a dynamic sleeve
|
||||
|
// using dynamic binding (to a per-access determined object pointer using the custom resolver)
|
||||
|
explicit Sleeve(const std::string& name, BasicSleeve& parent, ResolverFunc target_resolver) : |
||||
|
BasicSleeve(name, parent), |
||||
|
_target_resolver{ std::move(target_resolver) }, |
||||
|
_hosted_obj{ nullptr }, |
||||
|
_sptr{ obj(), _deleter_bypass } |
||||
|
{ |
||||
|
pEpLogClass("member binding sleeve"); |
||||
|
} |
||||
|
|
||||
|
// const AllocFunc _effective_alloc{ std::bind(&Sleeve::_default_alloc, this) };
|
||||
|
// const FreeFunc _effective_free{
|
||||
|
// std::bind(&Sleeve::_default_free, this, std::placeholders::_1)
|
||||
|
// };
|
||||
|
// const ResolverFunc _target_resolver{ nullptr };
|
||||
|
//
|
||||
|
// bool _is_owning{ true };
|
||||
|
// T* _hosted_obj{ nullptr };
|
||||
|
// SharedPtr _sptr{ nullptr };
|
||||
|
|
||||
|
// copy
|
||||
|
// copy constructor will always create a hosting sleeve
|
||||
|
// explicit Sleeve(const Sleeve<T*>& rhs) :
|
||||
|
// BasicSleeve(rhs),
|
||||
|
// _effective_alloc{ std::bind(&Sleeve::_default_alloc, this) },
|
||||
|
// _effective_free{
|
||||
|
// std::bind(&Sleeve::_default_free, this, std::placeholders::_1)
|
||||
|
// }, _target_resolver{ [this]() { return &_hosted_obj; } },
|
||||
|
// _hosted_obj{ _effective_alloc() },
|
||||
|
// _sptr{ obj(), _deleter_bypass }
|
||||
|
// {
|
||||
|
// pEpLogClass("copy ctor");
|
||||
|
// }
|
||||
|
|
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------
|
||||
|
// Assignment
|
||||
|
|
||||
|
Sleeve<T*>& operator=(const Sleeve<T*>& rhs) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if constexpr (std::is_class<T>::value) { |
||||
|
BasicSleeve::operator=(rhs); |
||||
|
} |
||||
|
|
||||
|
// replace own object
|
||||
|
leave_ownership(); |
||||
|
_sptr = rhs._sptr; |
||||
|
*target() = _sptr.get(); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// DYN TYPED ASSIGN ;p)
|
||||
|
// replace the object (managed)
|
||||
|
// take copy of the shared_ptr
|
||||
|
Sleeve<T*>& operator=(const BasicSleeve& rhs) override |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
try { |
||||
|
// try to cast rhs to own type
|
||||
|
const Sleeve<T*>& rhs_c = dynamic_cast<const Sleeve<T*>&>(rhs); |
||||
|
operator=(rhs_c); |
||||
|
} catch (...) { |
||||
|
throw std::runtime_error("INVALID TYPES"); |
||||
|
} |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// replace the value
|
||||
|
// Sleeve<T*>& operator=(T* rhs)
|
||||
|
// {
|
||||
|
// pEpLogClass("called");
|
||||
|
// leave_ownership();
|
||||
|
//
|
||||
|
// _sptr = SharedPtr{ rhs, _deleter_bypass };
|
||||
|
// *target() = rhs;
|
||||
|
//
|
||||
|
// if constexpr (std::is_class<T>::value) {
|
||||
|
// //rebind
|
||||
|
// }
|
||||
|
//
|
||||
|
// return *this;
|
||||
|
// }
|
||||
|
|
||||
|
// replace the value
|
||||
|
// deep-copy
|
||||
|
// if empty, create a new instance on the target
|
||||
|
Sleeve<T*>& operator=(const T& rhs) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
// only members leave ownership
|
||||
|
if constexpr (std::is_class<T>::value) { |
||||
|
BasicSleeve::leave_ownership_recurse(); |
||||
|
} |
||||
|
|
||||
|
// if empty, create a new obj
|
||||
|
if (is_empty()) { |
||||
|
pEpLogClass("creating new instance"); |
||||
|
*target() = _effective_alloc(); |
||||
|
_sptr = SharedPtr{ obj(), _deleter_bypass }; |
||||
|
} |
||||
|
|
||||
|
// copy in the value
|
||||
|
*obj() = rhs; |
||||
|
|
||||
|
// only members rebind
|
||||
|
if constexpr (std::is_class<T>::value) { |
||||
|
BasicSleeve::rebind(); |
||||
|
} |
||||
|
|
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
void rebind() override |
||||
|
{ |
||||
|
if constexpr (std::is_class<T>::value) { |
||||
|
BasicSleeve::rebind(); |
||||
|
} |
||||
|
_sptr = SharedPtr{ obj(), _deleter_bypass }; |
||||
|
} |
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------
|
||||
|
// Comparison
|
||||
|
|
||||
|
// value comparison
|
||||
|
// must be specialized for struct types
|
||||
|
bool cmp(const BasicSleeve& rhs) const override |
||||
|
{ |
||||
|
// pEpLogClass("called");
|
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
// try convert it to own type Sleeve<T>
|
||||
|
try { |
||||
|
const Sleeve<T*>& rhs_c = dynamic_cast<const Sleeve<T*>&>(rhs); |
||||
|
|
||||
|
// both have an object, lets compare values
|
||||
|
if (!is_empty() && !rhs_c.is_empty()) { |
||||
|
return *_this()->obj() == *const_cast<Sleeve<T*>&>(rhs_c).obj(); |
||||
|
} |
||||
|
// both have no object, they are equal
|
||||
|
if (is_empty() && rhs_c.is_empty()) { |
||||
|
return true; |
||||
|
} |
||||
|
// otherwise they are not the same
|
||||
|
return false; |
||||
|
} catch (...) { |
||||
|
return false; |
||||
|
} |
||||
|
} else { |
||||
|
return BasicSleeve::cmp(const_cast<BasicSleeve&>(rhs)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// TODO: we dont offer comparison to raw T /T*
|
||||
|
// Solution: create binding sleeve of T and compare Sleeves
|
||||
|
// OR: create hosting sleeve with copy of T and compare sleeves
|
||||
|
|
||||
|
// bool operator==(const T* rhs) const
|
||||
|
// {
|
||||
|
// if constexpr (!std::is_class<T>::value) {
|
||||
|
// if (rhs != nullptr && !is_empty()) {
|
||||
|
// return *_this()->obj() == *rhs;
|
||||
|
// }
|
||||
|
// if (rhs == nullptr && is_empty()) {
|
||||
|
// return true;
|
||||
|
// }
|
||||
|
// return false;
|
||||
|
// } else {
|
||||
|
// throw std::runtime_error("cant compare raw struct types by value");
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
// bool operator==(const T& rhs) const
|
||||
|
// {
|
||||
|
// pEpLogClass("called");
|
||||
|
// if constexpr (!std::is_class<T>::value) {
|
||||
|
// return *_this()->obj() == rhs;
|
||||
|
// } else {
|
||||
|
// throw std::runtime_error(
|
||||
|
// "cant compare raw struct types by value, must be implemented in structure aware specialization");
|
||||
|
// }
|
||||
|
// }
|
||||
|
//
|
||||
|
// bool operator!=(const Sleeve<T*>& rhs) const
|
||||
|
// {
|
||||
|
// pEpLogClass("called");
|
||||
|
// return !operator==(rhs);
|
||||
|
// }
|
||||
|
|
||||
|
bool operator!=(const T* rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
!operator==(rhs); |
||||
|
} else { |
||||
|
throw std::runtime_error( |
||||
|
"cant compare raw struct types by value, must be implemented in structure aware specialization"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool operator!=(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
!operator==(rhs); |
||||
|
} else { |
||||
|
throw std::runtime_error( |
||||
|
"cant compare raw struct types by value, must be implemented in structure aware specialization"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// identity comparison
|
||||
|
bool is(const Sleeve<T*>& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return id() == rhs.id(); |
||||
|
} |
||||
|
|
||||
|
bool is(const T* rhs) const |
||||
|
{ |
||||
|
return _this()->obj() == rhs; |
||||
|
} |
||||
|
|
||||
|
bool is(const T& rhs) const |
||||
|
{ |
||||
|
bool ret = _this()->obj() == &rhs; |
||||
|
//TODO: is this right?
|
||||
|
assert(ret == false); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------
|
||||
|
// Accessors
|
||||
|
|
||||
|
// // Access value
|
||||
|
operator T() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return value(); |
||||
|
} |
||||
|
//
|
||||
|
// Access value
|
||||
|
T value() const |
||||
|
{ |
||||
|
return *_this()->obj(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
operator T*() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return obj(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
T* obj() |
||||
|
{ |
||||
|
return *target(); |
||||
|
} |
||||
|
|
||||
|
// Access the object pointer r/w
|
||||
|
T** target() |
||||
|
{ |
||||
|
T** ret = _target_resolver(); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// -----------------------------------------------------------------------------------------
|
||||
|
// Destruction
|
||||
|
|
||||
|
// This is the only way to decide at 'destruction-time' if the last shared_ptr has to be freed or not
|
||||
|
~Sleeve() override |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
leave_ownership(); |
||||
|
} |
||||
|
|
||||
|
void leave_ownership_recurse() override |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if constexpr (std::is_class<T>::value) { |
||||
|
BasicSleeve::leave_ownership_recurse(); |
||||
|
} |
||||
|
leave_ownership(); |
||||
|
} |
||||
|
|
||||
|
void leave_ownership() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (_sptr.unique()) { |
||||
|
if (_is_owning) { |
||||
|
_effective_free(obj()); |
||||
|
} |
||||
|
} |
||||
|
*target() = nullptr; |
||||
|
_sptr = nullptr; |
||||
|
} |
||||
|
|
||||
|
// Misc
|
||||
|
// ----
|
||||
|
// object as id
|
||||
|
uintptr_t id() const |
||||
|
{ |
||||
|
return reinterpret_cast<uintptr_t>(_this()->obj()); |
||||
|
} |
||||
|
|
||||
|
void set_owner(bool is_owner) |
||||
|
{ |
||||
|
_is_owning = is_owner; |
||||
|
} |
||||
|
|
||||
|
bool is_bound() const |
||||
|
{ |
||||
|
return _this()->target() != nullptr; |
||||
|
} |
||||
|
|
||||
|
bool is_empty() const |
||||
|
{ |
||||
|
return _this()->obj() == nullptr; |
||||
|
} |
||||
|
|
||||
|
bool is_hosting() const |
||||
|
{ |
||||
|
return &_hosted_obj == _this()->target(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(int indent = 0) const override // override
|
||||
|
{ |
||||
|
std::stringstream builder; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t') << "{" << std::endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "this : " << CXX::Inspect::all(_this()) |
||||
|
<< std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "obj : " << CXX::Inspect::all(*_this()->target()) << std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "target : " << CXX::Inspect::all(_this()->target()) << std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "hosted_obj : " << CXX::Inspect::all(_this()->_hosted_obj) << std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "sptr obj : " << CXX::Inspect::all(_sptr.get()) << std::endl; |
||||
|
builder << std::string(indent, '\t') |
||||
|
<< "sptr count : " << CXX::Inspect::all(_sptr.use_count()) << std::endl; |
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
builder << std::string(indent, '\t') << "value : " |
||||
|
<< (!is_empty() ? CXX::Inspect::all(*_this()->obj()) : "<NULL>"); |
||||
|
} else { |
||||
|
builder << std::string(indent, '\t') << "value : "; |
||||
|
indent++; |
||||
|
builder << BasicSleeve::to_string(indent); |
||||
|
indent--; |
||||
|
} |
||||
|
indent--; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t') << "}" << std::endl; |
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string repr(int indent = 0) const override |
||||
|
{ |
||||
|
std::stringstream builder; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t'); |
||||
|
// builder << //PARENT THIS
|
||||
|
builder << CXX::Inspect::val(_this()) << " / "; |
||||
|
builder << CXX::Inspect::val(_this()->target()) << " / "; |
||||
|
builder << CXX::Inspect::val(_this()->obj()) << " / "; |
||||
|
builder << _sptr.use_count() << " / "; |
||||
|
builder << CXX::Inspect::type(_hosted_obj) << " - \""; |
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
builder << (!is_empty() ? CXX::Inspect::val(*_this()->obj()) : "<NULL>") << "\""; |
||||
|
} else { |
||||
|
builder << " {" << std::endl; |
||||
|
indent++; |
||||
|
builder << BasicSleeve::repr(indent); |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
} |
||||
|
return builder.str(); |
||||
|
} |
||||
|
// static bool log_enabled;
|
||||
|
Adapter::pEpLog::pEpLogger logger{ "Sleeve<" + std::string(typeid(T*).name()) + ">", true }; |
||||
|
|
||||
|
protected: |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
|
||||
|
const AllocFunc _effective_alloc{ std::bind(&Sleeve::_default_alloc, this) }; |
||||
|
const FreeFunc _effective_free{ |
||||
|
std::bind(&Sleeve::_default_free, this, std::placeholders::_1) |
||||
|
}; |
||||
|
const ResolverFunc _target_resolver{ nullptr }; |
||||
|
|
||||
|
bool _is_owning{ true }; |
||||
|
T* _hosted_obj{ nullptr }; |
||||
|
SharedPtr _sptr{ nullptr }; |
||||
|
|
||||
|
|
||||
|
// defaults for customizable functions
|
||||
|
// -----------------------------------
|
||||
|
T* _default_alloc() |
||||
|
{ |
||||
|
T* ret = (T*)::calloc(1, sizeof(T)); |
||||
|
pEpLogClass(CXX::Inspect::all(ret)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void _default_free(T* ptr) |
||||
|
{ |
||||
|
pEpLogClass(CXX::Inspect::all(ptr)); |
||||
|
::free(ptr); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private: |
||||
|
Sleeve<T*>* _this() const |
||||
|
{ |
||||
|
return const_cast<Sleeve<T*>*>(this); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
bool operator==(const BasicSleeve& a, const BasicSleeve& b) |
||||
|
{ |
||||
|
return a.cmp(b) && b.cmp(a); |
||||
|
} |
||||
|
|
||||
|
bool operator!=(const BasicSleeve& a, const BasicSleeve& b) |
||||
|
{ |
||||
|
return !(a == b); |
||||
|
} |
||||
|
}; // namespace POTS
|
||||
|
|
||||
|
using POTS::operator==; |
||||
|
using POTS::operator!=; |
||||
|
|
||||
|
|
||||
|
//--------------------------------------------------------------------------------------------------
|
||||
|
// Example Datatypes libC99
|
||||
|
//--------------------------------------------------------------------------------------------------
|
||||
|
// Struct type specialization
|
||||
|
// operator <<
|
||||
|
// operator ==
|
||||
|
// operator =
|
||||
|
|
||||
|
namespace LIBC99 { |
||||
|
using POTS::Sleeve; |
||||
|
|
||||
|
class C99_C : public Sleeve<::C99_C*> { |
||||
|
public: |
||||
|
// HS
|
||||
|
explicit C99_C() : Sleeve<::C99_C*>() {} |
||||
|
// explicit C99_C(const ::C99_C& val) : Sleeve<::C99_C*>(val) {}
|
||||
|
explicit C99_C(ResolverFunc target_resolver) : Sleeve<::C99_C*>(target_resolver) {} |
||||
|
|
||||
|
// MDS
|
||||
|
// explicit C99_C(const std::string& name, Sleeve& parent, ResolverFunc target_resolver) :
|
||||
|
// Sleeve<::C99_C*>(name, parent, std::move(target_resolver))
|
||||
|
// {
|
||||
|
// }
|
||||
|
|
||||
|
// copy
|
||||
|
// explicit C99_C(const C99_C& rhs) : Sleeve<::C99_C*>(rhs) {}
|
||||
|
// explicit Sleeve(const std::string& name, Sleeve& parent, ResolverFunc target_resolver) :
|
||||
|
Sleeve<int*> pi{ "pi", *this, [this]() { return &this->obj()->pi; } }; |
||||
|
// Sleeve<int*> pi{ "pi", *this };
|
||||
|
|
||||
|
C99_C& operator=(const ::C99_C& rhs) |
||||
|
{ |
||||
|
Sleeve<::C99_C*>::operator=(rhs); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// bool operator==(const ::C99_C& rhs) const
|
||||
|
// {
|
||||
|
// pEpLogClass("called");
|
||||
|
// C99_C tmp{ rhs };
|
||||
|
// // return *_this()->obj() == rhs;
|
||||
|
// }
|
||||
|
}; |
||||
|
} // namespace LIBC99
|
||||
|
|
||||
|
|
||||
|
#endif |
@ -0,0 +1,180 @@ |
|||||
|
#ifndef LIBPEPDATAYPES_LIBC99_HH |
||||
|
#define LIBPEPDATAYPES_LIBC99_HH |
||||
|
|
||||
|
#include "../examples/libc99/libc99.h" |
||||
|
#include <exception> |
||||
|
#include <vector> |
||||
|
#include <string> |
||||
|
|
||||
|
|
||||
|
namespace C99 { |
||||
|
namespace Utils { |
||||
|
// C99_Status
|
||||
|
std::string to_string(const C99_Status& data) |
||||
|
{ |
||||
|
switch (data) { |
||||
|
case OK: |
||||
|
return "OK"; |
||||
|
case ERROR: |
||||
|
return "ERROR"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const C99_Status*& data) |
||||
|
{ |
||||
|
if (data) { |
||||
|
return to_string(*data); |
||||
|
} else { |
||||
|
return "<NULL>"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// C99_Enum
|
||||
|
std::string to_string(const C99_Enum& data) |
||||
|
{ |
||||
|
switch (data) { |
||||
|
case ONE: |
||||
|
return "ONE"; |
||||
|
case TWO: |
||||
|
return "TWO"; |
||||
|
case THREE: |
||||
|
return "THREE"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const C99_Enum* data) |
||||
|
{ |
||||
|
if (data) { |
||||
|
return to_string(*data); |
||||
|
} else { |
||||
|
return "<NULL>"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// C99_C
|
||||
|
std::string to_string(const ::C99_C& data, int indent = 0) |
||||
|
{ |
||||
|
std::stringstream builder; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t') << "{" << std::endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "i: '" << data.i << "'" << std::endl; |
||||
|
builder << std::string(indent, '\t') << "pi: '" |
||||
|
<< (data.pi != nullptr ? std::to_string(*data.pi) : "<NULL>") << "'" |
||||
|
<< std::endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::C99_C* data, int indent = 0) |
||||
|
{ |
||||
|
if (data) { |
||||
|
return to_string(*data, indent); |
||||
|
} else { |
||||
|
return "<NULL>"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// C99_B
|
||||
|
std::string to_string(const ::C99_B& data, int indent = 0) |
||||
|
{ |
||||
|
std::stringstream builder; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t') << "{" << std::endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "c: '" + to_string(data.c, indent) << "'" |
||||
|
<< std::endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::C99_B* data, int indent = 0) |
||||
|
{ |
||||
|
if (data) { |
||||
|
return to_string(*data, indent); |
||||
|
} else { |
||||
|
return "<NULL>"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// C99_A
|
||||
|
std::string to_string(const ::C99_A& data, int indent = 0) |
||||
|
{ |
||||
|
std::stringstream builder; |
||||
|
builder << std::endl; |
||||
|
builder << std::string(indent, '\t') << "{" << std::endl; |
||||
|
indent++; |
||||
|
builder << std::string(indent, '\t') << "b: '" + to_string(data.b, indent) << "'" |
||||
|
<< std::endl; |
||||
|
indent--; |
||||
|
builder << std::string(indent, '\t') << "}"; |
||||
|
return builder.str(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string(const ::C99_A* data, int indent = 0) |
||||
|
{ |
||||
|
if (data) { |
||||
|
return to_string(*data, indent); |
||||
|
} else { |
||||
|
return "<NULL>"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} // namespace Utils
|
||||
|
} // namespace C99
|
||||
|
|
||||
|
// ostream inserters
|
||||
|
//C99_Status
|
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_Status& a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_Status* a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
|
||||
|
//C99_Enum
|
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_Enum& a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_Enum* a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
|
||||
|
//C99_C
|
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_C& a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_C* a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
|
||||
|
//C99_B
|
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_B& a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_B* a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
|
||||
|
//C99_A
|
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_A& a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
std::ostream& operator<<(std::ostream& o, const ::C99_A* a) |
||||
|
{ |
||||
|
return o << C99::Utils::to_string(a); |
||||
|
} |
||||
|
|
||||
|
#endif // LIBPEPDATAYPES_LIBC99_HH
|
@ -0,0 +1,676 @@ |
|||||
|
#include <iostream> |
||||
|
#include <cctype> |
||||
|
#include <utility> |
||||
|
#include <pEp/utils.hh> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
#include <pEp/inspect.hh> |
||||
|
#include <type_traits> |
||||
|
#include "../examples/libc99/libc99.h" |
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
|
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
#define EXSTR(msg) std::string(__FUNCTION__) + "() - " + msg |
||||
|
|
||||
|
template<class T> |
||||
|
class POD { |
||||
|
static_assert( |
||||
|
std::is_pod<T>::value && !std::is_pointer<T>::value, |
||||
|
"only POD value types supported"); |
||||
|
|
||||
|
public: |
||||
|
POD() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
}; |
||||
|
|
||||
|
explicit POD(T* pod_p, const T& init_val) |
||||
|
{ |
||||
|
bind(pod_p, init_val); |
||||
|
} |
||||
|
|
||||
|
// Best to use this constructor, as the object is in a valid state when the wrapped
|
||||
|
// c_str (char*) is known
|
||||
|
explicit POD(T* pod_p) |
||||
|
{ |
||||
|
bind(pod_p); |
||||
|
} |
||||
|
|
||||
|
void bind(T* pod_p, const T& init_val) |
||||
|
{ |
||||
|
bind(pod_p); |
||||
|
this->operator=(init_val); |
||||
|
} |
||||
|
|
||||
|
void bind(T* pod_p) |
||||
|
{ |
||||
|
if (pod_p == nullptr) { |
||||
|
throw Exception{ EXSTR("cant bind on a nullptr") }; |
||||
|
} |
||||
|
|
||||
|
if (_is_initialized) { |
||||
|
throw Exception{ EXSTR("can only bind once") }; |
||||
|
} |
||||
|
// init
|
||||
|
_pod_p = pod_p; |
||||
|
_is_initialized = true; |
||||
|
pEpLogClass(to_string()); |
||||
|
} |
||||
|
|
||||
|
// make a copy
|
||||
|
POD& operator=(T value) |
||||
|
{ |
||||
|
pEpLogClass("Before: " + to_string() + " - new val: '" + CXX::Inspect::val(value) + "'"); |
||||
|
*_pod_p = value; |
||||
|
// pEpLogClass("After: " + to_string());
|
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// return a copy
|
||||
|
operator T() const |
||||
|
{ |
||||
|
return *_pod_p; |
||||
|
} |
||||
|
|
||||
|
// return address of the wrappee
|
||||
|
T* data() |
||||
|
{ |
||||
|
return _pod_p; |
||||
|
} |
||||
|
|
||||
|
// return address of the wrappee (const)
|
||||
|
const T* c_data() const |
||||
|
{ |
||||
|
return _pod_p; |
||||
|
} |
||||
|
|
||||
|
std::string to_string() const |
||||
|
{ |
||||
|
std::string ret{ "[" + CXX::Inspect::all(_pod_p) + "]" }; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
static bool log_enabled; |
||||
|
|
||||
|
private: |
||||
|
bool _is_initialized{ false }; |
||||
|
T* _pod_p{ nullptr }; |
||||
|
|
||||
|
Adapter::pEpLog::pEpLogger logger{ "pEp::POD", log_enabled }; |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
|
||||
|
class Exception : public std::runtime_error { |
||||
|
public: |
||||
|
explicit Exception(const std::string& msg) : std::runtime_error(msg) {} |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
template<class T> |
||||
|
bool pEp::POD<T>::log_enabled{ false }; |
||||
|
|
||||
|
template<class T> |
||||
|
std::ostream& operator<<(std::ostream& o, pEp::POD<T> pEpPOD) |
||||
|
{ |
||||
|
return o << (T)pEpPOD; |
||||
|
} |
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
// Manages a char* to appear like a std::string
|
||||
|
// char* c_str
|
||||
|
// c_str MUST point to either:
|
||||
|
// * NULL - means there is no value/mem alloc yet
|
||||
|
// * dyn allocated memory
|
||||
|
// in case the mem is already allocated, there must be 2 modes
|
||||
|
// * take ownership (and free it)
|
||||
|
// * dont take ownership, only provide a C++ interface
|
||||
|
// There must be the option to construct the object before the wrapped c_str (char*)
|
||||
|
// is known. This leads to a pEp::String object in invalid state, and it must be initialized using
|
||||
|
// bind(). Otherwise all(most) functions will throw.
|
||||
|
// bind() can only be called once, will throw otherwise.
|
||||
|
// NON-owning mode, just does not free the string when it dies, owning mode does.
|
||||
|
// Thats the only difference.
|
||||
|
class String { |
||||
|
public: |
||||
|
// Best to use this constructor, as the object is in a valid state when the wrapped
|
||||
|
// c_str (char*) is known
|
||||
|
String(char** c_str_pp) |
||||
|
{ |
||||
|
bind(c_str_pp); |
||||
|
} |
||||
|
|
||||
|
// bind and set ownership
|
||||
|
void bind(char** c_str_pp) |
||||
|
{ |
||||
|
if (c_str_pp == nullptr) { |
||||
|
throw Exception{ EXSTR("cant bind on a nullptr") }; |
||||
|
} |
||||
|
|
||||
|
if (_is_bound) { |
||||
|
throw Exception{ EXSTR("can only be bound once") }; |
||||
|
} |
||||
|
|
||||
|
// init
|
||||
|
_target = c_str_pp; |
||||
|
_is_bound = true; |
||||
|
pEpLogClass(to_string()); |
||||
|
|
||||
|
//if the c_str_p is nullptr then init with ""
|
||||
|
if (*_target == nullptr) { |
||||
|
this->operator=(""); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
~String() |
||||
|
{ |
||||
|
if (_is_owner) { |
||||
|
_free(*_target); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// make a copy
|
||||
|
String& operator=(const std::string& str) |
||||
|
{ |
||||
|
pEpLogClass("Before: " + to_string() + " - new val: '" + pEp::Utils::clip(str, 30) + "'"); |
||||
|
if (_target == nullptr) { |
||||
|
throw Exception{ EXSTR("invalid state") }; |
||||
|
} |
||||
|
|
||||
|
// DEALLOCATION
|
||||
|
_free(*_target); |
||||
|
|
||||
|
// ALLOCATION
|
||||
|
*_target = _copy(str); |
||||
|
pEpLogClass("After: " + to_string()); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// return a copy of whatever c_str currently is (maybe created by us, maybe changed meanwhile)
|
||||
|
operator std::string() const |
||||
|
{ |
||||
|
if (_target == nullptr) { |
||||
|
throw Exception{ EXSTR("invalid state") }; |
||||
|
} |
||||
|
|
||||
|
if (*_target != nullptr) { |
||||
|
return { *_target }; |
||||
|
} |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
const char* c_data() const |
||||
|
{ |
||||
|
if (_target == nullptr) { |
||||
|
throw Exception{ EXSTR("invalid state") }; |
||||
|
} |
||||
|
return *_target; |
||||
|
} |
||||
|
|
||||
|
char* data() |
||||
|
{ |
||||
|
if (_target == nullptr) { |
||||
|
throw Exception{ EXSTR("invalid state") }; |
||||
|
} |
||||
|
return *_target; |
||||
|
} |
||||
|
|
||||
|
char** obj() |
||||
|
{ |
||||
|
return _target; |
||||
|
} |
||||
|
|
||||
|
operator const char*() const |
||||
|
{ |
||||
|
return c_data(); |
||||
|
} |
||||
|
|
||||
|
operator char*() |
||||
|
{ |
||||
|
return data(); |
||||
|
} |
||||
|
|
||||
|
operator char**() |
||||
|
{ |
||||
|
return obj(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool operator==(const pEp::String& pstr) const |
||||
|
{ |
||||
|
return *(pstr.c_data()) == (*c_data()); |
||||
|
} |
||||
|
|
||||
|
bool operator!=(const pEp::String& pstr) const |
||||
|
{ |
||||
|
return !(*this == pstr); |
||||
|
} |
||||
|
|
||||
|
std::string to_string() const |
||||
|
{ |
||||
|
|
||||
|
if (_target == nullptr) { |
||||
|
throw Exception{ EXSTR("invalid state") }; |
||||
|
} |
||||
|
|
||||
|
std::string ret{ "[" + CXX::Inspect::all(_target) + " / " + |
||||
|
CXX::Inspect::all(*_target) + "]" }; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void set_owner(bool is_owner) |
||||
|
{ |
||||
|
pEpLogClass(std::to_string(is_owner)); |
||||
|
_is_owner = is_owner; |
||||
|
} |
||||
|
|
||||
|
bool is_owner() const |
||||
|
{ |
||||
|
return _is_owner; |
||||
|
} |
||||
|
|
||||
|
static bool log_enabled; |
||||
|
|
||||
|
private: |
||||
|
char* _copy(const std::string& str) |
||||
|
{ |
||||
|
char* ret = strdup(str.c_str()); |
||||
|
pEpLogClass(CXX::Inspect::all(ret)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void _free(char* ptr_type) |
||||
|
{ |
||||
|
pEpLogClass(CXX::Inspect::all(ptr_type)); |
||||
|
::pEp_free(ptr_type); |
||||
|
} |
||||
|
|
||||
|
bool _is_owner{ true }; |
||||
|
bool _is_bound{ false }; |
||||
|
char** _target{ nullptr }; |
||||
|
|
||||
|
Adapter::pEpLog::pEpLogger logger{ "pEp::String", log_enabled }; |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
|
||||
|
class Exception : public std::runtime_error { |
||||
|
public: |
||||
|
explicit Exception(const std::string& msg) : std::runtime_error(msg) {} |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
bool pEp::String::log_enabled{ false }; |
||||
|
|
||||
|
std::ostream& operator<<(std::ostream& o, const pEp::String& pEpStr) |
||||
|
{ |
||||
|
return o << std::string(pEpStr); |
||||
|
} |
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
// TOOD:
|
||||
|
// ctor not exception safe
|
||||
|
// You can create an instance of a c-struct or you can wrap an already existing c-struct
|
||||
|
// In both cases, you can define if the wrapper owns the instance, or not.
|
||||
|
// If if owns it, it will free() it when the wrapper dies, otherwise it doesnt.
|
||||
|
class BasicSleeve { |
||||
|
public: |
||||
|
virtual ~BasicSleeve() = default; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename T> |
||||
|
class Sleeve : public BasicSleeve { |
||||
|
public: |
||||
|
// Creation
|
||||
|
// --------
|
||||
|
Sleeve() = delete; |
||||
|
|
||||
|
// Create a sleeve and an instance
|
||||
|
explicit Sleeve(const T& val) : _effective_resolver{ [this]() { return &_obj; } }, _obj(val) |
||||
|
{ |
||||
|
pEpLogClass("hosting sleeve"); |
||||
|
} |
||||
|
|
||||
|
// create a sleeve on an instance
|
||||
|
// using static binding to an existing object
|
||||
|
explicit Sleeve(T* target) : _effective_resolver{ [target]() { return target; } } |
||||
|
{ |
||||
|
pEpLogClass("static sleeve"); |
||||
|
} |
||||
|
|
||||
|
// create a sleeve on an instance
|
||||
|
// using dynamic binding (to a per-access determined object using the custom resolver)
|
||||
|
explicit Sleeve(std::function<T*()> resolver) : _effective_resolver{ std::move(resolver) } |
||||
|
{ |
||||
|
pEpLogClass("dynamic sleeve"); |
||||
|
} |
||||
|
|
||||
|
// create a new instance and copy the value
|
||||
|
explicit Sleeve(const Sleeve<T>& rhs) : |
||||
|
_effective_resolver{ [this]() { return &_obj; } }, |
||||
|
_obj{ rhs._obj } |
||||
|
{ |
||||
|
pEpLogClass("copy ctor"); |
||||
|
} |
||||
|
|
||||
|
// Assignment
|
||||
|
// ----------
|
||||
|
// takes a copy
|
||||
|
Sleeve<T>& operator=(const Sleeve<T>& rhs) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
*obj_ptr() = rhs._obj; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// assign the binding
|
||||
|
Sleeve<T>& operator=(const T& rhs) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
*obj_ptr() = rhs; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
// Comparison
|
||||
|
// ----------
|
||||
|
// value comparison
|
||||
|
bool operator==(const Sleeve<T>& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *const_cast<Sleeve<T>*>(this)->obj_ptr() == *const_cast<Sleeve<T>&>(rhs).obj_ptr(); |
||||
|
} |
||||
|
|
||||
|
bool operator==(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *const_cast<Sleeve<T>*>(this)->obj_ptr() == rhs; |
||||
|
} |
||||
|
|
||||
|
// bool operator!=(const Sleeve<T>& rhs) const
|
||||
|
// {
|
||||
|
// pEpLogClass("called");
|
||||
|
// return !operator==(rhs);
|
||||
|
// }
|
||||
|
|
||||
|
bool operator!=(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return !operator==(rhs); |
||||
|
} |
||||
|
|
||||
|
// object comparison
|
||||
|
bool is(const Sleeve<T>& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return id() == rhs.id(); |
||||
|
} |
||||
|
|
||||
|
bool is(const T& rhs) const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return const_cast<Sleeve<T>*>(this)->obj_ptr() == &rhs; |
||||
|
} |
||||
|
|
||||
|
// Accessors
|
||||
|
// ---------
|
||||
|
// Access the object data r/w
|
||||
|
T data() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *obj_ptr(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
operator T() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *obj_ptr(); |
||||
|
} |
||||
|
|
||||
|
// Access the object pointer r/w
|
||||
|
T* obj_ptr() |
||||
|
{ |
||||
|
// pEpLogClass("called");
|
||||
|
return _effective_resolver(); |
||||
|
} |
||||
|
|
||||
|
// Misc
|
||||
|
// ----
|
||||
|
// obj_pointer as id
|
||||
|
long id() const |
||||
|
{ |
||||
|
// pEpLogClass("called");
|
||||
|
return reinterpret_cast<long>(const_cast<Sleeve<T>*>(this)->obj_ptr()); |
||||
|
} |
||||
|
|
||||
|
std::string to_string() |
||||
|
{ |
||||
|
std::string ret{ "[" + CXX::Inspect::all(*obj_ptr()) + "]" }; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// static bool log_enabled;
|
||||
|
Adapter::pEpLog::pEpLogger logger{ typeid(T).name(), true }; |
||||
|
|
||||
|
protected: |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
|
||||
|
std::function<T*()> _effective_resolver; |
||||
|
T _obj; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename T> |
||||
|
class Sleeve<T*> : public BasicSleeve { |
||||
|
public: |
||||
|
// Creates a new sleeve managing and holding a newly created object
|
||||
|
explicit Sleeve() : |
||||
|
_target{ &_obj }, |
||||
|
_obj{ _alloc_wrapper() }, |
||||
|
_sptr{ *_target, std::bind(&Sleeve::_free_wrapper, this) } |
||||
|
{ |
||||
|
pEpLogClass("new"); |
||||
|
} |
||||
|
|
||||
|
//Create a sleeve managing a C - sleeve explicit
|
||||
|
Sleeve(T** target) : |
||||
|
_target(target), |
||||
|
_obj{ nullptr }, |
||||
|
_sptr{ *_target, std::bind(&Sleeve::_free_wrapper, this) } |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
} |
||||
|
|
||||
|
explicit Sleeve(std::function<T**()> resolver) : _effective_resolver{ std::move(resolver) } |
||||
|
{ |
||||
|
pEpLogClass("wrap"); |
||||
|
} |
||||
|
|
||||
|
const T* c_data() const |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *obj_ptr(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
T* data() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return *obj_ptr(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data read-only
|
||||
|
operator const T*() |
||||
|
{ |
||||
|
return c_data(); |
||||
|
} |
||||
|
|
||||
|
// Access the object data r/w
|
||||
|
operator T*() |
||||
|
{ |
||||
|
return data(); |
||||
|
} |
||||
|
|
||||
|
// T* abandon()
|
||||
|
// {
|
||||
|
// T* ret = *_target;
|
||||
|
// _is_owning = false;
|
||||
|
// _obj = nullptr;
|
||||
|
// _sptr.reset(*_target, std::bind(&Sleeve::_free_wrapper, this));
|
||||
|
// return ret;
|
||||
|
// }
|
||||
|
|
||||
|
// Access the object pointer r/w
|
||||
|
T** obj_ptr() |
||||
|
{ |
||||
|
return _effective_resolver(); |
||||
|
} |
||||
|
|
||||
|
std::string to_string() |
||||
|
{ |
||||
|
std::string ret{ "[" + CXX::Inspect::all(*obj_ptr()) + "]" }; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// static bool log_enabled;
|
||||
|
Adapter::pEpLog::pEpLogger logger{ typeid(T*).name(), true }; |
||||
|
|
||||
|
protected: |
||||
|
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
||||
|
|
||||
|
|
||||
|
const std::function<T*()> _effective_alloc{ std::bind(&Sleeve::_default_alloc, this) }; |
||||
|
const std::function<void(T*)> _effective_free{ |
||||
|
std::bind(&Sleeve::_default_free, this, std::placeholders::_1) |
||||
|
}; |
||||
|
|
||||
|
// We have as many indirections as we have levels in the hosting data structure
|
||||
|
// When the obj is member of a struct, the obj we actually wrap can change without
|
||||
|
// further noctice from the C99 side.
|
||||
|
// Therefore for EVERY access to to the obj we need to ask the hosting struct for the
|
||||
|
// address of our obj. If the hosting struct is a member of a struct itself, it will have to
|
||||
|
// to ask its hosting struct and so forth... recursively.
|
||||
|
// For every access, you have as many indirections as levels deep your object is in the struct.
|
||||
|
// Using this technique, we can also accommodate for wrapping an object which can
|
||||
|
// be REPLACED without further notice, handing out a T**.
|
||||
|
const std::function<T**()> _effective_resolver{ std::bind(&Sleeve::_default_resolver, this) }; |
||||
|
|
||||
|
bool _is_owning{ true }; |
||||
|
// we ALWAYS have a _target that points to either an internal or external obj
|
||||
|
T** _target{ nullptr }; |
||||
|
// we MAYBE also have an obj
|
||||
|
T* _obj{ nullptr }; |
||||
|
// we NEVER operate on the obj, but only on the _target
|
||||
|
|
||||
|
// All the shared ptr does, is freeing *_target when last copy dies
|
||||
|
// the shared pointer CAN NOT have the correct obj pointer at all times,
|
||||
|
// because the object can change without notice from the C99 side.
|
||||
|
// Thats why this class basically is an (infinitely) indirect shared pointer.
|
||||
|
std::shared_ptr<typename std::remove_pointer<T*>::type> _sptr; |
||||
|
|
||||
|
|
||||
|
// defaults for customizable functions
|
||||
|
// -----------------------------------
|
||||
|
|
||||
|
T* _default_alloc() |
||||
|
{ |
||||
|
T* ret = (T*)calloc(1, sizeof(T)); |
||||
|
pEpLogClass(CXX::Inspect::all(ret)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void _default_free(T* ptr) |
||||
|
{ |
||||
|
pEpLogClass(CXX::Inspect::all(ptr)); |
||||
|
free(ptr); |
||||
|
} |
||||
|
|
||||
|
T** _default_resolver() |
||||
|
{ |
||||
|
pEpLogClass(CXX::Inspect::all(_target)); |
||||
|
return _target; |
||||
|
} |
||||
|
|
||||
|
// wrappers
|
||||
|
// --------
|
||||
|
|
||||
|
T* _alloc_wrapper() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
return _effective_alloc(); |
||||
|
} |
||||
|
|
||||
|
void _free_wrapper() |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
if (_is_owning) { |
||||
|
_effective_free(*obj_ptr()); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// template<typename T>
|
||||
|
// class Sleeve<T*> : public BasicSleeve {
|
||||
|
//
|
||||
|
// };
|
||||
|
|
||||
|
|
||||
|
// TOOD://
|
||||
|
// alloc/free:
|
||||
|
// the alloc() and free() functions HAVE to use calloc/malloc NOT 'new', because we are interfacing
|
||||
|
// c99 code that could possibly get ownership of the struct and can only free memory that has
|
||||
|
// been allocated using malloc/calloc. (malloc/free - new/delete are NOT compatible)
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
class C : public Sleeve<::C99_C*> { |
||||
|
public: |
||||
|
// create a new instance
|
||||
|
explicit C() : Sleeve<::C99_C*>() {} |
||||
|
// create an instance wrapper
|
||||
|
// explicit C(::C* obj) : Sleeve<::C>(obj) {}
|
||||
|
// create an instance-ptr wrapper
|
||||
|
// explicit C(::C** obj_ptr) : Sleeve<::C>(obj_ptr) {}
|
||||
|
explicit C(std::function<::C99_C**()> resolver) : Sleeve<::C99_C*>(resolver) {} |
||||
|
|
||||
|
pEp::Sleeve<int> i{ [this]() { return &dynamic_cast<C*>(this)->data()->i; } }; |
||||
|
// pEp::Sleeve<int*> pi{ this, [](BasicSleeve* parent) {
|
||||
|
// return &dynamic_cast<C*>(parent)->data()->pi;
|
||||
|
// } };
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// // ------------------------------------------------------------------------------------------
|
||||
|
// class B : public Sleeve<::C99_B*> {
|
||||
|
// public:
|
||||
|
// // create a new instance
|
||||
|
// explicit B() : Sleeve<::C99_B*>() {}
|
||||
|
// // create an instance wrapper
|
||||
|
// // explicit B(::B* obj) : Sleeve<::B>(obj) {}
|
||||
|
// // create an instance-ptr wrapper
|
||||
|
// // explicit B(::B** obj_ptr) : Sleeve<::B>(obj_ptr) {}
|
||||
|
// explicit B(BasicSleeve* parent, std::function<::C99_B**(BasicSleeve*)> resolver) :
|
||||
|
// Sleeve<::C99_B*>(parent, resolver)
|
||||
|
// {
|
||||
|
// }
|
||||
|
//
|
||||
|
// pEp::C c{ this, [](BasicSleeve* parent) { return &dynamic_cast<B*>(parent)->data()->c; } };
|
||||
|
// };
|
||||
|
//
|
||||
|
//
|
||||
|
// // ------------------------------------------------------------------------------------------
|
||||
|
// class A : public Sleeve<::C99_A*> {
|
||||
|
// public:
|
||||
|
// // create a new instance
|
||||
|
// explicit A() : Sleeve<::C99_A*>() {}
|
||||
|
// // create an instance wrapper
|
||||
|
// // explicit A(::A* obj) : Sleeve<::A>(obj) {}
|
||||
|
// // create an instance-ptr wrapper
|
||||
|
// // explicit A(::A** obj_ptr) : Sleeve<::A>(obj_ptr) {}
|
||||
|
// explicit A(BasicSleeve* parent, std::function<::C99_A**(BasicSleeve*)> resolver) :
|
||||
|
// Sleeve<::C99_A*>(parent, resolver)
|
||||
|
// {
|
||||
|
// }
|
||||
|
//
|
||||
|
// pEp::B b{ this, [](BasicSleeve* parent) { return &dynamic_cast<A*>(parent)->data()->b; } };
|
||||
|
// };
|
||||
|
|
||||
|
} // namespace pEp
|
@ -1,23 +1,31 @@ |
|||||
include ../Makefile.conf |
include ../Makefile.conf |
||||
|
|
||||
LDFLAGS=-L../src -L$(PREFIX)/lib -L$(PREFIX_GTEST)/lib |
LIBC99_PATH=../examples/libc99/ |
||||
LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter |
LIBC99_STATIC=$(LIBC99_PATH)libc99.a |
||||
CXXFLAGS:=-I../src $(CXXFLAGS) -I$(PREFIX_GTEST)/include |
LIBPEPDATATYPES_PATH=../src/ |
||||
|
LIBPEPDATATYPES_STATIC=$(LIBPEPDATATYPES_PATH)libpepdatatypes.a |
||||
|
|
||||
TEST_SOURCE=$(wildcard *.cc) |
LDLIBS=-lstdc++ -lpEpEngine -lpEpCxx11 -lpEpAdapter -lPityTest11 -lpthread -ldl -lm $(LIBC99_STATIC) |
||||
TEST_OBJECTS=$(subst .cc,.o,$(TEST_SOURCE)) |
CXXFLAGS+=-I$(LIBPEPDATATYPES_PATH) -I$(LIBC99_PATH) |
||||
|
|
||||
.PHONY: all, clean |
# Test
|
||||
|
SRC_TEST=$(wildcard test_*.cc) |
||||
|
BIN_TEST=$(subst .cc,,$(SRC_TEST)) |
||||
|
|
||||
all: unittests |
.PHONY: libc99 tests all clean |
||||
|
|
||||
unittests: $(TEST_OBJECTS) ../src/libpEpDatatypes.a |
all: libc99 tests |
||||
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) -lgtest -lgtest_main |
|
||||
|
|
||||
|
libc99: $(LIBC99_STATIC) |
||||
|
|
||||
|
$(LIBC99_STATIC): |
||||
|
$(MAKE) -C ../examples/libc99 |
||||
|
|
||||
|
tests: $(BIN_TEST) |
||||
|
|
||||
|
|
||||
clean: |
clean: |
||||
rm -f unittests |
rm -f $(BIN_TEST) |
||||
rm -Rf *.dSYM |
rm -Rf *.dSYM |
||||
rm -f *.o |
rm -f *.d |
||||
|
rm -f *.o |
@ -0,0 +1,73 @@ |
|||||
|
#include <map> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
#include "pEp/inspect.hh" |
||||
|
#include "../examples/libc99/libc99.h" |
||||
|
#include "../src/libc99.hh" |
||||
|
//#include "../src/POTS.hh"
|
||||
|
|
||||
|
using namespace pEp; |
||||
|
|
||||
|
struct Struct { |
||||
|
int a; |
||||
|
int b; |
||||
|
}; |
||||
|
|
||||
|
template<typename T> |
||||
|
class Field { |
||||
|
public: |
||||
|
Field() = default; |
||||
|
Field(T* target) { |
||||
|
bind(target); |
||||
|
} |
||||
|
|
||||
|
void bind(T* target) { |
||||
|
_target = target; |
||||
|
} |
||||
|
operator T() |
||||
|
{ |
||||
|
return *_target; |
||||
|
} |
||||
|
|
||||
|
Field& operator=(T val) |
||||
|
{ |
||||
|
*_target = val; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
T* _target{ nullptr}; |
||||
|
}; |
||||
|
|
||||
|
class A : public Field<A> { |
||||
|
public: |
||||
|
A() : _obj{ std::make_shared<Struct>() } { |
||||
|
a.bind(&_obj->a); |
||||
|
b.bind(&_obj->b); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::shared_ptr<Struct> _obj; |
||||
|
Field<int> a{}; |
||||
|
Field<int> b{}; |
||||
|
}; |
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
Adapter::pEpLog::set_enabled(true); |
||||
|
pEpLog("start"); |
||||
|
A b{}; |
||||
|
pEpLog(b.a); |
||||
|
// pEpLog(b.b);
|
||||
|
|
||||
|
{ |
||||
|
A a{}; |
||||
|
a.a = 23; |
||||
|
a.b = 42; |
||||
|
pEpLog(a.a); |
||||
|
// pEpLog(a.b);
|
||||
|
|
||||
|
b = a; |
||||
|
} |
||||
|
pEpLog(b.a); |
||||
|
// pEpLog(b.b);
|
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
#include "../src/prototype.hh" |
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
|
||||
|
|
||||
|
//---------------------------------------------------------------------------------------------
|
||||
|
namespace pEp { |
||||
|
class Identity : public Sleeve<::pEp_identity> { |
||||
|
public: |
||||
|
Identity(::pEp_identity** ident_p = nullptr) : PODStruct<::pEp_identity>(ident_p) {} |
||||
|
|
||||
|
Identity( |
||||
|
const std::string& address = "", |
||||
|
const std::string& username = "", |
||||
|
const std::string& user_id = "", |
||||
|
const std::string& fpr = "") : |
||||
|
Sleeve<::pEp_identity>(nullptr) |
||||
|
{ |
||||
|
pEpLogClass("called"); |
||||
|
this->address = address; |
||||
|
this->username = username; |
||||
|
this->user_id = user_id; |
||||
|
this->fpr = fpr; |
||||
|
} |
||||
|
|
||||
|
pEp::String fpr{ &data()->fpr }; |
||||
|
pEp::String user_id{ &data()->user_id }; |
||||
|
pEp::String username{ &data()->username }; |
||||
|
pEp::POD<::PEP_comm_type> comm_type{ &data()->comm_type }; |
||||
|
//char[3] lang
|
||||
|
pEp::POD<bool> me{ &data()->me }; |
||||
|
pEp::POD<unsigned int> major_ver{ &data()->major_ver }; |
||||
|
pEp::POD<unsigned int> minor_ver{ &data()->minor_ver }; |
||||
|
pEp::POD<::PEP_enc_format> enc_format{ &data()->enc_format }; |
||||
|
pEp::POD<::identity_flags_t> flags{ &data()->flags }; |
||||
|
}; |
||||
|
|
||||
|
template<> |
||||
|
bool Sleeve<::pEp_identity>::log_enabled{ false }; |
||||
|
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
pEp::Adapter::pEpLog::set_enabled(true); |
||||
|
::PEP_SESSION session; |
||||
|
setenv("HOME", ".", 1); |
||||
|
::init(&session, nullptr, nullptr, nullptr); |
||||
|
|
||||
|
// create identity
|
||||
|
pEp::Identity id1{ "wrong@entry.lol", "wrong", "23", "INVA_FPR" }; |
||||
|
|
||||
|
pEpLog(id1.c_data()); |
||||
|
id1.username = "alice"; |
||||
|
id1.address = "alice@peptest.org"; |
||||
|
id1. |
||||
|
|
||||
|
pEpLog(id1.address); |
||||
|
pEpLog(id1.username); |
||||
|
::myself(session, id1); |
||||
|
pEpLog(id1.c_data()); |
||||
|
|
||||
|
pEp::Identity id2{ "bob" }; |
||||
|
::update_identity(session, id2); |
||||
|
pEpLog(id2.c_data()); |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,414 @@ |
|||||
|
#include <iostream> |
||||
|
#include <cctype> |
||||
|
#include <pEp/pEpEngine.h> |
||||
|
#include <pEp/message_api.h> |
||||
|
#include <pEp/keymanagement.h> |
||||
|
#include <pEp/identity_list.h> |
||||
|
#include <utility> |
||||
|
#include <pEp/utils.hh> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
#include <pEp/inspect.hh> |
||||
|
#include <type_traits> |
||||
|
//#include "../examples/libc99/libc99.h"
|
||||
|
#include "../src/prototype.hh" |
||||
|
|
||||
|
void test_getters(int* c_int_p, pEp::POD<int>& pint, int expected) |
||||
|
{ |
||||
|
// pEpLog("to_string(): " + pint.to_string());
|
||||
|
// compare addresses
|
||||
|
pEpLog("addresses == c_int_p"); |
||||
|
assert(pint.c_data() == c_int_p); |
||||
|
assert(pint.data() == c_int_p); |
||||
|
|
||||
|
// compare values
|
||||
|
if (c_int_p != nullptr) { |
||||
|
pEpLog("operator int(): " + std::to_string(pint)); |
||||
|
assert(pint == *c_int_p); |
||||
|
assert(pint == expected); |
||||
|
|
||||
|
// will segfault with nullptr, and this is correct
|
||||
|
pEpLog("data(): " + std::to_string(*pint.data())); |
||||
|
assert(*pint.data() == *c_int_p); |
||||
|
assert(*pint.data() == expected); |
||||
|
|
||||
|
pEpLog("c_data(): " + std::to_string(*pint.c_data())); |
||||
|
assert(*pint.c_data() == *c_int_p); |
||||
|
assert(*pint.c_data() == expected); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void test_assign(int* c_int_p, pEp::POD<int>& pint) |
||||
|
{ |
||||
|
{ |
||||
|
pEpLogH2("assign operator"); |
||||
|
int new_val = 23; |
||||
|
pint = new_val; |
||||
|
test_getters(c_int_p, pint, new_val); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("raw c_str assign"); |
||||
|
int new_val = 23; |
||||
|
*c_int_p = new_val; |
||||
|
test_getters(c_int_p, pint, new_val); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void test_getters(char** c_str_p, pEp::String& pstr, const std::string& expected) |
||||
|
{ |
||||
|
pEpLog("to_string(): " + pstr.to_string()); |
||||
|
// compare addresses
|
||||
|
pEpLog("addresses == c_str_p"); |
||||
|
assert(pstr.c_data() == *c_str_p); |
||||
|
assert(pstr.obj() == c_str_p); |
||||
|
|
||||
|
// compare values
|
||||
|
if (*c_str_p != nullptr) { |
||||
|
pEpLog("operator std::string(): " + std::string(pstr)); |
||||
|
assert(std::string(pstr) == std::string(*c_str_p)); |
||||
|
assert(std::string(pstr) == expected); |
||||
|
|
||||
|
// will segfault with nullptr, and this is correct
|
||||
|
pEpLog("data(): " + std::string(*pstr.obj())); |
||||
|
assert(std::string(*pstr.obj()) == std::string(*c_str_p)); |
||||
|
assert(std::string(*pstr.obj()) == expected); |
||||
|
|
||||
|
pEpLog("c_data(): " + std::string(pstr.c_data())); |
||||
|
assert(std::string(pstr.c_data()) == std::string(*c_str_p)); |
||||
|
assert(std::string(pstr.c_data()) == expected); |
||||
|
} else { |
||||
|
std::string tmp{ pstr }; |
||||
|
pEpLog("operator std::string(): " + tmp); |
||||
|
assert(tmp.empty()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void test_assign(char** c_str_p, pEp::String& pstr) |
||||
|
{ |
||||
|
{ |
||||
|
pEpLogH2("assign operator"); |
||||
|
std::string new_val{ "assign operator" }; |
||||
|
pstr = new_val; |
||||
|
test_getters(c_str_p, pstr, new_val); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("raw c_str assign"); |
||||
|
std::string new_val{ "raw c_str assign" }; |
||||
|
free(*c_str_p); |
||||
|
*c_str_p = strdup(new_val.c_str()); |
||||
|
test_getters(c_str_p, pstr, new_val); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
//void test_func1(char** out) {
|
||||
|
// *out = strdup("fds");
|
||||
|
//}
|
||||
|
|
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
// c-types are always POD
|
||||
|
// we need to handle pointer types and value types differently
|
||||
|
// pointer types need to be memory-managed (heap)
|
||||
|
// value types are being copied around (stack)
|
||||
|
static_assert(std::is_pod<int>::value && !std::is_pointer<int>::value, "not an integral"); |
||||
|
static_assert( |
||||
|
std::is_pod<::C99_Enum>::value && !std::is_pointer<::C99_Enum>::value, |
||||
|
"not an integral"); |
||||
|
static_assert(std::is_pod<::C99_B>::value && !std::is_pointer<::C99_B>::value, "not an integral"); |
||||
|
|
||||
|
// pEp::Utils::readKey();
|
||||
|
pEp::Adapter::pEpLog::set_enabled(true); |
||||
|
|
||||
|
// char* tmp = strdup("fd");
|
||||
|
// std::cout << pEp::CXX::Inspect::all(tmp) << std::endl;
|
||||
|
// change_ptr(tmp);
|
||||
|
// std::cout << pEp::CXX::Inspect::all(tmp) << std::endl;
|
||||
|
|
||||
|
// char *ht;
|
||||
|
// pEp::String tmp1{true,&ht};
|
||||
|
//
|
||||
|
// test_func1(tmp1);
|
||||
|
// std::cout << tmp1;
|
||||
|
|
||||
|
// POD
|
||||
|
if (0) { |
||||
|
// VALID USAGE
|
||||
|
int init_val = 0; |
||||
|
// new pEp::POD on int
|
||||
|
{ |
||||
|
pEpLogH1("new pEp::POD on int"); |
||||
|
int c_int = init_val; |
||||
|
pEp::POD<int> pint(&c_int); |
||||
|
test_getters(&c_int, pint, init_val); |
||||
|
test_assign(&c_int, pint); |
||||
|
} |
||||
|
// equality operator
|
||||
|
{ |
||||
|
pEpLogH1("equality operator"); |
||||
|
int c_int1 = init_val; |
||||
|
int c_int2 = init_val; |
||||
|
pEp::POD<int> pint1(&c_int1); |
||||
|
pEp::POD<int> pint2(&c_int2); |
||||
|
assert(pint1 == pint2); |
||||
|
|
||||
|
c_int2 = 23; |
||||
|
assert(pint1 != pint2); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// String
|
||||
|
// pEp::String::log_enabled = false;
|
||||
|
if (0) { |
||||
|
//TODO: Test non-owning mode
|
||||
|
//
|
||||
|
// INVALID USAGE
|
||||
|
// char* c_str_u; // uninitialized == INVALID
|
||||
|
// undefined behaviour, most likely "pointer being freed was not allocated"
|
||||
|
// {
|
||||
|
// char* c_str;
|
||||
|
// pEp::String pstr(c_str);
|
||||
|
// }
|
||||
|
// char* c_str_s = "fdsfs"; // statically initialized == INVALID
|
||||
|
// {
|
||||
|
// char ca[4] = { 'p', 'E', 'p'};
|
||||
|
// char* c_str = ca;
|
||||
|
// pEp::String pstr(c_str);
|
||||
|
// }
|
||||
|
|
||||
|
// VALID USAGE
|
||||
|
{ |
||||
|
pEpLogH1("new pEp::String on char* pointing to NULL"); |
||||
|
char* c_str = NULL; // nullptr
|
||||
|
|
||||
|
pEp::String pstr(&c_str); |
||||
|
test_getters(&c_str, pstr, ""); |
||||
|
test_assign(&c_str, pstr); |
||||
|
} |
||||
|
|
||||
|
std::string init_val{ "initialized c string" }; |
||||
|
{ |
||||
|
pEpLogH1("new pEp::String on already initalized char*"); |
||||
|
char* c_str = strdup(init_val.c_str()); |
||||
|
|
||||
|
pEp::String pstr(&c_str); |
||||
|
test_getters(&c_str, pstr, init_val); |
||||
|
test_assign(&c_str, pstr); |
||||
|
} |
||||
|
|
||||
|
// equality operator
|
||||
|
{ |
||||
|
pEpLogH1("equality operator"); |
||||
|
|
||||
|
char* c_str1 = strdup(init_val.c_str()); |
||||
|
char* c_str2 = strdup(init_val.c_str()); |
||||
|
pEp::String pstr1{ &c_str1 }; |
||||
|
pEp::String pstr2{ &c_str2 }; |
||||
|
assert(pstr1 == pstr2); |
||||
|
pstr2 = "huhu"; |
||||
|
assert(pstr1 != pstr2); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
if (1) { |
||||
|
pEpLogH2("Create a sleeve and an instance"); |
||||
|
int i = 23; |
||||
|
pEp::Sleeve<int> ot_i{ i }; |
||||
|
|
||||
|
|
||||
|
pEpLog(pEp::CXX::Inspect::all(i)); |
||||
|
pEpLog(ot_i.to_string()); |
||||
|
assert(ot_i == i); |
||||
|
assert(!ot_i.is(i)); |
||||
|
|
||||
|
pEpLogH3("change from C++ / POTS"); |
||||
|
pEp::Sleeve<int> i_pots{42}; |
||||
|
ot_i = i_pots; |
||||
|
assert(ot_i == i_pots); |
||||
|
assert(!ot_i.is(i_pots)); |
||||
|
|
||||
|
pEpLogH3("change from C++ / native"); |
||||
|
int i_native = 23; |
||||
|
ot_i = i_native; |
||||
|
assert(ot_i == i_native); |
||||
|
assert(!ot_i.is(i_native)); |
||||
|
|
||||
|
pEpLogH3("change from C99"); |
||||
|
i = 42; |
||||
|
int* pi = ot_i.obj_ptr(); |
||||
|
*pi = i; |
||||
|
assert(ot_i == i); |
||||
|
assert(!ot_i.is(i)); |
||||
|
} |
||||
|
|
||||
|
if (1) { |
||||
|
pEpLogH2("create a sleeve on an instance, static"); |
||||
|
int i{ 23 }; |
||||
|
pEp::Sleeve<int> ot_i{ &i }; |
||||
|
pEpLog(pEp::CXX::Inspect::all(i)); |
||||
|
pEpLog(ot_i.to_string()); |
||||
|
assert(ot_i == i); |
||||
|
assert(ot_i.is(i)); |
||||
|
|
||||
|
pEpLogH3("change from C++ / POTS"); |
||||
|
pEp::Sleeve<int> i_pots{42}; |
||||
|
ot_i = i_pots; |
||||
|
assert(ot_i == i_pots); |
||||
|
assert(!ot_i.is(i_pots)); |
||||
|
|
||||
|
pEpLogH3("change from C++ / native"); |
||||
|
int i_native = 23; |
||||
|
ot_i = i_native; |
||||
|
assert(ot_i == i_native); |
||||
|
assert(!ot_i.is(i_native)); |
||||
|
|
||||
|
pEpLogH3("change from C99"); |
||||
|
i = 42; |
||||
|
int* pi = ot_i.obj_ptr(); |
||||
|
*pi = i; |
||||
|
assert(ot_i == i); |
||||
|
assert(ot_i.is(i)); |
||||
|
} |
||||
|
|
||||
|
if (1) { |
||||
|
pEpLogH2("create a sleeve on an instance, dynamic"); |
||||
|
int i{ 23 }; |
||||
|
pEp::Sleeve<int> ot_i{ [&i](){ return &i;} }; |
||||
|
pEpLog(pEp::CXX::Inspect::all(i)); |
||||
|
pEpLog(ot_i.to_string()); |
||||
|
assert(ot_i == i); |
||||
|
assert(ot_i.is(i)); |
||||
|
|
||||
|
pEpLogH3("change from C++ / POTS"); |
||||
|
pEp::Sleeve<int> i_pots{42}; |
||||
|
ot_i = i_pots; |
||||
|
assert(ot_i == i_pots); |
||||
|
assert(!ot_i.is(i_pots)); |
||||
|
|
||||
|
pEpLogH3("change from C++ / native"); |
||||
|
int i_native = 23; |
||||
|
ot_i = i_native; |
||||
|
assert(ot_i == i_native); |
||||
|
assert(!ot_i.is(i_native)); |
||||
|
|
||||
|
pEpLogH3("change from C99"); |
||||
|
i = 42; |
||||
|
int* pi = ot_i.obj_ptr(); |
||||
|
*pi = i; |
||||
|
assert(ot_i == i); |
||||
|
assert(ot_i.is(i)); |
||||
|
} |
||||
|
|
||||
|
// Struct
|
||||
|
/* if (0) {
|
||||
|
// sleeve empty
|
||||
|
{ |
||||
|
pEp::Sleeve<::B> pstruct1{ nullptr }; |
||||
|
const B* cc_struct = pstruct1; |
||||
|
B* c_struct = pstruct1; |
||||
|
assert(pstruct1.data() == nullptr); |
||||
|
assert(pstruct1.c_data() == nullptr); |
||||
|
assert(c_struct == nullptr); |
||||
|
assert(cc_struct == nullptr); |
||||
|
pEpLog("DONE"); |
||||
|
|
||||
|
// return_struct(pstruct1);
|
||||
|
} |
||||
|
|
||||
|
// Creates a sleeve managing and holding a newly created object
|
||||
|
{ |
||||
|
pEp::Sleeve<::B> pstruct1{}; |
||||
|
B* c_struct = pstruct1; |
||||
|
c_struct->c_int = 3; |
||||
|
c_struct->c_str = std::string("huhu").data(); |
||||
|
c_struct->c_enum = TWO; |
||||
|
pEpLog("DONE"); |
||||
|
} |
||||
|
|
||||
|
// Create a sleeve managing and holding an already existing object
|
||||
|
{ |
||||
|
// create an object
|
||||
|
::B* c_struct1 = ::new_B(0, ONE, "pEp"); |
||||
|
pEpLog(c_struct1->c_int); |
||||
|
pEpLog(c_struct1->c_enum); |
||||
|
pEpLog(c_struct1->c_str); |
||||
|
pEpLog("DONE"); |
||||
|
|
||||
|
// reference the object
|
||||
|
pEp::Sleeve<::B> pstruct1{ c_struct1 }; |
||||
|
pEpLog("DONE"); |
||||
|
} |
||||
|
|
||||
|
// Create a sleeve managing a C-sleeve
|
||||
|
{ |
||||
|
|
||||
|
B* c_struct = nullptr; |
||||
|
pEp::Sleeve<::B> pstruct1{ &c_struct }; |
||||
|
// c_struct->c_str = strdup("pEp");
|
||||
|
// c_struct->c_int = 5;
|
||||
|
// c_struct->c_enum = TWO;
|
||||
|
} |
||||
|
} |
||||
|
*/ |
||||
|
// Calling conventions
|
||||
|
// pEp::Utils::readKey();
|
||||
|
// {
|
||||
|
// pEpLogH1("use_struct()");
|
||||
|
// {
|
||||
|
// pEp::A a{};
|
||||
|
// use_struct(a);
|
||||
|
// }
|
||||
|
// pEpLogH1("c99_supply_struct()");
|
||||
|
// {
|
||||
|
// int val = 23;
|
||||
|
// // C99
|
||||
|
// {
|
||||
|
// // prepare data structure
|
||||
|
// ::C99_A* c_a = ::c99_A_new();
|
||||
|
// c_a->b = c99_B_new();
|
||||
|
// c_a->b->c = c99_C_new();
|
||||
|
// c_a->b->c->pi = (int*)calloc(1, sizeof(int));
|
||||
|
// *c_a->b->c->pi = val;
|
||||
|
//
|
||||
|
// // call supply
|
||||
|
// ::C99_Status status = c99_supply_struct(c_a);
|
||||
|
//
|
||||
|
// // test
|
||||
|
// assert(!status);
|
||||
|
// assert(*c_a->b->c->pi == val * 2);
|
||||
|
// }
|
||||
|
|
||||
|
// C++
|
||||
|
{ |
||||
|
|
||||
|
// a = b;
|
||||
|
// b = 5
|
||||
|
// a.b = pEp::B{};
|
||||
|
// a.b.c = pEp::C{};
|
||||
|
// a.b.c.pi = (int*)calloc(1, sizeof(int));
|
||||
|
// a.b.c.pi = 23;
|
||||
|
// ::Status status = supply_struct(a);
|
||||
|
// test
|
||||
|
// assert(!status);
|
||||
|
// assert(*a.b.c.pi == val * 2);
|
||||
|
} |
||||
|
// pstruct1.c_int
|
||||
|
// }
|
||||
|
// pEpLogH1("provide_struct()");
|
||||
|
// {
|
||||
|
// pEp::A a{};
|
||||
|
// //release ownership
|
||||
|
// provide_struct(a);
|
||||
|
// }
|
||||
|
// pEpLogH1("return_struct()");
|
||||
|
// {
|
||||
|
// A* a = NULL;
|
||||
|
// return_struct(&a);
|
||||
|
// pEp::A pa{ a };
|
||||
|
// pEpLog(*(pa.b.c.pi.data()));
|
||||
|
// }
|
||||
|
// }
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,593 @@ |
|||||
|
#include <iostream> |
||||
|
#include <utility> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
#include "../src/POTS.hh" |
||||
|
#include "../src/libc99.hh" |
||||
|
//using namespace pEp;
|
||||
|
using POTS::operator==; |
||||
|
|
||||
|
#define TEST_IS_COPY(a, b) \ |
||||
|
do { \ |
||||
|
pEpLog("Test is copy"); \ |
||||
|
assert(b == a); \ |
||||
|
assert(!b.is(a)); \ |
||||
|
} while (0); |
||||
|
|
||||
|
#define TEST_IS_REF(a, b) \ |
||||
|
do { \ |
||||
|
pEpLog("Test is ref"); \ |
||||
|
assert(b == a); \ |
||||
|
assert(b.is(a)); \ |
||||
|
} while (0); |
||||
|
|
||||
|
//template<typename A, typename B>
|
||||
|
//int TEST_IS_COPY(const A& a, const B& b)
|
||||
|
//{
|
||||
|
// pEpLog("Test is copy");
|
||||
|
// assert(b == a);
|
||||
|
// assert(!b.is(a));
|
||||
|
// return 0;
|
||||
|
//}
|
||||
|
//
|
||||
|
//template<typename A, typename B>
|
||||
|
//int TEST_IS_REF(const A& a, const B& b)
|
||||
|
//{
|
||||
|
// pEpLog("Test is ref");
|
||||
|
// assert(b == a);
|
||||
|
// assert(b.is(a));
|
||||
|
// return 0;
|
||||
|
//}
|
||||
|
|
||||
|
//template<typename T, typename Enabled = void>
|
||||
|
//class TestSleeve;
|
||||
|
|
||||
|
// -------------------------------------------------------------------------------------------------
|
||||
|
// FUNDAMENTAL
|
||||
|
// -------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
template<typename T> |
||||
|
class PODFactory { |
||||
|
public: |
||||
|
using FactoryFunc = const std::function<T*(const T&)>; |
||||
|
|
||||
|
public: |
||||
|
PODFactory() = delete; |
||||
|
PODFactory(const T& value) : _factory_func{ new_ }, _value{ value } {} |
||||
|
PODFactory(FactoryFunc& init1, const T& value) : _factory_func{ init1 }, _value{ value } {} |
||||
|
|
||||
|
operator T() |
||||
|
{ |
||||
|
return new_value(); |
||||
|
} |
||||
|
|
||||
|
operator T*() |
||||
|
{ |
||||
|
return new_obj(); |
||||
|
} |
||||
|
|
||||
|
T* new_obj() |
||||
|
{ |
||||
|
return _factory_func(_value); |
||||
|
} |
||||
|
|
||||
|
T& new_value() |
||||
|
{ |
||||
|
return *new_obj(); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
static T* new_(const T& val) |
||||
|
{ |
||||
|
T* ret = (T*)calloc(1, sizeof(T)); |
||||
|
*ret = val; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
FactoryFunc _factory_func; |
||||
|
const T& _value; |
||||
|
}; |
||||
|
|
||||
|
template<typename T> |
||||
|
class TestSleeve; |
||||
|
|
||||
|
// VALUE -------------------------------------------------------------------------------------------------
|
||||
|
template<typename T> |
||||
|
class TestSleeve { |
||||
|
public: |
||||
|
TestSleeve(PODFactory<T> init1, PODFactory<T> init2) : factory1{ init1 }, factory2{ init2 } |
||||
|
{ |
||||
|
test_sleeve(); |
||||
|
} |
||||
|
|
||||
|
int test_sleeve() |
||||
|
{ |
||||
|
pEpLogH1("Test sleeve<" + std::string(typeid(T).name()) + ">"); |
||||
|
test_HS(); |
||||
|
test_BS(); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_HS() |
||||
|
{ |
||||
|
pEpLogH1("Test HS<" + std::string(typeid(T).name()) + ">"); |
||||
|
{ |
||||
|
pEpLogH2("Test HS ctor"); |
||||
|
T a = factory1; |
||||
|
POTS::Sleeve<T> b{ a }; |
||||
|
pEpLog(b.to_string()); |
||||
|
TEST_IS_COPY(a, b); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign HS"); |
||||
|
T a1 = factory1; |
||||
|
POTS::Sleeve<T> b1{ a1 }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T a2 = factory2; |
||||
|
POTS::Sleeve<T> b2{ a2 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_COPY(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign BS"); |
||||
|
T a1 = factory1; |
||||
|
POTS::Sleeve<T> b1{ a1 }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T a2 = factory2; |
||||
|
; |
||||
|
POTS::Sleeve<T> b2{ [&a2]() { return &a2; } }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_COPY(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test copy ctor"); |
||||
|
T a = factory1; |
||||
|
POTS::Sleeve<T> b1{ a }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
POTS::Sleeve<T> b2{ b1 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
TEST_IS_COPY(b1, b2); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_BS() |
||||
|
{ |
||||
|
pEpLogH1("Test BS<" + std::string(typeid(T).name()) + ">"); |
||||
|
{ |
||||
|
pEpLogH2("Test BS ctor"); |
||||
|
T a1 = factory1; |
||||
|
POTS::Sleeve<T> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(a1, b1); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign HS"); |
||||
|
T a1 = factory1; |
||||
|
POTS::Sleeve<T> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T a2 = factory2; |
||||
|
; |
||||
|
POTS::Sleeve<T> b2{ a2 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_COPY(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign BS"); |
||||
|
T a1 = factory1; |
||||
|
POTS::Sleeve<T> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T a2 = factory2; |
||||
|
; |
||||
|
POTS::Sleeve<T> b2{ [&a2]() { return &a2; } }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_COPY(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test copy ctor"); |
||||
|
T a1 = factory1; |
||||
|
pEpLog(a1); |
||||
|
POTS::Sleeve<T> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1); |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
POTS::Sleeve<T> b2{ b1 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
TEST_IS_COPY(b1, b2); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
PODFactory<T> factory1; |
||||
|
PODFactory<T> factory2; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// POINTER -------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
template<typename T> |
||||
|
class TestSleeve<T*> { |
||||
|
public: |
||||
|
TestSleeve(PODFactory<T> init1, PODFactory<T> init2) : factory1{ init1 }, factory2{ init2 } |
||||
|
{ |
||||
|
test_sleeve(); |
||||
|
} |
||||
|
|
||||
|
int test_sleeve() |
||||
|
{ |
||||
|
pEpLogH1("Test sleeve<" + std::string(typeid(T*).name()) + ">"); |
||||
|
test_HS(); |
||||
|
test_BS(); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_HS() |
||||
|
{ |
||||
|
pEpLogH1("Test HS<" + std::string(typeid(T*).name()) + ">"); |
||||
|
{ |
||||
|
pEpLogH2("Test HS ctor"); |
||||
|
POTS::Sleeve<T*> b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign RAW-T (value)"); |
||||
|
POTS::Sleeve<T*> b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T b2 = factory2; |
||||
|
pEpLog(b2); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_COPY(b2, b1); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign HS"); |
||||
|
POTS::Sleeve<T*> b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
POTS::Sleeve<T*> b2{}; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign BS"); |
||||
|
POTS::Sleeve<T*> b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T* a2 = factory1; |
||||
|
POTS::Sleeve<T*> b2{ [&a2]() { return &a2; } }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test copy ctor"); |
||||
|
POTS::Sleeve<T*> b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
POTS::Sleeve<T*> b2{ b1 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_BS() |
||||
|
{ |
||||
|
pEpLogH1("Test BS"); |
||||
|
{ |
||||
|
pEpLogH2("Test BS ctor"); |
||||
|
T* a1 = factory1; |
||||
|
POTS::Sleeve<T*> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(a1, b1); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign RAW-T (value)"); |
||||
|
T* a1 = factory1; |
||||
|
POTS::Sleeve<T*> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T b2 = factory2; |
||||
|
pEpLog(b2); |
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_COPY(b2, b1); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign HS"); |
||||
|
T* a1 = factory1; |
||||
|
POTS::Sleeve<T*> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
POTS::Sleeve<T*> b2{}; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign BS"); |
||||
|
T* a1 = factory1; |
||||
|
POTS::Sleeve<T*> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
T* a2 = factory2; |
||||
|
POTS::Sleeve<T*> b2{ [&a2]() { return &a2; } }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test copy ctor"); |
||||
|
|
||||
|
T* a1 = factory1; |
||||
|
POTS::Sleeve<T*> b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
POTS::Sleeve<T*> b2{ b1 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
PODFactory<T> factory1; |
||||
|
PODFactory<T> factory2; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// STRUCT P -------------------------------------------------------------------------------------------------
|
||||
|
template<> |
||||
|
//class TestSleeve<T*, typename std::enable_if<std::is_fundamental<T>::value || std::is_enum<T>::value>::type> {
|
||||
|
class TestSleeve<::C99_C*> { |
||||
|
public: |
||||
|
TestSleeve(PODFactory<::C99_C> init1, PODFactory<::C99_C> init2) : |
||||
|
factory1{ init1 }, |
||||
|
factory2{ init2 } |
||||
|
{ |
||||
|
test_sleeve(); |
||||
|
} |
||||
|
|
||||
|
int test_sleeve() |
||||
|
{ |
||||
|
pEpLogH1("Test sleeve<" + std::string(typeid(::C99_C*).name()) + ">"); |
||||
|
test_HS(); |
||||
|
test_BS(); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_HS() |
||||
|
{ |
||||
|
pEpLogH1("Test HS<" + std::string(typeid(::C99_C*).name()) + ">"); |
||||
|
{ |
||||
|
pEpLogH2("Test HS ctor"); |
||||
|
LIBC99::C99_C b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
pEpLog(b1.to_string()); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign RAW-T (value)"); |
||||
|
LIBC99::C99_C b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
::C99_C b2 = factory2; |
||||
|
|
||||
|
pEpLog(b2); |
||||
|
pEpLog(CXX::Inspect::all(b2.pi)); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
// TODO: cant test yet
|
||||
|
// TEST_IS_COPY(b2, b1);
|
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign HS"); |
||||
|
LIBC99::C99_C b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
LIBC99::C99_C b2{}; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign BS"); |
||||
|
LIBC99::C99_C b1{}; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
::C99_C* a2 = factory1; |
||||
|
LIBC99::C99_C b2{ [&a2]() { return &a2; } }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b2.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
if (1 ) { |
||||
|
pEpLogH2("Test copy ctor"); |
||||
|
LIBC99::C99_C b1{}; |
||||
|
b1.pi = 23; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
LIBC99::C99_C b2{ b1 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int test_BS() |
||||
|
{ |
||||
|
pEpLogH1("Test BS"); |
||||
|
{ |
||||
|
pEpLogH2("Test BS ctor"); |
||||
|
::C99_C* a1 = factory1; |
||||
|
LIBC99::C99_C b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(a1, b1); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign RAW-T (value)"); |
||||
|
::C99_C* a1 = factory1; |
||||
|
LIBC99::C99_C b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
::C99_C b2 = factory2; |
||||
|
|
||||
|
pEpLog(b2); |
||||
|
pEpLog(CXX::Inspect::all(b2.pi)); |
||||
|
|
||||
|
b1 = b2; |
||||
|
|
||||
|
pEpLog(b1.to_string()); |
||||
|
// TODO: cant test yet
|
||||
|
// TEST_IS_COPY(b2, b1);
|
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign HS"); |
||||
|
::C99_C* a1 = factory1; |
||||
|
LIBC99::C99_C b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
LIBC99::C99_C b2{}; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
{ |
||||
|
pEpLogH2("Test assign BS"); |
||||
|
::C99_C* a1 = factory1; |
||||
|
LIBC99::C99_C b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
::C99_C* a2 = factory2; |
||||
|
LIBC99::C99_C b2{ [&a2]() { return &a2; } }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
|
||||
|
b1 = b2; |
||||
|
pEpLog(b1.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
if (0) { |
||||
|
pEpLogH2("Test copy ctor"); |
||||
|
::C99_C* a1 = factory1; |
||||
|
LIBC99::C99_C b1{ [&a1]() { return &a1; } }; |
||||
|
pEpLog(b1.to_string()); |
||||
|
|
||||
|
LIBC99::C99_C b2{ b1 }; |
||||
|
pEpLog(b2.to_string()); |
||||
|
TEST_IS_REF(b1, b2); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
PODFactory<::C99_C> factory1; |
||||
|
PODFactory<::C99_C> factory2; |
||||
|
}; |
||||
|
|
||||
|
template<typename T> |
||||
|
int test_sleeve(PODFactory<T> init1, PODFactory<T> init2) |
||||
|
{ |
||||
|
// TestSleeve<T>{ init1, init2 };
|
||||
|
TestSleeve<T*>{ init1, init2 }; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
// Utils::readKey();
|
||||
|
pEp::Adapter::pEpLog::set_enabled(true); |
||||
|
test_sleeve<int>(PODFactory<int>(23), PODFactory<int>(42)); |
||||
|
// test_sleeve<char>(PODFactory<char>('a'), PODFactory<char>('b'));
|
||||
|
// test_sleeve<float>(PODFactory<float>(2.3f), PODFactory<float>(4.2f));
|
||||
|
// test_sleeve<bool>(PODFactory<bool>(true), PODFactory<bool>(false));
|
||||
|
// test_sleeve<::C99_Status>(PODFactory<::C99_Status>(OK), PODFactory<::C99_Status>(ERROR));
|
||||
|
|
||||
|
|
||||
|
// pEpLog(CXX::Inspect::all(*a.pi));
|
||||
|
|
||||
|
::C99_C a{}; |
||||
|
a.i = 1; |
||||
|
a.pi = PODFactory<int>(23); |
||||
|
|
||||
|
::C99_C b{}; |
||||
|
b.i = 2; |
||||
|
b.pi = PODFactory<int>(42); |
||||
|
|
||||
|
test_sleeve<::C99_C>( |
||||
|
PODFactory<::C99_C>( |
||||
|
[](const ::C99_C& val) { |
||||
|
::C99_C* a = (::C99_C*)calloc(1, sizeof(::C99_C)); |
||||
|
a->i = PODFactory<int>(val.i); |
||||
|
a->pi = PODFactory<int>(*val.pi); |
||||
|
return a; |
||||
|
}, |
||||
|
a), |
||||
|
PODFactory<::C99_C>( |
||||
|
[](const ::C99_C& val) { |
||||
|
::C99_C* a = (::C99_C*)calloc(1, sizeof(::C99_C)); |
||||
|
a->i = PODFactory<int>(val.i); |
||||
|
a->pi = PODFactory<int>(*val.pi); |
||||
|
return a; |
||||
|
}, |
||||
|
b)); |
||||
|
|
||||
|
/* {
|
||||
|
::C99_C c{}; |
||||
|
c.i = 1; |
||||
|
c.pi = PODFactory<int>(23); |
||||
|
|
||||
|
::C99_B b{}; |
||||
|
b.c = PODFactory<::C99_C>(c); |
||||
|
|
||||
|
::C99_A a{}; |
||||
|
a.b = PODFactory<::C99_B>(b); |
||||
|
} |
||||
|
*/ |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,237 @@ |
|||||
|
#include <map> |
||||
|
#include <pEp/pEpLog.hh> |
||||
|
#include "pEp/inspect.hh" |
||||
|
#include "../examples/libc99/libc99.h" |
||||
|
#include "../src/libc99.hh" |
||||
|
//#include "../src/POTS.hh"
|
||||
|
|
||||
|
using namespace pEp; |
||||
|
|
||||
|
|
||||
|
// This is a protoype pattern trying to make it possible to compare objects of
|
||||
|
// (possibly) different types.
|
||||
|
|
||||
|
//
|
||||
|
|
||||
|
namespace NA { |
||||
|
class ABase; |
||||
|
bool operator==(ABase& a, ABase& b); |
||||
|
bool operator!=(ABase& a, ABase& b); |
||||
|
|
||||
|
class ABase { |
||||
|
public: |
||||
|
ABase() = default; |
||||
|
ABase(const std::string& name, ABase& a) |
||||
|
{ |
||||
|
a.add(name, *this); |
||||
|
} |
||||
|
|
||||
|
void add(const std::string& name, ABase& a) |
||||
|
{ |
||||
|
_members.insert(std::pair<std::string, ABase&>(name, a)); |
||||
|
} |
||||
|
|
||||
|
virtual bool cmp(ABase& rhs) |
||||
|
{ |
||||
|
for (std::pair<std::string, ABase&> member : _members) { |
||||
|
try { |
||||
|
ABase& other = rhs._members.at(member.first); |
||||
|
if (other != member.second) { |
||||
|
return false; |
||||
|
} |
||||
|
} catch (const std::out_of_range& e) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
protected: |
||||
|
std::map<std::string, ABase&> _members{}; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename T> |
||||
|
class A : public ABase { |
||||
|
public: |
||||
|
A(T* obj) : _obj{ obj } |
||||
|
{ |
||||
|
pEpLog("T"); |
||||
|
} |
||||
|
|
||||
|
A(const std::string& name, ABase& a, T* obj) : ABase(name, a), _obj{ obj } {} |
||||
|
|
||||
|
|
||||
|
bool cmp(ABase& rhs) override |
||||
|
{ |
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
try { |
||||
|
A<T>& rhs_c = dynamic_cast<A<T>&>(rhs); |
||||
|
if (*_obj == *rhs_c._obj) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} catch (...) { |
||||
|
try { |
||||
|
A<T*>& rhs_c = dynamic_cast<A<T*>&>(rhs); |
||||
|
if (*_obj == **rhs_c._obj) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} catch (...) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
return ABase::cmp(rhs); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// T _value;
|
||||
|
T* _obj; |
||||
|
}; |
||||
|
|
||||
|
template<typename T> |
||||
|
class A<T*> : public ABase { |
||||
|
public: |
||||
|
A(T** obj) : _obj{ obj } |
||||
|
{ |
||||
|
pEpLog("T*"); |
||||
|
} |
||||
|
|
||||
|
A(const std::string& name, ABase& a, T** obj) : ABase(name, a), _obj{ obj } {} |
||||
|
|
||||
|
bool cmp(ABase& rhs) override |
||||
|
{ |
||||
|
if constexpr (!std::is_class<T>::value) { |
||||
|
try { |
||||
|
A<T*>& rhs_c = dynamic_cast<A<T*>&>(rhs); |
||||
|
if (**_obj == **rhs_c._obj) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} catch (...) { |
||||
|
try { |
||||
|
A<T>& rhs_c = dynamic_cast<A<T>&>(rhs); |
||||
|
if (**_obj == *rhs_c._obj) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} catch (...) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
return ABase::cmp(rhs); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// T* _value_ptr;
|
||||
|
T** _obj; |
||||
|
}; |
||||
|
|
||||
|
bool operator==(ABase& a, ABase& b) |
||||
|
{ |
||||
|
return a.cmp(b) && b.cmp(a); |
||||
|
} |
||||
|
|
||||
|
bool operator!=(ABase& a, ABase& b) |
||||
|
{ |
||||
|
return !(a == b); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
template<typename T> |
||||
|
class B : public A<T> { |
||||
|
public: |
||||
|
B() : A<T>() |
||||
|
{ |
||||
|
pEpLog("T"); |
||||
|
} |
||||
|
int _T_Bool_ext; |
||||
|
}; |
||||
|
*/ |
||||
|
|
||||
|
//template<typename T>
|
||||
|
//class A<T*, typename std::enable_if<std::is_same<T, bool>::value>::type> : public A<T*, T*> {
|
||||
|
//public:
|
||||
|
// A()
|
||||
|
// {
|
||||
|
// pEpLog("T* bool");
|
||||
|
// }
|
||||
|
// int _Tp_Bool_ext;
|
||||
|
//};
|
||||
|
|
||||
|
|
||||
|
//template<>
|
||||
|
//class A<char*> {
|
||||
|
//public:
|
||||
|
// A()
|
||||
|
// {
|
||||
|
// pEpLog("char*");
|
||||
|
// }
|
||||
|
//
|
||||
|
// char* a;
|
||||
|
//};
|
||||
|
|
||||
|
struct Struct { |
||||
|
int a; |
||||
|
int b; |
||||
|
}; |
||||
|
|
||||
|
using NA::operator==; |
||||
|
using NA::operator!=; |
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
Adapter::pEpLog::set_enabled(true); |
||||
|
pEpLog("start"); |
||||
|
// A<int> i{};
|
||||
|
// A<int*> ip{};
|
||||
|
// B<int> bi{};
|
||||
|
// B<int*> bip{};
|
||||
|
|
||||
|
// A<bool> b{};
|
||||
|
// A<bool*> bp{};
|
||||
|
{ |
||||
|
float f = 3.0f; |
||||
|
int i = 23; |
||||
|
int* pi = &i; |
||||
|
NA::A<int> a{ &i }; |
||||
|
NA::A<float> b{ &f }; |
||||
|
NA::A<int*> ap{ &pi }; |
||||
|
assert(a != b); |
||||
|
assert(a == ap); |
||||
|
} |
||||
|
{ |
||||
|
Struct a{}; |
||||
|
a.a = 23; |
||||
|
a.b = 42; |
||||
|
NA::A<Struct> b1{ &a }; |
||||
|
NA::A<int> b1_a{ "a", b1, &a.a }; |
||||
|
NA::A<int> b1_b{ "b", b1, &a.b }; |
||||
|
|
||||
|
NA::A<Struct> b2{ &a }; |
||||
|
NA::A<int> b2_a{ "a", b2, &a.a }; |
||||
|
NA::A<int> b2_b{ "b", b2, &a.b }; |
||||
|
|
||||
|
assert(b1 == b2); |
||||
|
|
||||
|
Struct a2{}; |
||||
|
a2.a = 23; |
||||
|
a2.b = 42; |
||||
|
|
||||
|
NA::A<Struct> b3{ &a2 }; |
||||
|
NA::A<int> b3_a{ "a", b3, &a2.a }; |
||||
|
NA::A<int> b3_b{ "b", b3, &a2.b }; |
||||
|
|
||||
|
assert(b2 == b3); |
||||
|
} |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
include ../Makefile.conf |
||||
|
|
||||
|
LDFLAGS=-L../src_old -L$(PREFIX)/lib -L$(PREFIX_GTEST)/lib |
||||
|
LDLIBS=-lstdc++ -lpEpCxx11 -lpEpEngine -lpEpAdapter |
||||
|
CXXFLAGS:=-I../src_old $(CXXFLAGS) -I$(PREFIX_GTEST)/include |
||||
|
|
||||
|
TEST_SOURCE=$(wildcard *.cc) |
||||
|
TEST_OBJECTS=$(subst .cc,.o,$(TEST_SOURCE)) |
||||
|
|
||||
|
.PHONY: all, clean |
||||
|
|
||||
|
all: unittests |
||||
|
|
||||
|
unittests: $(TEST_OBJECTS) ../src_old/libpEpDatatypes.a |
||||
|
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) -lgtest -lgtest_main |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
clean: |
||||
|
rm -f unittests |
||||
|
rm -Rf *.dSYM |
||||
|
rm -f *.o |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/types.hh" |
#include "../src_old/types.hh" |
||||
|
|
||||
|
|
||||
TEST(PepIdentity, Simple) |
TEST(PepIdentity, Simple) |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/types.hh" |
#include "../src_old/types.hh" |
||||
|
|
||||
namespace { |
namespace { |
||||
static const char* |
static const char* |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/nfc.hh" // for illegal_utf8 exception |
#include "../src_old/nfc.hh" // for illegal_utf8 exception |
||||
#include <vector> |
#include <vector> |
||||
|
|
||||
using namespace pEp; |
using namespace pEp; |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/nfc.hh" // for illegal_utf8 exception |
#include "../src_old/nfc.hh" // for illegal_utf8 exception |
||||
#include <vector> |
#include <vector> |
||||
|
|
||||
using namespace pEp; |
using namespace pEp; |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/nfc.hh" // for illegal_utf8 exception |
#include "../src_old/nfc.hh" // for illegal_utf8 exception |
||||
#include <vector> |
#include <vector> |
||||
|
|
||||
using namespace pEp; |
using namespace pEp; |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/types.hh" |
#include "../src_old/types.hh" |
||||
|
|
||||
|
|
||||
TEST(StringList, Simple) |
TEST(StringList, Simple) |
@ -1,6 +1,6 @@ |
|||||
#include <gtest/gtest.h> |
#include <gtest/gtest.h> |
||||
|
|
||||
#include "../src/types.hh" |
#include "../src_old/types.hh" |
||||
|
|
||||
typedef pEp::StringPair SP; |
typedef pEp::StringPair SP; |
||||
|
|
Loading…
Reference in new issue