1 // license:GPL-2.0+
2 // copyright-holders:Couriersud
3
4 #ifndef PSTATE_H_
5 #define PSTATE_H_
6
7 ///
8 /// \file pstate.h
9 ///
10
11 #include "pstring.h"
12 #include "ptypes.h"
13
14 #include <array>
15 #include <memory>
16 #include <vector>
17
18 // ----------------------------------------------------------------------------------------
19 // state saving ...
20 // ----------------------------------------------------------------------------------------
21
22 namespace plib {
23 class state_manager_t
24 {
25 public:
26
27 struct datatype_t
28 {
datatype_tdatatype_t29 datatype_t(std::size_t bsize, bool bintegral, bool bfloat)
30 : m_size(bsize), m_is_integral(bintegral), m_is_float(bfloat), m_is_custom(false)
31 {}
datatype_tdatatype_t32 explicit datatype_t(bool bcustom)
33 : m_size(0), m_is_integral(false), m_is_float(false), m_is_custom(bcustom)
34 {}
35
sizedatatype_t36 std::size_t size() const noexcept { return m_size; }
is_integraldatatype_t37 bool is_integral() const noexcept { return m_is_integral; }
is_floatdatatype_t38 bool is_float() const noexcept { return m_is_float; }
is_customdatatype_t39 bool is_custom() const noexcept { return m_is_custom; }
40
41 private:
42 std::size_t m_size;
43 bool m_is_integral;
44 bool m_is_float;
45 bool m_is_custom;
46 };
47
48 template<typename T>
dtype()49 static datatype_t dtype()
50 {
51 return datatype_t(sizeof(T),
52 plib::is_integral<T>::value || std::is_enum<T>::value,
53 plib::is_floating_point<T>::value);
54 }
55
56 struct callback_t
57 {
58 public:
59 using list_t = std::vector<callback_t *>;
60
61 virtual void register_state(state_manager_t &manager, const pstring &module) = 0;
62 virtual void on_pre_save(state_manager_t &manager) = 0;
63 virtual void on_post_load(state_manager_t &manager) = 0;
64 protected:
65 callback_t() = default;
66 virtual ~callback_t() = default;
67 PCOPYASSIGNMOVE(callback_t, default)
68 };
69
70 struct entry_t
71 {
72 using list_t = std::vector<entry_t>;
73
entry_tentry_t74 entry_t(const pstring &stname, const datatype_t &dt, const void *owner,
75 const std::size_t count, void *ptr)
76 : m_name(stname), m_dt(dt), m_owner(owner), m_callback(nullptr), m_count(count), m_ptr(ptr) { }
77
entry_tentry_t78 entry_t(const pstring &stname, const void *owner, callback_t *callback)
79 : m_name(stname), m_dt(datatype_t(true)), m_owner(owner), m_callback(callback), m_count(0), m_ptr(nullptr) { }
80
nameentry_t81 pstring name() const noexcept { return m_name; }
dtentry_t82 datatype_t dt() const noexcept { return m_dt; }
ownerentry_t83 const void * owner() const noexcept { return m_owner; }
callbackentry_t84 callback_t * callback() const noexcept { return m_callback; }
countentry_t85 std::size_t count() const noexcept { return m_count; }
ptrentry_t86 void * ptr() const noexcept { return m_ptr; }
87
88 private:
89 pstring m_name;
90 datatype_t m_dt;
91 const void * m_owner;
92 callback_t * m_callback;
93 std::size_t m_count;
94 void * m_ptr;
95 };
96
97 state_manager_t() = default;
98
99 struct saver_t
100 {
saver_tsaver_t101 saver_t(state_manager_t &sm, const void *owner, const pstring &membername)
102 : m_sm(sm)
103 , m_owner(owner)
104 , m_membername(membername)
105 { }
106
107 template <typename XS>
save_itemsaver_t108 void save_item(XS &xstate, const pstring &itemname)
109 {
110 m_sm.save_item(m_owner, xstate, m_membername + "." + itemname);
111 }
112
113 state_manager_t &m_sm;
114 const void * m_owner;
115 const pstring m_membername;
116 };
117
118 template<typename C>
save_item(const void * owner,C & state,const pstring & stname)119 void save_item(const void *owner, C &state, const pstring &stname)
120 {
121 save_item_dispatch(owner, state, stname);
122 }
123
124 template<typename C, std::size_t N>
save_item(const void * owner,C (& state)[N],const pstring & stname)125 void save_item(const void *owner, C (&state)[N], const pstring &stname) // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
126 {
127 save_state_ptr(owner, stname, dtype<C>(), N, &(state[0]));
128 }
129
130 template<typename C>
save_item(const void * owner,C * state,const pstring & stname,const std::size_t count)131 void save_item(const void *owner, C *state, const pstring &stname, const std::size_t count)
132 {
133 save_state_ptr(owner, stname, dtype<C>(), count, state);
134 }
135
136 template<typename C, typename A>
save_item(const void * owner,std::vector<C,A> & v,const pstring & stname)137 void save_item(const void *owner, std::vector<C, A> &v, const pstring &stname)
138 {
139 save_state_ptr(owner, stname, dtype<C>(), v.size(), v.data());
140 }
141
142 template<typename C, std::size_t N>
save_item(const void * owner,std::array<C,N> & a,const pstring & stname)143 void save_item(const void *owner, std::array<C, N> &a, const pstring &stname)
144 {
145 save_state_ptr(owner, stname, dtype<C>(), N, a.data());
146 }
147
save_state_ptr(const void * owner,const pstring & stname,const datatype_t & dt,const std::size_t count,void * ptr)148 void save_state_ptr(const void *owner, const pstring &stname, const datatype_t &dt, const std::size_t count, void *ptr)
149 {
150 m_save.emplace_back(stname, dt, owner, count, ptr);
151 }
152
pre_save()153 void pre_save()
154 {
155 for (auto & s : m_custom)
156 s.callback()->on_pre_save(*this);
157 }
158
post_load()159 void post_load()
160 {
161 for (auto & s : m_custom)
162 s.callback()->on_post_load(*this);
163 }
164
remove_save_items(const void * owner)165 void remove_save_items(const void *owner)
166 {
167 auto i = m_save.end();
168 while (i != m_save.begin())
169 {
170 i--;
171 if (i->owner() == owner)
172 i = m_save.erase(i);
173 }
174 i = m_custom.end();
175 while (i > m_custom.begin())
176 {
177 i--;
178 if (i->owner() == owner)
179 i = m_custom.erase(i);
180 }
181 }
182
save_list()183 std::vector<const entry_t *> save_list() const
184 {
185 std::vector<const entry_t *> ret;
186 for (const auto &i : m_save)
187 ret.push_back(&i);
188 return ret;
189 }
190
191 protected:
192
193 private:
194
195 template<typename C>
196 std::enable_if_t<plib::is_integral<C>::value || std::is_enum<C>::value
197 || plib::is_floating_point<C>::value>
save_item_dispatch(const void * owner,C & state,const pstring & stname)198 save_item_dispatch(const void *owner, C &state, const pstring &stname)
199 {
200 save_state_ptr( owner, stname, dtype<C>(), 1, &state);
201 }
202
203 template<typename C>
204 std::enable_if_t<!(plib::is_integral<C>::value || std::is_enum<C>::value
205 || plib::is_floating_point<C>::value)>
save_item_dispatch(const void * owner,C & state,const pstring & stname)206 save_item_dispatch(const void *owner, C &state, const pstring &stname)
207 {
208 saver_t sav(*this, owner, stname);
209 state.save_state(sav);
210 }
211
212 entry_t::list_t m_save;
213 entry_t::list_t m_custom;
214
215 };
216
217 template<>
save_item(const void * owner,callback_t & state,const pstring & stname)218 inline void state_manager_t::save_item(const void *owner, callback_t &state, const pstring &stname)
219 {
220 m_custom.emplace_back(stname, owner, &state);
221 state.register_state(*this, stname);
222 }
223
224
225 } // namespace plib
226
227 #endif // PSTATE_H_
228