1//
2// immer: immutable data structures for C++
3// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4//
5// This software is distributed under the Boost Software License, Version 1.0.
6// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7//
8
9#pragma once
10
11#include <immer/config.hpp>
12#include <immer/heap/tags.hpp>
13
14#if IMMER_HAS_LIBGC
15#include <gc/gc.h>
16#else
17#error "Using garbage collection requires libgc"
18#endif
19
20#include <cstdlib>
21#include <memory>
22
23namespace immer {
24
25#ifdef __APPLE__
26#define IMMER_GC_REQUIRE_INIT 1
27#else
28#define IMMER_GC_REQUIRE_INIT 0
29#endif
30
31#if IMMER_GC_REQUIRE_INIT
32
33namespace detail {
34
35template <int Dummy=0>
36struct gc_initializer
37{
38 gc_initializer() { GC_init(); }
39 static gc_initializer init;
40};
41
42template <int D>
43gc_initializer<D> gc_initializer<D>::init {};
44
45inline void gc_initializer_guard()
46{
47 static gc_initializer<> init_ = gc_initializer<>::init;
48 (void) init_;
49}
50
51} // namespace detail
52
53#define IMMER_GC_INIT_GUARD_ ::immer::detail::gc_initializer_guard()
54
55#else
56
57#define IMMER_GC_INIT_GUARD_
58
59#endif // IMMER_GC_REQUIRE_INIT
60
61/*!
62 * Heap that uses a tracing garbage collector.
63 *
64 * @rst
65 *
66 * This heap uses the `Boehm's conservative garbage collector`_ under
67 * the hood. This is a tracing garbage collector that automatically
68 * reclaims unused memory. Thus, it is not needed to call
69 * ``deallocate()`` in order to release memory.
70 *
71 * .. admonition:: Dependencies
72 * :class: tip
73 *
74 * In order to use this header file, you need to make sure that
75 * Boehm's ``libgc`` is your include path and link to its binary
76 * library.
77 *
78 * .. caution:: Memory that is allocated with the standard ``malloc``
79 * and ``free`` is not visible to ``libgc`` when it is looking for
80 * references. This means that if, let's say, you store a
81 * :cpp:class:`immer::vector` using a ``gc_heap`` inside a
82 * ``std::vector`` that uses a standard allocator, the memory of
83 * the former might be released automatically at unexpected times
84 * causing crashes.
85 *
86 * .. caution:: When using a ``gc_heap`` in combination with immutable
87 * containers, the destructors of the contained objects will never
88 * be called. It is ok to store containers inside containers as
89 * long as all of them use a ``gc_heap`` consistently, but storing
90 * other kinds of objects with relevant destructors
91 * (e.g. containers with reference counting or other kinds of
92 * *resource handles*) might cause memory leaks and other problems.
93 *
94 * .. _boehm's conservative garbage collector: https://github.com/ivmai/bdwgc
95 *
96 * @endrst
97 */
98class gc_heap
99{
100public:
101 static void* allocate(std::size_t n)
102 {
103 IMMER_GC_INIT_GUARD_;
104 auto p = GC_malloc(n);
105 if (IMMER_UNLIKELY(!p))
106 throw std::bad_alloc{};
107 return p;
108 }
109
110 static void* allocate(std::size_t n, norefs_tag)
111 {
112 IMMER_GC_INIT_GUARD_;
113 auto p = GC_malloc_atomic(n);
114 if (IMMER_UNLIKELY(!p))
115 throw std::bad_alloc{};
116 return p;
117 }
118
119 static void deallocate(std::size_t, void* data)
120 {
121 GC_free(data);
122 }
123
124 static void deallocate(std::size_t, void* data, norefs_tag)
125 {
126 GC_free(data);
127 }
128};
129
130} // namespace immer
131