Coverage Report

Created: 2025-10-10 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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