// file : xsde/cxx/serializer/substitution-map.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include #include // strlen, strcmp, strncmp #ifndef XSDE_EXCEPTIONS # include // assert # include // exit #endif #ifdef XSDE_CUSTOM_ALLOCATOR # include #endif #include #include #include namespace xsde { namespace cxx { namespace serializer { substitution_map* substitution_map_init::map = 0; size_t substitution_map_init::count = 0; substitution_map:: ~substitution_map () { for (const_iterator i (begin ()), e (end ()); i != e; ++i) { hashmap* p = *static_cast (const_cast (*i)); #ifndef XSDE_CUSTOM_ALLOCATOR delete p; #else if (p) p->~hashmap (); cxx::free (p); #endif } } void substitution_map:: insert (const char* root, const char* member_ns, const char* member_name, const char* member_type) { hashmap* m; if (const void* p = find (root)) m = *static_cast (const_cast (p)); else { #ifndef XSDE_CUSTOM_ALLOCATOR m = new hashmap (XSDE_SERIALIZER_SMAP_BUCKET_BUCKETS, sizeof (value)); #else m = static_cast (alloc (sizeof (hashmap))); #ifdef XSDE_EXCEPTIONS alloc_guard mg (m); new (m) hashmap (XSDE_SERIALIZER_SMAP_BUCKET_BUCKETS, sizeof (value)); mg.release (); #else if (m) new (m) hashmap (XSDE_SERIALIZER_SMAP_BUCKET_BUCKETS, sizeof (value)); #endif #endif #ifndef XSDE_EXCEPTIONS if (m == 0 || m->_error () != hashmap::error_none) { error_ = error_no_memory; return; } #endif hashmap::insert (root, &m); #ifndef XSDE_EXCEPTIONS if (_error () != error_none) return; #endif } value v; v.ns_ = member_ns; v.name_ = member_name; m->insert (member_type, &v); #ifndef XSDE_EXCEPTIONS if (m->_error () != hashmap::error_none) error_ = error_no_memory; #endif } bool substitution_map:: check_ (const char*& ns, const char*& name, const char* type, const void* obj, bool top) const { // Call the callback first to allow the user to provide a custom // substitution group mapping. // if (top && callback_ != 0) { if (callback_ (type, obj, ns, name)) return true; } size_t h = hash (name); if (ns) { h = hash (h, " ", 1); h = hash (h, ns); } const bucket* p = find (h); if (p != 0) { // Search for the entry in the bucket. // const size_t el_size = sizeof (element) + sizeof (hashmap*); const char* b = reinterpret_cast (p) + sizeof (bucket); const char* e = b + p->size_ * el_size; size_t nl = ns ? strlen (name) : 0; for (; b < e; b += el_size) { const element* e = reinterpret_cast (b); if (e->hash_ == h) { if (ns == 0) { if (strcmp (e->key_, name) == 0) break; } else { if (strncmp (e->key_, name, nl) == 0 && e->key_[nl] == ' ' && strcmp (e->key_ + nl + 1, ns) == 0) break; } } } if (b != e) { const hashmap* map = *reinterpret_cast ( b + sizeof (element)); // See if we have a direct substitution. // if (const value* v = static_cast (map->find (type))) { ns = v->ns_; name = v->name_; return true; } // Otherwise we have to iterate over possible substitutions and // see if any of them can in turn be substituted with something // that we can use. // for (const_iterator i (map->begin ()), end (map->end ()); i != end; ++i) { const value* v = static_cast (*i); const char* tns = v->ns_; const char* tn = v->name_; if (check_ (tns, tn, type, obj, false)) { ns = tns; name = tn; return true; } } } } return false; } // substitution_map_init // substitution_map_init:: substitution_map_init () { if (count == 0) { #ifndef XSDE_CUSTOM_ALLOCATOR map = new substitution_map (XSDE_SERIALIZER_SMAP_BUCKETS); #else map = static_cast ( alloc (sizeof (substitution_map))); #ifdef XSDE_EXCEPTIONS alloc_guard mg (map); new (map) substitution_map (XSDE_SERIALIZER_SMAP_BUCKETS); mg.release (); #else if (map) new (map) substitution_map (XSDE_SERIALIZER_SMAP_BUCKETS); #endif #endif #ifndef XSDE_EXCEPTIONS if (map == 0 || map->_error () != substitution_map::error_none) { // This is static initialization so there is nothing we can do. // The best thing is to fail fast. abort() would have probably // been the better choice here but it is not available on some // platforms (notably, WinCE). // assert (false); exit (1); } #endif } ++count; } substitution_map_init:: ~substitution_map_init () { if (--count == 0) { #ifndef XSDE_CUSTOM_ALLOCATOR delete map; #else map->~substitution_map (); cxx::free (map); #endif } } // substitution_map_entry // substitution_map_entry:: substitution_map_entry (const char* root, const char* member_ns, const char* member_name, const char* member_type) { substitution_map& m = substitution_map_instance (); m.insert (root, member_ns, member_name, member_type); #ifndef XSDE_EXCEPTIONS if (m._error () != substitution_map::error_none) { // This is static initialization so there is nothing we can do. // The best thing is to fail fast. abort() would have probably // been the better choice here but it is not available on some // platforms (notably, WinCE). // assert (false); exit (1); } #endif } // Callback. // void serializer_smap_callback ( bool (*callback) ( const char* type, const void* obj, const char*& ns, const char*& name)) { substitution_map_instance ().callback (callback); } // Load. // size_t serializer_smap_elements () { return substitution_map_instance ().size (); } size_t serializer_smap_bucket_elements () { size_t r = 0; substitution_map& m = substitution_map_instance (); for (substitution_map::const_iterator i (m.begin ()), e (m.end ()); i != e; ++i) { const hashmap* h = *static_cast (*i); if (h->size () > r) r = h->size (); } return r; } } } }