summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2019-04-20 01:54:54 +0200
committerMarkus Mittendrein <git@maxmitti.tk>2019-04-20 02:43:37 +0200
commit43931c7e187bda85e2be12bccb14bd826a6c34c0 (patch)
tree1987ad09d84049a87bbf482af7569b0f93e7d5fe
parent712a61956cdd0e2e2907fb730b6dde9b5cc3524a (diff)
downloadcc4group-43931c7e187bda85e2be12bccb14bd826a6c34c0.tar.gz
cc4group-43931c7e187bda85e2be12bccb14bd826a6c34c0.zip
Add custom memory management strategies to cppc4group
-rw-r--r--CMakeLists.txt1
-rw-r--r--examples/cppc4group_memorymanagement.cpp51
-rw-r--r--src/cc4group.h4
-rw-r--r--src/cppc4group.cpp81
-rw-r--r--src/cppc4group.hpp41
5 files changed, 152 insertions, 26 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4604c81..c3a5d02 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -70,6 +70,7 @@ example(c4rm)
example(c4mkdir)
examplepp(c4ls_asChildPp)
+examplepp(cppc4group_memorymanagement)
add_executable(c4cat examples/c4cat.c)
target_link_libraries(c4cat PRIVATE cc4group)
diff --git a/examples/cppc4group_memorymanagement.cpp b/examples/cppc4group_memorymanagement.cpp
new file mode 100644
index 0000000..b29adae
--- /dev/null
+++ b/examples/cppc4group_memorymanagement.cpp
@@ -0,0 +1,51 @@
+#include "cppc4group.hpp"
+#include <string_view>
+#include <cstring>
+#include <iostream>
+
+using namespace std::literals;
+
+int main()
+{
+ CppC4Group g;
+ g.create();
+
+ constexpr auto takeContents = "This is only some dummy text for testing."sv;
+ void* takeData = malloc(takeContents.size());
+ memcpy(takeData, takeContents.data(), takeContents.size());
+
+ auto takeContentsString = new std::string{takeContents};
+
+ (g.create() &&
+ g.createFile("Take") &&
+ g.createFile("Reference") &&
+ g.createFile("Copy") &&
+ g.createFile("Custom") &&
+ g.createFile("CustomNoOpStart") &&
+
+
+ g.setEntryData("Take", takeData, takeContents.size(), CppC4Group::MemoryManagement::Take) &&
+ g.setEntryData("Reference", takeContents.data(), takeContents.size(), CppC4Group::MemoryManagement::Reference) &&
+ g.setEntryData("Copy", takeContents.data(), takeContents.size(), CppC4Group::MemoryManagement::Copy) &&
+ g.setEntryData("Custom", takeContents.data(), takeContents.size(), {
+ [](void* const data, size_t const size) -> void*
+ {
+ auto retData = new char[size];
+ memcpy(retData, data, size);
+ return retData;
+ },
+ [](void* const data)
+ {
+ delete [] reinterpret_cast<char*>(data);
+ }
+ }) &&
+ g.setEntryData("CustomNoOpStart", takeContentsString->data(), takeContentsString->size(), {CppC4Group::MemoryManagement::NoOpStart,
+ [takeContentsString](void* const)
+ {
+ delete takeContentsString;
+ }
+ }) &&
+
+ g.save("cppc4group_memorymanagement.c4d")) || (std::cerr << g.getErrorMessage() << '\n', true);
+ return 0;
+} \ No newline at end of file
diff --git a/src/cc4group.h b/src/cc4group.h
index 780c50e..2309338 100644
--- a/src/cc4group.h
+++ b/src/cc4group.h
@@ -44,7 +44,7 @@
// ...it will be a great help in debugging mistakes that are made by the programmer
// for lazy writers or just some testing, the nature of the API actually makes it possible to just chain a bunch of API calls with && and...
// ...thanks to short-circuiting it will stop exactly at the error and the whole expression will return false and the error information can be retrieved as usual
-// sadly, this trick didn't seem to make it into any example, as they are written to output additional, more user-friendly, information together with the error message
+// this can be seen in the cppc4group_memorymanagement example (and works the same for cc4group)
// - finally (and i still forgot some other general aspect used for sure), because the return value of the functions is already used for the success-bool, ...
// ...functions that should actually return some real data have one (or more) pointer-arguments where they store the returned information
// - if you are such a patient reader and you made it here, you may now look at some of the examples (in the examples folder)
@@ -146,7 +146,7 @@ typedef struct {
void* (*start)(void* const data, const size_t size, void* const arg);
void (*end)(void* const data, void* const arg);
void* arg;
-} const CC4Group_MemoryManagement_t;
+} CC4Group_MemoryManagement_t;
typedef CC4Group_MemoryManagement_t* CC4Group_MemoryManagement;
diff --git a/src/cppc4group.cpp b/src/cppc4group.cpp
index 2d85537..329d6de 100644
--- a/src/cppc4group.cpp
+++ b/src/cppc4group.cpp
@@ -39,6 +39,66 @@ struct CppC4Group::Private {
}
};
+struct CppC4Group::MemoryManagement::Private {
+ bool predefined;
+ MemoryManagementStrategy strategy;
+
+ Start start;
+ End end;
+};
+
+CppC4Group::MemoryManagement::MemoryManagement(MemoryManagementStrategy strategy) : p{new Private{true, strategy}}
+{
+
+}
+
+CppC4Group::MemoryManagement::MemoryManagement(Start&& start, End&& end) : p{new Private{false, {}, start, end}}
+{
+
+}
+
+CppC4Group::MemoryManagement::~MemoryManagement()
+{
+ delete p;
+}
+
+CppC4Group::MemoryManagement::MemoryManagementStrategy CppC4Group::MemoryManagement::operator()() const
+{
+ if(p->predefined)
+ {
+ return p->strategy;
+ }
+ else
+ {
+ struct CustomMemoryManagement {
+ CC4Group_MemoryManagement_t realMemoryManagement;
+
+ Start start;
+ End end;
+
+ static void* callStart(void* const data, size_t const size, void* const arg)
+ {
+ return reinterpret_cast<CustomMemoryManagement*>(arg)->start(data, size);
+ }
+
+ static void callEndAndCleanup(void* const data, void* const arg)
+ {
+ auto customMemoryManagement = reinterpret_cast<CustomMemoryManagement*>(arg);
+ customMemoryManagement->end(data);
+ delete customMemoryManagement;
+ }
+ };
+
+ auto customManagement = new CustomMemoryManagement{{CustomMemoryManagement::callStart, CustomMemoryManagement::callEndAndCleanup}, p->start, p->end};
+ customManagement->realMemoryManagement.arg = static_cast<void*>(customManagement);
+ return reinterpret_cast<MemoryManagementStrategy>(&customManagement->realMemoryManagement);
+ }
+}
+
+const CppC4Group::MemoryManagement CppC4Group::MemoryManagement::Take{reinterpret_cast<MemoryManagement::MemoryManagementStrategy>(cc4group.MemoryManagement.Take)};
+const CppC4Group::MemoryManagement CppC4Group::MemoryManagement::Copy{reinterpret_cast<MemoryManagement::MemoryManagementStrategy>(cc4group.MemoryManagement.Copy)};
+const CppC4Group::MemoryManagement CppC4Group::MemoryManagement::Reference{reinterpret_cast<MemoryManagement::MemoryManagementStrategy>(cc4group.MemoryManagement.Reference)};
+
namespace {
CC4Group_TmpMemoryStrategy convertTmpMemoryStrategy(const CppC4Group::TmpMemoryStrategy strategy)
{
@@ -54,22 +114,13 @@ namespace {
return cc4group.TmpMemoryStrategies.Auto;
}
- CC4Group_MemoryManagement convertMemoryManagement(const CppC4Group::MemoryManagement management)
+ CC4Group_MemoryManagement convertMemoryManagement(const CppC4Group::MemoryManagement& memoryManagement)
{
- switch(management)
- {
- case CppC4Group::Take:
- return cc4group.MemoryManagement.Take;
- case CppC4Group::Copy:
- return cc4group.MemoryManagement.Copy;
- case CppC4Group::Reference:
- return cc4group.MemoryManagement.Reference;
- }
- return cc4group.MemoryManagement.Copy;
+ return reinterpret_cast<CC4Group_MemoryManagement>(memoryManagement());
}
}
-CppC4Group::CppC4Group() : p{new CppC4Group::Private{}}
+CppC4Group::CppC4Group() : p{new Private{}}
{
}
@@ -110,12 +161,12 @@ bool CppC4Group::openFilePointer(FILE* file)
return cc4group.openFilePointer(p->g, file);
}
-bool CppC4Group::openMemory(const void* const data, const size_t size, const MemoryManagement management)
+bool CppC4Group::openMemory(const void* const data, const size_t size, const MemoryManagement& management)
{
return cc4group.openMemory(p->g, data, size, convertMemoryManagement(management));
}
-bool CppC4Group::openWithReadCallback(const ReadCallback callback, void* const callbackArg, const MemoryManagement management, SetupCallback initCallback, SetupCallback deinitCallback)
+bool CppC4Group::openWithReadCallback(const ReadCallback callback, void* const callbackArg, const MemoryManagement& management, SetupCallback initCallback, SetupCallback deinitCallback)
{
return cc4group.openWithReadCallback(p->g, callback, callbackArg, convertMemoryManagement(management), initCallback, deinitCallback);
}
@@ -311,7 +362,7 @@ bool CppC4Group::createFile(const std::string& path)
return cc4group.createFile(p->g, path.c_str());
}
-bool CppC4Group::setEntryData(const std::string& path, const void*const data, const size_t size, const MemoryManagement management)
+bool CppC4Group::setEntryData(const std::string& path, const void*const data, const size_t size, const MemoryManagement& management)
{
return cc4group.setEntryData(p->g, path.c_str(), data, size, convertMemoryManagement(management));
}
diff --git a/src/cppc4group.hpp b/src/cppc4group.hpp
index f11387c..d946cee 100644
--- a/src/cppc4group.hpp
+++ b/src/cppc4group.hpp
@@ -76,6 +76,35 @@ public:
// or an empty optional on failure
using TmpMemoryCallback = std::optional<TmpMemory>(*)(size_t size);
+ // the C++ memory management strategies work exactly the same way as in C, but with std::function instead
+ class MemoryManagement {
+ public:
+ struct MemoryManagementStrategy_t;
+ using MemoryManagementStrategy = MemoryManagementStrategy_t*;
+
+ using Start = std::function<void*(void* memory, size_t size)>;
+ using End = std::function<void(void* memory)>;
+
+ private:
+ struct Private;
+ Private* p;
+
+ public:
+ MemoryManagement(Start&& start, End&& end);
+ MemoryManagement(MemoryManagementStrategy strategy);
+
+ ~MemoryManagement();
+
+ MemoryManagementStrategy operator()() const;
+
+ // this may be used as start function if it need not do anything but return the original pointer
+ static constexpr auto NoOpStart = [](void* memory, size_t) { return memory; };
+
+ static const MemoryManagement Take;
+ static const MemoryManagement Copy;
+ static const MemoryManagement Reference;
+ };
+
// these are equivalent to their C counterparts
using ReadCallback = bool(*)(const void** const data, size_t* const size, void* const arg);
using SetupCallback = bool(*)(void* const arg);
@@ -88,12 +117,6 @@ public:
Auto
};
- enum MemoryManagement {
- Take,
- Copy,
- Reference
- };
-
// use this to set one of the predefined strategies
static void setTmpMemoryStrategy(const TmpMemoryStrategy strategy);
@@ -115,8 +138,8 @@ public:
bool openExisting(const std::string& path);
bool openFd(const int fd);
bool openFilePointer(FILE* file);
- bool openMemory(const void* const data, const size_t size, const MemoryManagement management = Reference);
- bool openWithReadCallback(const ReadCallback callback, void* const callbackArg, const MemoryManagement management = Take, SetupCallback initCallback = nullptr, SetupCallback deinitCallback = nullptr);
+ bool openMemory(const void* const data, const size_t size, const MemoryManagement& management = MemoryManagement::Reference);
+ bool openWithReadCallback(const ReadCallback callback, void* const callbackArg, const MemoryManagement& management = MemoryManagement::Take, SetupCallback initCallback = nullptr, SetupCallback deinitCallback = nullptr);
// save actually maps to both cc4group.save and cc4group.saveOverwrite, thanks to default arguments (yes, thats the reason why they are separate in the C-API)
bool save(const std::string& path, const bool overwrite = false);
@@ -148,7 +171,7 @@ public:
bool createFile(const std::string& path);
- bool setEntryData(const std::string& path, const void* const data = nullptr, const size_t size = 0, const MemoryManagement management = Copy);
+ bool setEntryData(const std::string& path, const void* const data = nullptr, const size_t size = 0, const MemoryManagement& management = MemoryManagement::Copy);
// to get the child group out of the optional in case of success, construct a new CppC4Group with the move constructor: CppC4Group child{std::move(*optionalChild)};
std::optional<CppC4Group> openAsChild(const std::string& path);