source: trunk/nv/types.hh @ 78

Last change on this file since 78 was 78, checked in by epyon, 12 years ago
  • types.hh - basing totally on typeid now
  • types.hh - removed hash_string and name registration defines (get_type_name template)
  • types.hh - name is defined at registration via create_type
  • types.hh - overall the code is much cleaner now
File size: 10.9 KB
Line 
1// Copyright (C) 2012 Kornel Kisielewicz
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#ifndef NV_TYPES_HH
6#define NV_TYPES_HH
7
8#include <glm/glm.hpp>
9#include <nv/common.hh>
10#include <nv/object.hh>
11#include <type_traits>
12#include <typeinfo>
13#include <typeindex>
14#include <utility>
15#include <unordered_map>
16#include <vector>
17#include <string>
18
19namespace nv
20{
21
22        enum datatype
23        {
24                INT,
25                BYTE,
26                SHORT,
27                UINT,
28                UBYTE,
29                USHORT,
30                FLOAT,
31                FLOAT_VECTOR_2,
32                FLOAT_VECTOR_3,
33                FLOAT_VECTOR_4,
34                FLOAT_MATRIX_2,
35                FLOAT_MATRIX_3,
36                FLOAT_MATRIX_4,
37                INT_VECTOR_2,
38                INT_VECTOR_3,
39                INT_VECTOR_4,
40                // unsupported gl conversion, remove?
41                BYTE_VECTOR_2,
42                BYTE_VECTOR_3,
43                BYTE_VECTOR_4,
44        };
45
46        template <typename T>
47        struct datatype_traits
48        {
49                typedef T type;
50                typedef T base_type;
51                static const size_t size = 1;
52        };
53
54        template <typename T>
55        struct datatype_traits< glm::detail::tvec2<T> >
56        {
57                typedef glm::detail::tvec2<T> type;
58                typedef typename type::value_type base_type;
59                static const size_t size = 2;
60        };
61
62        template <typename T>
63        struct datatype_traits< glm::detail::tvec3<T> >
64        {
65                typedef glm::detail::tvec3<T> type;
66                typedef typename type::value_type base_type;
67                static const size_t size = 3;
68        };
69
70        template <typename T>
71        struct datatype_traits< glm::detail::tvec4<T> >
72        {
73                typedef glm::detail::tvec4<T> type;
74                typedef typename type::value_type base_type;
75                static const size_t size = 4;
76        };
77
78        typedef glm::detail::tvec2<sint8> i8vec2;
79        typedef glm::detail::tvec3<sint8> i8vec3;
80        typedef glm::detail::tvec4<sint8> i8vec4;
81
82        typedef glm::vec2 vec2;
83        typedef glm::vec3 vec3;
84        typedef glm::vec4 vec4;
85
86        typedef glm::ivec2 ivec2;
87        typedef glm::ivec3 ivec3;
88        typedef glm::ivec4 ivec4;
89
90        typedef glm::mat2 mat2;
91        typedef glm::mat3 mat3;
92        typedef glm::mat4 mat4;
93
94        template < datatype EnumType > struct enum_to_type {};
95
96        template <> struct enum_to_type< INT >   { typedef int type; };
97        template <> struct enum_to_type< UINT >  { typedef unsigned int type; };
98        template <> struct enum_to_type< SHORT > { typedef short type; };
99        template <> struct enum_to_type< USHORT >{ typedef unsigned short type; };
100        template <> struct enum_to_type< BYTE >  { typedef char type; };
101        template <> struct enum_to_type< UBYTE > { typedef unsigned char type; };
102        template <> struct enum_to_type< FLOAT > { typedef f32 type; };
103
104        template <> struct enum_to_type< FLOAT_VECTOR_2 > { typedef vec2 type; };
105        template <> struct enum_to_type< FLOAT_VECTOR_3 > { typedef vec3 type; };
106        template <> struct enum_to_type< FLOAT_VECTOR_4 > { typedef vec4 type; };
107
108        template <> struct enum_to_type< INT_VECTOR_2 > { typedef ivec2 type; };
109        template <> struct enum_to_type< INT_VECTOR_3 > { typedef ivec3 type; };
110        template <> struct enum_to_type< INT_VECTOR_4 > { typedef ivec4 type; };
111
112        template <> struct enum_to_type< BYTE_VECTOR_2 > { typedef i8vec2 type; };
113        template <> struct enum_to_type< BYTE_VECTOR_3 > { typedef i8vec3 type; };
114        template <> struct enum_to_type< BYTE_VECTOR_4 > { typedef i8vec4 type; };
115
116        template <> struct enum_to_type< FLOAT_MATRIX_2 > { typedef mat2 type; };
117        template <> struct enum_to_type< FLOAT_MATRIX_3 > { typedef mat3 type; };
118        template <> struct enum_to_type< FLOAT_MATRIX_4 > { typedef mat4 type; };
119
120        template < typename TYPE > struct type_to_enum {};
121
122        template <> struct type_to_enum< int >           { static const datatype type = INT; };
123        template <> struct type_to_enum< unsigned int >  { static const datatype type = UINT; };
124        template <> struct type_to_enum< short >         { static const datatype type = SHORT; };
125        template <> struct type_to_enum< unsigned short >{ static const datatype type = USHORT; };
126        template <> struct type_to_enum< char >          { static const datatype type = BYTE; };
127        template <> struct type_to_enum< signed char >   { static const datatype type = BYTE; };
128        template <> struct type_to_enum< unsigned char > { static const datatype type = UBYTE; };
129        template <> struct type_to_enum< f32 > { static const datatype type = FLOAT; };
130
131        template <> struct type_to_enum< vec2 > { static const datatype type = FLOAT_VECTOR_2; };
132        template <> struct type_to_enum< vec3 > { static const datatype type = FLOAT_VECTOR_3; };
133        template <> struct type_to_enum< vec4 > { static const datatype type = FLOAT_VECTOR_4; };
134
135        template <> struct type_to_enum< ivec2 > { static const datatype type = INT_VECTOR_2; };
136        template <> struct type_to_enum< ivec3 > { static const datatype type = INT_VECTOR_3; };
137        template <> struct type_to_enum< ivec4 > { static const datatype type = INT_VECTOR_4; };
138
139        template <> struct type_to_enum< i8vec2 > { static const datatype type = BYTE_VECTOR_2; };
140        template <> struct type_to_enum< i8vec3 > { static const datatype type = BYTE_VECTOR_3; };
141        template <> struct type_to_enum< i8vec4 > { static const datatype type = BYTE_VECTOR_4; };
142
143        template <> struct type_to_enum< mat2 > { static const datatype type = FLOAT_MATRIX_2; };
144        template <> struct type_to_enum< mat3 > { static const datatype type = FLOAT_MATRIX_3; };
145        template <> struct type_to_enum< mat4 > { static const datatype type = FLOAT_MATRIX_4; };
146
147        template<typename T>
148        struct is_container
149        {
150        private:
151                typedef char                      yes;
152                typedef struct { char array[2]; } no;
153                template<typename C> static yes test(typename C::iterator*);
154                template<typename C> static no  test(...);
155        public:
156                static const bool value = sizeof(test<T>(0)) == sizeof(yes);
157        };
158
159        template<>
160        struct is_container< std::string > {
161                static const bool value = false;
162        };
163
164        struct type_entry;
165
166        enum type_flag
167        {
168                TF_POINTER      = 0x01, //< field is a pointer
169                TF_NOSERIALIZE  = 0x02, //< ignore during serialization
170                TF_INVISIBLE    = 0x04, //< field invisible to API
171                TF_READONLY     = 0x08, //< read only field
172                TF_SIMPLETYPE   = 0x10, //< raw binary I/O possible
173                TF_OWNED        = 0x20,
174                TF_CONTAINER    = 0x40, //< is a container
175        };
176
177        struct type_field
178        {
179                std::string      name;      //< name of the field
180                std::string      type_name; //< name of the type of the field
181                const type_info* type_inf;  //< typeinfo for later retrieval of type
182                type_entry*      type;      //< pointer to field type
183                unsigned int     flags;     //< flags
184                size_t           offset;
185
186                template< typename TOBJECT, typename TFIELD >
187                type_field( const char* name, TFIELD TOBJECT::*field, typename std::enable_if< is_container<TFIELD>::value, void* >::type = nullptr )
188                        : name(name)
189                        , type_name()
190                        , type_inf( &typeid( std::remove_pointer<typename TFIELD::value_type>::type ) )
191                        , type( nullptr )
192                        , flags( 0 )
193                        , offset( offsetof( TOBJECT, *field ) )
194                        // NOTE: if offsetof behaves badly, check offset_of in common.hh
195                {
196                        flags = TF_CONTAINER |
197                                ( std::is_pointer<TFIELD::value_type>::value ? TF_POINTER : 0 ) |
198                                ( std::is_pod<TFIELD::value_type>::value ? TF_SIMPLETYPE : 0 );
199                }
200
201                template< typename TOBJECT, typename TFIELD >
202                type_field( const char* name, TFIELD TOBJECT::*field, typename std::enable_if< !is_container<TFIELD>::value, void* >::type = nullptr )
203                        : name(name)
204                        , type_name()
205                        , type_inf( &typeid( std::remove_pointer<TFIELD>::type ) )
206                        , type( nullptr )
207                        , flags( 0 )
208                        , offset( offsetof( TOBJECT, *field ) )
209                        // NOTE: if offsetof behaves badly, check offset_of in common.hh
210                {
211                        flags =
212                                ( std::is_pointer<TFIELD>::value ? TF_POINTER : 0 ) |
213                                ( std::is_pod<TFIELD>::value ? TF_SIMPLETYPE : 0 );
214                }
215
216                type_field& flag( unsigned int f )
217                {
218                        flags |= f;
219                        return *this;
220                }
221        };
222
223        struct type_enum
224        {
225                std::string name;
226                int         value;
227                type_enum( const char* name, int value ) : name(name), value(value) {}
228        };
229
230    struct type_entry
231    {
232                 // Function types for the constructor and destructor of registered types
233            typedef void (*constructor_func)(void*);
234            typedef void (*destructor_func)(void*);
235
236                // Parent type database
237        class type_database* type_db;
238
239        // Scoped C++ name of the type
240        std::string name;
241 
242        // Pointers to the constructor and destructor functions
243        constructor_func constructor;
244        destructor_func  destructor;
245 
246        // Result of sizeof(type) operation
247        size_t size;
248
249                // Base type
250                type_entry* base_type;
251
252                // Field list
253                std::vector<type_field> field_list;
254
255                // Enum list
256                std::vector<type_enum> enum_list;
257
258                template <int TYPE>
259                type_entry& base()
260                {
261                        base_type = type_db->get_type( typeid(TYPE) );
262                }
263
264                template <int SIZE>
265                type_entry& fields( type_field (&init_fields)[SIZE] )
266                {
267                        for (int i = 0; i < SIZE; i++)
268                        {
269                                type_field f = init_fields[i];
270                                f.type = type_db->get_type(*(f.type_inf));
271                                f.type_name = f.type->name;
272                                field_list.push_back(f);
273                        }
274                        return *this;
275                }
276
277                template <int SIZE>
278                type_entry& enums( type_enum (&init_enums)[SIZE] )
279                {
280                        for (int i = 0; i < SIZE; i++)
281                        {
282                                enum_list.push_back( init_enums[i] );
283                        }
284                        return *this;
285                }
286    };
287
288        // TODO: we don't need the get_type_name template? Can we just base on typeid now, and
289        //       pass type name on creation?
290    class type_database
291    {
292    public:
293                template< typename TYPE >
294        type_entry& create_type( const char* name )
295                {
296                        type_entry* i_type = nullptr;
297                        type_name_map::iterator it = m_name_types.find( name );
298                        if ( it != m_name_types.end() )
299                        {
300                                return *(it->second);
301                        }
302                        i_type          = new type_entry;
303                        i_type->type_db = this;
304                        i_type->name    = name;
305                        i_type->size    = sizeof(TYPE);
306                       
307                        i_type->constructor = ConstructObject<TYPE>;
308                        i_type->destructor  = DestructObject<TYPE>;
309
310                        m_name_types[name]        = i_type;
311                        m_idx_types[typeid(TYPE)] = i_type;
312                        return *i_type;
313                }
314
315                type_entry* get_type( const std::string name )
316                {
317                        type_name_map::iterator it = m_name_types.find( name );
318                        if ( it != m_name_types.end() )
319                        {
320                                return it->second;
321                        }
322                        return nullptr;
323                }
324
325                type_entry* get_type( const type_info& t )
326                {
327                        type_info_map::iterator it = m_idx_types.find( std::type_index(t) );
328                        if ( it != m_idx_types.end() )
329                        {
330                                return it->second;
331                        }
332                        return nullptr;
333                }
334    private:
335                struct compare_type_info {
336                        bool operator ()(const type_info* a, const type_info* b) const {
337                                return a->before(*b);
338                        }
339                };
340
341        typedef std::unordered_map<std::string, type_entry*>     type_name_map;
342                typedef std::unordered_map<std::type_index, type_entry*> type_info_map;
343        type_name_map m_name_types;
344                type_info_map m_idx_types;
345        };
346
347        template <typename TYPE> void ConstructObject(void* object)
348    {
349        // Use placement new to call the constructor
350        new (object) TYPE;
351    }
352    template <typename TYPE> void DestructObject(void* object)
353    {
354        // Explicit call of the destructor
355        ((TYPE*)object)->TYPE::~TYPE();
356    }
357
358}
359
360#endif
361
Note: See TracBrowser for help on using the repository browser.