diff options
author | Qyriad <qyriad@qyriad.me> | 2024-07-15 16:18:36 -0600 |
---|---|---|
committer | Qyriad <qyriad@qyriad.me> | 2024-07-20 20:20:01 +0000 |
commit | a3361557e3f4a53b90ca5067e68ba9788df20928 (patch) | |
tree | 60899a6f30348b8b919c289e06b59fa644003b9d /src/libexpr/gc-alloc.hh | |
parent | 0109368c3faf5516aeddde45e8dc3c33e7163838 (diff) |
libexpr: refactor gc-agnostic helpers into one place
Change-Id: Icc4b367e4f670d47256f62a3a002cd248a5c2d3b
Diffstat (limited to 'src/libexpr/gc-alloc.hh')
-rw-r--r-- | src/libexpr/gc-alloc.hh | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/libexpr/gc-alloc.hh b/src/libexpr/gc-alloc.hh new file mode 100644 index 000000000..a16bc65e4 --- /dev/null +++ b/src/libexpr/gc-alloc.hh @@ -0,0 +1,119 @@ +#pragma once +/// @file Aliases and wrapper functions that are transparently GC-enabled +/// if Lix is compiled with BoehmGC enabled. + +#include <cstddef> +#include <cstring> +#include <list> +#include <map> +#include <new> +#include <vector> + +#if HAVE_BOEHMGC +#include <functional> // std::less +#include <utility> // std::pair +#define GC_INCLUDE_NEW +#include <gc/gc.h> +#include <gc/gc_allocator.h> +#include <gc/gc_cpp.h> + +/// calloc, transparently GC-enabled. +#define LIX_GC_CALLOC(size) GC_MALLOC(size) + +/// strdup, transaprently GC-enabled. +#define LIX_GC_STRDUP(str) GC_STRDUP(str) + +/// Atomic GC malloc() with GC enabled, or regular malloc() otherwise. +#define LIX_GC_MALLOC_ATOMIC(size) GC_MALLOC_ATOMIC(size) + +namespace nix +{ + +/// Alias for std::map which uses BoehmGC's allocator conditional on this Lix +/// build having GC enabled. +template<typename KeyT, typename ValueT> +using GcMap = std::map< + KeyT, + ValueT, + std::less<KeyT>, + traceable_allocator<std::pair<KeyT const, ValueT>> +>; + +/// Alias for std::vector which uses BoehmGC's allocator conditional on this Lix +/// build having GC enabled. +template<typename ItemT> +using GcVector = std::vector<ItemT, traceable_allocator<ItemT>>; + +/// Alias for std::list which uses BoehmGC's allocator conditional on this Lix +/// build having GC enabled. +template<typename ItemT> +using GcList = std::list<ItemT, traceable_allocator<ItemT>>; + +} + +#else + +#include <cstdlib> + +/// calloc, transparently GC-enabled. +#define LIX_GC_CALLOC(size) calloc(size, 1) + +/// strdup, transparently GC-enabled. +#define LIX_GC_STRDUP(str) strdup(str) + +/// Atomic GC malloc() with GC enabled, or regular malloc() otherwise. +/// The returned memory must never contain pointers. +#define LIX_GC_MALLOC_ATOMIC(size) malloc(size) + +namespace nix +{ + +/// Alias for std::map which uses BoehmGC's allocator conditional on this Lix +/// build having GC enabled. +template<typename KeyT, typename ValueT> +using GcMap = std::map<KeyT, ValueT>; + +/// Alias for std::vector which uses BoehmGC's allocator conditional on this Lix +/// build having GC enabled. +template<typename ItemT> +using GcVector = std::vector<ItemT>; + +/// Alias for std::list which uses BoehmGC's allocator conditional on this Lix +/// build having GC enabled. +template<typename ItemT> +using GcList = std::list<ItemT>; + +} + +#endif + +namespace nix +{ + +[[gnu::always_inline]] +inline void * gcAllocBytes(size_t n) +{ + // Note: various places expect the allocated memory to be zero. + // Hence: calloc(). + void * ptr = LIX_GC_CALLOC(n); + if (ptr == nullptr) { + throw std::bad_alloc(); + } + + return ptr; +} + +/// GC-transparently allocates a buffer for a C-string of @ref size *bytes*, +/// meaning you should include the size needed by the NUL terminator in the +/// passed size. Memory allocated with this function must never contain other +/// pointers. +inline char * gcAllocString(size_t size) +{ + char * cstr = static_cast<char *>(LIX_GC_MALLOC_ATOMIC(size)); + if (cstr == nullptr) { + throw std::bad_alloc(); + } + return cstr; +} + +} |