1 //-*****************************************************************************
2 //
3 // Copyright (c) 2009-2012,
4 //  Sony Pictures Imageworks Inc. and
5 //  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
12 // *       Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // *       Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following disclaimer
16 // in the documentation and/or other materials provided with the
17 // distribution.
18 // *       Neither the name of Sony Pictures Imageworks, nor
19 // Industrial Light & Magic, nor the names of their contributors may be used
20 // to endorse or promote products derived from this software without specific
21 // prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 //
35 //-*****************************************************************************
36 
37 #ifndef Alembic_Util_PlainOldDataType_h
38 #define Alembic_Util_PlainOldDataType_h
39 
40 #include <Alembic/Util/Foundation.h>
41 #include <Alembic/Util/Exception.h>
42 
43 // stdint.h is not in anything prior to Visual Studio 2010
44 #if !defined(_MSC_VER) || _MSC_VER >= 1600
45 #include <stdint.h>
46 #endif
47 
48 namespace Alembic {
49 namespace Util {
50 namespace ALEMBIC_VERSION_NS {
51 
52 //-*****************************************************************************
53 //! Bytes are unsigned chars, by definition.
54 //! We use bytes in Alembic as the name of anonymous storage memory, since
55 //! it is not possible to create arrays of voids.
56 typedef unsigned char           byte_t;
57 
58 //-*****************************************************************************
59 //-*****************************************************************************
60 //! BOOLEAN BASE TYPE - since C++ doesn't explicitly demand that bool
61 //! be a given bit depth, but we need it to be here, we make our own
62 //! bool type, which is a bit silly. This is purely for storage reasons.
63 //-*****************************************************************************
64 class bool_t
65 {
66 public:
bool_t()67     bool_t() : m_byte( 0 ) {}
68 
bool_t(bool tf)69     bool_t( bool tf ) : m_byte( static_cast<byte_t>( tf ) ) {}
bool_t(byte_t b)70     bool_t( byte_t b ) : m_byte( b ) {}
71 
72 
73     //! Using default copy constructor
74     //! ...
75 
76     //! Using default assignment operator
77     //! ...
78 
79     bool_t& operator=( bool tf )
80     {
81         m_byte = static_cast<byte_t>( tf );
82         return *this;
83     }
84 
85     bool_t& operator=( byte_t b )
86     {
87         m_byte = b;
88         return *this;
89     }
90 
91     bool_t operator!( void )
92     {
93         return bool_t( m_byte == 0 );
94     }
95 
asBool()96     bool asBool() const { return ( m_byte != 0 ); }
97     operator bool() const { return ( m_byte != 0 ); }
98 
99 private:
100     byte_t m_byte;
101 };
102 
103 //-*****************************************************************************
104 inline bool operator==( const bool_t &a, const bool_t &b )
105 {
106     return a.asBool() == b.asBool();
107 }
108 
109 //-*****************************************************************************
110 inline bool operator==( const bool_t &a, bool b )
111 {
112     return a.asBool() == b;
113 }
114 
115 //-*****************************************************************************
116 inline bool operator==( bool a, const bool_t &b )
117 {
118     return a == b.asBool();
119 }
120 
121 //-*****************************************************************************
122 inline bool operator!=( const bool_t &a, const bool_t &b )
123 {
124     return a.asBool() != b.asBool();
125 }
126 
127 //-*****************************************************************************
128 inline bool operator!=( const bool_t &a, bool b )
129 {
130     return a.asBool() != b;
131 }
132 
133 //-*****************************************************************************
134 inline bool operator!=( bool a, const bool_t &b )
135 {
136     return a != b.asBool();
137 }
138 
139 #if !defined(_MSC_VER) || _MSC_VER >= 1600
140 using ::uint8_t;
141 using ::int8_t;
142 using ::uint16_t;
143 using ::int16_t;
144 using ::uint32_t;
145 using ::int32_t;
146 using ::uint64_t;
147 using ::int64_t;
148 #else
149 typedef unsigned char           uint8_t;
150 typedef signed char             int8_t;
151 typedef unsigned short          uint16_t;
152 typedef signed short            int16_t;
153 typedef unsigned int            uint32_t;
154 typedef int                     int32_t;
155 typedef unsigned long long      uint64_t;
156 typedef long long               int64_t;
157 #endif
158 
159 typedef half                    float16_t;
160 typedef float                   float32_t;
161 typedef double                  float64_t;
162 
163 //! Last, but not least, standard strings.
164 //! These are CLEARLY not "Plain Old Data Types", however, "strings" are
165 //! such ubiquitous components of programming, and without an enclosing
166 //! structure like std::string, they're so difficult to use from an API
167 //! point of view (call first time to find out length! allocate your own array!
168 //! call second time to get string value!), that I'm going to put my foot down
169 //! and say - from Alembic's point of view, std::string and std::wstring are
170 //! "Kinda Sorta POD types". Please pardon the abuse of the idiom.
171 using std::string;
172 using std::wstring;
173 
174 //-*****************************************************************************
175 //! I'm using explicit names here because the terms 'int', 'short', 'long', etc,
176 //! have different bit-depths on different machine architectures. To avoid
177 //! any ambiguity whatsoever, I'm just making these explicit. End users will
178 //! rarely see these anyway, so it's okay to be a bit pedantic.
179 //!
180 //! These are always represented in the endian-ness of the host machine when
181 //! resident in working memory, but need to have an explicit endian-ness when
182 //! being written out. That's hidden from the user by HDF5.
183 enum PlainOldDataType
184 {
185     //! Booleans are difficult to store in arrays in a 'one bit per bool'
186     //! kind of way, so we actually file them as bytes (uint8).  But again
187     //! this is entirely hidden from the end user. Implemented via the
188     //! "bool_t" type defined above.
189     kBooleanPOD,
190 
191     //! Char/UChar
192     kUint8POD,
193     kInt8POD,
194 
195     //! Short/UShort
196     kUint16POD,
197     kInt16POD,
198 
199     //! Int/UInt
200     kUint32POD,
201     kInt32POD,
202 
203     //! Long/ULong
204     kUint64POD,
205     kInt64POD,
206 
207     //! Half/Float/Double
208     kFloat16POD,
209     kFloat32POD,
210     kFloat64POD,
211 
212     //! String Pointer
213     kStringPOD,
214 
215     //! Wide String Pointer
216     kWstringPOD,
217 
218     //! Number of POD
219     kNumPlainOldDataTypes,
220 
221     //! Unknown
222     kUnknownPOD = 127
223 };
224 
225 //-*****************************************************************************
226 //-*****************************************************************************
227 //-*****************************************************************************
228 // A little traits class that binds these things together.
229 //-*****************************************************************************
230 //-*****************************************************************************
231 //-*****************************************************************************
232 template <PlainOldDataType PODT, class T > struct PODTraits {};
233 
234 //-*****************************************************************************
235 //! Unfortunately, C++ only allows for static const declaration of constants
236 //! with integral types, not floating. Therefore, we have the whole
237 //! inlined static function for default values.
238 #define DECLARE_TRAITS( PENUM, PTYPE, PNAME, DFLT, PTDEF )                    \
239 template <>                                                                   \
240 struct PODTraits< PENUM , PTYPE >                                             \
241 {                                                                             \
242     static const PlainOldDataType       pod_enum = PENUM ;                    \
243     typedef PTYPE                       value_type ;                          \
244     static const char *                 name() { return PNAME ; }             \
245     static PTYPE                        default_value()                       \
246     { return ( DFLT ) ; }                                                     \
247     static size_t                       numBytes()                            \
248     { return sizeof( PTYPE ) ; }                                              \
249 };                                                                            \
250 typedef PODTraits< PENUM , PTYPE > PTDEF
251 
252 //-*****************************************************************************
253 // Actual specialized traits
254 DECLARE_TRAITS( kBooleanPOD, bool_t,    "bool_t",    false, BooleanPODTraits );
255 DECLARE_TRAITS( kUint8POD,   uint8_t,   "uint8_t",   0,     Uint8PODTraits );
256 DECLARE_TRAITS( kInt8POD,    int8_t,    "int8_t",    0,     Int8PODTraits );
257 DECLARE_TRAITS( kUint16POD,  uint16_t,  "uint16_t",  0,     Uint16PODTraits );
258 DECLARE_TRAITS( kInt16POD,   int16_t,   "int16_t",   0,     Int16PODTraits );
259 DECLARE_TRAITS( kUint32POD,  uint32_t,  "uint32_t",  0,     Uint32PODTraits );
260 DECLARE_TRAITS( kInt32POD,   int32_t,   "int32_t",   0,     Int32PODTraits );
261 DECLARE_TRAITS( kUint64POD,  uint64_t,  "uint64_t",  0,     Uint64PODTraits );
262 DECLARE_TRAITS( kInt64POD,   int64_t,   "int64_t",   0,     Int64PODTraits );
263 DECLARE_TRAITS( kFloat16POD, float16_t, "float16_t", 0,     Float16PODTraits );
264 DECLARE_TRAITS( kFloat32POD, float32_t, "float32_t", 0,     Float32PODTraits );
265 DECLARE_TRAITS( kFloat64POD, float64_t, "float64_t", 0,     Float64PODTraits );
266 DECLARE_TRAITS( kStringPOD,  string,    "string",    "",    StringPODTraits );
267 DECLARE_TRAITS( kWstringPOD, wstring,   "wstring",   L"",   WstringPODTraits );
268 
269 #undef DECLARE_TRAITS
270 
271 //-*****************************************************************************
272 //-*****************************************************************************
273 // Okay, now tools for extracting POD Traits from enums and from types.
274 // No easy way to do it from a name.
275 //-*****************************************************************************
276 
277 //-*****************************************************************************
278 //-*****************************************************************************
279 // FROM ENUMS
280 //-*****************************************************************************
281 //-*****************************************************************************
282 template <PlainOldDataType PENUM>
283 struct PODTraitsFromEnum {};
284 
285 //-*****************************************************************************
286 // Actual specializations
287 template <> struct PODTraitsFromEnum<kBooleanPOD> : public BooleanPODTraits {};
288 template <> struct PODTraitsFromEnum<kUint8POD> : public Uint8PODTraits {};
289 template <> struct PODTraitsFromEnum<kInt8POD> : public Int8PODTraits {};
290 template <> struct PODTraitsFromEnum<kUint16POD> : public Uint16PODTraits {};
291 template <> struct PODTraitsFromEnum<kInt16POD> : public Int16PODTraits {};
292 template <> struct PODTraitsFromEnum<kUint32POD> : public Uint32PODTraits {};
293 template <> struct PODTraitsFromEnum<kInt32POD> : public Int32PODTraits {};
294 template <> struct PODTraitsFromEnum<kUint64POD> : public Uint64PODTraits {};
295 template <> struct PODTraitsFromEnum<kInt64POD> : public Int64PODTraits {};
296 template <> struct PODTraitsFromEnum<kFloat16POD> : public Float16PODTraits {};
297 template <> struct PODTraitsFromEnum<kFloat32POD> : public Float32PODTraits {};
298 template <> struct PODTraitsFromEnum<kFloat64POD> : public Float64PODTraits {};
299 template <> struct PODTraitsFromEnum<kStringPOD> : public StringPODTraits {};
300 template <> struct PODTraitsFromEnum<kWstringPOD> : public WstringPODTraits {};
301 
302 //-*****************************************************************************
303 //-*****************************************************************************
304 // FROM TYPES
305 //-*****************************************************************************
306 //-*****************************************************************************
307 template <class PTYPE>
308 struct PODTraitsFromType {};
309 
310 //-*****************************************************************************
311 // Actual specializations
312 template <> struct PODTraitsFromType<bool_t> : public BooleanPODTraits {};
313 template <> struct PODTraitsFromType<uint8_t> : public Uint8PODTraits {};
314 template <> struct PODTraitsFromType<int8_t> : public Int8PODTraits {};
315 template <> struct PODTraitsFromType<uint16_t> : public Uint16PODTraits {};
316 template <> struct PODTraitsFromType<int16_t> : public Int16PODTraits {};
317 template <> struct PODTraitsFromType<uint32_t> : public Uint32PODTraits {};
318 template <> struct PODTraitsFromType<int32_t> : public Int32PODTraits {};
319 template <> struct PODTraitsFromType<uint64_t> : public Uint64PODTraits {};
320 template <> struct PODTraitsFromType<int64_t> : public Int64PODTraits {};
321 template <> struct PODTraitsFromType<float16_t> : public Float16PODTraits {};
322 template <> struct PODTraitsFromType<float32_t> : public Float32PODTraits {};
323 template <> struct PODTraitsFromType<float64_t> : public Float64PODTraits {};
324 template <> struct PODTraitsFromType<string> : public StringPODTraits {};
325 template <> struct PODTraitsFromType<wstring> : public WstringPODTraits {};
326 
327 //-*****************************************************************************
328 //-*****************************************************************************
329 // Some runtime stuff, for when templates won't help.
330 //-*****************************************************************************
331 //-*****************************************************************************
332 inline size_t PODNumBytes( PlainOldDataType pod )
333 {
334     switch ( pod )
335     {
336     case kBooleanPOD: return BooleanPODTraits::numBytes();
337     case kUint8POD: return Uint8PODTraits::numBytes();
338     case kInt8POD: return Int8PODTraits::numBytes();
339     case kUint16POD: return Uint16PODTraits::numBytes();
340     case kInt16POD: return Int16PODTraits::numBytes();
341     case kUint32POD: return Uint32PODTraits::numBytes();
342     case kInt32POD: return Int32PODTraits::numBytes();
343     case kUint64POD: return Uint64PODTraits::numBytes();
344     case kInt64POD: return Int64PODTraits::numBytes();
345     case kFloat16POD: return Float16PODTraits::numBytes();
346     case kFloat32POD: return Float32PODTraits::numBytes();
347     case kFloat64POD: return Float64PODTraits::numBytes();
348     case kStringPOD: return StringPODTraits::numBytes();
349     case kWstringPOD: return WstringPODTraits::numBytes();
350     default:
351         // Badness!
352         assert( false );
353         return 0;
354     };
355 }
356 
357 //-*****************************************************************************
358 inline const char *PODName( PlainOldDataType pod )
359 {
360     switch ( pod )
361     {
362     case kBooleanPOD: return BooleanPODTraits::name();
363     case kUint8POD: return Uint8PODTraits::name();
364     case kInt8POD: return Int8PODTraits::name();
365     case kUint16POD: return Uint16PODTraits::name();
366     case kInt16POD: return Int16PODTraits::name();
367     case kUint32POD: return Uint32PODTraits::name();
368     case kInt32POD: return Int32PODTraits::name();
369     case kUint64POD: return Uint64PODTraits::name();
370     case kInt64POD: return Int64PODTraits::name();
371     case kFloat16POD: return Float16PODTraits::name();
372     case kFloat32POD: return Float32PODTraits::name();
373     case kFloat64POD: return Float64PODTraits::name();
374     case kStringPOD: return StringPODTraits::name();
375     case kWstringPOD: return WstringPODTraits::name();
376     default:
377         // Can't throw from here, so just return 0.
378         // assert( false );
379         return "UNKNOWN";
380         // return 0;
381     };
382 }
383 
384 //-*****************************************************************************
385 inline PlainOldDataType PODFromName( const std::string &n )
386 {
387     if ( n == BooleanPODTraits::name() ) return BooleanPODTraits::pod_enum;
388     else if ( n == Uint8PODTraits::name() ) return Uint8PODTraits::pod_enum;
389     else if ( n == Int8PODTraits::name() ) return Int8PODTraits::pod_enum;
390     else if ( n == Uint16PODTraits::name() ) return Uint16PODTraits::pod_enum;
391     else if ( n == Int16PODTraits::name() ) return Int16PODTraits::pod_enum;
392     else if ( n == Uint32PODTraits::name() ) return Uint32PODTraits::pod_enum;
393     else if ( n == Int32PODTraits::name() ) return Int32PODTraits::pod_enum;
394     else if ( n == Uint64PODTraits::name() ) return Uint64PODTraits::pod_enum;
395     else if ( n == Int64PODTraits::name() ) return Int64PODTraits::pod_enum;
396     else if ( n == Float16PODTraits::name() ) return Float16PODTraits::pod_enum;
397     else if ( n == Float32PODTraits::name() ) return Float32PODTraits::pod_enum;
398     else if ( n == Float64PODTraits::name() ) return Float64PODTraits::pod_enum;
399     else if ( n == StringPODTraits::name() ) return StringPODTraits::pod_enum;
400     else if ( n == WstringPODTraits::name() ) return WstringPODTraits::pod_enum;
401     else return kUnknownPOD;
402 }
403 
404 //-*****************************************************************************
405 //! This actually does work with strings!
406 template <PlainOldDataType POD>
407 inline void PODSetDefaultPOD( void *addr )
408 {
409     typedef typename PODTraitsFromEnum<POD>::value_type value_type;
410     value_type *valPtr = reinterpret_cast<value_type*>( addr );
411     if ( valPtr ) { *valPtr = PODTraitsFromEnum<POD>::default_value(); }
412 }
413 
414 //-*****************************************************************************
415 inline void PODSetDefault( PlainOldDataType pod, void *bytes )
416 {
417     switch ( pod )
418     {
419     case kBooleanPOD: PODSetDefaultPOD<kBooleanPOD>( bytes ); return;
420     case kUint8POD: PODSetDefaultPOD<kUint8POD>( bytes ); return;
421     case kInt8POD: PODSetDefaultPOD<kInt8POD>( bytes ); return;
422     case kUint16POD: PODSetDefaultPOD<kUint16POD>( bytes ); return;
423     case kInt16POD: PODSetDefaultPOD<kInt16POD>( bytes ); return;
424     case kUint32POD: PODSetDefaultPOD<kUint32POD>( bytes ); return;
425     case kInt32POD: PODSetDefaultPOD<kInt32POD>( bytes ); return;
426     case kUint64POD: PODSetDefaultPOD<kUint64POD>( bytes ); return;
427     case kInt64POD: PODSetDefaultPOD<kInt64POD>( bytes ); return;
428     case kFloat16POD: PODSetDefaultPOD<kFloat16POD>( bytes ); return;
429     case kFloat32POD: PODSetDefaultPOD<kFloat32POD>( bytes ); return;
430     case kFloat64POD: PODSetDefaultPOD<kFloat64POD>( bytes ); return;
431 
432         // This isn't tremendously valid for the string types. Eeek.
433     case kStringPOD: PODSetDefaultPOD<kStringPOD>( bytes ); return;
434     case kWstringPOD: PODSetDefaultPOD<kWstringPOD>( bytes ); return;
435     default:
436         // Can't throw, but in debug...
437         assert( false );
438     };
439 }
440 
441 } // End namespace ALEMBIC_VERSION_NS
442 
443 using namespace ALEMBIC_VERSION_NS;
444 
445 } // End namespace Util
446 } // End namespace Alembic
447 
448 #endif
449 
450