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