Project
Loading...
Searching...
No Matches
RootSerializableKeyValueStore.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef ALICEO2_ROOTSERKEYVALUESTORE_H
13#define ALICEO2_ROOTSERKEYVALUESTORE_H
14
15#include <map>
16#include <string>
17#include <TClass.h>
18#include <Rtypes.h>
19#include <typeinfo>
20#include <typeindex>
21#include <TBufferFile.h>
22#include <type_traits>
23#include <cstring>
24#include <memory>
25
26namespace o2
27{
28namespace utils
29{
30
38{
39 public:
42 SerializedInfo() = default;
44 std::unique_ptr<char> buffer, TClass const* cl, std::string const& s) : N(N), cl(cl), typeinfo_name(s)
45 {
46 bufferptr = buffer.get();
47 buffer.release();
48 }
50 {
51 // we do a deep copy
52 N = other.N;
53 bufferptr = new char[N];
54
55 std::memcpy(bufferptr, other.bufferptr, sizeof(char) * N);
56 cl = other.cl;
57 typeinfo_name = other.typeinfo_name;
58 }
60 {
62 std::swap(*this, temp);
63 return *this;
64 }
66 {
67 // we are the owner of this ... so delete it
68 delete bufferptr;
69 }
70
71 void* objptr = nullptr;
72 Int_t N = 0;
73 char* bufferptr = nullptr; //[N] pointer to serialized buffer
74
75 // we use the TClass and/or the type_index_hash for type idendification
76 TClass const* cl = nullptr;
77 std::string typeinfo_name; // typeinfo name that can be used to store type if TClass not available (for PODs!)
79 };
80
81 enum class GetState {
82 kOK = 0,
83 kNOSUCHKEY = 1,
84 kWRONGTYPE = 2,
85 kNOTCLASS = 3
86 };
87
88 private:
89 static constexpr const char* GetStateString[4] = {
90 "ok",
91 "no such key",
92 "wrong type",
93 "no TClass"};
94
95 public:
96 static const char* getStateString(GetState state)
97 {
98 return (int)state < 4 ? GetStateString[(int)state] : nullptr;
99 };
100
102
105 template <typename T>
106 void put(std::string const& key, T const& value)
107 {
108 remove_entry(key);
109 GetState s;
110 return put_impl(key, value, s, int{});
111 }
112
114 template <typename T>
115 const T* get(std::string const& key) const
116 {
117 GetState s;
118 return get_impl<T>(key, s, int{});
119 }
120
122 template <typename T>
123 const T* get(std::string const& key, GetState& state) const
124 {
125 return get_impl<T>(key, state, int{});
126 }
127
130 template <typename T>
131 const T& getRef(std::string const& key, GetState& state) const
132 {
133 auto ptr = get_impl<T>(key, state, int{});
134 if (ptr) {
135 return *ptr;
136 } else {
137 static T t = T();
138 // in case of error we return a default object
139 return t;
140 }
141 }
142
144 bool has(std::string const& key) const
145 {
146 return mStore.find(key) != mStore.end();
147 }
148
150 void clear()
151 {
152 mStore.clear();
153 }
154
156 void print(bool includetypeinfo = false) const;
157
160 {
161 mStore.clear();
162 mStore = other.mStore;
163 }
164
165 private:
166 std::map<std::string, SerializedInfo> mStore;
167
168 // generic implementation for put relying on TClass
169 template <typename T>
170 void put_impl(std::string const& key, T const& value, GetState& state, ...)
171 {
172 // make sure we have a TClass for this
173 // if there is a TClass, we'll use ROOT serialization to encode into the buffer
174 auto ptr = std::make_unique<T>(T{value});
175 auto cl = TClass::GetClass(typeid(value));
176 if (!cl) {
178 return;
179 }
180 std::unique_ptr<char> bufferptr(nullptr);
181 TBufferFile buff(TBuffer::kWrite);
182 buff.WriteObjectAny(ptr.get(), cl);
183 int N = buff.Length();
184 bufferptr.reset(new char[N]);
185 memcpy(bufferptr.get(), buff.Buffer(), sizeof(char) * N);
186
187 auto name = std::type_index(typeid(value)).name();
188 mStore.insert(std::pair<std::string, SerializedInfo>(key, SerializedInfo(N, std::move(bufferptr), cl, name)));
189 }
190
191 // implementation for put for trivial types
192 template <typename T, typename std::enable_if<std::is_trivial<T>::value, T>::type* = nullptr>
193 void put_impl(std::string const& key, T const& value, GetState& state, int)
194 {
195 // we forbid pointers
196 static_assert(!std::is_pointer<T>::value);
197 // serialization of trivial types is easy (not based on ROOT)
198 auto ptr = std::make_unique<T>(T{value});
199 int N = sizeof(T);
200 std::unique_ptr<char> bufferptr(new char[N]);
201 memcpy(bufferptr.get(), (char*)ptr.get(), sizeof(char) * N);
202
203 auto name = std::type_index(typeid(value)).name();
204 mStore.insert(std::pair<std::string, SerializedInfo>(key, SerializedInfo(N, std::move(bufferptr), nullptr, name)));
205 }
206
207 // generic implementation for get relying on TClass
208 template <typename T>
209 const T* get_impl(std::string const& key, GetState& state, ...) const
210 {
212 auto iter = mStore.find(key);
213 if (iter != mStore.end()) {
214 auto& info = const_cast<SerializedInfo&>(iter->second);
215 auto cl = TClass::GetClass(typeid(T));
216 if (!cl) {
218 return nullptr;
219 }
220 if (info.cl && strcmp(cl->GetName(), info.cl->GetName()) == 0) {
221 // if there is a (cached) object pointer ... we return it
222 if (info.objptr) {
223 return (T*)info.objptr;
224 }
225 // do this only once and cache instance into info.objptr
226 TBufferFile buff(TBuffer::kRead, info.N, info.bufferptr, false, nullptr);
227 buff.Reset();
228 auto instance = (T*)buff.ReadObjectAny(cl);
229 info.objptr = instance;
230 return (T*)info.objptr;
231 } else {
233 return nullptr;
234 }
235 }
237 return nullptr;
238 }
239
240 // implementation for standard POD types
241 template <typename T, typename std::enable_if<std::is_trivial<T>::value, T>::type* = nullptr>
242 const T* get_impl(std::string const& key, GetState& state, int) const
243 {
245 auto iter = mStore.find(key);
246 if (iter != mStore.end()) {
247 auto& info = const_cast<SerializedInfo&>(iter->second);
248 if (strcmp(std::type_index(typeid(T)).name(), info.typeinfo_name.c_str()) == 0) {
249 // if there is a (cached) object pointer ... we return it
250 if (info.objptr) {
251 return (T*)info.objptr;
252 }
253 info.objptr = (T*)info.bufferptr;
254 return (T*)info.objptr;
255 } else {
257 return nullptr;
258 }
259 }
261 return nullptr;
262 }
263
264 // removes a previous entry
265 void remove_entry(std::string const& key)
266 {
267 auto iter = mStore.find(key);
268 if (iter != mStore.end()) {
269 mStore.erase(iter);
270 }
271 }
272
273 ClassDefNV(RootSerializableKeyValueStore, 2);
274};
275
276} // namespace utils
277} // namespace o2
278
279#endif
benchmark::State & state
void print() const
TBranch * ptr
StringRef key
const T & getRef(std::string const &key, GetState &state) const
const T * get(std::string const &key, GetState &state) const
returns object pointer for this key or nullptr if error or does not exist; state is set with meaningf...
void put(std::string const &key, T const &value)
const T * get(std::string const &key) const
returns object pointer for this key or nullptr if error or does not exist.
static const char * getStateString(GetState state)
void copyFrom(RootSerializableKeyValueStore const &other)
resets store to the store of another object
bool has(std::string const &key) const
checks if a key exists
GLuint buffer
Definition glcorearb.h:655
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Common utility functions.
Structure encapsulating the stored information: raw buffers and attached type information (combinatio...
SerializedInfo(int N, std::unique_ptr< char > buffer, TClass const *cl, std::string const &s)
VectorOfTObjectPtrs other