1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 #ifndef STDADAPTORS_H
17 #define STDADAPTORS_H
18
19 #include "lib/StdCompiler.h"
20
21 // * Wrappers for C4Compiler-types
22
23 // Whole-line string, automatic size deduction (C4Compiler-String)
24 #define toC4CStr(szString) mkStringAdaptMA(szString)
25 #define toC4CStrBuf(rBuf) mkParAdapt(rBuf, StdCompiler::RCT_All)
26
27 // Integer-array with default 0, automatic size deduction
28 #define toC4CArr(rArr) mkArrayAdaptDM(rArr, 0)
29 #define toC4CArrU(rArr) mkArrayAdaptDM(rArr, 0u)
30
31 // * Null Adaptor
32 // Doesn't compile anything
33 struct StdNullAdapt
34 {
CompileFuncStdNullAdapt35 inline void CompileFunc(StdCompiler *pComp) const { }
36 };
37
38 // * Defaulting Adaptor
39 // Sets default if CompileFunc fails with a Exception of type NotFoundException
40 template <class T, class D>
41 struct StdDefaultAdapt
42 {
43 T &rValue; const D &rDefault;
StdDefaultAdaptStdDefaultAdapt44 StdDefaultAdapt(T &rValue, const D &rDefault) : rValue(rValue), rDefault(rDefault) { }
CompileFuncStdDefaultAdapt45 inline void CompileFunc(StdCompiler *pComp) const
46 {
47 try
48 {
49 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
50 if (!pComp->ValueSafe(rValue))
51 rValue = rDefault;
52 #else
53 pComp->Value(rValue);
54 #endif
55 }
56 catch (StdCompiler::NotFoundException *pEx)
57 {
58 rValue = rDefault;
59 delete pEx;
60 }
61 }
62 };
63 template <class T, class D>
mkDefaultAdapt(T && rValue,const D & rDefault)64 inline StdDefaultAdapt<T, D> mkDefaultAdapt(T &&rValue, const D &rDefault) { return StdDefaultAdapt<T, D>(rValue, rDefault); }
65
66 // * Naming Adaptor
67 // Embeds a value into a named section, failsafe
68 // (use for values that do defaulting themselves - e.g. objects using naming)
69 template <class T>
70 struct StdNamingAdapt
71 {
72 T &rValue; const char *szName;
StdNamingAdaptStdNamingAdapt73 StdNamingAdapt(T &rValue, const char *szName) : rValue(rValue), szName(szName) { }
CompileFuncStdNamingAdapt74 inline void CompileFunc(StdCompiler *pComp) const
75 {
76 pComp->Name(szName);
77 try
78 {
79 pComp->Value(rValue);
80 }
81 catch (StdCompiler::Exception *)
82 {
83 pComp->NameEnd(true);
84 throw;
85 }
86 pComp->NameEnd();
87 }
88 template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
89 template <class D> inline StdNamingAdapt &operator = (const D &nValue) { rValue = nValue; return *this; }
90 };
91 template <class T>
mkNamingAdapt(T && rValue,const char * szName)92 inline StdNamingAdapt<T> mkNamingAdapt(T &&rValue, const char *szName) { return StdNamingAdapt<T>(rValue, szName); }
93
94 // * Naming Adaptor (defaulting)
95 // Embeds a value into a named section, sets default on fail
96 template <class T, class D>
97 struct StdNamingDefaultAdapt
98 {
99 T &rValue; const char *szName; const D &rDefault; bool fPrefillDefault; bool fStoreDefault;
StdNamingDefaultAdaptStdNamingDefaultAdapt100 StdNamingDefaultAdapt(T &rValue, const char *szName, const D &rDefault, bool fPrefillDefault, bool fStoreDefault) : rValue(rValue), szName(szName), rDefault(rDefault), fPrefillDefault(fPrefillDefault), fStoreDefault(fStoreDefault) { }
CompileFuncStdNamingDefaultAdapt101 inline void CompileFunc(StdCompiler *pComp) const
102 {
103 // Default check
104 if (pComp->hasNaming() && pComp->isSerializer() && rValue == rDefault && !fStoreDefault)
105 {
106 if (pComp->Default(szName)) return;
107 }
108 try
109 {
110 // Search named section, set default if not found
111 if (pComp->Name(szName))
112 {
113 if (fPrefillDefault && pComp->isDeserializer()) rValue = rDefault; // default prefill if desired
114 pComp->Value(mkDefaultAdapt(rValue, rDefault));
115 }
116 else
117 rValue = rDefault;
118 }
119 catch (StdCompiler::Exception *)
120 {
121 pComp->NameEnd(true);
122 throw;
123 }
124 // End section
125 pComp->NameEnd();
126 }
127 };
128 template <class T, class D>
129 inline StdNamingDefaultAdapt<T,D> mkNamingAdapt(T &&rValue, const char *szName, const D &rDefault, bool fPrefillDefault=false, bool fStoreDefault=false) { return StdNamingDefaultAdapt<T,D>(rValue, szName, rDefault, fPrefillDefault, fStoreDefault); }
130
131 // * Decompiling Adaptor
132 // Allows to use const objects if the compiler won't change the targets
133 template <class T>
134 struct StdDecompileAdapt
135 {
136 const T &rValue;
StdDecompileAdaptStdDecompileAdapt137 explicit StdDecompileAdapt(const T &rValue) : rValue(rValue) { }
CompileFuncStdDecompileAdapt138 inline void CompileFunc(StdCompiler *pComp) const
139 {
140 assert(pComp->isSerializer());
141 pComp->Value(const_cast<T &>(rValue));
142 }
143
144 // make this work with in combination with StdParameterAdapt
145 template<typename ... P>
CompileFuncStdDecompileAdapt146 inline void CompileFunc(StdCompiler* pComp, P && ... pars) const
147 {
148 assert(pComp->isSerializer());
149 pComp->Value(mkParAdapt(const_cast<T &>(rValue), std::forward<P>(pars)...));
150 }
151 };
152 template <class T>
mkDecompileAdapt(const T & rValue)153 inline StdDecompileAdapt<T> mkDecompileAdapt(const T& rValue) { return StdDecompileAdapt<T>(rValue); }
154
155 // * Runtime value Adaptor
156 // Allows the C4ValueSetCompiler to set the value
157 template <class T>
158 struct StdRuntimeValueAdapt
159 {
160 T &rValue;
StdRuntimeValueAdaptStdRuntimeValueAdapt161 explicit StdRuntimeValueAdapt(T &rValue) : rValue(rValue) { }
CompileFuncStdRuntimeValueAdapt162 inline void CompileFunc(StdCompiler *pComp) const
163 {
164 pComp->setRuntimeWritesAllowed(+1);
165 pComp->Value(rValue);
166 pComp->setRuntimeWritesAllowed(-1);
167 }
168 template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
169 template <class D> inline StdRuntimeValueAdapt<T> &operator = (const D &nValue) { rValue = nValue; return *this; }
170 };
171 template <class T>
mkRuntimeValueAdapt(T && rValue)172 inline StdRuntimeValueAdapt<T> mkRuntimeValueAdapt(T &&rValue) { return StdRuntimeValueAdapt<T>(rValue); }
173
174 // * String adaptor
175 struct StdStringAdapt
176 {
177 char *szString; int iMaxLength; StdCompiler::RawCompileType eRawType;
178 StdStringAdapt(char *szString, int iMaxLength, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
szStringStdStringAdapt179 : szString(szString), iMaxLength(iMaxLength), eRawType(eRawType) { }
CompileFuncStdStringAdapt180 inline void CompileFunc(StdCompiler *pComp) const
181 {
182 pComp->String(szString, iMaxLength, eRawType);
183 }
184 inline bool operator == (const char *szDefault) const { return SEqual(szString, szDefault); }
185 inline StdStringAdapt &operator = (const char *szDefault) { SCopy(szDefault, szString, iMaxLength); return *this; }
186 };
187 inline StdStringAdapt mkStringAdapt(char *szString, int iMaxLength, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
188 { return StdStringAdapt(szString, iMaxLength, eRawType); }
189 #define mkStringAdaptM(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1)
190 #define mkStringAdaptMA(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1, StdCompiler::RCT_All)
191 #define mkStringAdaptMI(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1, StdCompiler::RCT_Idtf)
192 #define mkStringAdaptMIE(szString) mkStringAdapt(szString, (sizeof(szString) / sizeof(*szString)) - 1, StdCompiler::RCT_IdtfAllowEmpty)
193
194 // * std::string adaptor
195 struct StdStdStringAdapt
196 {
197 std::string& string; StdCompiler::RawCompileType eRawType;
198 StdStdStringAdapt(std::string& string, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
stringStdStdStringAdapt199 : string(string), eRawType(eRawType) { }
CompileFuncStdStdStringAdapt200 inline void CompileFunc(StdCompiler *pComp) const
201 {
202 pComp->String(string, eRawType);
203 }
204 inline bool operator == (const char *szDefault) const { return string == szDefault; }
205 inline StdStdStringAdapt &operator = (const char *szDefault) { string = szDefault; return *this; }
206 };
207 inline StdStdStringAdapt mkStringAdapt(std::string& string, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
208 { return StdStdStringAdapt(string, eRawType); }
mkStringAdaptA(std::string & string)209 inline StdStdStringAdapt mkStringAdaptA(std::string& string)
210 { return StdStdStringAdapt(string, StdCompiler::RCT_All); }
211
212 // * Raw adaptor
213 struct StdRawAdapt
214 {
215 void *pData; size_t iSize; StdCompiler::RawCompileType eRawType;
216 StdRawAdapt(void *pData, size_t iSize, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
pDataStdRawAdapt217 : pData(pData), iSize(iSize), eRawType(eRawType) { }
CompileFuncStdRawAdapt218 inline void CompileFunc(StdCompiler *pComp) const
219 {
220 pComp->Raw(pData, iSize, eRawType);
221 }
222 inline bool operator == (const void *pDefault) const { return !memcmp(pDefault, pData, iSize); }
223 inline StdRawAdapt &operator = (const void *pDefault) { memcpy(pData, pDefault, iSize); return *this; }
224 };
225 inline StdRawAdapt mkRawAdapt(void *pData, size_t iSize, StdCompiler::RawCompileType eRawType = StdCompiler::RCT_Escaped)
226 { return StdRawAdapt(pData, iSize, eRawType); }
227 #define mkRawAdaptM(X) mkRawAdapt(&X, sizeof(X))
228
229 // * Integer Adaptor
230 // Stores Integer-like datatypes (Enumerations)
231 template <class T, class int_t = int32_t>
232 struct StdIntAdapt
233 {
234 T &rValue;
StdIntAdaptStdIntAdapt235 explicit StdIntAdapt(T &rValue) : rValue(rValue) { }
CompileFuncStdIntAdapt236 inline void CompileFunc(StdCompiler *pComp) const
237 {
238 // Cast
239 int_t iVal = int_t(rValue);
240 pComp->Value(iVal);
241 rValue = T(iVal);
242 }
243 // Operators for default checking/setting
244 template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
245 template <class D> inline StdIntAdapt &operator = (const D &nValue) { rValue = nValue; return *this; }
246 };
mkIntAdapt(T & rValue)247 template <class T> inline StdIntAdapt<T> mkIntAdapt(T &rValue) { return StdIntAdapt<T>(rValue); }
mkIntAdaptT(T & rValue)248 template <class int_t, class T> StdIntAdapt<T, int_t> mkIntAdaptT(T &rValue) { return StdIntAdapt<T, int_t>(rValue); }
249
250 // * Casting Adaptor
251 // Does a reinterprete_cast
252 template <class T, class to_t>
253 struct StdCastAdapt
254 {
255 T &rValue;
StdCastAdaptStdCastAdapt256 explicit StdCastAdapt(T &rValue) : rValue(rValue) { }
CompileFuncStdCastAdapt257 inline void CompileFunc(StdCompiler *pComp) const
258 {
259 // Cast
260 static_assert(sizeof(to_t) == sizeof(T), "CastAdapt sanity: sizes match");
261 static_assert(std::is_pod<to_t>::value, "CastAdapt sanity: to-type is POD");
262 static_assert(std::is_pod<T>::value, "CastAdapt sanity: from-type is POD");
263 to_t vVal;
264 std::memcpy(&vVal, &rValue, sizeof(to_t));
265 pComp->Value(vVal);
266 std::memcpy(&rValue, &vVal, sizeof(T));
267 }
268 // Operators for default checking/setting
269 template <class D> inline bool operator == (const D &nValue) const { return rValue == nValue; }
270 template <class D> inline StdCastAdapt &operator = (const D &nValue) { rValue = nValue; return *this; }
271 };
mkCastAdapt(T & rValue)272 template <class to_t, class T> StdCastAdapt<T, to_t> mkCastAdapt(T &rValue) { return StdCastAdapt<T, to_t>(rValue); }
mkCastIntAdapt(T & rValue)273 template <class T> StdCastAdapt<T, int32_t> mkCastIntAdapt(T &rValue) { return StdCastAdapt<T, int32_t>(rValue); }
274
275 // Helper: Identity function class
276 template <class T>
277 struct _IdFuncClass
278 {
operator_IdFuncClass279 T &operator ()(T &rValue) const { return rValue; }
280 };
281
282 // * Array Adaptor
283 // Stores a separated list
284 template <class T, class M = _IdFuncClass<T> >
285 struct StdArrayAdapt
286 {
287 StdArrayAdapt(T *pArray, int iSize, M && map = M())
pArrayStdArrayAdapt288 : pArray(pArray), iSize(iSize), map(std::forward<M>(map))
289 { }
290 T *pArray; int iSize; M && map;
CompileFuncStdArrayAdapt291 inline void CompileFunc(StdCompiler *pComp) const
292 {
293 for (int i = 0; i < iSize; i++)
294 {
295 if (i) pComp->Separator(StdCompiler::SEP_SEP);
296 pComp->Value(map(pArray[i]));
297 }
298 }
299 // Operators for default checking/setting
300 inline bool operator == (const T &rDefault) const
301 {
302 for (int i = 0; i < iSize; i++)
303 if (pArray[i] != rDefault)
304 return false;
305 return true;
306 }
307 inline StdArrayAdapt &operator = (const T &rDefault)
308 {
309 for (int i = 0; i < iSize; i++)
310 pArray[i] = rDefault;
311 return *this;
312 }
313 inline bool operator == (const T *pDefaults) const
314 {
315 for (int i = 0; i < iSize; i++)
316 if (pArray[i] != pDefaults[i])
317 return false;
318 return true;
319 }
320 inline StdArrayAdapt &operator = (const T *pDefaults)
321 {
322 for (int i = 0; i < iSize; i++)
323 pArray[i] = pDefaults[i];
324 return *this;
325 }
326 };
327 template <class T>
mkArrayAdapt(T * pArray,int iSize)328 inline StdArrayAdapt<T> mkArrayAdapt(T *pArray, int iSize) { return StdArrayAdapt<T>(pArray, iSize); }
329 #define mkArrayAdaptM(A) mkArrayAdapt(A, sizeof(A) / sizeof(*(A)))
330 template <class T, class M>
mkArrayAdaptMap(T * pArray,int iSize,M && map)331 inline StdArrayAdapt<T, M> mkArrayAdaptMap(T *pArray, int iSize, M && map) { return StdArrayAdapt<T, M>(pArray, iSize, std::forward<M>(map)); }
332 #define mkArrayAdaptMapM(A, M) mkArrayAdaptMap(A, sizeof(A) / sizeof(*(A)), M)
333
334 // * Array Adaptor (defaulting)
335 // Stores a separated list, sets defaults if a value or separator is missing.
336 template <class T, class D, class M = _IdFuncClass<T> >
337 struct StdArrayDefaultAdapt
338 {
339 StdArrayDefaultAdapt(T *pArray, size_t iSize, const D &rDefault, const M &map = M())
pArrayStdArrayDefaultAdapt340 : pArray(pArray), iSize(iSize), rDefault(rDefault), map(map)
341 { }
342 T *pArray; size_t iSize; const D &rDefault; const M map;
CompileFuncStdArrayDefaultAdapt343 inline void CompileFunc(StdCompiler *pComp) const
344 {
345 size_t i, iWrite = iSize;
346 bool deserializing = pComp->isDeserializer();
347 // Decompiling: Omit defaults
348 if (!deserializing && pComp->hasNaming())
349 while (iWrite > 0 && pArray[iWrite - 1] == rDefault)
350 iWrite--;
351 // Read/write values
352 for (i = 0; i < iWrite; i++)
353 {
354 // Separator?
355 if (i) if (!pComp->Separator(StdCompiler::SEP_SEP)) break;
356 // Expect a value. Default if not found.
357 pComp->Value(mkDefaultAdapt(map(pArray[i]), rDefault));
358 }
359 // Fill rest of array
360 if (deserializing)
361 for (; i < iSize; i++)
362 pArray[i] = rDefault;
363 }
364 // Additional defaulting (whole array)
365 inline bool operator == (const T *pDefaults) const
366 {
367 for (size_t i = 0; i < iSize; i++)
368 if (pArray[i] != pDefaults[i])
369 return false;
370 return true;
371 }
372 inline StdArrayDefaultAdapt &operator = (const T *pDefaults)
373 {
374 for (size_t i = 0; i < iSize; i++)
375 pArray[i] = pDefaults[i];
376 return *this;
377 }
378 };
379 template <class T, class D>
mkArrayAdapt(T * pArray,size_t iSize,const D & rDefault)380 inline StdArrayDefaultAdapt<T, D> mkArrayAdapt(T *pArray, size_t iSize, const D &rDefault) { return StdArrayDefaultAdapt<T, D>(pArray, iSize, rDefault); }
381 #define mkArrayAdaptDM(A, D) mkArrayAdapt(A, sizeof(A) / sizeof(*(A)), D)
382 template <class T, class D, class M>
mkArrayAdaptMap(T * pArray,size_t iSize,const D & rDefault,M map)383 inline StdArrayDefaultAdapt<T, D, M> mkArrayAdaptMap(T *pArray, size_t iSize, const D &rDefault, M map) { return StdArrayDefaultAdapt<T, D, M>(pArray, iSize, rDefault, map); }
384 #define mkArrayAdaptMapDM(A, D, M) mkArrayAdaptMap(A, sizeof(A) / sizeof(*(A)), D, M)
385
386 // * Array Adaptor (defaulting to another array)
387 // Stores a separated list, sets defaults if a value or separator is missing.
388 template <class T, class D, class M = _IdFuncClass<T> >
389 struct StdArrayDefaultArrayAdapt
390 {
391 StdArrayDefaultArrayAdapt(T *pArray, size_t iSize, const D &rDefault, const M &map = M())
pArrayStdArrayDefaultArrayAdapt392 : pArray(pArray), iSize(iSize), rDefault(rDefault), map(map)
393 { }
394 T *pArray; size_t iSize; const D &rDefault; const M map;
CompileFuncStdArrayDefaultArrayAdapt395 inline void CompileFunc(StdCompiler *pComp) const
396 {
397 size_t i, iWrite = iSize;
398 bool deserializing = pComp->isDeserializer();
399 // Decompiling: Omit defaults
400 if (!deserializing && pComp->hasNaming())
401 while (iWrite > 0 && pArray[iWrite - 1] == rDefault[iWrite - 1])
402 iWrite--;
403 // Read/write values
404 for (i = 0; i < iWrite; i++)
405 {
406 // Separator?
407 if (i) if (!pComp->Separator(StdCompiler::SEP_SEP)) break;
408 // Expect a value. Default if not found.
409 pComp->Value(mkDefaultAdapt(map(pArray[i]), rDefault[i]));
410 }
411 // Fill rest of array
412 if (deserializing)
413 for (; i < iSize; i++)
414 pArray[i] = rDefault[i];
415 }
416 // Additional defaulting (whole array)
417 inline bool operator == (const T *pDefaults) const
418 {
419 for (size_t i = 0; i < iSize; i++)
420 if (pArray[i] != pDefaults[i])
421 return false;
422 return true;
423 }
424 inline StdArrayDefaultArrayAdapt &operator = (const T *pDefaults)
425 {
426 for (size_t i = 0; i < iSize; i++)
427 pArray[i] = pDefaults[i];
428 return *this;
429 }
430 };
431 template <class T, class D>
mkArrayAdaptDefArr(T * pArray,size_t iSize,const D & rDefault)432 inline StdArrayDefaultArrayAdapt<T, D> mkArrayAdaptDefArr(T *pArray, size_t iSize, const D &rDefault) { return StdArrayDefaultArrayAdapt<T, D>(pArray, iSize, rDefault); }
433 #define mkArrayAdaptDMA(A, D) mkArrayAdaptDefArr(A, sizeof(A) / sizeof(*(A)), D)
434 template <class T, class D, class M>
mkArrayAdaptDefArrMap(T * pArray,size_t iSize,const D & rDefault,const M & map)435 inline StdArrayDefaultArrayAdapt<T, D, M> mkArrayAdaptDefArrMap(T *pArray, size_t iSize, const D &rDefault, const M &map) { return StdArrayDefaultArrayAdapt<T, D, M>(pArray, iSize, rDefault, map); }
436 #define mkArrayAdaptDMAM(A, D, M) mkArrayAdaptDefArrMap(A, sizeof(A) / sizeof(*(A)), D, M)
437
438 // * Insertion Adaptor
439 // Compile a value before / after another
440 template <class T, class I>
441 struct StdInsertAdapt
442 {
443 StdInsertAdapt(T &rObj, I &rIns, bool fBefore = true)
rObjStdInsertAdapt444 : rObj(rObj), rIns(rIns), fBefore(fBefore)
445 { }
446 T &rObj; I &rIns; bool fBefore;
CompileFuncStdInsertAdapt447 void CompileFunc(StdCompiler *pComp) const
448 {
449 if (fBefore) pComp->Value(rIns);
450 pComp->Value(rObj);
451 if (!fBefore) pComp->Value(rIns);
452 }
453 };
454 template <class T, class I>
455 inline StdInsertAdapt<T, I> mkInsertAdapt(T &&rObj, I &&rIns, bool fBefore = true) { return StdInsertAdapt<T,I>(rObj, rIns, fBefore); }
456
457 // * Parameter Adaptor
458 // Specify a second parameter for the CompileFunc
459 template <class T, class P>
460 struct StdParameterAdapt
461 {
StdParameterAdaptStdParameterAdapt462 StdParameterAdapt(T && rObj, P && rPar) : rObj(std::forward<T>(rObj)), Par(std::forward<P>(rPar)) { }
463 T && rObj; P && Par;
CompileFuncStdParameterAdapt464 void CompileFunc(StdCompiler *pComp) const
465 {
466 std::forward<T>(rObj).CompileFunc(pComp, std::forward<P>(Par));
467 }
468 // Operators for default checking/setting
469 template <class D> inline bool operator == (const D &nValue) const { return rObj == nValue; }
470 template <class D> inline StdParameterAdapt &operator = (const D &nValue) { rObj = nValue; return *this; }
471
472 // getting value
GetObjStdParameterAdapt473 inline T && GetObj() { return std::forward<T>(rObj); }
474 };
475 template <class T, class P>
mkParAdapt(T && rObj,P && rPar)476 inline StdParameterAdapt<T, P> mkParAdapt(T && rObj, P && rPar)
477 { return StdParameterAdapt<T, P>(std::forward<T>(rObj), std::forward<P>(rPar)); }
478
479 // for mkArrayAdaptMap
480 template <class P>
481 struct StdParameterAdaptMaker
482 {
483 P && Par;
StdParameterAdaptMakerStdParameterAdaptMaker484 StdParameterAdaptMaker(P && rPar) : Par(std::forward<P>(rPar)) { }
485 template <class T>
operatorStdParameterAdaptMaker486 StdParameterAdapt<T, P> operator ()(T && rObj) const { return StdParameterAdapt<T, P>(std::forward<T>(rObj), std::forward<P>(Par)); }
487 };
488 template <class P>
mkParAdaptMaker(P && rPar)489 inline StdParameterAdaptMaker<P> mkParAdaptMaker(P && rPar) { return StdParameterAdaptMaker<P>(std::forward<P>(rPar)); }
490
491 // * Parameter Adaptor 2
492 // Specify a second and a third parameter for the CompileFunc
493 template <class T, class P1, class P2>
494 struct StdParameter2Adapt
495 {
StdParameter2AdaptStdParameter2Adapt496 StdParameter2Adapt(T && rObj, P1 && rPar1, P2 && rPar2) :
497 rObj(std::forward<T>(rObj)), rPar1(std::forward<P1>(rPar1)), rPar2(std::forward<P2>(rPar2)) { }
498 T && rObj; P1 && rPar1; P2 && rPar2;
CompileFuncStdParameter2Adapt499 void CompileFunc(StdCompiler *pComp) const
500 {
501 std::forward<T>(rObj).CompileFunc(pComp, std::forward<P1>(rPar1), std::forward<P2>(rPar2));
502 }
503 // Operators for default checking/setting
504 template <class D> inline bool operator == (const D &nValue) const { return rObj == nValue; }
505 template <class D> inline StdParameter2Adapt &operator = (const D &nValue) { rObj = nValue; return *this; }
506 };
507 template <class T, class P1, class P2>
mkParAdapt(T && rObj,P1 && rPar1,P2 && rPar2)508 inline StdParameter2Adapt<T, P1, P2> mkParAdapt(T && rObj, P1 && rPar1, P2 && rPar2)
509 { return StdParameter2Adapt<T, P1, P2>(std::forward<T>(rObj), std::forward<P1>(rPar1), std::forward<P2>(rPar2)); }
510
511 template <class T>
512 struct StdBasicPtrAdapt
513 {
514 StdBasicPtrAdapt(T *&rpObj, bool fAllowNull = true, const char *szNaming = "Data")
rpObjStdBasicPtrAdapt515 : rpObj(rpObj), fAllowNull(fAllowNull), szNaming(szNaming) {}
516 T *&rpObj; bool fAllowNull; const char *szNaming;
517
518 // Operators for default checking/setting
519 inline bool operator == (const T &nValue) const { return rpObj && *rpObj == nValue; }
520 inline StdBasicPtrAdapt &operator = (const T &nValue) { delete rpObj; rpObj = new T(nValue); return *this; }
521 inline bool operator == (const T *pValue) const { return rpObj == pValue; }
522 inline StdBasicPtrAdapt &operator = (const T *pValue) { delete rpObj; rpObj = pValue; return *this; }
523 };
524
525 // * Store pointer (contents)
526 // Defaults to null
527 template <class T>
528 struct StdPtrAdapt: StdBasicPtrAdapt<T>
529 {
530 StdPtrAdapt(T *&rpObj, bool fAllowNull = true, const char *szNaming = "Data")
531 : StdBasicPtrAdapt<T>(rpObj, fAllowNull, szNaming)
532 { }
533
CompileFuncStdPtrAdapt534 void CompileFunc(StdCompiler *pComp) const
535 {
536 StdPtrAdaptCompileFunc(pComp, *this);
537 }
538
539 // For use with StdParAdapt
540 template<typename ... P>
CompileFuncStdPtrAdapt541 void CompileFunc(StdCompiler *pComp, P && ...pars)
542 {
543 StdPtrAdaptCompileFunc(pComp, *this, std::forward<P>(pars)...);
544 }
545 };
546
547 template <class T, class ContextT>
548 struct StdContextPtrAdapt: StdBasicPtrAdapt<T>
549 {
550 StdContextPtrAdapt(T *&rpObj, const ContextT& rCtx, bool fAllowNull = true, const char *szNaming = "Data")
551 : StdBasicPtrAdapt<T>(rpObj, fAllowNull, szNaming), pCtx(&rCtx)
552 { }
553
554 const ContextT* pCtx;
555
CompileFuncStdContextPtrAdapt556 void CompileFunc(StdCompiler *pComp) const
557 {
558 StdPtrAdaptCompileFunc(pComp, *this);
559 }
560
561 // For use with StdParAdapt
562 template<class P>
CompileFuncStdContextPtrAdapt563 void CompileFunc(StdCompiler *pComp, const P& p)
564 {
565 StdPtrAdaptCompileFunc(pComp, *this, p);
566 }
567 };
568
569 template <class T, typename ... P>
StdPtrAdaptCompileFunc(StdCompiler * pComp,const T & adapt,P &&...pars)570 void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt, P && ...pars)
571 {
572 bool deserializing = pComp->isDeserializer(),
573 fNaming = pComp->hasNaming();
574 // Compiling? Clear object before
575 if(deserializing) { delete adapt.rpObj; adapt.rpObj = nullptr; }
576 // Null checks - different with naming support.
577 if(adapt.fAllowNull)
578 if(fNaming)
579 {
580 // Null check: just omit when writing
581 if(!deserializing && !adapt.rpObj) return;
582 // Set up naming
583 if(!pComp->Name(adapt.szNaming)) { assert(deserializing); pComp->NameEnd(); return; }
584 }
585 else
586 {
587 bool fNull = !! adapt.rpObj;
588 pComp->Value(fNull);
589 // Null? Nothing further to do
590 if(fNull) return;
591 }
592 else if(!deserializing)
593 assert(adapt.rpObj);
594 // Compile value
595 if(deserializing)
596 StdPtrAdaptCompileNewFunc(adapt, pComp, std::forward<P>(pars)...);
597 else
598 StdPtrAdaptDecompileNewFunc(adapt, pComp, std::forward<P>(pars)...);
599
600 // Close naming
601 if(adapt.fAllowNull && fNaming) pComp->NameEnd();
602 }
603
604
605 template <class T, typename ... P>
StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T> & adapt,StdCompiler * pComp,P &&...pars)606 void StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFunc(adapt.rpObj, pComp, std::forward<P>(pars)...); }
607 template <class T, class ContextT, typename ... P>
StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T,ContextT> & adapt,StdCompiler * pComp,P &&...pars)608 void StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFuncCtx(adapt.rpObj, pComp, *adapt.pCtx, std::forward<P>(pars)...); }
609
610 template <class T>
StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T> & adapt,StdCompiler * pComp)611 void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); }
612 template <class T, class ContextT>
StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T,ContextT> & adapt,StdCompiler * pComp)613 void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); }
614 template <class T, typename ... P>
StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T> & adapt,StdCompiler * pComp,P &&...pars)615 void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward<P>(pars)...)); }
616 template <class T, class ContextT, typename ... P>
StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T,ContextT> & adapt,StdCompiler * pComp,P &&...pars)617 void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward<P>(pars)...)); }
618
619 template <class T>
620 inline StdPtrAdapt<T> mkPtrAdapt(T *&rpObj, bool fAllowNull = true) { return StdPtrAdapt<T>(rpObj, fAllowNull); }
621 template <class T>
mkNamingPtrAdapt(T * & rpObj,const char * szNaming)622 inline StdPtrAdapt<T> mkNamingPtrAdapt(T *&rpObj, const char *szNaming) { return StdPtrAdapt<T>(rpObj, true, szNaming); }
623 template <class T>
mkPtrAdaptNoNull(T * & rpObj)624 inline StdPtrAdapt<T> mkPtrAdaptNoNull(T *&rpObj) { return mkPtrAdapt<T>(rpObj, false); }
625
626 template <class T, class ContextT>
627 inline StdContextPtrAdapt<T, ContextT> mkContextPtrAdapt(T *&rpObj, const ContextT& ctx, bool fAllowNull = true) { return StdContextPtrAdapt<T, ContextT>(rpObj, ctx, fAllowNull); }
628 template <class T, class ContextT>
mkNamingContextPtrAdapt(T * & rpObj,const ContextT & ctx,const char * szNaming)629 inline StdContextPtrAdapt<T, ContextT> mkNamingContextPtrAdapt(T *&rpObj, const ContextT& ctx, const char* szNaming) { return StdContextPtrAdapt<T, ContextT>(rpObj, ctx, true, szNaming); }
630 template <class T, class ContextT>
mkContextPtrAdaptNoNull(T * & rpObj,const ContextT & ctx)631 inline StdContextPtrAdapt<T, ContextT> mkContextPtrAdaptNoNull(T *&rpObj, const ContextT& ctx) { return mkContextPtrAdapt<T, ContextT>(rpObj, ctx, false); }
632
633 // * Adaptor for STL containers
634 // Writes a comma-separated list for compilers that support it. Otherwise, the size is calculated and safed.
635 // The defaulting uses the standard STL operators (full match)
636 template <class C>
637 struct StdSTLContainerAdapt
638 {
639 StdSTLContainerAdapt(C &rStruct, StdCompiler::Sep eSep = StdCompiler::SEP_SEP)
rStructStdSTLContainerAdapt640 : rStruct(rStruct), eSep(eSep) { }
641 C &rStruct; const StdCompiler::Sep eSep;
CompileFuncStdSTLContainerAdapt642 inline void CompileFunc(StdCompiler *pComp) const
643 {
644 typedef typename C::value_type T;
645 // Get compiler specs
646 bool deserializing = pComp->isDeserializer();
647 bool fNaming = pComp->hasNaming();
648 // Decompiling?
649 if (!deserializing)
650 {
651 // Write size (binary only)
652 if (!fNaming)
653 {
654 int32_t iSize = rStruct.size();
655 pComp->Value(iSize);
656 }
657 // Write all entries
658 for (typename C::const_iterator i = rStruct.begin(); i != rStruct.end(); ++i)
659 {
660 if (i != rStruct.begin() && eSep) pComp->Separator(eSep);
661 pComp->Value(const_cast<T &>(*i));
662 }
663 }
664 else
665 {
666 // Compiling: Empty previous
667 rStruct.clear();
668 // Read size (binary only)
669 uint32_t iSize;
670 if (!fNaming) pComp->Value(iSize);
671 // Read new
672 do
673 {
674 // No entries left to read?
675 if (!fNaming && !iSize--)
676 break;
677 // Read entries
678 try
679 {
680 T val;
681 pComp->Value(val);
682 rStruct.push_back(val);
683 }
684 catch (StdCompiler::NotFoundException *pEx)
685 {
686 // No value found: Stop reading loop
687 delete pEx;
688 break;
689 }
690 }
691 while (!eSep || pComp->Separator(eSep));
692 }
693 }
694 // Operators for default checking/setting
695 inline bool operator == (const C &nValue) const { return rStruct == nValue; }
696 inline StdSTLContainerAdapt &operator = (const C &nValue) { rStruct = nValue; return *this; }
697 };
698 template <class C>
699 inline StdSTLContainerAdapt<C> mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep = StdCompiler::SEP_SEP) { return StdSTLContainerAdapt<C>(rTarget, eSep); }
700
701 // Write an integer that is supposed to be small most of the time. The adaptor writes it in
702 // 7-bit-pieces, bit 8 being a continuation marker: If it's set, more data is following, if not,
703 // all following bits are 0.
704 // Code lengths for uint32_t:
705 // 0x00000000 (0) - 0x0000007F (127) : 1 byte
706 // 0x00000080 (128) - 0x00003FFF (16383) : 2 byte
707 // 0x00004000 (16384) - 0x001FFFFF (2097151) : 3 byte
708 // 0x00200000 (2097152) - 0x0FFFFFFF (268435456) : 4 byte
709 // 0x10000000 (268435456) - 0xFFFFFFFF (4294967295) : 5 byte
710 // So this sort of packing is always useful when the integer in question is almost impossible to
711 // grow bigger than 2,097,151.
712 template <class T>
713 struct StdIntPackAdapt
714 {
StdIntPackAdaptStdIntPackAdapt715 StdIntPackAdapt(T &rVal) : rVal(rVal) { }
716 T &rVal;
717
clearUpperStdIntPackAdapt718 inline T clearUpper(T x) const
719 {
720 const int CLEARBITS = 8 * sizeof(T) - 7;
721 return (x << CLEARBITS) >> CLEARBITS;
722 }
723
CompileFuncStdIntPackAdapt724 void CompileFunc(StdCompiler *pComp) const
725 {
726 // simply write for textual compilers
727 if (pComp->hasNaming())
728 {
729 pComp->Value(rVal);
730 return;
731 }
732 T val; uint8_t tmp;
733 // writing?
734 if (!pComp->isDeserializer())
735 {
736 val = rVal;
737 for (;;)
738 {
739 tmp = uint8_t(clearUpper(val));
740 // last byte?
741 if (clearUpper(val) == val)
742 break;
743 // write byte
744 tmp ^= 0x80; pComp->Value(tmp);
745 // advance
746 val >>= 7;
747 }
748 // write last byte
749 pComp->Value(tmp);
750 }
751 // reading?
752 else
753 {
754 // read first byte
755 pComp->Value(tmp);
756 val = clearUpper(T(tmp));
757 // read remaining bytes
758 int i = 7; T data = val;
759 while ( uint8_t(data) != tmp )
760 {
761 // read byte
762 pComp->Value(tmp);
763 // add to value
764 data = clearUpper(T(tmp));
765 val = (data << i) | (val & ((1 << i) - 1));
766 // next byte
767 i+=7;
768 }
769 // write
770 rVal = val;
771 }
772 }
773 template <class D> inline bool operator == (const D &nValue) const { return rVal == nValue; }
774 template <class D> inline StdIntPackAdapt &operator = (const D &nValue) { rVal = nValue; return *this; }
775 };
776 template <class T>
mkIntPackAdapt(T & rVal)777 StdIntPackAdapt<T> mkIntPackAdapt(T &rVal) { return StdIntPackAdapt<T>(rVal); }
778
779 template <class T>
780 struct StdEnumEntry
781 {
782 const char *Name;
783 T Val;
784 };
785
786 // Enumeration: For text compilers, write a given name for a value.
787 // For everything else, just write an integer of given type.
788 template <class T, class int_t = int32_t>
789 struct StdEnumAdapt
790 {
791 typedef StdEnumEntry<T> Entry;
792
StdEnumAdaptStdEnumAdapt793 StdEnumAdapt(T &rVal, const Entry *pNames) : rVal(rVal), pNames(pNames) { assert(pNames); }
794 T &rVal; const Entry *pNames;
795
CompileFuncStdEnumAdapt796 void CompileFunc(StdCompiler *pComp) const
797 {
798 // Write as int
799 if (!pComp->isVerbose())
800 {
801 pComp->Value(mkIntAdaptT<int_t>(rVal));
802 return;
803 }
804 // writing?
805 if (!pComp->isDeserializer())
806 {
807 // Find value
808 const Entry *pName = pNames;
809 for (; pName->Name; pName++)
810 if (pName->Val == rVal)
811 {
812 // Put name
813 pComp->String(const_cast<char **>(&pName->Name), StdCompiler::RCT_Idtf);
814 break;
815 }
816 // No name found?
817 if (!pName->Name)
818 // Put value as integer
819 pComp->Value(mkIntAdaptT<int_t>(rVal));
820 }
821 // reading?
822 else
823 {
824 int_t val = 0;
825 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
826 // Try to read as number
827 if (!pComp->ValueSafe(val))
828 {
829 rVal = T(val);
830 #else
831 // Try to read as number
832 try
833 {
834 pComp->Value(val);
835 rVal = T(val);
836 }
837 catch (StdCompiler::NotFoundException *pEx)
838 {
839 delete pEx;
840 #endif
841 // Try to read as string
842 StdStrBuf Name;
843 pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf));
844 // Search in name list
845 const Entry *pName = pNames;
846 for (; pName->Name; pName++)
847 if (Name == pName->Name)
848 {
849 rVal = pName->Val;
850 break;
851 }
852 // Not found? Warn
853 if (!pName->Name)
854 pComp->Warn("Unknown bit name: %s", Name.getData());
855 }
856 }
857 }
858
859 template <class D> inline bool operator == (const D &nValue) const { return rVal == nValue; }
860 template <class D> inline StdEnumAdapt<T, int_t> &operator = (const D &nValue) { rVal = nValue; return *this; }
861 };
862 template <class T, class int_t>
mkEnumAdapt(T & rVal,const StdEnumEntry<T> * pNames)863 StdEnumAdapt<T, int_t> mkEnumAdapt(T &rVal, const StdEnumEntry<T> *pNames) { return StdEnumAdapt<T, int_t>(rVal, pNames); }
864 template <class int_t, class T>
mkEnumAdaptT(T & rVal,const StdEnumEntry<T> * pNames)865 StdEnumAdapt<T, int_t> mkEnumAdaptT(T &rVal, const StdEnumEntry<T> *pNames) { return StdEnumAdapt<T, int_t>(rVal, pNames); }
866
867 template <class T>
868 struct StdBitfieldEntry
869 {
870 const char *Name;
871 T Val;
872 };
873
874 // Convert a bitfield into/from something like "foo | bar | baz", where "foo", "bar" and "baz" are given constants.
875 template <class T>
876 struct StdBitfieldAdapt
877 {
878 typedef StdBitfieldEntry<T> Entry;
879
StdBitfieldAdaptStdBitfieldAdapt880 StdBitfieldAdapt(T &rVal, const Entry *pNames) : rVal(rVal), pNames(pNames) { assert(pNames); }
881 T &rVal; const Entry *pNames;
882
CompileFuncStdBitfieldAdapt883 void CompileFunc(StdCompiler *pComp) const
884 {
885 // simply write for non-verbose compilers
886 if (!pComp->isVerbose())
887 {
888 pComp->Value(rVal);
889 return;
890 }
891 // writing?
892 if (!pComp->isDeserializer())
893 {
894 T val = rVal, orig_val = rVal;
895 // Write until value is comsumed
896 bool fFirst = true;
897 for (const Entry *pName = pNames; pName->Name; pName++)
898 if ((pName->Val & val) == pName->Val)
899 {
900 // Avoid writing meaningless none-values (e.g. Category=C4D_None|C4D_Object)
901 if (orig_val && !pName->Val) continue;
902 // Put "|"
903 if (!fFirst) pComp->Separator(StdCompiler::SEP_VLINE);
904 // Put name
905 pComp->String(const_cast<char **>(&pName->Name), StdCompiler::RCT_Idtf);
906 fFirst = false;
907 // Remove bits
908 val &= ~pName->Val;
909 }
910 // Anything left is written as number, or a simple 0 in case no default was used
911 if (val || fFirst)
912 {
913 // Put "|"
914 if (!fFirst) pComp->Separator(StdCompiler::SEP_VLINE);
915 // Put value
916 pComp->Value(val);
917 }
918 }
919 // reading?
920 else
921 {
922 T val = 0;
923 // Read
924 do
925 {
926 #ifdef STDCOMPILER_EXCEPTION_WORKAROUND
927 T tmp;
928 // Try to read as number
929 if (pComp->ValueSafe(tmp))
930 val |= tmp;
931 else
932 {
933 #else
934 // Try to read as number
935 try
936 {
937 T tmp;
938 pComp->Value(tmp);
939 val |= tmp;
940 }
941 catch (StdCompiler::NotFoundException *pEx)
942 {
943 delete pEx;
944 #endif
945 // Try to read as string
946 StdStrBuf Name;
947 pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf));
948 // Search in name list
949 const Entry *pName = pNames;
950 for (; pName->Name; pName++)
951 if (Name == pName->Name)
952 {
953 val |= pName->Val;
954 break;
955 }
956 // Not found? Warn
957 if (!pName->Name)
958 pComp->Warn("Unknown bit name: %s", Name.getData());
959 }
960 // Expect separation
961 } while (pComp->Separator(StdCompiler::SEP_VLINE));
962 // Write value back
963 rVal = val;
964 }
965 }
966
967 template <class D> inline bool operator == (const D &nValue) const { return rVal == nValue; }
968 template <class D> inline StdBitfieldAdapt<T> &operator = (const D &nValue) { rVal = nValue; return *this; }
969 };
970 template <class T>
mkBitfieldAdapt(T & rVal,const StdBitfieldEntry<T> * pNames)971 StdBitfieldAdapt<T> mkBitfieldAdapt(T &rVal, const StdBitfieldEntry<T> *pNames) { return StdBitfieldAdapt<T>(rVal, pNames); }
972
973 // * Name count adapter
974 // For compilers without name support, this just compiles the given value. Otherwise, the count
975 // of given namings is returned on compiling, and nothing is done for decompiling (The caller
976 // has to make sure that an appropriate number of namings will be created)
977 template <class int_t>
978 struct StdNamingCountAdapt
979 {
980 int_t &iCount; const char *szName;
StdNamingCountAdaptStdNamingCountAdapt981 StdNamingCountAdapt(int_t &iCount, const char *szName) : iCount(iCount), szName(szName) { }
CompileFuncStdNamingCountAdapt982 inline void CompileFunc(StdCompiler *pComp) const
983 {
984 if (pComp->hasNaming())
985 {
986 if (pComp->isDeserializer())
987 iCount = pComp->NameCount(szName);
988 }
989 else
990 pComp->Value(mkIntPackAdapt(iCount));
991 }
992 };
993 template <class int_t>
mkNamingCountAdapt(int_t & iCount,const char * szName)994 inline StdNamingCountAdapt<int_t> mkNamingCountAdapt(int_t &iCount, const char *szName) { return StdNamingCountAdapt<int_t>(iCount, szName); }
995
996 // * Hex adapter
997 // Writes raw binary data in hexadecimal
998 class StdHexAdapt
999 {
1000 void *pData; size_t iSize;
1001 public:
StdHexAdapt(void * pData,size_t iSize)1002 StdHexAdapt(void *pData, size_t iSize) : pData(pData), iSize(iSize) { }
CompileFunc(StdCompiler * pComp)1003 inline void CompileFunc(StdCompiler *pComp) const
1004 {
1005 if (!pComp->isVerbose())
1006 pComp->Raw(pData, iSize);
1007 char szData[2+1]; bool deserializing = pComp->isDeserializer();
1008 for (size_t i = 0; i < iSize; i++)
1009 {
1010 uint8_t *pByte = reinterpret_cast<uint8_t *>(pData) + i;
1011 if (!deserializing) sprintf(szData, "%02x", *pByte);
1012 pComp->String(szData, 2, StdCompiler::RCT_Idtf);
1013 if (deserializing)
1014 {
1015 unsigned int b;
1016 if (sscanf(szData, "%02x", &b) != 1)
1017 pComp->excNotFound(i ? "hexadecimal data: bytes missing!" : "hexadecimal data missing!");
1018 *pByte = b;
1019 }
1020 }
1021 }
1022 };
mkHexAdapt(void * pData,size_t iSize)1023 inline StdHexAdapt mkHexAdapt(void *pData, size_t iSize) { return StdHexAdapt(pData, iSize); }
1024 template <class T>
mkHexAdapt(T & rData)1025 inline StdHexAdapt mkHexAdapt(T &rData) { return StdHexAdapt(&rData, sizeof(rData)); }
1026
1027
1028 #endif //STDADAPTORS_H
1029