
11 changed files with 2757 additions and 404 deletions
@ -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,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);
|
|||
} |
@ -1,247 +0,0 @@ |
|||
#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.data() == 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.data())); |
|||
assert(std::string(*pstr.data()) == std::string(*c_str_p)); |
|||
assert(std::string(*pstr.data()) == 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); |
|||
} |
|||
} |
|||
|
|||
|
|||
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<::Test_enum>::value && !std::is_pointer<::Test_enum>::value, |
|||
"not an integral"); |
|||
static_assert( |
|||
std::is_pod<::Test_struct1>::value && !std::is_pointer<::Test_struct1>::value, |
|||
"not an integral"); |
|||
|
|||
// pEp::Utils::readKey();
|
|||
pEp::Adapter::pEpLog::set_enabled(true); |
|||
|
|||
// POD
|
|||
if (1) { |
|||
// 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 (1) { |
|||
//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
|
|||
// new pEp::String on char* pointing to NULL
|
|||
{ |
|||
pEpLogH1("new pEp::String on char* pointing to NULL"); |
|||
char* c_str = NULL; // nullptr
|
|||
|
|||
pEp::String pstr(true, &c_str); |
|||
test_getters(&c_str, pstr, ""); |
|||
test_assign(&c_str, pstr); |
|||
} |
|||
|
|||
std::string init_val{ "initialized c string" }; |
|||
// new pEp::String on already initalized char*
|
|||
{ |
|||
pEpLogH1("new pEp::String on already initalized char*"); |
|||
char* c_str = strdup(init_val.c_str()); |
|||
|
|||
pEp::String pstr(true, &c_str); |
|||
test_getters(&c_str, pstr, init_val); |
|||
test_assign(&c_str, pstr); |
|||
} |
|||
|
|||
// bind()
|
|||
{ |
|||
pEpLogH1("bind()"); |
|||
pEp::String pstr{}; |
|||
|
|||
char* c_str = strdup(init_val.c_str()); |
|||
//TODO: PITYASSERT_THROWS
|
|||
pstr.bind(true, &c_str); |
|||
test_getters(&c_str, pstr, init_val); |
|||
test_assign(&c_str, pstr); |
|||
} |
|||
|
|||
// equality operator
|
|||
{ |
|||
pEpLogH1("equality operator"); |
|||
pEp::String pstr1{}; |
|||
|
|||
char* c_str1 = strdup(init_val.c_str()); |
|||
char* c_str2 = strdup(init_val.c_str()); |
|||
pstr1.bind(true, &c_str1); |
|||
pEp::String pstr2{ true, &c_str2 }; |
|||
assert(pstr1 == pstr2); |
|||
pstr2 = "huhu"; |
|||
assert(pstr1 != pstr2); |
|||
} |
|||
} |
|||
|
|||
// Struct
|
|||
if (1) { |
|||
// create an instance
|
|||
if (1) { |
|||
pEp::TestStruct1 pstruct1{ true }; |
|||
// pEp::TestStruct1 pstruct1(true, 23, TWO, "pEp");
|
|||
pEpLog(pstruct1.c_int); |
|||
pEpLog(pstruct1.c_enum); |
|||
pEpLog(pstruct1.c_str); |
|||
|
|||
::Test_struct1* c_struct1 = pstruct1; |
|||
pEpLog(c_struct1->c_int); |
|||
pEpLog(c_struct1->c_enum); |
|||
pEpLog(c_struct1->c_str); |
|||
pEpLog("DONE"); |
|||
} |
|||
|
|||
// wrap already existing instance
|
|||
{ |
|||
::Test_struct1* c_struct1 = ::new_test_struct(0, ONE, "pEp"); |
|||
pEpLog(c_struct1->c_int); |
|||
pEpLog(c_struct1->c_enum); |
|||
pEpLog(c_struct1->c_str); |
|||
pEpLog("DONE"); |
|||
|
|||
pEp::TestStruct1 pstruct1(true, &c_struct1); |
|||
pEpLog(pstruct1.c_int); |
|||
pEpLog(pstruct1.c_enum); |
|||
pEpLog(pstruct1.c_str); |
|||
pEpLog("DONE"); |
|||
} |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
Loading…
Reference in new issue