aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/gc-alloc.hh
diff options
context:
space:
mode:
authorQyriad <qyriad@qyriad.me>2024-07-15 16:18:36 -0600
committerQyriad <qyriad@qyriad.me>2024-07-20 20:20:01 +0000
commita3361557e3f4a53b90ca5067e68ba9788df20928 (patch)
tree60899a6f30348b8b919c289e06b59fa644003b9d /src/libexpr/gc-alloc.hh
parent0109368c3faf5516aeddde45e8dc3c33e7163838 (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.hh119
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;
+}
+
+}