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 |
|||
|
|||
LDFLAGS=-L../src -L$(PREFIX)/lib -L$(PREFIX_GTEST)/lib |
|||
LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter |
|||
CXXFLAGS:=-I../src $(CXXFLAGS) -I$(PREFIX_GTEST)/include |
|||
LIBC99_PATH=../examples/libc99/ |
|||
LIBC99_STATIC=$(LIBC99_PATH)libc99.a |
|||
LIBPEPDATATYPES_PATH=../src/ |
|||
LIBPEPDATATYPES_STATIC=$(LIBPEPDATATYPES_PATH)libpepdatatypes.a |
|||
|
|||
TEST_SOURCE=$(wildcard *.cc) |
|||
TEST_OBJECTS=$(subst .cc,.o,$(TEST_SOURCE)) |
|||
LDLIBS=-lstdc++ -lpEpEngine -lpEpCxx11 -lpEpAdapter -lPityTest11 -lpthread -ldl -lm $(LIBC99_STATIC) |
|||
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 |
|||
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) -lgtest -lgtest_main |
|||
all: libc99 tests |
|||
|
|||
libc99: $(LIBC99_STATIC) |
|||
|
|||
$(LIBC99_STATIC): |
|||
$(MAKE) -C ../examples/libc99 |
|||
|
|||
tests: $(BIN_TEST) |
|||
|
|||
|
|||
clean: |
|||
rm -f unittests |
|||
rm -f $(BIN_TEST) |
|||
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 "../src/types.hh" |
|||
#include "../src_old/types.hh" |
|||
|
|||
|
|||
TEST(PepIdentity, Simple) |
@ -1,6 +1,6 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "../src/types.hh" |
|||
#include "../src_old/types.hh" |
|||
|
|||
namespace { |
|||
static const char* |
@ -1,6 +1,6 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "../src/nfc.hh" // for illegal_utf8 exception |
|||
#include "../src_old/nfc.hh" // for illegal_utf8 exception |
|||
#include <vector> |
|||
|
|||
using namespace pEp; |
@ -1,6 +1,6 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "../src/nfc.hh" // for illegal_utf8 exception |
|||
#include "../src_old/nfc.hh" // for illegal_utf8 exception |
|||
#include <vector> |
|||
|
|||
using namespace pEp; |
@ -1,6 +1,6 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "../src/nfc.hh" // for illegal_utf8 exception |
|||
#include "../src_old/nfc.hh" // for illegal_utf8 exception |
|||
#include <vector> |
|||
|
|||
using namespace pEp; |
@ -1,6 +1,6 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "../src/types.hh" |
|||
#include "../src_old/types.hh" |
|||
|
|||
|
|||
TEST(StringList, Simple) |
@ -1,6 +1,6 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "../src/types.hh" |
|||
#include "../src_old/types.hh" |
|||
|
|||
typedef pEp::StringPair SP; |
|||
|
Loading…
Reference in new issue