Add memory allocation API with templated C++ delegates & minor fixups #1123
@@ -106,6 +106,35 @@ static int YGDefaultLog(
|
|||||||
#undef YG_UNUSED
|
#undef YG_UNUSED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static YGAllocatorAllocateFunc gAllocatorAllocateFunc = &malloc;
|
||||||
|
static YGAllocatorFreeFunc gAllocatorFreeFunc = &free;
|
||||||
|
|
||||||
|
YOGA_EXPORT void YGSetAllocationCallbacks(
|
||||||
|
YGAllocatorAllocateFunc allocFunc,
|
||||||
|
YGAllocatorFreeFunc freeFunc) {
|
||||||
|
gAllocatorAllocateFunc = allocFunc;
|
||||||
|
gAllocatorFreeFunc = freeFunc;
|
||||||
|
}
|
||||||
|
|||||||
|
|
||||||
|
YOGA_EXPORT void YGGetAllocationCallbacks(
|
||||||
|
YGAllocatorAllocateFunc* allocFunc,
|
||||||
|
YGAllocatorFreeFunc* freeFunc) {
|
||||||
|
if(allocFunc != nullptr) {
|
||||||
|
*allocFunc = gAllocatorAllocateFunc;
|
||||||
|
}
|
||||||
|
if(freeFunc != nullptr) {
|
||||||
|
*freeFunc = gAllocatorFreeFunc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
YOGA_EXPORT void* YGMemoryAllocate(size_t size) {
|
||||||
|
return gAllocatorAllocateFunc(size);
|
||||||
|
}
|
||||||
|
|
||||||
![]() If these are global, they will need to be protected by mutex, in case multiple threads are using Yoga at once. I think it would be cleaner if the allocator was set as part of YGConfig, though it would mean YGConfig itself could not be allocated using the custom allocator. Though, Yoga may otherwise call functions which perform their dynamic allocations, so if the goal is just for the large structures, I think it could still be okay. If these are global, they will need to be protected by mutex, in case multiple threads are using Yoga at once.
I think it would be cleaner if the allocator was set as part of YGConfig, though it would mean YGConfig itself could not be allocated using the custom allocator. Though, Yoga may otherwise call functions which perform their dynamic allocations, so if the goal is just for the large structures, I think it could still be okay.
|
|||||||
|
YOGA_EXPORT void YGMemoryFree(void* memory) {
|
||||||
|
gAllocatorFreeFunc(memory);
|
||||||
![]()
```suggestion
YOGA_EXPORT void YGSetAllocator(
```
|
|||||||
|
}
|
||||||
|
|
||||||
static inline bool YGDoubleIsUndefined(const double value) {
|
static inline bool YGDoubleIsUndefined(const double value) {
|
||||||
return facebook::yoga::isUndefined(value);
|
return facebook::yoga::isUndefined(value);
|
||||||
}
|
}
|
||||||
@@ -192,7 +221,7 @@ YOGA_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(
|
|||||||
int32_t gConfigInstanceCount = 0;
|
int32_t gConfigInstanceCount = 0;
|
||||||
|
|
||||||
YOGA_EXPORT WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
|
YOGA_EXPORT WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
|
||||||
const YGNodeRef node = new YGNode{config};
|
const YGNodeRef node = YGAllocate<YGNode>(config);
|
||||||
YGAssertWithConfig(
|
YGAssertWithConfig(
|
||||||
config, node != nullptr, "Could not allocate memory for node");
|
config, node != nullptr, "Could not allocate memory for node");
|
||||||
Event::publish<Event::NodeAllocation>(node, {config});
|
Event::publish<Event::NodeAllocation>(node, {config});
|
||||||
@@ -210,7 +239,7 @@ YOGA_EXPORT YGNodeRef YGNodeNew(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) {
|
YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) {
|
||||||
YGNodeRef node = new YGNode(*oldNode);
|
YGNodeRef node = YGAllocate<YGNode>(*oldNode);
|
||||||
YGAssertWithConfig(
|
YGAssertWithConfig(
|
||||||
oldNode->getConfig(),
|
oldNode->getConfig(),
|
||||||
node != nullptr,
|
node != nullptr,
|
||||||
@@ -221,7 +250,7 @@ YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
|
static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
|
||||||
const YGConfigRef config = new YGConfig(oldConfig);
|
const YGConfigRef config = YGAllocate<YGConfig>(oldConfig);
|
||||||
YGAssert(config != nullptr, "Could not allocate memory for config");
|
YGAssert(config != nullptr, "Could not allocate memory for config");
|
||||||
gConfigInstanceCount++;
|
gConfigInstanceCount++;
|
||||||
return config;
|
return config;
|
||||||
@@ -229,7 +258,7 @@ static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
|
|||||||
|
|
||||||
static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
|
static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
|
||||||
auto config = YGConfigClone(*oldNode->getConfig());
|
auto config = YGConfigClone(*oldNode->getConfig());
|
||||||
auto node = new YGNode{*oldNode, config};
|
auto node = YGAllocate<YGNode>(*oldNode, config);
|
||||||
node->setOwner(nullptr);
|
node->setOwner(nullptr);
|
||||||
Event::publish<Event::NodeAllocation>(node, {node->getConfig()});
|
Event::publish<Event::NodeAllocation>(node, {node->getConfig()});
|
||||||
|
|
||||||
@@ -260,13 +289,13 @@ YOGA_EXPORT void YGNodeFree(const YGNodeRef node) {
|
|||||||
|
|
||||||
node->clearChildren();
|
node->clearChildren();
|
||||||
Event::publish<Event::NodeDeallocation>(node, {node->getConfig()});
|
Event::publish<Event::NodeDeallocation>(node, {node->getConfig()});
|
||||||
delete node;
|
YGFree(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void YGConfigFreeRecursive(const YGNodeRef root) {
|
static void YGConfigFreeRecursive(const YGNodeRef root) {
|
||||||
if (root->getConfig() != nullptr) {
|
if (root->getConfig() != nullptr) {
|
||||||
gConfigInstanceCount--;
|
gConfigInstanceCount--;
|
||||||
delete root->getConfig();
|
YGFree(root->getConfig());
|
||||||
}
|
}
|
||||||
// Delete configs recursively for childrens
|
// Delete configs recursively for childrens
|
||||||
for (auto* child : root->getChildren()) {
|
for (auto* child : root->getChildren()) {
|
||||||
@@ -308,16 +337,16 @@ int32_t YGConfigGetInstanceCount(void) {
|
|||||||
|
|
||||||
YOGA_EXPORT YGConfigRef YGConfigNew(void) {
|
YOGA_EXPORT YGConfigRef YGConfigNew(void) {
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
const YGConfigRef config = new YGConfig(YGAndroidLog);
|
const YGConfigRef config = YGAllocate<YGConfig>(YGAndroidLog);
|
||||||
#else
|
#else
|
||||||
const YGConfigRef config = new YGConfig(YGDefaultLog);
|
const YGConfigRef config = YGAllocate<YGConfig>(YGDefaultLog);
|
||||||
#endif
|
#endif
|
||||||
gConfigInstanceCount++;
|
gConfigInstanceCount++;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
YOGA_EXPORT void YGConfigFree(const YGConfigRef config) {
|
YOGA_EXPORT void YGConfigFree(const YGConfigRef config) {
|
||||||
delete config;
|
YGFree(config);
|
||||||
gConfigInstanceCount--;
|
gConfigInstanceCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
yoga/Yoga.h
25
yoga/Yoga.h
@@ -29,6 +29,9 @@ typedef struct YGSize {
|
|||||||
float height;
|
float height;
|
||||||
} YGSize;
|
} YGSize;
|
||||||
|
|
||||||
|
typedef void* (*YGAllocatorAllocateFunc)(size_t size);
|
||||||
|
typedef void (*YGAllocatorFreeFunc)(void* memory);
|
||||||
|
|
||||||
typedef struct YGConfig* YGConfigRef;
|
typedef struct YGConfig* YGConfigRef;
|
||||||
|
|
||||||
typedef struct YGNode* YGNodeRef;
|
typedef struct YGNode* YGNodeRef;
|
||||||
@@ -53,6 +56,13 @@ typedef int (*YGLogger)(
|
|||||||
typedef YGNodeRef (
|
typedef YGNodeRef (
|
||||||
*YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex);
|
*YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex);
|
||||||
|
|
||||||
|
// Memory allocation
|
||||||
|
WIN_EXPORT void YGSetAllocationCallbacks(YGAllocatorAllocateFunc allocFunc, YGAllocatorFreeFunc freeFunc);
|
||||||
|
WIN_EXPORT void YGGetAllocationCallbacks(YGAllocatorAllocateFunc* allocFunc, YGAllocatorFreeFunc* freeFunc);
|
||||||
|
|
||||||
|
WIN_EXPORT void* YGMemoryAllocate(size_t size);
|
||||||
|
WIN_EXPORT void YGMemoryFree(void* memory);
|
||||||
|
|
||||||
// YGNode
|
// YGNode
|
||||||
WIN_EXPORT YGNodeRef YGNodeNew(void);
|
WIN_EXPORT YGNodeRef YGNodeNew(void);
|
||||||
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigRef config);
|
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigRef config);
|
||||||
@@ -363,6 +373,21 @@ YG_EXTERN_C_END
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
// Templated delegates for YGMemoryAllocate & YGMemoryFree, so we don't have to
|
||||||
|
// cast nor pass in the size of the allocated chunk of memory explicitly.
|
||||||
|
template<typename T, typename... A>
|
||||||
|
T* YGAllocate(A&&... arguments) {
|
||||||
|
auto* memory = reinterpret_cast<T*>(YGMemoryAllocate(sizeof(T)));
|
||||||
|
new(memory) T(std::forward<A>(arguments)...);
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void YGFree(T* memory) {
|
||||||
|
memory->~T();
|
||||||
|
YGMemoryFree(memory);
|
||||||
|
}
|
||||||
|
|
||||||
// Calls f on each node in the tree including the given node argument.
|
// Calls f on each node in the tree including the given node argument.
|
||||||
void YGTraversePreOrder(
|
void YGTraversePreOrder(
|
||||||
|
Reference in New Issue
Block a user
nit: why are these macros vs a regular function?