diff --git a/test/test_nr1.cc b/test/test_nr1.cc index 3a69452..23081b5 100644 --- a/test/test_nr1.cc +++ b/test/test_nr1.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ namespace pEp { //--------------------------------------------------------------------------------------------- -#define EXSTR(msg) std::string(__FUNCTION__) + " - " + msg +#define EXSTR(msg) std::string(__FUNCTION__) + "() - " + msg template class POD { @@ -431,35 +432,36 @@ void test_assign(char** c_str_p, pEp::String& pstr) namespace pEp { // TOOD: // ctor not exception safe - class TestStruct1 { + // 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. + template + class PODStruct { public: - // Create a new instance - TestStruct1(int i, ::Test_enum e, const std::string& str) - { - pEpLogClass("called"); - _c_struct_p = ::new_test_struct(0, ONE, nullptr); //dont use raw-setters - bind(true, &_c_struct_p); - // need to use these setter because of value conversions - this->c_int = i; - this->c_enum = e; - this->c_str = str; - } + PODStruct() = delete; - // Wrap an existing instance - TestStruct1() + // Creates a new instance or binds an existing one + PODStruct( + bool is_owner, + std::function alloc, + std::function free, + T** c_struct_pp = nullptr) : + _alloc(std::move(alloc)), + _free(std::move(free)) { pEpLogClass("called"); - } - // Best to use this constructor, as the object is in a valid state when the wrapped - // c_struct_pp is known - TestStruct1(bool is_owner, ::Test_struct1** c_struct_pp) - { - pEpLogClass("called"); - bind(is_owner, c_struct_pp); + // if no pp is given, alloc new, + // otherwise bind to it + if (!c_struct_pp) { + _c_struct_p = _alloc(); + bind(is_owner, &_c_struct_p); + } else { + bind(is_owner, c_struct_pp); + } } - void bind(bool is_owner, ::Test_struct1** c_struct_pp) + void bind(bool is_owner, T** c_struct_pp) { if (c_struct_pp == nullptr) { throw Exception{ EXSTR("cant bind on a nullptr") }; @@ -474,18 +476,17 @@ namespace pEp { _c_struct_p = *_c_struct_pp; _is_bound = true; pEpLogClass(to_string()); - _bind_members(); set_owner(is_owner); } - ~TestStruct1() + ~PODStruct() { if (_is_owner) { - _free(); + _free(_c_struct_p); } } - operator ::Test_struct1*() + operator T*() { return _c_struct_p; } @@ -507,31 +508,18 @@ namespace pEp { return _is_owner; } - pEp::POD c_int{}; - pEp::POD<::Test_enum> c_enum{}; - pEp::String c_str{}; - static bool log_enabled; - private: - void _bind_members() - { - this->c_int.bind(&_c_struct_p->c_int); - this->c_enum.bind(&_c_struct_p->c_enum); - this->c_str.bind(false, &_c_struct_p->c_str); - } + protected: + const std::function _alloc; + const std::function _free; - void _free() - { - pEpLogClass("called"); - ::free_test_struct(_c_struct_p); - } bool _is_bound{ false }; bool _is_owner{ false }; - ::Test_struct1** _c_struct_pp{ nullptr }; - ::Test_struct1* _c_struct_p{ nullptr }; + T** _c_struct_pp{ nullptr }; + T* _c_struct_p{ nullptr }; - Adapter::pEpLog::pEpLogger logger{ "TestStruct", log_enabled }; + Adapter::pEpLog::pEpLogger logger{ "typeid(T).name()", log_enabled }; Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; class Exception : public std::runtime_error { @@ -540,8 +528,43 @@ namespace pEp { }; }; + // 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. + // + // alloc/free: + // the alloc() and free() functions HAVE to use calloc/malloc NOT 'new', because we are interfacing + // c99 code, that could possible 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 TestStruct1 : public PODStruct<::Test_struct1> { + public: + TestStruct1(bool is_owner, ::Test_struct1** test_struct1_p = nullptr) : + PODStruct<::Test_struct1>(is_owner, _alloc, _free, test_struct1_p) + { + } + + // fields of the struct as 'properties' ;) + pEp::POD c_int{ &_c_struct_p->c_int }; + pEp::POD<::Test_enum> c_enum{ &_c_struct_p->c_enum }; + pEp::String c_str{ false, &_c_struct_p->c_str,"fd" }; + + private: + static Test_struct1* _alloc() + { + return (Test_struct1*)calloc(1, sizeof(Test_struct1)); + } + + static void _free(Test_struct1* ptr) + { + pEpLog("called"); + ::free_test_struct(ptr); + } + }; - bool TestStruct1::log_enabled{ true }; + template<> + bool PODStruct<::Test_struct1>::log_enabled{ true }; } // namespace pEp @@ -559,7 +582,7 @@ int main() std::is_pod<::Test_struct1>::value && !std::is_pointer<::Test_struct1>::value, "not an integral"); - // pEp::Utils::readKey(); + pEp::Utils::readKey(); pEp::Adapter::pEpLog::set_enabled(true); // POD @@ -590,7 +613,7 @@ int main() // String // pEp::String::log_enabled = false; - if (1) { + if (0) { //TODO: Test non-owning mode // INVALID USAGE @@ -657,10 +680,11 @@ int main() } // Struct - if (0) { - // create - { - pEp::TestStruct1 pstruct1(23, TWO, "pEp"); + if (1) { + // create an instance + if (0) { + pEp::TestStruct1 pstruct1{ true }; + // pEp::TestStruct1 pstruct1(true, 23, TWO, "pEp"); pEpLog(pstruct1.c_int); pEpLog(pstruct1.c_enum); pEpLog(pstruct1.c_str); @@ -672,9 +696,9 @@ int main() pEpLog("DONE"); } - // wrap + // wrap already existing instance { - ::Test_struct1* c_struct1 = new_test_struct(0, ONE, "pEp"); + ::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); @@ -684,6 +708,7 @@ int main() pEpLog(pstruct1.c_int); pEpLog(pstruct1.c_enum); pEpLog(pstruct1.c_str); + pEpLog("DONE"); } }