/src/immer/immer/transience/gc_transience_policy.hpp
Line | Count | Source |
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/heap/tags.hpp> |
12 | | |
13 | | #include <atomic> |
14 | | #include <memory> |
15 | | #include <utility> |
16 | | |
17 | | namespace immer { |
18 | | |
19 | | /*! |
20 | | * Provides transience ownership tracking when a *tracing garbage |
21 | | * collector* is used instead of reference counting. |
22 | | * |
23 | | * @rst |
24 | | * |
25 | | * .. warning:: Using this policy without an allocation scheme that |
26 | | * includes automatic tracing garbage collection may cause memory |
27 | | * leaks. |
28 | | * |
29 | | * @endrst |
30 | | */ |
31 | | struct gc_transience_policy |
32 | | { |
33 | | template <typename HeapPolicy> |
34 | | struct apply |
35 | | { |
36 | | struct type |
37 | | { |
38 | | using heap_ = typename HeapPolicy::type; |
39 | | |
40 | | struct edit |
41 | | { |
42 | | void* v; |
43 | | edit(void* v_) |
44 | 1.53M | : v{v_} |
45 | 1.53M | { |
46 | 1.53M | } |
47 | | edit() = delete; |
48 | 1.49M | bool operator==(edit x) const { return v == x.v; } |
49 | 12.3k | bool operator!=(edit x) const { return v != x.v; } |
50 | | }; |
51 | | |
52 | | struct owner |
53 | | { |
54 | | void* make_token_() |
55 | 20.0k | { |
56 | 20.0k | return heap_::allocate(1, norefs_tag{}); |
57 | 20.0k | }; |
58 | | |
59 | | mutable std::atomic<void*> token_; |
60 | | |
61 | 1.51M | operator edit() { return {token_}; } |
62 | | |
63 | | owner() |
64 | 20.0k | : token_{make_token_()} |
65 | 20.0k | { |
66 | 20.0k | } |
67 | | owner(const owner& o) |
68 | | : token_{make_token_()} |
69 | | { |
70 | | o.token_ = make_token_(); |
71 | | } |
72 | | owner(owner&& o) noexcept |
73 | | : token_{o.token_.load()} |
74 | | { |
75 | | } |
76 | | owner& operator=(const owner& o) |
77 | | { |
78 | | o.token_ = make_token_(); |
79 | | token_ = make_token_(); |
80 | | return *this; |
81 | | } |
82 | | owner& operator=(owner&& o) noexcept |
83 | 16.1k | { |
84 | 16.1k | token_ = o.token_.load(); |
85 | 16.1k | return *this; |
86 | 16.1k | } |
87 | | }; |
88 | | |
89 | | struct ownee |
90 | | { |
91 | | edit token_{nullptr}; |
92 | | |
93 | | ownee& operator=(edit e) |
94 | 12.3k | { |
95 | 12.3k | assert(e != noone); |
96 | | // This would be a nice safety plug but it sadly |
97 | | // does not hold during transient concatenation. |
98 | | // assert(token_ == e || token_ == edit{nullptr}); |
99 | 12.3k | token_ = e; |
100 | 12.3k | return *this; |
101 | 12.3k | } |
102 | | |
103 | 1.49M | bool can_mutate(edit t) const { return token_ == t; } |
104 | | bool owned() const { return token_ != edit{nullptr}; } |
105 | | }; |
106 | | |
107 | | static owner noone; |
108 | | }; |
109 | | }; |
110 | | }; |
111 | | |
112 | | template <typename HP> |
113 | | typename gc_transience_policy::apply<HP>::type::owner |
114 | | gc_transience_policy::apply<HP>::type::noone = {}; |
115 | | |
116 | | } // namespace immer |