aboutsummaryrefslogtreecommitdiff
path: root/src/unique.hpp
blob: 829fa497bf8e2848f0e7c96c9dc349bbcc818ce8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#pragma once

// #################################################################################################

// A unique type generator
template <typename T, typename TAG, typename specialization = void>
class Unique
{
    private:
    T val; // no default initialization so that std::is_trivial_v<Unique<T>> == true

    public:
    using type = T;

    ~Unique() = default;
    constexpr explicit Unique(T b_)
    : val{ b_ }
    {
    }

    // rule of 5
    constexpr Unique() = default;
    constexpr Unique(Unique const&) = default;
    constexpr Unique(Unique&&) = default;
    constexpr Unique& operator=(Unique const&) = default;
    constexpr Unique& operator=(Unique&&) = default;

    // can't implicitly affect from base type
    Unique& operator=(T const&) = delete;
    constexpr Unique& operator=(T&&) = delete;

    // cast
    constexpr operator T() const noexcept { return val; }

    // pre-increment
    auto& operator++() noexcept
    {
        ++val;
        return *this;
    }
    // post-increment
    auto operator++(int) noexcept
    {
        return Unique<T, TAG>{ std::exchange(val, val + 1) };
    }
};

template <typename T, typename TAG>
class Unique<T, TAG, std::enable_if_t<!std::is_scalar_v<T>>>
: public T
{
    public:
    using type = T;
    using T::T;
    explicit Unique(T const& b_)
    : T{ b_ }
    {
    }
};

#define DECLARE_UNIQUE_TYPE(_name, _type) using _name = Unique<_type, class Unique_##_name##_Tag>