Fairport  v1.0.38
fairport/ltp/nameid.h
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 #ifndef FAIRPORT_LTP_NAMEID_H
00007 #define FAIRPORT_LTP_NAMEID_H
00008 
00009 #include <string>
00010 #include <algorithm>
00011 
00012 #include "fairport/util/primitives.h"
00013 
00014 #include "fairport/ndb/database_iface.h"
00015 
00016 #include "fairport/ltp/propbag.h"
00017 
00018 namespace fairport
00019 {
00020 
00023 
00030 class named_prop
00031 {
00032 public:
00036     named_prop(const guid& g, long id) 
00037         : m_guid(g), m_is_string(false), m_id(id) { }
00041     named_prop(const guid& g, const std::wstring& name)
00042         : m_guid(g), m_is_string(true), m_id(0), m_name(name) { }
00043 
00046     const guid& get_guid() const { return m_guid; }
00049     bool is_string() const { return m_is_string; }
00053     long get_id() const { return m_id; }
00057     const std::wstring& get_name() const { return m_name; }
00058 
00059 private:
00060     guid m_guid;            
00061     bool m_is_string;       
00062     long m_id;              
00063     std::wstring m_name;    
00064 };
00065 
00075 class name_id_map : private boost::noncopyable
00076 {
00077 public:
00082     name_id_map(const shared_db_ptr& db) 
00083         : m_bag(db->lookup_node(nid_name_id_map)), m_buckets(m_bag.read_prop<slong>(0x1)), m_entry_stream(m_bag.open_prop_stream(0x3)), m_guid_stream(m_bag.open_prop_stream(0x2)), m_string_stream(m_bag.open_prop_stream(0x4)) { }
00084 
00089     bool name_exists(const guid& g, const std::wstring& name) const
00090         { return named_prop_exists(named_prop(g, name)); }
00095     bool id_exists(const guid& g, long id) const
00096         { return named_prop_exists(named_prop(g, id)); }
00100     bool named_prop_exists(const named_prop& p) const;
00104     bool prop_id_exists(prop_id id) const;
00107     size_t get_prop_count() const;
00108 
00111     std::vector<prop_id> get_prop_list() const;
00112 
00118     prop_id lookup(const guid& g, const std::wstring& name) const
00119         { return lookup(named_prop(g, name)); }
00125     prop_id lookup(const guid& g, long id) const
00126         { return lookup(named_prop(g, id)); }
00131     prop_id lookup(const named_prop& p) const;
00132 
00137     named_prop lookup(prop_id id) const;
00138 
00139 private:
00140     // helper functions
00141     named_prop construct(const disk::nameid& entry) const;
00142     named_prop construct(ulong index) const;
00147     guid read_guid(ushort guid_index) const;
00148     ushort get_guid_index(const guid& g) const;
00149     std::wstring read_wstring(ulong string_offset) const;
00150     ulong compute_hash_base(const named_prop& n) const; 
00151     ulong compute_hash_value(ushort guid_index, const named_prop& n) const
00152         { return (n.is_string() ? ((guid_index << 1) | 1) : (guid_index << 1)) ^ compute_hash_base(n); }
00153     prop_id get_bucket_prop(ulong hash_value) const
00154         { return static_cast<prop_id>((hash_value % m_buckets) + 0x1000); }
00155 
00156     property_bag m_bag;                     
00157     ulong m_buckets;                        
00158     mutable prop_stream m_entry_stream;     
00159     mutable prop_stream m_guid_stream;      
00160     mutable prop_stream m_string_stream;    
00161 };
00162 
00163 inline fairport::named_prop fairport::name_id_map::construct(const disk::nameid& entry) const
00164 {
00165     if(nameid_is_string(entry))
00166         return named_prop(read_guid(disk::nameid_get_guid_index(entry)), read_wstring(entry.string_offset));
00167     else
00168         return named_prop(read_guid(disk::nameid_get_guid_index(entry)), entry.id);
00169 }
00170 
00171 inline fairport::named_prop fairport::name_id_map::construct(ulong index) const
00172 {
00173     disk::nameid entry;
00174     m_entry_stream.seekg(index * sizeof(disk::nameid), std::ios_base::beg);
00175     m_entry_stream.read((char*)&entry, sizeof(entry));
00176     return construct(entry);
00177 }
00178 
00179 inline fairport::guid fairport::name_id_map::read_guid(ushort guid_index) const
00180 {
00181     if(guid_index == 0)
00182         return ps_none;
00183     if(guid_index == 1)
00184         return ps_mapi;
00185     if(guid_index == 2)
00186         return ps_public_strings;
00187 
00188     guid g;
00189     m_guid_stream.seekg((guid_index-3) * sizeof(guid), std::ios_base::beg);
00190     m_guid_stream.read((char*)&g, sizeof(g));
00191     return g;
00192 }
00193 
00194 inline fairport::ushort fairport::name_id_map::get_guid_index(const guid& g) const
00195 {
00196     if(memcmp(&g, &ps_none, sizeof(g)) == 0)
00197         return 0;
00198     if(memcmp(&g, &ps_mapi, sizeof(g)) == 0)
00199         return 1;
00200     if(memcmp(&g, &ps_public_strings, sizeof(g)) == 0)
00201         return 2;
00202 
00203     guid g_disk;
00204     ushort num = 0;
00205     m_guid_stream.seekg(0, std::ios_base::beg);
00206     while(m_guid_stream.read((char*)&g_disk, sizeof(g_disk)))
00207     {
00208         if(memcmp(&g, &g_disk, sizeof(g)) == 0)
00209             return num + 3;
00210         ++num;
00211     }
00212 
00213     // didn't find it
00214     m_guid_stream.clear();
00215     throw key_not_found<guid>(g);
00216 }
00217 
00218 inline std::wstring fairport::name_id_map::read_wstring(ulong string_offset) const
00219 {
00220     m_string_stream.seekg(string_offset, std::ios_base::beg);
00221 
00222     ulong size;
00223     m_string_stream.read((char*)&size, sizeof(size));
00224 
00225     std::vector<byte> buffer(size);
00226     m_string_stream.read(reinterpret_cast<char *>(&buffer[0]), size);
00227 
00228     return bytes_to_wstring(buffer);
00229 }
00230 
00231 inline fairport::ulong fairport::name_id_map::compute_hash_base(const named_prop& n) const {
00232     if(n.is_string())
00233     {
00234         std::vector<byte> bytes(wstring_to_bytes(n.get_name()));
00235         return disk::compute_crc(&bytes[0], bytes.size());
00236     }
00237     else
00238     {
00239         return n.get_id();
00240     }
00241 }
00242 
00243 inline bool fairport::name_id_map::named_prop_exists(const named_prop& p) const
00244 {
00245     try 
00246     {
00247         lookup(p);
00248         return true;
00249     }
00250     catch(std::exception&)
00251     {
00252         return false;
00253     }
00254 }
00255 
00256 inline bool fairport::name_id_map::prop_id_exists(prop_id id) const
00257 {
00258     if(id >= 0x8000)
00259         return static_cast<size_t>((id - 0x8000)) < get_prop_count();
00260 
00261     // id < 0x8000 is a ps_mapi prop
00262     return true;
00263 }
00264 
00265 inline std::vector<prop_id> fairport::name_id_map::get_prop_list() const
00266 {
00267     disk::nameid entry;
00268     std::vector<prop_id> props;
00269 
00270     m_entry_stream.seekg(0, std::ios_base::beg);
00271     while(m_entry_stream.read((char*)&entry, sizeof(entry)) != 0)
00272         props.push_back(nameid_get_prop_index(entry) + 0x8000);
00273 
00274     m_entry_stream.clear();
00275 
00276     return props;
00277 }
00278 
00279 inline size_t fairport::name_id_map::get_prop_count() const
00280 {
00281     m_entry_stream.seekg(0, std::ios_base::end);
00282 
00283     return static_cast<size_t>(m_entry_stream.tellg()) / sizeof(disk::nameid);
00284 }
00285 
00286 inline fairport::prop_id fairport::name_id_map::lookup(const named_prop& p) const
00287 {
00288     ushort guid_index;
00289     
00290     try
00291     {
00292         guid_index = get_guid_index(p.get_guid());
00293     }
00294     catch(key_not_found<guid>&)
00295     {
00296         throw key_not_found<named_prop>(p);
00297     }
00298 
00299     // special handling of ps_mapi
00300     if(guid_index == 1)
00301     {
00302         if(p.is_string()) throw key_not_found<named_prop>(p);
00303         if(p.get_id() >= 0x8000) throw key_not_found<named_prop>(p);
00304         return static_cast<prop_id>(p.get_id());
00305     }
00306 
00307     ulong hash_value = compute_hash_value(guid_index, p);
00308     ulong hash_base = compute_hash_base(p);
00309 
00310     if(!m_bag.prop_exists(get_bucket_prop(hash_value)))
00311         throw key_not_found<named_prop>(p);
00312 
00313     prop_stream bucket(const_cast<name_id_map*>(this)->m_bag.open_prop_stream(get_bucket_prop(hash_value)));
00314     disk::nameid_hash_entry entry;
00315     while(bucket.read((char*)&entry, sizeof(entry)) != 0)
00316     {
00317         if( (entry.hash_base == hash_base) &&
00318             (disk::nameid_is_string(entry) == p.is_string()) &&
00319             (disk::nameid_get_guid_index(entry) == guid_index)
00320         )
00321         {
00322             // just double check the string..
00323             if(p.is_string())
00324             {
00325                 if(construct(disk::nameid_get_prop_index(entry)).get_name() != p.get_name())
00326                     continue;
00327             }
00328 
00329             // found it!
00330             return disk::nameid_get_prop_index(entry) + 0x8000;
00331         }
00332     }
00333 
00334     throw key_not_found<named_prop>(p);
00335 }
00336 
00337 inline fairport::named_prop fairport::name_id_map::lookup(prop_id id) const
00338 {
00339     if(id < 0x8000)
00340         return named_prop(ps_mapi, id);
00341 
00342     ulong index = id - 0x8000;
00343 
00344     if(index > get_prop_count())
00345         throw key_not_found<prop_id>(id);
00346 
00347     return construct(index);
00348 }
00349 
00350 } // end namespace fairport
00351 
00352 #endif