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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#pragma once

#include <unordered_map><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <memory><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <optional><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "internal/dev_env.hpp"

namespace uni {

template<class T, class ID = int, template<class,class> class storage = std::unordered_map>
struct restorable_stack {
    using value_type = T;
    using key_type = ID;

  protected:
    struct node;
    using node_ptr = std::shared_ptr<node>;

    struct node {
        std::optional<value_type> val = std::nullopt;
        node_ptr parent;
    };

    node_ptr _current;
    storage<key_type, node_ptr> _storage;

  public:
    restorable_stack() noexcept(NO_EXCEPT) { this->clear(); };

    inline bool empty() const noexcept(NO_EXCEPT) {
        return !this->_current->val.has_value();
    }

    inline bool stored(const key_type& x) const noexcept(NO_EXCEPT) {
        return this->_storage.count(x);
    }


    inline const value_type& top() const noexcept(NO_EXCEPT) {
        return this->_current->val.value();
    }

    inline auto get() const noexcept(NO_EXCEPT) {
        return this->_current.val;
    }


    template<std::convertible_to<T> U = T>
    inline auto top_or(U &&v) const noexcept(NO_EXCEPT) {
        return this->_current->val.value_or(std::forward<U>(v));
    }


    inline auto& push(const value_type& x) noexcept(NO_EXCEPT) {
        this->_current.reset(new node{ x, this->_current });
        return *this;
    }

    inline auto& pop() noexcept(NO_EXCEPT) {
        this->_current = this->_current->parent;
        return *this;
    }


    inline auto& save(const key_type& x) noexcept(NO_EXCEPT) {
        this->_storage[x] = this->_current;
        return *this;
    }

    inline auto& load(const key_type& x) noexcept(NO_EXCEPT) {
        assert(this->stored(x));
        this->_current = this->_storage[x];
        return *this;
    }

    inline auto& clear() noexcept(NO_EXCEPT) {
        this->_current.reset(new node{});
        return *this;
    }

    inline auto& load_or_clear(const key_type& x) noexcept(NO_EXCEPT) {
        if(this->stored(x)) this->load(x);
        else this->clear();
        return *this;
    }
};

} // namespace uni