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 <memory>
14#include <utility>
15#include <atomic>
16
17namespace 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 */
31struct 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() = delete;
44 bool operator==(edit x) const { return v == x.v; }
45 bool operator!=(edit x) const { return v != x.v; }
46 };
47
48 struct owner
49 {
50 void* make_token_()
51 {
52 return heap_::allocate(1, norefs_tag{});
53 };
54
55 mutable std::atomic<void*> token_;
56
57 operator edit () { return { token_ }; }
58
59 owner()
60 : token_{make_token_()}
61 {}
62 owner(const owner& o)
63 : token_{make_token_()}
64 {
65 o.token_ = make_token_();
66 }
67 owner(owner&& o) noexcept
68 : token_{o.token_.load()}
69 {}
70 owner& operator=(const owner& o)
71 {
72 o.token_ = make_token_();
73 token_ = make_token_();
74 return *this;
75 }
76 owner& operator=(owner&& o) noexcept
77 {
78 token_ = o.token_.load();
79 return *this;
80 }
81 };
82
83 struct ownee
84 {
85 edit token_ {nullptr};
86
87 ownee& operator=(edit e)
88 {
89 assert(e != noone);
90 // This would be a nice safety plug but it sadly
91 // does not hold during transient concatenation.
92 // assert(token_ == e || token_ == edit{nullptr});
93 token_ = e;
94 return *this;
95 }
96
97 bool can_mutate(edit t) const { return token_ == t; }
98 bool owned() const { return token_ != edit{nullptr}; }
99 };
100
101 static owner noone;
102 };
103 };
104};
105
106template <typename HP>
107typename gc_transience_policy::apply<HP>::type::owner
108gc_transience_policy::apply<HP>::type::noone = {};
109
110} // namespace immer
111