Add memory allocation API with templated C++ delegates & minor fixups #1123
@@ -5,6 +5,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
project(yoga)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
add_compile_options(
|
||||
@@ -13,12 +14,13 @@ add_compile_options(
|
||||
-fvisibility=hidden
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
-fPIC
|
||||
-Wall
|
||||
-std=c++11)
|
||||
|
||||
file(GLOB_RECURSE yogacore_SRC yoga/*.cpp)
|
||||
add_library(yogacore STATIC ${yogacore_SRC})
|
||||
file(GLOB_RECURSE YOGA_SRC yoga/*.cpp)
|
||||
add_library(${CMAKE_PROJECT_NAME} STATIC ${YOGA_SRC})
|
||||
|
||||
target_include_directories(yogacore PUBLIC .)
|
||||
target_link_libraries(yogacore android log)
|
||||
set_target_properties(yogacore PROPERTIES CXX_STANDARD 11)
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC .)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} android log)
|
||||
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES CXX_STANDARD 11)
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "Utils.h"
|
||||
#include "YGNode.h"
|
||||
#include "YGNodePrint.h"
|
||||
@@ -106,6 +105,51 @@ static int YGDefaultLog(
|
||||
#undef YG_UNUSED
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define YG_ALLOC_ALIGNED ([](size_t a, size_t s) -> void* { \
|
||||
return _aligned_malloc(s, a); \
|
||||
})
|
||||
#define YG_FREE_ALIGNED ([](void* m) -> void { \
|
||||
_aligned_free(m); \
|
||||
})
|
||||
#else
|
||||
#define YG_ALLOC_ALIGNED ([](size_t a, size_t s) -> void* { \
|
||||
return aligned_alloc(a, s); \
|
||||
|
||||
})
|
||||
#define YG_FREE_ALIGNED ([](void* m) -> void { \
|
||||
free(m); \
|
||||
})
|
||||
#endif
|
||||
|
||||
static YGAllocatorAllocateFunc gAllocatorAllocateFunc = YG_ALLOC_ALIGNED;
|
||||
static YGAllocatorFreeFunc gAllocatorFreeFunc = YG_FREE_ALIGNED;
|
||||
|
||||
YOGA_EXPORT void YGSetAllocationCallbacks(
|
||||
YGAllocatorAllocateFunc allocFunc,
|
||||
YGAllocatorFreeFunc freeFunc) {
|
||||
gAllocatorAllocateFunc = allocFunc;
|
||||
gAllocatorFreeFunc = freeFunc;
|
||||
}
|
||||
|
||||
![]() 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 YGGetAllocationCallbacks(
|
||||
YGAllocatorAllocateFunc* allocFunc,
|
||||
![]()
```suggestion
YOGA_EXPORT void YGSetAllocator(
```
|
||||
YGAllocatorFreeFunc* freeFunc) {
|
||||
if(allocFunc != nullptr) {
|
||||
*allocFunc = gAllocatorAllocateFunc;
|
||||
}
|
||||
if(freeFunc != nullptr) {
|
||||
*freeFunc = gAllocatorFreeFunc;
|
||||
}
|
||||
}
|
||||
|
||||
YOGA_EXPORT void* YGMemoryAllocate(size_t alignment, size_t size) {
|
||||
return gAllocatorAllocateFunc(alignment, size);
|
||||
}
|
||||
|
||||
YOGA_EXPORT void YGMemoryFree(void* memory) {
|
||||
gAllocatorFreeFunc(memory);
|
||||
}
|
||||
|
||||
static inline bool YGDoubleIsUndefined(const double value) {
|
||||
![]() nit: Do we need to expose allocate and free as part of the public Yoga API? This already has an API for getting the allocators which are set. It doesn't seem like a good code pattern for folks to use Yoga's APIs for their own memory allocation. nit: Do we need to expose allocate and free as part of the public Yoga API? This already has an API for getting the allocators which are set. It doesn't seem like a good code pattern for folks to use Yoga's APIs for their own memory allocation.
|
||||
return facebook::yoga::isUndefined(value);
|
||||
}
|
||||
@@ -192,7 +236,7 @@ YOGA_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(
|
||||
int32_t gConfigInstanceCount = 0;
|
||||
|
||||
YOGA_EXPORT WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
|
||||
const YGNodeRef node = new YGNode{config};
|
||||
const YGNodeRef node = YGAllocate<YGNode>(config);
|
||||
YGAssertWithConfig(
|
||||
config, node != nullptr, "Could not allocate memory for node");
|
||||
Event::publish<Event::NodeAllocation>(node, {config});
|
||||
@@ -210,7 +254,7 @@ YOGA_EXPORT YGNodeRef YGNodeNew(void) {
|
||||
}
|
||||
|
||||
YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) {
|
||||
YGNodeRef node = new YGNode(*oldNode);
|
||||
YGNodeRef node = YGAllocate<YGNode>(*oldNode);
|
||||
YGAssertWithConfig(
|
||||
oldNode->getConfig(),
|
||||
node != nullptr,
|
||||
@@ -221,7 +265,7 @@ YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) {
|
||||
}
|
||||
|
||||
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");
|
||||
gConfigInstanceCount++;
|
||||
return config;
|
||||
@@ -229,7 +273,7 @@ static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
|
||||
|
||||
static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
|
||||
auto config = YGConfigClone(*oldNode->getConfig());
|
||||
auto node = new YGNode{*oldNode, config};
|
||||
auto node = YGAllocate<YGNode>(*oldNode, config);
|
||||
node->setOwner(nullptr);
|
||||
Event::publish<Event::NodeAllocation>(node, {node->getConfig()});
|
||||
|
||||
@@ -260,13 +304,13 @@ YOGA_EXPORT void YGNodeFree(const YGNodeRef node) {
|
||||
|
||||
node->clearChildren();
|
||||
Event::publish<Event::NodeDeallocation>(node, {node->getConfig()});
|
||||
delete node;
|
||||
YGFree(node);
|
||||
}
|
||||
|
||||
static void YGConfigFreeRecursive(const YGNodeRef root) {
|
||||
if (root->getConfig() != nullptr) {
|
||||
gConfigInstanceCount--;
|
||||
delete root->getConfig();
|
||||
YGFree(root->getConfig());
|
||||
}
|
||||
// Delete configs recursively for childrens
|
||||
for (auto* child : root->getChildren()) {
|
||||
@@ -308,16 +352,16 @@ int32_t YGConfigGetInstanceCount(void) {
|
||||
|
||||
YOGA_EXPORT YGConfigRef YGConfigNew(void) {
|
||||
#ifdef ANDROID
|
||||
const YGConfigRef config = new YGConfig(YGAndroidLog);
|
||||
const YGConfigRef config = YGAllocate<YGConfig>(YGAndroidLog);
|
||||
#else
|
||||
const YGConfigRef config = new YGConfig(YGDefaultLog);
|
||||
const YGConfigRef config = YGAllocate<YGConfig>(YGDefaultLog);
|
||||
#endif
|
||||
gConfigInstanceCount++;
|
||||
return config;
|
||||
}
|
||||
|
||||
YOGA_EXPORT void YGConfigFree(const YGConfigRef config) {
|
||||
delete config;
|
||||
YGFree(config);
|
||||
gConfigInstanceCount--;
|
||||
}
|
||||
|
||||
|
24
yoga/Yoga.h
24
yoga/Yoga.h
@@ -29,6 +29,9 @@ typedef struct YGSize {
|
||||
float height;
|
||||
} YGSize;
|
||||
|
||||
typedef void* (*YGAllocatorAllocateFunc)(size_t alignment, size_t size);
|
||||
typedef void (*YGAllocatorFreeFunc)(void* memory);
|
||||
|
||||
typedef struct YGConfig* YGConfigRef;
|
||||
|
||||
typedef struct YGNode* YGNodeRef;
|
||||
@@ -53,6 +56,13 @@ typedef int (*YGLogger)(
|
||||
typedef YGNodeRef (
|
||||
*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 alignment, size_t size);
|
||||
WIN_EXPORT void YGMemoryFree(void* memory);
|
||||
|
||||
// YGNode
|
||||
WIN_EXPORT YGNodeRef YGNodeNew(void);
|
||||
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigRef config);
|
||||
@@ -364,6 +374,20 @@ YG_EXTERN_C_END
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
// 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), alignof(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.
|
||||
void YGTraversePreOrder(
|
||||
YGNodeRef node,
|
||||
|
Reference in New Issue
Block a user
nit: why are these macros vs a regular function?