diff --git a/CMakeLists.txt b/CMakeLists.txt index 018c269f..3a426ad0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index 99862797..e1b63fa5 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #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; +} + +YOGA_EXPORT void YGGetAllocationCallbacks( + YGAllocatorAllocateFunc* allocFunc, + 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) { 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(config); YGAssertWithConfig( config, node != nullptr, "Could not allocate memory for node"); Event::publish(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(*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(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(*oldNode, config); node->setOwner(nullptr); Event::publish(node, {node->getConfig()}); @@ -260,13 +304,13 @@ YOGA_EXPORT void YGNodeFree(const YGNodeRef node) { node->clearChildren(); Event::publish(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(YGAndroidLog); #else - const YGConfigRef config = new YGConfig(YGDefaultLog); + const YGConfigRef config = YGAllocate(YGDefaultLog); #endif gConfigInstanceCount++; return config; } YOGA_EXPORT void YGConfigFree(const YGConfigRef config) { - delete config; + YGFree(config); gConfigInstanceCount--; } diff --git a/yoga/Yoga.h b/yoga/Yoga.h index 3444658b..f54e5f9e 100644 --- a/yoga/Yoga.h +++ b/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 #include +// 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 +T* YGAllocate(A&&... arguments) { + auto* memory = reinterpret_cast(YGMemoryAllocate(sizeof(T), alignof(T))); + new(memory) T(std::forward(arguments)...); + return memory; +} +template +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,