Compare commits

...

34 Commits

Author SHA1 Message Date
heck 7e823516d4 FAILED ATTEMPT - just committing everything 5 months after losing my sanity. 3 years ago
heck 342986dc06 .gitignore 3 years ago
heck bc4873b286 .clang-tidy 3 years ago
heck a7bba8210e libc99 is prototyping the patterns and semantics of the pEpEngine, that are valid. 3 years ago
heck 90685f41e5 .gitignore 3 years ago
heck d3f2e1b279 Test: add test_identity.cc 3 years ago
heck b463d27c5d separate prototype from test 3 years ago
heck 4bee3b821a maybe add some include guards 3 years ago
heck c363bd7924 prototype: pEp::PODStruct - logger classname defines by T 3 years ago
heck 0a641597d4 prototype: remove alloc/free routines from namespace pEp, they have been moved into the respective classes, (might generalize and extract them later again) 3 years ago
heck 224c52b96c prototype: TestStruct1 - use default alloc/free from PODStruct, and use data() method to access wrapped struct for binding 3 years ago
heck 26e0848fa1 prototype: pEp::PODStruct - created default alloc/free, and a constructor to provide custom alloc/free 3 years ago
heck 6b0ab94595 prototype: pEp::String - move alloc/free routines into class 3 years ago
heck ba0857c930 prototype: pEp::String - does never host a char*, but only wraps one thats hosted somehwere else, so we only need a char**, no char* 3 years ago
heck 33b898fa23 prototype: pEp::String - avoid nullptr in the char* (if the c_str_p is nullptr then init with "") 3 years ago
heck 7e5d39f28b prototype: just comments and prints 3 years ago
heck 3f2f9ee3b3 Build: change default make target to test and bypass src (nothing there yet) 3 years ago
heck 41fff66a0c Build: tests - link against libc99 (example lib) 3 years ago
heck 79a3dfecf8 prtotype: make struct wrapper generic 3 years ago
heck c25c114082 prtotype: prefix libc99 usage with :: 3 years ago
heck 8d9a1272b8 move protoyping into new dir 'test' 3 years ago
heck fafde0f22a .gitignore 3 years ago
heck 9ab1fe5d75 add example c99 library mimicking the structures of the pEpEngine in a minimal way. 3 years ago
heck d7c3e61322 move 'test' to 'test_old' 3 years ago
heck 47a1ea9e4c move 'src' to 'src_old' 3 years ago
heck 1df9c84511 protyping: Structs wrapper / ownership / more tests 3 years ago
heck e0634523a6 protyping: POD / String types, and more tests 3 years ago
heck 82d64f8c58 Build: link against libpEpCxx11 3 years ago
heck 20075f1167 Coding Conventions: .clang-tidy - allow implicit bool conversion 3 years ago
heck e49c88052d Add generic class 'POD', a generic POD-wrapper 3 years ago
heck 0853bea66c Coding Conventions: update .clang-tidy 3 years ago
heck eed57ef631 func name typo 3 years ago
heck 3b556c2e99 using std::shared_ptr is too complicated for this. 3 years ago
heck 3737da708d Inital prototyping 3 years ago
  1. 5
      .clang-tidy
  2. 6
      .gitignore
  3. 11
      Makefile
  4. 2
      Makefile.conf
  5. 204
      examples/libc99/libc99.c
  6. 93
      examples/libc99/libc99.h
  7. 27
      examples/libc99/makefile
  8. 897
      src/POTS.hh
  9. 180
      src/libc99.hh
  10. 676
      src/prototype.hh
  11. 0
      src_old/Makefile
  12. 0
      src_old/bloblist.cc
  13. 0
      src_old/bloblist.hh
  14. 0
      src_old/crlf.cc
  15. 0
      src_old/crlf.hh
  16. 0
      src_old/identity.cc
  17. 0
      src_old/nfc.cc
  18. 0
      src_old/nfc.hh
  19. 0
      src_old/nfc_sets.cc
  20. 0
      src_old/nfc_sets.hh
  21. 0
      src_old/stringlist.cc
  22. 0
      src_old/types.cc
  23. 0
      src_old/types.hh
  24. 0
      src_old/wrapper.hh
  25. 30
      test/Makefile
  26. 73
      test/test_cxx.cc
  27. 71
      test/test_identity.cc
  28. 414
      test/test_prototype.cc
  29. 593
      test/test_sleeve.cc
  30. 237
      test/test_struct_cmp.cc
  31. 23
      test_old/Makefile
  32. 2
      test_old/unittest_identity.cc
  33. 2
      test_old/unittest_message.cc
  34. 2
      test_old/unittest_nfc.cc
  35. 2
      test_old/unittest_nfc16.cc
  36. 2
      test_old/unittest_nfcstring.cc
  37. 2
      test_old/unittest_stringlist.cc
  38. 2
      test_old/unittest_stringpair.cc

5
.clang-tidy

@ -20,7 +20,9 @@ Checks: >
-llvm-*, -llvm-*,
-llvmlibc-*, -llvmlibc-*,
misc-*, misc-*,
-misc-non-private-member-variables-in-classes,
modernize-*, modernize-*,
-modernize-use-auto,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
-modernize-use-nodiscard, -modernize-use-nodiscard,
-mpi-*, -mpi-*,
@ -29,4 +31,7 @@ Checks: >
performance-*, performance-*,
portability-*, portability-*,
readability-*, readability-*,
-readability-function-cognitive-complexity,
-readability-implicit-bool-conversion,
-readability-named-parameter,
-zircon-*, -zircon-*,

6
.gitignore

@ -3,8 +3,14 @@
*.d *.d
*.swp *.swp
*~ *~
*.dSYM
ws ws
unittests unittests
local.conf local.conf
build/ build/
/.idea/ /.idea/
/test/test_nr1
/examples/libc99/libc99.so
/test/test_identity
/test/.pEp/
/test/test_sleeve

11
Makefile

@ -5,16 +5,17 @@
.PHONY: all src test install uninstall clean .PHONY: all src test install uninstall clean
all: src #all: src test
all: test
src: #src:
$(MAKE) -C src # $(MAKE) -C src
test: src test:
$(MAKE) -C test $(MAKE) -C test
clean: clean:
$(MAKE) -C src clean # $(MAKE) -C src clean
$(MAKE) -C test clean $(MAKE) -C test clean
install: install:

2
Makefile.conf

@ -34,3 +34,5 @@ else
endif endif
CXXFLAGS+=-I$(PREFIX)/include CXXFLAGS+=-I$(PREFIX)/include
LDFLAGS+=-L$(PREFIX)/lib

204
examples/libc99/libc99.c

@ -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;
}

93
examples/libc99/libc99.h

@ -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

27
examples/libc99/makefile

@ -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)

897
src/POTS.hh

@ -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

180
src/libc99.hh

@ -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

676
src/prototype.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

0
src/Makefile → src_old/Makefile

0
src/bloblist.cc → src_old/bloblist.cc

0
src/bloblist.hh → src_old/bloblist.hh

0
src/crlf.cc → src_old/crlf.cc

0
src/crlf.hh → src_old/crlf.hh

0
src/identity.cc → src_old/identity.cc

0
src/nfc.cc → src_old/nfc.cc

0
src/nfc.hh → src_old/nfc.hh

0
src/nfc_sets.cc → src_old/nfc_sets.cc

0
src/nfc_sets.hh → src_old/nfc_sets.hh

0
src/stringlist.cc → src_old/stringlist.cc

0
src/types.cc → src_old/types.cc

0
src/types.hh → src_old/types.hh

0
src/wrapper.hh → src_old/wrapper.hh

30
test/Makefile

@ -1,23 +1,31 @@
include ../Makefile.conf include ../Makefile.conf
LDFLAGS=-L../src -L$(PREFIX)/lib -L$(PREFIX_GTEST)/lib LIBC99_PATH=../examples/libc99/
LDLIBS=-lstdc++ -lpEpEngine -lpEpAdapter LIBC99_STATIC=$(LIBC99_PATH)libc99.a
CXXFLAGS:=-I../src $(CXXFLAGS) -I$(PREFIX_GTEST)/include LIBPEPDATATYPES_PATH=../src/
LIBPEPDATATYPES_STATIC=$(LIBPEPDATATYPES_PATH)libpepdatatypes.a
TEST_SOURCE=$(wildcard *.cc) LDLIBS=-lstdc++ -lpEpEngine -lpEpCxx11 -lpEpAdapter -lPityTest11 -lpthread -ldl -lm $(LIBC99_STATIC)
TEST_OBJECTS=$(subst .cc,.o,$(TEST_SOURCE)) CXXFLAGS+=-I$(LIBPEPDATATYPES_PATH) -I$(LIBC99_PATH)
.PHONY: all, clean # Test
SRC_TEST=$(wildcard test_*.cc)
BIN_TEST=$(subst .cc,,$(SRC_TEST))
all: unittests .PHONY: libc99 tests all clean
unittests: $(TEST_OBJECTS) ../src/libpEpDatatypes.a all: libc99 tests
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) -lgtest -lgtest_main
libc99: $(LIBC99_STATIC)
$(LIBC99_STATIC):
$(MAKE) -C ../examples/libc99
tests: $(BIN_TEST)
clean: clean:
rm -f unittests rm -f $(BIN_TEST)
rm -Rf *.dSYM rm -Rf *.dSYM
rm -f *.o rm -f *.d
rm -f *.o

73
test/test_cxx.cc

@ -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);
}

71
test/test_identity.cc

@ -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;
}

414
test/test_prototype.cc

@ -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;
}

593
test/test_sleeve.cc

@ -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;
}

237
test/test_struct_cmp.cc

@ -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);
}
}

23
test_old/Makefile

@ -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

2
test/unittest_identity.cc → test_old/unittest_identity.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/types.hh" #include "../src_old/types.hh"
TEST(PepIdentity, Simple) TEST(PepIdentity, Simple)

2
test/unittest_message.cc → test_old/unittest_message.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/types.hh" #include "../src_old/types.hh"
namespace { namespace {
static const char* static const char*

2
test/unittest_nfc.cc → test_old/unittest_nfc.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/nfc.hh" // for illegal_utf8 exception #include "../src_old/nfc.hh" // for illegal_utf8 exception
#include <vector> #include <vector>
using namespace pEp; using namespace pEp;

2
test/unittest_nfc16.cc → test_old/unittest_nfc16.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/nfc.hh" // for illegal_utf8 exception #include "../src_old/nfc.hh" // for illegal_utf8 exception
#include <vector> #include <vector>
using namespace pEp; using namespace pEp;

2
test/unittest_nfcstring.cc → test_old/unittest_nfcstring.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/nfc.hh" // for illegal_utf8 exception #include "../src_old/nfc.hh" // for illegal_utf8 exception
#include <vector> #include <vector>
using namespace pEp; using namespace pEp;

2
test/unittest_stringlist.cc → test_old/unittest_stringlist.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/types.hh" #include "../src_old/types.hh"
TEST(StringList, Simple) TEST(StringList, Simple)

2
test/unittest_stringpair.cc → test_old/unittest_stringpair.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "../src/types.hh" #include "../src_old/types.hh"
typedef pEp::StringPair SP; typedef pEp::StringPair SP;
Loading…
Cancel
Save