Monero C++ Library
Loading...
Searching...
No Matches
gen_utils.h
1
52#pragma once
53
54#ifndef gen_utils_h
55#define gen_utils_h
56
57#include <boost/lexical_cast.hpp>
58#include <boost/uuid/uuid.hpp>
59#include <boost/uuid/uuid_generators.hpp>
60#include <boost/uuid/uuid_io.hpp>
61#include <boost/property_tree/ptree.hpp>
62#include <boost/property_tree/json_parser.hpp>
63#include "rapidjson/document.h"
64#include <boost/thread/recursive_mutex.hpp>
65#include <boost/thread/thread.hpp>
66#include <boost/thread/condition_variable.hpp>
67#include <chrono>
68#include <thread>
69#include <atomic>
70#include "include_base_utils.h"
71#include "common/util.h"
72
76namespace gen_utils
77{
78
84 static std::string get_uuid() {
85 boost::uuids::random_generator generator;
86 boost::uuids::uuid uuid = generator();
87 return boost::uuids::to_string(uuid);
88 }
89
95 static void wait_for(uint64_t duration_ms) {
96 std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms));
97 }
98
99 static bool bool_equals(bool val, const boost::optional<bool>& opt_val) {
100 return opt_val == boost::none ? false : val == *opt_val;
101 }
102
103 // ------------------------- SERIALIZATION ---------------------------
104
105 // TODO: fully switch from property trees to rapidjson
106
107 std::string serialize(const rapidjson::Document& doc);
108 std::string serialize(const boost::property_tree::ptree& node);
109 void deserialize(const std::string& json, boost::property_tree::ptree& root);
110
111 template<typename T>
112 std::shared_ptr<T> deserialize(const std::string& json) {
113 boost::property_tree::ptree root;
114 gen_utils::deserialize(json, root);
115 std::shared_ptr<T> obj = std::make_shared<T>();
116 T::from_property_tree(root, obj);
117 return obj;
118 }
119
120 // ------------------------- VALUE RECONCILATION ----------------------------
121
122 // TODO: refactor common template code
123 template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type* = nullptr>
124 boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> resolve_max, const std::string& err_msg = "") {
125
126 // check for equality
127 if (val1 == val2) return val1;
128
129 // resolve one value none
130 if (val1 == boost::none || val2 == boost::none) {
131 if (resolve_defined != boost::none && *resolve_defined == false) return boost::none;
132 else return val1 == boost::none ? val2 : val1;
133 }
134
135 throw std::runtime_error(std::string("Cannot reconcile strings: ") + boost::lexical_cast<std::string>(val1) + std::string(" vs ") + boost::lexical_cast<std::string>(val2) + (!err_msg.empty() ? std::string(". ") + err_msg : std::string("")));
136 }
137 template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type* = nullptr>
138 boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const std::string& err_msg = "") {
139 return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
140 }
141
142 template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
143 boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> resolve_max, const std::string& err_msg = "") {
144
145 // check for equality
146 if (val1 == val2) return val1;
147
148 // resolve one value none
149 if (val1 == boost::none || val2 == boost::none) {
150 if (resolve_defined != boost::none && *resolve_defined == false) return boost::none;
151 else return val1 == boost::none ? val2 : val1;
152 }
153
154 // resolve different booleans
155 if (resolve_true != boost::none) return *val1 == *resolve_true ? val1 : val2; // resolve conflicting booleans to the preferred value
156
157 // resolve different numbers
158 if (resolve_max != boost::none) return *resolve_max ? std::max(*val1, *val2) : std::min(*val1, *val2);
159
160 // cannot reconcile
161 throw std::runtime_error(std::string("Cannot reconcile integrals: ") + boost::lexical_cast<std::string>(val1) + std::string(" vs ") + boost::lexical_cast<std::string>(val2) + (!err_msg.empty() ? std::string(". ") + err_msg : std::string("")));
162 }
163 template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
164 boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const std::string& err_msg = "") {
165 return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
166 }
167
168 template <class T>
169 std::vector<T> reconcile(const std::vector<T>& v1, const std::vector<T>& v2, const std::string& err_msg = "") {
170
171 // check for equality
172 if (v1 == v2) return v1;
173
174 // resolve one vector empty
175 if (v1.empty()) return v2;
176 if (v2.empty()) return v1;
177
178 // otherwise cannot reconcile
179 throw std::runtime_error("Cannot reconcile vectors" + (!err_msg.empty() ? std::string(". ") + err_msg : std::string("")));
180 }
181
182 // ------------------------- THREAD POLLER ----------------------------
183
184 // WARNING: Only destroy a thread_poller from a thread other than its own pool thread.
185 // (e.g. a listener callback running on the poll thread, drops the last owning reference/unique_ptr
186 // to the poller.)
187 class thread_poller {
188 public:
189 thread_poller();
190 virtual ~thread_poller();
191
192 bool is_polling() const { return m_is_polling; }
193 void set_is_polling(bool is_polling);
194 void request_is_polling(bool is_polling);
195
196 void set_period_in_ms(uint64_t period_ms) { m_poll_period_ms = period_ms; }
197 virtual void poll() = 0;
198 void wait_for_callbacks_idle();
199
200 class announce_scope {
201 public:
202 explicit announce_scope(thread_poller& poller);
203 ~announce_scope();
204 announce_scope(const announce_scope&) = delete;
205 announce_scope& operator=(const announce_scope&) = delete;
206 private:
207 thread_poller& m_poller;
208 };
209
210 protected:
211 std::string m_name;
212 boost::recursive_mutex m_mutex;
213 boost::mutex m_polling_mutex; // guards the interruptible periodic sleep (m_poll_cv)
214 boost::mutex m_lifecycle_mutex; // guards m_poll_loop_running/m_poll_thread_id and start/stop coordination
215 boost::thread::id m_poll_thread_id; // id of the currently running loop thread; guarded by m_lifecycle_mutex
216 std::atomic<bool> m_is_polling;
217 bool m_poll_loop_running; // guarded by m_lifecycle_mutex
218 std::atomic<uint64_t> m_poll_period_ms;
219 boost::condition_variable m_poll_cv; // periodic-sleep interrupt
220 boost::condition_variable m_lifecycle_cv; // notified (under m_lifecycle_mutex) when the loop actually exits
221 boost::mutex m_announce_mutex; // guards m_announce_count
222 boost::condition_variable m_announce_cv; // notified (under m_announce_mutex) when m_announce_count reaches 0
223 int m_announce_count = 0; // number of announce_scope instances currently alive, across all threads
224
225 void init_common(const std::string& name);
226 void run_poll_loop();
227 };
228}
229#endif /* gen_utils_h */
Definition gen_utils.h:77