]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_value.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_value.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_value.h
28 #pragma once
29
30 #include "vogl_core.h"
31 #include "vogl_strutils.h"
32 #include "vogl_dynamic_string.h"
33 #include "vogl_vec.h"
34 #include "vogl_hash_map.h"
35 #include "vogl_data_stream.h"
36 #include "vogl_json.h"
37
38 namespace vogl
39 {
40     // adding: uint8, int64_t, uint64_t, double, blob
41     enum value_data_type
42     {
43         cDTInvalid,
44         cDTBool,
45         cDTInt8,
46         cDTUInt8,
47         cDTInt16,
48         cDTUInt16,
49         cDTInt,
50         cDTUInt,
51         cDTInt64,
52         cDTUInt64,
53         cDTFloat,
54         cDTDouble,
55         cDTVoidPtr,
56         cDTStringHash,
57         cDTFirstDynamic,
58         cDTString = cDTFirstDynamic,
59         cDTVec3F,
60         cDTVec3I,
61         cDTBlob,
62         cDTJSONDoc,
63         cDTTotal
64     };
65
66     extern const char *g_value_data_type_strings[cDTTotal + 1];
67
68     value_data_type string_to_value_data_type(const char *pStr);
69
70     class value
71     {
72         enum
73         {
74             cFlagsHasUserData = 1
75         };
76
77     public:
78         inline value()
79             : m_uint64(0),
80               m_user_data(0),
81               m_type(cDTInvalid),
82               m_flags(0)
83         {
84             VOGL_ASSUME(sizeof(float) == sizeof(int));
85             VOGL_ASSUME(sizeof(double) == sizeof(uint64_t));
86         }
87
88         inline value(const char *pStr)
89             : m_pStr(vogl_new(dynamic_string, pStr)), m_user_data(0), m_type(cDTString), m_flags(0)
90         {
91         }
92
93         inline value(const dynamic_string &str)
94             : m_pStr(vogl_new(dynamic_string, str)), m_user_data(0), m_type(cDTString), m_flags(0)
95         {
96         }
97
98         inline value(const uint8 *pBuf, uint size)
99             : m_pBlob(vogl_new(uint8_vec, size)), m_user_data(0), m_type(cDTBlob), m_flags(0)
100         {
101             if (size)
102                 memcpy(m_pBlob->get_ptr(), pBuf, size);
103         }
104
105         inline value(const uint8_vec &blob)
106             : m_pBlob(vogl_new(uint8_vec, blob)), m_user_data(0), m_type(cDTBlob), m_flags(0)
107         {
108         }
109
110         inline value(const json_document &doc)
111             : m_pJSONDoc(vogl_new(json_document, doc)), m_user_data(0), m_type(cDTJSONDoc), m_flags(0)
112         {
113         }
114
115         inline explicit value(bool v)
116             : m_bool(v), m_user_data(0), m_type(cDTBool), m_flags(0)
117         {
118         }
119
120         inline explicit value(void *p)
121             : m_pPtr(p), m_user_data(0), m_type(cDTVoidPtr), m_flags(0)
122         {
123         }
124
125         inline value(int8 v)
126             : m_int8(v), m_user_data(0), m_type(cDTInt8), m_flags(0)
127         {
128         }
129
130         inline value(uint8 v)
131             : m_uint8(v), m_user_data(0), m_type(cDTUInt8), m_flags(0)
132         {
133         }
134
135         inline value(int16 v)
136             : m_int16(v), m_user_data(0), m_type(cDTInt16), m_flags(0)
137         {
138         }
139
140         inline value(uint16 v)
141             : m_uint16(v), m_user_data(0), m_type(cDTUInt16), m_flags(0)
142         {
143         }
144
145         inline value(int v)
146             : m_int(v), m_user_data(0), m_type(cDTInt), m_flags(0)
147         {
148         }
149
150         inline value(uint v)
151             : m_uint(v), m_user_data(0), m_type(cDTUInt), m_flags(0)
152         {
153         }
154
155         inline value(int64_t v)
156             : m_int64(v), m_user_data(0), m_type(cDTInt64), m_flags(0)
157         {
158         }
159
160         inline value(uint64_t v)
161             : m_uint64(v), m_user_data(0), m_type(cDTUInt64), m_flags(0)
162         {
163         }
164
165         inline value(float v)
166             : m_float(v), m_user_data(0), m_type(cDTFloat), m_flags(0)
167         {
168         }
169
170         inline value(double v)
171             : m_double(v), m_user_data(0), m_type(cDTDouble), m_flags(0)
172         {
173         }
174
175         inline value(const vec3F &v)
176             : m_pVec3F(vogl_new(vec3F, v)), m_user_data(0), m_type(cDTVec3F), m_flags(0)
177         {
178         }
179
180         inline value(const vec3I &v)
181             : m_pVec3I(vogl_new(vec3I, v)), m_user_data(0), m_type(cDTVec3I), m_flags(0)
182         {
183         }
184
185         inline value(const value &other)
186             : m_type(cDTInvalid),
187               m_flags(0)
188         {
189             *this = other;
190         }
191
192         inline value(const string_hash &hash)
193             : m_user_data(0), m_type(cDTStringHash), m_flags(0)
194         {
195             get_string_hash_ref() = hash;
196         }
197
198         inline ~value()
199         {
200             clear_dynamic();
201         }
202
203         value &operator=(const value &other);
204
205         bool operator==(const value &other) const;
206         bool operator!=(const value &other) const
207         {
208             return !(*this == other);
209         }
210
211         bool operator<(const value &other) const;
212
213         inline value_data_type get_data_type() const
214         {
215             return m_type;
216         }
217
218         inline void clear()
219         {
220             clear_dynamic();
221
222             m_type = cDTInvalid;
223             m_user_data = 0;
224             m_uint64 = 0;
225             m_flags = 0;
226         }
227
228         inline void set_bool(bool v)
229         {
230             clear_dynamic();
231             m_type = cDTBool;
232             m_bool = v;
233         }
234
235         inline void set_int8(int8 v)
236         {
237             clear_dynamic();
238             m_type = cDTInt8;
239             m_int8 = v;
240         }
241
242         inline void set_uint8(uint8 v)
243         {
244             clear_dynamic();
245             m_type = cDTUInt8;
246             m_uint8 = v;
247         }
248
249         inline void set_int16(int16 v)
250         {
251             clear_dynamic();
252             m_type = cDTInt16;
253             m_int16 = v;
254         }
255
256         inline void set_uint16(uint16 v)
257         {
258             clear_dynamic();
259             m_type = cDTUInt16;
260             m_uint16 = v;
261         }
262
263         inline void set_int(int v)
264         {
265             clear_dynamic();
266             m_type = cDTInt;
267             m_int = v;
268         }
269
270         inline void set_uint(uint v)
271         {
272             clear_dynamic();
273             m_type = cDTUInt;
274             m_uint = v;
275         }
276
277         inline void set_int64(int64_t v)
278         {
279             clear_dynamic();
280             m_type = cDTInt64;
281             m_int64 = v;
282         }
283
284         inline void set_uint64(uint64_t v)
285         {
286             clear_dynamic();
287             m_type = cDTUInt64;
288             m_uint64 = v;
289         }
290
291         inline void set_float(float v)
292         {
293             clear_dynamic();
294             m_type = cDTFloat;
295             m_float = v;
296         }
297
298         inline void set_double(double v)
299         {
300             clear_dynamic();
301             m_type = cDTDouble;
302             m_double = v;
303         }
304
305         inline void set_void_ptr(void *p)
306         {
307             clear_dynamic();
308             m_type = cDTVoidPtr;
309             m_pPtr = p;
310         }
311
312         inline void set_vec(const vec3F &v)
313         {
314             change_type(cDTVec3F);
315             m_pVec3F->set(v);
316         }
317
318         inline void set_vec(const vec3I &v)
319         {
320             change_type(cDTVec3I);
321             m_pVec3I->set(v);
322         }
323
324         inline void set_string(const char *pStr)
325         {
326             set_str(pStr);
327         }
328
329         inline bool set_blob(const uint8 *pBlob, uint size)
330         {
331             change_type(cDTBlob);
332             if (!m_pBlob->try_resize(size))
333                 return false;
334             if (size)
335                 memcpy(m_pBlob->get_ptr(), pBlob, size);
336             return true;
337         }
338
339         inline bool set_blob(const uint8_vec &v)
340         {
341             return set_blob(v.get_ptr(), v.size());
342         }
343
344         inline void set_blob_take_ownership(uint8_vec &v)
345         {
346             change_type(cDTBlob);
347             m_pBlob->swap(v);
348         }
349
350         inline bool set_json_document(const json_document &doc)
351         {
352             change_type(cDTJSONDoc);
353             *m_pJSONDoc = doc;
354             return true;
355         }
356
357         inline bool set_json_document_take_ownership(json_document &doc)
358         {
359             change_type(cDTJSONDoc);
360             m_pJSONDoc->swap(doc);
361             return true;
362         }
363
364         inline json_document *init_json_document()
365         {
366             change_type(cDTJSONDoc);
367             return m_pJSONDoc;
368         }
369
370         inline void set_string_hash(const string_hash &hash)
371         {
372             change_type(cDTStringHash);
373             m_type = cDTStringHash;
374             get_string_hash_ref() = hash;
375         }
376
377         inline value &operator=(bool value)
378         {
379             set_bool(value);
380             return *this;
381         }
382         inline value &operator=(uint8 value)
383         {
384             set_uint8(value);
385             return *this;
386         }
387         inline value &operator=(int16 value)
388         {
389             set_int16(value);
390             return *this;
391         }
392         inline value &operator=(uint16 value)
393         {
394             set_uint16(value);
395             return *this;
396         }
397         inline value &operator=(int value)
398         {
399             set_int(value);
400             return *this;
401         }
402         inline value &operator=(uint value)
403         {
404             set_uint(value);
405             return *this;
406         }
407         inline value &operator=(int64_t value)
408         {
409             set_int64(value);
410             return *this;
411         }
412         inline value &operator=(uint64_t value)
413         {
414             set_uint64(value);
415             return *this;
416         }
417         inline value &operator=(float value)
418         {
419             set_float(value);
420             return *this;
421         }
422         inline value &operator=(double value)
423         {
424             set_double(value);
425             return *this;
426         }
427         inline value &operator=(void *pPtr)
428         {
429             set_void_ptr(pPtr);
430             return *this;
431         }
432         inline value &operator=(const vec3F &value)
433         {
434             set_vec(value);
435             return *this;
436         }
437         inline value &operator=(const vec3I &value)
438         {
439             set_vec(value);
440             return *this;
441         }
442         inline value &operator=(const uint8_vec &value)
443         {
444             set_blob(value);
445             return *this;
446         }
447         inline value &operator=(const dynamic_string &value)
448         {
449             set_string(value.get_ptr());
450             return *this;
451         }
452         inline value &operator=(const char *pStr)
453         {
454             set_string(pStr);
455             return *this;
456         }
457         inline value &operator=(const string_hash &hash)
458         {
459             set_string_hash(hash);
460             return *this;
461         }
462         inline value &operator=(const json_document &doc)
463         {
464             set_json_document(doc);
465             return *this;
466         }
467
468         bool parse(const char *p);
469
470         dynamic_string &get_string(dynamic_string &dst, bool quote_strings = false) const;
471
472         inline dynamic_string get_string(bool quote_strings = false) const
473         {
474             dynamic_string str;
475             get_string(str, quote_strings);
476             return str;
477         }
478         inline dynamic_string *get_string_ptr() const
479         {
480             return (m_type == cDTString) ? m_pStr : NULL;
481         }
482
483         // on failure, the destination val is NOT modified
484         bool get_int8_or_fail(int8 &val, uint component) const;
485         bool get_uint8_or_fail(uint8 &val, uint component) const;
486         bool get_int16_or_fail(int16 &val, uint component) const;
487         bool get_uint16_or_fail(uint16 &val, uint component) const;
488         bool get_int_or_fail(int &val, uint component = 0) const;
489         bool get_int64_or_fail(int64_t &val, uint component = 0) const;
490         bool get_uint_or_fail(uint &val, uint component = 0) const;
491         bool get_uint64_or_fail(uint64_t &val, uint component = 0) const;
492         bool get_bool_or_fail(bool &val, uint component = 0) const;
493         bool get_double_or_fail(double &val, uint component = 0) const;
494         bool get_float_or_fail(float &val, uint component = 0) const;
495         bool get_vec3F_or_fail(vec3F &val) const;
496         bool get_vec3I_or_fail(vec3I &val) const;
497         bool get_string_hash_or_fail(string_hash &hash) const;
498
499         inline int8 get_int8(int8 def = 0, uint component = 0) const
500         {
501             int8 result = def;
502             get_int8_or_fail(result, component);
503             return result;
504         }
505         inline int16 get_int16(int16 def = 0, uint component = 0) const
506         {
507             int16 result = def;
508             get_int16_or_fail(result, component);
509             return result;
510         }
511         inline uint8 get_uint8(uint8 def = 0, uint component = 0) const
512         {
513             uint8 result = def;
514             get_uint8_or_fail(result, component);
515             return result;
516         }
517         inline uint16 get_uint16(uint16 def = 0, uint component = 0) const
518         {
519             uint16 result = def;
520             get_uint16_or_fail(result, component);
521             return result;
522         }
523         inline int get_int(int def = 0, uint component = 0) const
524         {
525             int result = def;
526             get_int_or_fail(result, component);
527             return result;
528         }
529         inline int64_t get_int64(int64_t def = 0, uint component = 0) const
530         {
531             int64_t result = def;
532             get_int64_or_fail(result, component);
533             return result;
534         }
535         inline uint get_uint(uint def = 0, uint component = 0) const
536         {
537             uint result = def;
538             get_uint_or_fail(result, component);
539             return result;
540         }
541         inline uint64_t get_uint64(uint64_t def = 0, uint component = 0) const
542         {
543             uint64_t result = def;
544             get_uint64_or_fail(result, component);
545             return result;
546         }
547
548         inline bool get_bool(bool def = false, uint component = 0) const
549         {
550             bool result = def;
551             get_bool_or_fail(result, component);
552             return result;
553         }
554         inline double get_double(double def = 0.0f, uint component = 0) const
555         {
556             double result = def;
557             get_double_or_fail(result, component);
558             return result;
559         }
560         inline float get_float(float def = 0.0f, uint component = 0) const
561         {
562             float result = def;
563             get_float_or_fail(result, component);
564             return result;
565         }
566         inline vec3F get_vec3F(const vec3F &def = vec3F(0)) const
567         {
568             vec3F result(def);
569             get_vec3F_or_fail(result);
570             return result;
571         }
572         inline vec3I get_vec3I(const vec3I &def = vec3I(0)) const
573         {
574             vec3I result(def);
575             get_vec3I_or_fail(result);
576             return result;
577         }
578         inline string_hash get_string_hash(const string_hash &def = string_hash(0U)) const
579         {
580             string_hash result(def);
581             get_string_hash_or_fail(result);
582             return result;
583         }
584
585         inline const uint8_vec *get_blob() const
586         {
587             return (m_type == cDTBlob) ? m_pBlob : NULL;
588         }
589
590         inline uint8_vec *get_blob()
591         {
592             return (m_type == cDTBlob) ? m_pBlob : NULL;
593         }
594
595         inline void *get_void_ptr() const
596         {
597             return (m_type == cDTVoidPtr) ? m_pPtr : NULL;
598         }
599
600         inline const json_document *get_json_document() const
601         {
602             return (m_type == cDTJSONDoc) ? m_pJSONDoc : NULL;
603         }
604
605         inline json_document *get_json_document()
606         {
607             return (m_type == cDTJSONDoc) ? m_pJSONDoc : NULL;
608         }
609
610         inline bool set_zero()
611         {
612             switch (m_type)
613             {
614                 case cDTInvalid:
615                 {
616                     return false;
617                 }
618                 case cDTString:
619                 {
620                     m_pStr->empty();
621                     break;
622                 }
623                 case cDTBool:
624                 {
625                     m_bool = false;
626                     break;
627                 }
628                 case cDTInt8:
629                 case cDTUInt8:
630                 case cDTInt16:
631                 case cDTUInt16:
632                 case cDTInt:
633                 case cDTUInt:
634                 case cDTInt64:
635                 case cDTUInt64:
636                 case cDTFloat:
637                 case cDTDouble:
638                 case cDTVoidPtr:
639                 {
640                     m_uint64 = 0;
641                     break;
642                 }
643                 case cDTVec3F:
644                 {
645                     m_pVec3F->clear();
646                     break;
647                 }
648                 case cDTVec3I:
649                 {
650                     m_pVec3I->clear();
651                     break;
652                 }
653                 case cDTBlob:
654                 {
655                     m_pBlob->clear();
656                     break;
657                 }
658                 case cDTJSONDoc:
659                 {
660                     m_pJSONDoc->clear();
661                     break;
662                 }
663                 default:
664                     VOGL_ASSERT_ALWAYS;
665                     break;
666             }
667             return true;
668         }
669
670         inline bool is_valid() const
671         {
672             return m_type != cDTInvalid;
673         }
674
675         inline bool is_dynamic() const
676         {
677             return m_type >= cDTFirstDynamic;
678         }
679
680         inline bool is_vector() const
681         {
682             switch (m_type)
683             {
684                 case cDTVec3F:
685                 case cDTVec3I:
686                     return true;
687                 default:
688                     break;
689             }
690             return false;
691         }
692
693         inline uint get_num_components() const
694         {
695             switch (m_type)
696             {
697                 case cDTVec3F:
698                 case cDTVec3I:
699                     return 3;
700                 case cDTBlob:
701                     return m_pBlob->size();
702                 default:
703                     break;
704             }
705             return 1;
706         }
707
708         inline bool is_numeric() const
709         {
710             switch (m_type)
711             {
712                 case cDTInt8:
713                 case cDTUInt8:
714                 case cDTInt:
715                 case cDTUInt:
716                 case cDTInt16:
717                 case cDTUInt16:
718                 case cDTInt64:
719                 case cDTUInt64:
720                 case cDTFloat:
721                 case cDTDouble:
722                 case cDTVec3F:
723                 case cDTVec3I:
724                 case cDTStringHash:
725                     return true;
726                 default:
727                     break;
728             }
729             return false;
730         }
731
732         inline const void *get_data_ptr() const
733         {
734             if (m_type >= cDTFirstDynamic)
735             {
736                 switch (m_type)
737                 {
738                     case cDTString:
739                         return m_pStr->get_ptr();
740                     case cDTVec3F:
741                         return m_pVec3F;
742                     case cDTVec3I:
743                         return m_pVec3I;
744                     case cDTBlob:
745                         return m_pBlob->get_ptr();
746                     case cDTJSONDoc:
747                         return NULL;
748                     default:
749                         VOGL_ASSERT_ALWAYS;
750                         break;
751                 }
752             }
753
754             return &m_bool;
755         }
756
757         inline uint get_data_size_in_bytes() const
758         {
759             switch (m_type)
760             {
761                 case cDTInvalid:
762                     return 0;
763                 case cDTBool:
764                 case cDTInt8:
765                 case cDTUInt8:
766                     return sizeof(uint8);
767                 case cDTInt16:
768                 case cDTUInt16:
769                     return sizeof(uint16);
770                 case cDTInt:
771                 case cDTUInt:
772                 case cDTFloat:
773                 case cDTStringHash:
774                     return sizeof(uint32);
775                 case cDTInt64:
776                 case cDTUInt64:
777                 case cDTDouble:
778                     return sizeof(uint64_t);
779                 case cDTVoidPtr:
780                     return sizeof(void *);
781                 case cDTString:
782                     return (m_pStr->get_len() + 1);
783                 case cDTVec3F:
784                     return sizeof(vec3F);
785                 case cDTVec3I:
786                     return sizeof(vec3I);
787                 case cDTBlob:
788                     return m_pBlob->size_in_bytes();
789                 case cDTJSONDoc:
790                     return 0;
791                 default:
792                     VOGL_ASSERT_ALWAYS;
793                     break;
794             }
795             return 0;
796         }
797
798         inline bool is_float() const
799         {
800             switch (m_type)
801             {
802                 case cDTFloat:
803                 case cDTDouble:
804                 case cDTVec3F:
805                     return true;
806                 default:
807                     break;
808             }
809             return false;
810         }
811
812         inline bool is_integer() const
813         {
814             switch (m_type)
815             {
816                 case cDTInt8:
817                 case cDTUInt8:
818                 case cDTInt16:
819                 case cDTUInt16:
820                 case cDTInt:
821                 case cDTUInt:
822                 case cDTInt64:
823                 case cDTUInt64:
824                 case cDTVec3I:
825                 case cDTStringHash:
826                     return true;
827                 default:
828                     break;
829             }
830             return false;
831         }
832
833         inline bool is_unsigned() const
834         {
835             switch (m_type)
836             {
837                 case cDTUInt8:
838                 case cDTUInt16:
839                 case cDTUInt:
840                 case cDTUInt64:
841                 case cDTStringHash:
842                     return true;
843                 default:
844                     break;
845             }
846             return false;
847         }
848
849         inline bool is_signed() const
850         {
851             switch (m_type)
852             {
853                 case cDTInt8:
854                 case cDTInt:
855                 case cDTInt16:
856                 case cDTInt64:
857                 case cDTFloat:
858                 case cDTDouble:
859                 case cDTVec3F:
860                 case cDTVec3I:
861                     return true;
862                 default:
863                     break;
864             }
865             return false;
866         }
867
868         inline bool is_string() const
869         {
870             return m_type == cDTString;
871         }
872
873         inline bool is_blob() const
874         {
875             return m_type == cDTBlob;
876         }
877
878         inline bool is_string_hash() const
879         {
880             return m_type == cDTStringHash;
881         }
882
883         inline bool is_json_document() const
884         {
885             return m_type == cDTJSONDoc;
886         }
887
888         uint get_serialize_size(bool serialize_user_data) const;
889         int serialize(void *pBuf, uint buf_size, bool little_endian, bool serialize_user_data) const;
890         int deserialize(const void *pBuf, uint buf_size, bool little_endian, bool serialize_user_data);
891
892         inline value &swap(value &other)
893         {
894             std::swap(m_uint64, other.m_uint64);
895             std::swap(m_type, other.m_type);
896             std::swap(m_user_data, other.m_user_data);
897             std::swap(m_flags, other.m_flags);
898             return *this;
899         }
900
901         inline bool has_user_data() const
902         {
903             return (m_flags & cFlagsHasUserData) != 0;
904         }
905         inline uint get_user_data() const
906         {
907             return m_user_data;
908         }
909         inline void set_user_data(uint16 v)
910         {
911             m_user_data = v;
912             m_flags |= cFlagsHasUserData;
913         }
914         inline void clear_user_data()
915         {
916             m_flags &= ~cFlagsHasUserData;
917         }
918
919         inline size_t get_hash() const
920         {
921             if (m_type == cDTJSONDoc)
922             {
923                 uint8_vec data;
924                 m_pJSONDoc->binary_serialize(data);
925                 return (((fast_hash(data.get_ptr(), data.size_in_bytes()) + m_type) ^ (m_type << 20)) - bitmix32(m_user_data)) ^ bitmix32(m_flags);
926             }
927             else
928             {
929                 return (((fast_hash(get_data_ptr(), get_data_size_in_bytes()) + m_type) ^ (m_type << 20)) - bitmix32(m_user_data)) ^ bitmix32(m_flags);
930             }
931         }
932
933     private:
934         inline void clear_dynamic()
935         {
936             if (m_type >= cDTFirstDynamic)
937             {
938                 if (m_type == cDTVec3F)
939                     vogl_delete(m_pVec3F);
940                 else if (m_type == cDTVec3I)
941                     vogl_delete(m_pVec3I);
942                 else if (m_type == cDTString)
943                     vogl_delete(m_pStr);
944                 else if (m_type == cDTBlob)
945                     vogl_delete(m_pBlob);
946                 else if (m_type == cDTJSONDoc)
947                     vogl_delete(m_pJSONDoc);
948                 else
949                 {
950                     VOGL_ASSERT_ALWAYS;
951                 }
952
953                 m_pPtr = NULL;
954                 m_type = cDTInvalid;
955             }
956         }
957
958         inline void change_type(value_data_type type)
959         {
960             if (type != m_type)
961             {
962                 clear_dynamic();
963
964                 m_type = type;
965                 if (m_type >= cDTFirstDynamic)
966                 {
967                     switch (m_type)
968                     {
969                         case cDTString:
970                             m_pStr = vogl_new(dynamic_string);
971                             break;
972                         case cDTVec3F:
973                             m_pVec3F = vogl_new(vec3F);
974                             break;
975                         case cDTVec3I:
976                             m_pVec3I = vogl_new(vec3I);
977                             break;
978                         case cDTBlob:
979                             m_pBlob = vogl_new(uint8_vec);
980                             break;
981                         case cDTJSONDoc:
982                             m_pJSONDoc = vogl_new(json_document);
983                             break;
984                         default:
985                             break;
986                     }
987                 }
988             }
989         }
990
991         inline void set_str(const dynamic_string &s)
992         {
993             if (m_type == cDTString)
994                 m_pStr->set(s);
995             else
996             {
997                 clear_dynamic();
998
999                 m_type = cDTString;
1000                 m_pStr = vogl_new(dynamic_string, s);
1001             }
1002         }
1003
1004         inline void set_str(const char *p)
1005         {
1006             if (m_type == cDTString)
1007                 m_pStr->set(p);
1008             else
1009             {
1010                 clear_dynamic();
1011
1012                 m_type = cDTString;
1013                 m_pStr = vogl_new(dynamic_string, p);
1014             }
1015         }
1016
1017         union
1018         {
1019             bool m_bool;
1020
1021             int8 m_int8;
1022             uint8 m_uint8;
1023
1024             int16 m_int16;
1025             uint16 m_uint16;
1026
1027             int m_int;
1028             uint m_uint;
1029
1030             int64_t m_int64;
1031             uint64_t m_uint64;
1032
1033             float m_float;
1034             double m_double;
1035             void *m_pPtr;
1036
1037             vec3F *m_pVec3F;
1038             vec3I *m_pVec3I;
1039             dynamic_string *m_pStr;
1040             uint8_vec *m_pBlob;
1041             json_document *m_pJSONDoc;
1042         };
1043
1044         const string_hash &get_string_hash_ref() const
1045         {
1046             VOGL_ASSUME(sizeof(string_hash) == sizeof(uint));
1047             return *reinterpret_cast<const string_hash *>(&m_uint);
1048         }
1049         string_hash &get_string_hash_ref()
1050         {
1051             VOGL_ASSUME(sizeof(string_hash) == sizeof(uint));
1052             return *reinterpret_cast<string_hash *>(&m_uint);
1053         }
1054
1055         // I'm torn about m_user_data/m_flags - may not be useful, but there's room for it due to alignment.
1056         uint16 m_user_data;
1057         value_data_type m_type;
1058         uint8 m_flags;
1059     };
1060
1061     typedef vogl::vector<value> value_vector;
1062
1063     template <>
1064     struct hasher<value>
1065     {
1066         inline size_t operator()(const value &key) const
1067         {
1068             return key.get_hash();
1069         }
1070     };
1071
1072     typedef hash_map<value, value> value_to_value_hash_map;
1073
1074     class key_value_map
1075     {
1076     public:
1077         typedef value_to_value_hash_map::iterator iterator;
1078         typedef value_to_value_hash_map::const_iterator const_iterator;
1079
1080         inline key_value_map()
1081         {
1082         }
1083
1084         inline ~key_value_map()
1085         {
1086             clear();
1087         }
1088
1089         inline key_value_map(const key_value_map &other)
1090         {
1091             *this = other;
1092         }
1093
1094         inline key_value_map &operator=(const key_value_map &rhs)
1095         {
1096             if (this == &rhs)
1097                 return *this;
1098             m_key_values = rhs.m_key_values;
1099             return *this;
1100         }
1101
1102         inline bool operator==(const key_value_map &other) const
1103         {
1104             if (m_key_values.size() != other.m_key_values.size())
1105                 return false;
1106
1107             for (const_iterator it = begin(); it != end(); ++it)
1108             {
1109                 const_iterator other_it = other.find(it->first);
1110                 if (other_it == other.end())
1111                     return false;
1112                 if (it->second != other_it->second)
1113                     return false;
1114             }
1115
1116             return true;
1117         }
1118
1119         inline bool operator!=(const key_value_map &other) const
1120         {
1121             return !(*this == other);
1122         }
1123
1124         inline size_t get_hash() const
1125         {
1126             size_t h = 0xDEADBEEF ^ bitmix32(get_num_key_values());
1127
1128             for (const_iterator it = begin(); it != end(); ++it)
1129             {
1130                 h ^= it->first.get_hash();
1131                 h -= it->second.get_hash();
1132             }
1133
1134             return h;
1135         }
1136
1137         inline void clear()
1138         {
1139             m_key_values.clear();
1140         }
1141
1142         inline void reset()
1143         {
1144             m_key_values.reset();
1145         }
1146
1147         inline void reserve(uint new_capacity)
1148         {
1149             m_key_values.reserve(new_capacity);
1150         }
1151
1152         inline uint size() const
1153         {
1154             return m_key_values.size();
1155         }
1156
1157         inline uint64_t get_serialize_size(bool serialize_user_data) const
1158         {
1159             uint64_t l = sizeof(uint) * 2;
1160
1161             for (const_iterator it = begin(); it != end(); ++it)
1162                 l += it->first.get_serialize_size(serialize_user_data) + it->second.get_serialize_size(serialize_user_data);
1163
1164             return l;
1165         }
1166
1167         inline int serialize_to_buffer(void *pBuf, uint buf_size, bool little_endian, bool serialize_user_data) const
1168         {
1169             if (buf_size < sizeof(uint) * 2)
1170                 return -1;
1171
1172             uint buf_left = buf_size;
1173
1174             void *pSize = reinterpret_cast<uint *>(pBuf);
1175             if (!utils::write_obj(buf_left, pBuf, buf_left, little_endian))
1176                 return -1;
1177
1178             uint n = get_num_key_values();
1179             if (!utils::write_obj(n, pBuf, buf_left, little_endian))
1180                 return -1;
1181
1182             for (const_iterator it = begin(); it != end(); ++it)
1183             {
1184                 int num_bytes_written = it->first.serialize(pBuf, buf_left, little_endian, serialize_user_data);
1185                 if (num_bytes_written < 0)
1186                     return -1;
1187
1188                 pBuf = static_cast<uint8 *>(pBuf) + num_bytes_written;
1189                 buf_left -= num_bytes_written;
1190
1191                 num_bytes_written = it->second.serialize(pBuf, buf_left, little_endian, serialize_user_data);
1192                 if (num_bytes_written < 0)
1193                     return -1;
1194
1195                 pBuf = static_cast<uint8 *>(pBuf) + num_bytes_written;
1196                 buf_left -= num_bytes_written;
1197             }
1198
1199             uint total_bytes_written = buf_size - buf_left;
1200
1201             n = sizeof(uint);
1202             utils::write_obj(total_bytes_written, pSize, n, little_endian);
1203
1204             return total_bytes_written;
1205         }
1206
1207         inline int deserialize_from_buffer(const void *pBuf, uint buf_size, bool little_endian, bool serialize_user_data)
1208         {
1209             m_key_values.reset();
1210
1211             uint buf_left = buf_size;
1212
1213             uint len = 0;
1214             if (!utils::read_obj(len, pBuf, buf_left, little_endian))
1215                 return -1;
1216
1217             if (len < sizeof(uint) * 2)
1218                 return -1;
1219
1220             if ((buf_left + sizeof(uint)) < len)
1221                 return -1;
1222
1223             uint n = 0;
1224             if (!utils::read_obj(n, pBuf, buf_left, little_endian))
1225                 return -1;
1226
1227             for (uint i = 0; i < n; ++i)
1228             {
1229                 value key;
1230                 int num_bytes_read = key.deserialize(pBuf, buf_left, little_endian, serialize_user_data);
1231                 if (num_bytes_read < 0)
1232                     return -1;
1233
1234                 pBuf = static_cast<const uint8 *>(pBuf) + num_bytes_read;
1235                 buf_left -= num_bytes_read;
1236
1237                 value val;
1238                 num_bytes_read = val.deserialize(pBuf, buf_left, little_endian, serialize_user_data);
1239                 if (num_bytes_read < 0)
1240                     return -1;
1241
1242                 pBuf = static_cast<const uint8 *>(pBuf) + num_bytes_read;
1243                 buf_left -= num_bytes_read;
1244
1245                 if (!insert(key, val).second)
1246                     return -1;
1247             }
1248
1249             uint total_bytes_read = buf_size - buf_left;
1250             if (total_bytes_read != len)
1251                 return -1;
1252             return total_bytes_read;
1253         }
1254
1255         inline int serialize_to_stream(data_stream &stream, bool little_endian, bool serialize_user_data) const
1256         {
1257             uint64_t num_bytes_needed = get_serialize_size(serialize_user_data);
1258             if (num_bytes_needed > static_cast<uint64_t>(cINT32_MAX))
1259                 return -1;
1260
1261             uint8 buf[2048];
1262             uint8 *pBuf = buf;
1263             uint8_vec dyn_buf;
1264
1265             if (num_bytes_needed > sizeof(buf))
1266             {
1267                 dyn_buf.resize(static_cast<uint>(num_bytes_needed));
1268                 pBuf = dyn_buf.get_ptr();
1269             }
1270
1271             int num_bytes_written = serialize_to_buffer(pBuf, static_cast<uint>(num_bytes_needed), little_endian, serialize_user_data);
1272             if (num_bytes_written < 0)
1273                 return -1;
1274             VOGL_ASSERT(num_bytes_needed == static_cast<uint64_t>(num_bytes_written));
1275
1276             uint num_bytes_streamed = stream.write(pBuf, num_bytes_written);
1277             if (num_bytes_streamed != static_cast<uint>(num_bytes_written))
1278                 return -1;
1279
1280             return num_bytes_written;
1281         }
1282
1283         inline int deserialize_from_stream(data_stream &stream, bool little_endian, bool serialize_user_data)
1284         {
1285             uint num_bytes_read = sizeof(uint) * 2;
1286             VOGL_NOTE_UNUSED(num_bytes_read);
1287
1288             uint raw_size;
1289             if (stream.read(&raw_size, sizeof(raw_size)) != sizeof(raw_size))
1290                 return -1;
1291
1292             uint size = raw_size;
1293             if (little_endian != c_vogl_little_endian_platform)
1294                 size = utils::swap32(size);
1295
1296             if ((size < sizeof(uint) * 2) || (size > static_cast<uint>(cINT32_MAX)))
1297                 return -1;
1298
1299             uint8_vec buf(size);
1300             *reinterpret_cast<uint *>(buf.get_ptr()) = raw_size;
1301
1302             if (stream.read(buf.get_ptr() + sizeof(uint), buf.size() - sizeof(uint)) != (buf.size() - sizeof(uint)))
1303                 return -1;
1304
1305             return deserialize_from_buffer(buf.get_ptr(), buf.size(), little_endian, serialize_user_data);
1306         }
1307
1308         // result.first will be an iterator
1309         // result.second will be true if the key was inserted, or false if the key already exists (in which case it will not be modified).
1310         inline value_to_value_hash_map::insert_result insert(const value &key, const value &val)
1311         {
1312             return m_key_values.insert(key, val);
1313         }
1314
1315         inline iterator find(const value &key)
1316         {
1317             return m_key_values.find(key);
1318         }
1319         inline const_iterator find(const value &key) const
1320         {
1321             return m_key_values.find(key);
1322         }
1323
1324         // TODO: add more/easier to use gets
1325         inline value get_value(const value &key, const value &def) const
1326         {
1327             const_iterator it = m_key_values.find(key);
1328             return (it == m_key_values.end()) ? def : it->second;
1329         }
1330
1331         // On failure, the destination val is NOT modified
1332         inline bool get_string_if_found(const value &key, dynamic_string &dst, bool quote_strings = false) const;
1333         inline bool get_int_if_found(const value &key, int &val, uint component = 0) const;
1334         inline bool get_int64_if_found(const value &key, int64_t &val, uint component = 0) const;
1335         inline bool get_uint_if_found(const value &key, uint &val, uint component = 0) const;
1336         inline bool get_uint64_if_found(const value &key, uint64_t &val, uint component = 0) const;
1337         inline bool get_bool_if_found(const value &key, bool &val, uint component = 0) const;
1338         inline bool get_double_if_found(const value &key, double &val, uint component = 0) const;
1339         inline bool get_float_if_found(const value &key, float &val, uint component = 0) const;
1340         inline bool get_vec3F_if_found(const value &key, vec3F &val) const;
1341         inline bool get_vec3I_if_found(const value &key, vec3I &val) const;
1342         inline bool get_string_hash_if_found(const value &key, string_hash &val) const;
1343
1344         inline dynamic_string get_string(const value &key, const char *pDef = "", bool quote_strings = false) const
1345         {
1346             dynamic_string result = pDef;
1347             get_string_if_found(key, result, quote_strings);
1348             return result;
1349         }
1350         inline int get_int(const value &key, int32 def = 0, uint component = 0) const
1351         {
1352             int result = def;
1353             get_int_if_found(key, result, component);
1354             return result;
1355         }
1356         inline int64_t get_int64(const value &key, int64_t def = 0, uint component = 0) const
1357         {
1358             int64_t result = def;
1359             get_int64_if_found(key, result, component);
1360             return result;
1361         }
1362         inline uint get_uint(const value &key, uint def = 0, uint component = 0) const
1363         {
1364             uint result = def;
1365             get_uint_if_found(key, result, component);
1366             return result;
1367         }
1368         inline uint64_t get_uint64(const value &key, uint64_t def = 0, uint component = 0) const
1369         {
1370             uint64_t result = def;
1371             get_uint64_if_found(key, result, component);
1372             return result;
1373         }
1374         inline bool get_bool(const value &key, bool def = false, uint component = 0) const
1375         {
1376             bool result = def;
1377             get_bool_if_found(key, result, component);
1378             return result;
1379         }
1380         inline float get_float(const value &key, float def = 0.0f, uint component = 0) const
1381         {
1382             float result = def;
1383             get_float_if_found(key, result, component);
1384             return result;
1385         }
1386         inline double get_double(const value &key, double def = 0.0f, uint component = 0) const
1387         {
1388             double result = def;
1389             get_double_if_found(key, result, component);
1390             return result;
1391         }
1392         inline vec3F get_vec3F(const value &key, const vec3F &def = vec3F(0.0f)) const
1393         {
1394             vec3F result(def);
1395             get_vec3F_if_found(key, result);
1396             return result;
1397         }
1398         inline vec3I get_vecI(const value &key, const vec3I &def = vec3I(0)) const
1399         {
1400             vec3I result(def);
1401             get_vec3I_if_found(key, result);
1402             return result;
1403         }
1404         inline string_hash get_string_hash(const value &key, const string_hash &def = string_hash(0U)) const
1405         {
1406             string_hash result(def);
1407             get_string_hash_if_found(key, result);
1408             return result;
1409         }
1410
1411         inline dynamic_string *get_string_ptr(const value &key) const;
1412
1413         inline const uint8_vec *get_blob(const value &key) const;
1414         inline uint8_vec *get_blob(const value &key);
1415
1416         inline const json_document *get_json_document(const value &key) const;
1417         inline json_document *get_json_document(const value &key);
1418
1419         inline bool does_key_exist(const value &key) const
1420         {
1421             return find(key) != end();
1422         }
1423
1424         inline void set(const value &key, const value &val)
1425         {
1426             iterator it = find(key);
1427             if (it == end())
1428                 insert(key, val);
1429             else
1430                 it->second = val;
1431         }
1432
1433         // erase() invalidates any active iterators
1434         inline bool erase(const value &key)
1435         {
1436             return m_key_values.erase(key);
1437         }
1438
1439         inline uint get_num_key_values() const
1440         {
1441             return m_key_values.size();
1442         }
1443
1444         inline iterator begin()
1445         {
1446             return m_key_values.begin();
1447         }
1448         inline const_iterator begin() const
1449         {
1450             return m_key_values.begin();
1451         }
1452
1453         inline iterator end()
1454         {
1455             return m_key_values.end();
1456         }
1457         inline const_iterator end() const
1458         {
1459             return m_key_values.end();
1460         }
1461
1462         inline value_to_value_hash_map &get_map()
1463         {
1464             return m_key_values;
1465         }
1466         inline const value_to_value_hash_map &get_map() const
1467         {
1468             return m_key_values;
1469         }
1470
1471     private:
1472         value_to_value_hash_map m_key_values;
1473     };
1474
1475     inline bool key_value_map::get_string_if_found(const value &key, dynamic_string &dst, bool quote_strings) const
1476     {
1477         const_iterator it = m_key_values.find(key);
1478         if (it == m_key_values.end())
1479             return false;
1480         it->second.get_string(dst, quote_strings);
1481         return true;
1482     }
1483
1484     inline bool key_value_map::get_int_if_found(const value &key, int &val, uint component) const
1485     {
1486         const_iterator it = m_key_values.find(key);
1487         if (it == m_key_values.end())
1488             return false;
1489         return it->second.get_int_or_fail(val, component);
1490     }
1491
1492     inline bool key_value_map::get_int64_if_found(const value &key, int64_t &val, uint component) const
1493     {
1494         const_iterator it = m_key_values.find(key);
1495         if (it == m_key_values.end())
1496             return false;
1497         return it->second.get_int64_or_fail(val, component);
1498     }
1499
1500     inline bool key_value_map::get_uint_if_found(const value &key, uint &val, uint component) const
1501     {
1502         const_iterator it = m_key_values.find(key);
1503         if (it == m_key_values.end())
1504             return false;
1505         return it->second.get_uint_or_fail(val, component);
1506     }
1507
1508     inline bool key_value_map::get_uint64_if_found(const value &key, uint64_t &val, uint component) const
1509     {
1510         const_iterator it = m_key_values.find(key);
1511         if (it == m_key_values.end())
1512             return false;
1513         return it->second.get_uint64_or_fail(val, component);
1514     }
1515
1516     inline bool key_value_map::get_bool_if_found(const value &key, bool &val, uint component) const
1517     {
1518         const_iterator it = m_key_values.find(key);
1519         if (it == m_key_values.end())
1520             return false;
1521         return it->second.get_bool_or_fail(val, component);
1522     }
1523
1524     inline bool key_value_map::get_double_if_found(const value &key, double &val, uint component) const
1525     {
1526         const_iterator it = m_key_values.find(key);
1527         if (it == m_key_values.end())
1528             return false;
1529         return it->second.get_double_or_fail(val, component);
1530     }
1531
1532     inline bool key_value_map::get_float_if_found(const value &key, float &val, uint component) const
1533     {
1534         const_iterator it = m_key_values.find(key);
1535         if (it == m_key_values.end())
1536             return false;
1537         return it->second.get_float_or_fail(val, component);
1538     }
1539
1540     inline bool key_value_map::get_vec3F_if_found(const value &key, vec3F &val) const
1541     {
1542         const_iterator it = m_key_values.find(key);
1543         if (it == m_key_values.end())
1544             return false;
1545         return it->second.get_vec3F_or_fail(val);
1546     }
1547
1548     inline bool key_value_map::get_vec3I_if_found(const value &key, vec3I &val) const
1549     {
1550         const_iterator it = m_key_values.find(key);
1551         if (it == m_key_values.end())
1552             return false;
1553         return it->second.get_vec3I_or_fail(val);
1554     }
1555
1556     inline bool key_value_map::get_string_hash_if_found(const value &key, string_hash &val) const
1557     {
1558         const_iterator it = m_key_values.find(key);
1559         if (it == m_key_values.end())
1560             return false;
1561         return it->second.get_string_hash_or_fail(val);
1562     }
1563
1564     inline dynamic_string *key_value_map::get_string_ptr(const value &key) const
1565     {
1566         const_iterator it = m_key_values.find(key);
1567         if (it == m_key_values.end())
1568             return NULL;
1569         return it->second.get_string_ptr();
1570     }
1571
1572     inline const uint8_vec *key_value_map::get_blob(const value &key) const
1573     {
1574         const_iterator it = m_key_values.find(key);
1575         if (it == m_key_values.end())
1576             return NULL;
1577         return it->second.get_blob();
1578     }
1579
1580     inline uint8_vec *key_value_map::get_blob(const value &key)
1581     {
1582         iterator it = m_key_values.find(key);
1583         if (it == m_key_values.end())
1584             return NULL;
1585         return it->second.get_blob();
1586     }
1587
1588     inline const json_document *key_value_map::get_json_document(const value &key) const
1589     {
1590         const_iterator it = m_key_values.find(key);
1591         if (it == m_key_values.end())
1592             return NULL;
1593         return it->second.get_json_document();
1594     }
1595
1596     inline json_document *key_value_map::get_json_document(const value &key)
1597     {
1598         iterator it = m_key_values.find(key);
1599         if (it == m_key_values.end())
1600             return NULL;
1601         return it->second.get_json_document();
1602     }
1603
1604 } // namespace vogl