1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL.  If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so.  If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact:  Jari Sundell <jaris@ifi.uio.no>
33 //
34 //           Skomakerveien 33
35 //           3185 Skoppum, NORWAY
36 
37 #ifndef LIBTORRENT_OBJECT_H
38 #define LIBTORRENT_OBJECT_H
39 
40 #include <string>
41 #include <map>
42 #include <vector>
43 #include <torrent/common.h>
44 #include <torrent/exceptions.h>
45 #include <torrent/object_raw_bencode.h>
46 
47 namespace torrent {
48 
49 class LIBTORRENT_EXPORT Object {
50 public:
51   typedef int64_t                           value_type;
52   typedef std::string                       string_type;
53   typedef std::vector<Object>               list_type;
54   typedef std::map<std::string, Object>     map_type;
55   typedef map_type*                         map_ptr_type;
56   typedef map_type::key_type                key_type;
57   typedef std::pair<std::string, Object*>   dict_key_type;
58 
59   typedef list_type::iterator               list_iterator;
60   typedef list_type::const_iterator         list_const_iterator;
61   typedef list_type::reverse_iterator       list_reverse_iterator;
62   typedef list_type::const_reverse_iterator list_const_reverse_iterator;
63 
64   typedef map_type::iterator                map_iterator;
65   typedef map_type::const_iterator          map_const_iterator;
66   typedef map_type::reverse_iterator        map_reverse_iterator;
67   typedef map_type::const_reverse_iterator  map_const_reverse_iterator;
68 
69   typedef std::pair<map_iterator, bool>     map_insert_type;
70 
71   // Flags in the range of 0xffff0000 may be set by the user, however
72   // 0x00ff0000 are reserved for keywords defined by libtorrent.
73   static const uint32_t mask_type     = 0xff;
74   static const uint32_t mask_flags    = ~mask_type;
75   static const uint32_t mask_internal = 0xffff;
76   static const uint32_t mask_public   = ~mask_internal;
77 
78   static const uint32_t flag_unordered    = 0x100;    // bencode dictionary was not sorted
79   static const uint32_t flag_static_data  = 0x010000;  // Object does not change across sessions.
80   static const uint32_t flag_session_data = 0x020000;  // Object changes between sessions.
81   static const uint32_t flag_function     = 0x040000;  // A function object.
82   static const uint32_t flag_function_q1  = 0x080000;  // A quoted function object.
83   static const uint32_t flag_function_q2  = 0x100000;  // A double-quoted function object.
84 
85   static const uint32_t mask_function     = 0x1C0000;  // Mask for function objects.
86 
87   enum type_type {
88     TYPE_NONE,
89     TYPE_RAW_BENCODE,
90     TYPE_RAW_STRING,
91     TYPE_RAW_LIST,
92     TYPE_RAW_MAP,
93     TYPE_VALUE,
94     TYPE_STRING,
95     TYPE_LIST,
96     TYPE_MAP,
97     TYPE_DICT_KEY
98   };
99 
Object()100   Object()                     : m_flags(TYPE_NONE) {}
Object(const value_type v)101   Object(const value_type v)   : m_flags(TYPE_VALUE) { new (&_value()) value_type(v); }
Object(const char * s)102   Object(const char* s)        : m_flags(TYPE_STRING) { new (&_string()) string_type(s); }
Object(const string_type & s)103   Object(const string_type& s) : m_flags(TYPE_STRING) { new (&_string()) string_type(s); }
Object(const raw_bencode & r)104   Object(const raw_bencode& r) : m_flags(TYPE_RAW_BENCODE) { new (&_raw_bencode()) raw_bencode(r); }
Object(const raw_string & r)105   Object(const raw_string& r)  : m_flags(TYPE_RAW_STRING) { new (&_raw_string()) raw_string(r); }
Object(const raw_list & r)106   Object(const raw_list& r)    : m_flags(TYPE_RAW_LIST) { new (&_raw_list()) raw_list(r); }
Object(const raw_map & r)107   Object(const raw_map& r)     : m_flags(TYPE_RAW_MAP) { new (&_raw_map()) raw_map(r); }
108   Object(const Object& b);
109 
~Object()110   ~Object() { clear(); }
111 
112   // TODO: Move this out of the class namespace, call them
113   // make_object_.
114   static Object       create_empty(type_type t);
create_value()115   static Object       create_value()  { return Object(value_type()); }
create_string()116   static Object       create_string() { return Object(string_type()); }
create_list()117   static Object       create_list()   { Object tmp; tmp.m_flags = TYPE_LIST; new (&tmp._list()) list_type(); return tmp; }
create_map()118   static Object       create_map()    { Object tmp; tmp.m_flags = TYPE_MAP; tmp._map_ptr() = new map_type(); return tmp; }
119   static Object       create_dict_key();
120 
121   static Object       create_raw_bencode(raw_bencode obj = raw_bencode());
122   static Object       create_raw_string(raw_string obj = raw_string());
123   static Object       create_raw_list(raw_list obj = raw_list());
124   static Object       create_raw_map(raw_map obj = raw_map());
125 
126   template <typename ForwardIterator>
127   static Object       create_list_range(ForwardIterator first, ForwardIterator last);
128 
from_list(const list_type & src)129   static Object       from_list(const list_type& src) { Object tmp; tmp.m_flags = TYPE_LIST; new (&tmp._list()) list_type(src); return tmp; }
130 
131   // Clear should probably not be inlined due to size and not being
132   // optimized away in pretty much any case. Might not work well in
133   // cases where we pass constant rvalues.
134   void                clear();
135 
type()136   type_type           type() const                            { return (type_type)(m_flags & mask_type); }
flags()137   uint32_t            flags() const                           { return m_flags & mask_flags; }
138 
set_flags(uint32_t f)139   void                set_flags(uint32_t f)                   { m_flags |= f & mask_public; }
unset_flags(uint32_t f)140   void                unset_flags(uint32_t f)                 { m_flags &= ~(f & mask_public); }
141 
set_internal_flags(uint32_t f)142   void                set_internal_flags(uint32_t f)          { m_flags |= f & (mask_internal & ~mask_type); }
unset_internal_flags(uint32_t f)143   void                unset_internal_flags(uint32_t f)        { m_flags &= ~(f & (mask_internal & ~mask_type)); }
144 
145   // Add functions for setting/clearing the public flags.
146 
is_empty()147   bool                is_empty() const                        { return type() == TYPE_NONE; }
is_not_empty()148   bool                is_not_empty() const                    { return type() != TYPE_NONE; }
is_value()149   bool                is_value() const                        { return type() == TYPE_VALUE; }
is_string()150   bool                is_string() const                       { return type() == TYPE_STRING; }
is_string_empty()151   bool                is_string_empty() const                 { return type() != TYPE_STRING || _string().empty(); }
is_list()152   bool                is_list() const                         { return type() == TYPE_LIST; }
is_map()153   bool                is_map() const                          { return type() == TYPE_MAP; }
is_dict_key()154   bool                is_dict_key() const                     { return type() == TYPE_DICT_KEY; }
is_raw_bencode()155   bool                is_raw_bencode() const                  { return type() == TYPE_RAW_BENCODE; }
is_raw_string()156   bool                is_raw_string() const                   { return type() == TYPE_RAW_STRING; }
is_raw_list()157   bool                is_raw_list() const                     { return type() == TYPE_RAW_LIST; }
is_raw_map()158   bool                is_raw_map() const                      { return type() == TYPE_RAW_MAP; }
159 
as_value()160   value_type&         as_value()                              { check_throw(TYPE_VALUE); return _value(); }
as_value()161   const value_type&   as_value() const                        { check_throw(TYPE_VALUE); return _value(); }
as_string()162   string_type&        as_string()                             { check_throw(TYPE_STRING); return _string(); }
as_string()163   const string_type&  as_string() const                       { check_throw(TYPE_STRING); return _string(); }
as_string_c()164   const string_type&  as_string_c() const                     { check_throw(TYPE_STRING); return _string(); }
as_list()165   list_type&          as_list()                               { check_throw(TYPE_LIST); return _list(); }
as_list()166   const list_type&    as_list() const                         { check_throw(TYPE_LIST); return _list(); }
as_map()167   map_type&           as_map()                                { check_throw(TYPE_MAP); return _map(); }
as_map()168   const map_type&     as_map() const                          { check_throw(TYPE_MAP); return _map(); }
as_dict_key()169   string_type&        as_dict_key()                           { check_throw(TYPE_DICT_KEY); return _dict_key().first; }
as_dict_key()170   const string_type&  as_dict_key() const                     { check_throw(TYPE_DICT_KEY); return _dict_key().first; }
as_dict_obj()171   Object&             as_dict_obj()                           { check_throw(TYPE_DICT_KEY); return *_dict_key().second; }
as_dict_obj()172   const Object&       as_dict_obj() const                     { check_throw(TYPE_DICT_KEY); return *_dict_key().second; }
as_raw_bencode()173   raw_bencode&        as_raw_bencode()                        { check_throw(TYPE_RAW_BENCODE); return _raw_bencode(); }
as_raw_bencode()174   const raw_bencode&  as_raw_bencode() const                  { check_throw(TYPE_RAW_BENCODE); return _raw_bencode(); }
as_raw_string()175   raw_string&         as_raw_string()                         { check_throw(TYPE_RAW_STRING); return _raw_string(); }
as_raw_string()176   const raw_string&   as_raw_string() const                   { check_throw(TYPE_RAW_STRING); return _raw_string(); }
as_raw_list()177   raw_list&           as_raw_list()                           { check_throw(TYPE_RAW_LIST); return _raw_list(); }
as_raw_list()178   const raw_list&     as_raw_list() const                     { check_throw(TYPE_RAW_LIST); return _raw_list(); }
as_raw_map()179   raw_map&            as_raw_map()                            { check_throw(TYPE_RAW_MAP); return _raw_map(); }
as_raw_map()180   const raw_map&      as_raw_map() const                      { check_throw(TYPE_RAW_MAP); return _raw_map(); }
181 
has_key(const key_type & k)182   bool                has_key(const key_type& k) const        { check_throw(TYPE_MAP); return _map().find(k) != _map().end(); }
has_key_value(const key_type & k)183   bool                has_key_value(const key_type& k) const  { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_VALUE); }
has_key_string(const key_type & k)184   bool                has_key_string(const key_type& k) const { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_STRING); }
has_key_list(const key_type & k)185   bool                has_key_list(const key_type& k) const   { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_LIST); }
has_key_map(const key_type & k)186   bool                has_key_map(const key_type& k) const    { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_MAP); }
has_key_raw_bencode(const key_type & k)187   bool                has_key_raw_bencode(const key_type& k) const { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_RAW_BENCODE); }
has_key_raw_string(const key_type & k)188   bool                has_key_raw_string(const key_type& k) const { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_RAW_STRING); }
has_key_raw_list(const key_type & k)189   bool                has_key_raw_list(const key_type& k) const { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_RAW_LIST); }
has_key_raw_map(const key_type & k)190   bool                has_key_raw_map(const key_type& k) const { check_throw(TYPE_MAP); return check(_map().find(k), TYPE_RAW_MAP); }
191 
192   // Should have an interface for that returns pointer or something,
193   // so we don't need to search twice.
194 
195   // Make these inline...
196 
197   Object&             get_key(const key_type& k);
198   const Object&       get_key(const key_type& k) const;
199   Object&             get_key(const char* k);
200   const Object&       get_key(const char* k) const;
201 
get_key_value(const T & k)202   template <typename T> value_type&        get_key_value(const T& k)        { return get_key(k).as_value(); }
get_key_value(const T & k)203   template <typename T> const value_type&  get_key_value(const T& k) const  { return get_key(k).as_value(); }
get_key_string(const T & k)204   template <typename T> string_type&       get_key_string(const T& k)       { return get_key(k).as_string(); }
get_key_string(const T & k)205   template <typename T> const string_type& get_key_string(const T& k) const { return get_key(k).as_string(); }
get_key_list(const T & k)206   template <typename T> list_type&         get_key_list(const T& k)         { return get_key(k).as_list(); }
get_key_list(const T & k)207   template <typename T> const list_type&   get_key_list(const T& k) const   { return get_key(k).as_list(); }
get_key_map(const T & k)208   template <typename T> map_type&          get_key_map(const T& k)          { return get_key(k).as_map(); }
get_key_map(const T & k)209   template <typename T> const map_type&    get_key_map(const T& k) const    { return get_key(k).as_map(); }
210 
insert_key(const key_type & k,const Object & b)211   Object&             insert_key(const key_type& k, const Object& b) { check_throw(TYPE_MAP); return _map()[k] = b; }
insert_key_move(const key_type & k,Object & b)212   Object&             insert_key_move(const key_type& k, Object& b)  { check_throw(TYPE_MAP); return _map()[k].move(b); }
213 
214   // 'insert_preserve_*' inserts the object 'b' if the key 'k' does
215   // not exist, else it returns the old entry. The type specific
216   // versions also require the old entry to be of the same type.
217   //
218   // Consider making insert_preserve_* return std::pair<Foo*,bool> or
219   // something similar.
insert_preserve_any(const key_type & k,const Object & b)220   map_insert_type     insert_preserve_any(const key_type& k, const Object& b) { check_throw(TYPE_MAP); return _map().insert(map_type::value_type(k, b)); }
221   map_insert_type     insert_preserve_type(const key_type& k, Object& b);
insert_preserve_copy(const key_type & k,Object b)222   map_insert_type     insert_preserve_copy(const key_type& k, Object b) { return insert_preserve_type(k, b); }
223 
erase_key(const key_type & k)224   void                erase_key(const key_type& k)                   { check_throw(TYPE_MAP); _map().erase(k); }
225 
insert_front(const Object & b)226   Object&             insert_front(const Object& b)                  { check_throw(TYPE_LIST); return *_list().insert(_list().begin(), b); }
insert_back(const Object & b)227   Object&             insert_back(const Object& b)                   { check_throw(TYPE_LIST); return *_list().insert(_list().end(), b); }
228 
229   // Copy and merge operations:
230   Object&             move(Object& b);
231   Object&             swap(Object& b);
232   Object&             swap_same_type(Object& b);
233 
234   // Only map entries are merged.
235   Object&             merge_move(Object& object, uint32_t maxDepth = ~uint32_t());
236   Object&             merge_copy(const Object& object,
237                                  uint32_t skip_mask = flag_static_data,
238                                  uint32_t maxDepth = ~uint32_t());
239 
240   Object&             operator = (const Object& b);
241 
242   // Internal:
243   void                swap_same_type(Object& left, Object& right);
244 
245  private:
check(map_type::const_iterator itr,type_type t)246   inline bool         check(map_type::const_iterator itr, type_type t) const { return itr != _map().end() && itr->second.type() == t; }
check_throw(type_type t)247   inline void         check_throw(type_type t) const                         { if (t != type()) throw bencode_error("Wrong object type."); }
248 
249   uint32_t            m_flags;
250 
251 #ifndef HAVE_STDCXX_0X
_value()252   value_type&         _value()             { return t_value; }
_value()253   const value_type&   _value() const       { return t_value; }
_string()254   string_type&        _string()            { return t_string; }
_string()255   const string_type&  _string() const      { return t_string; }
_list()256   list_type&          _list()              { return t_list; }
_list()257   const list_type&    _list() const        { return t_list; }
_map()258   map_type&           _map()               { return *t_map; }
_map()259   const map_type&     _map() const         { return *t_map; }
_map_ptr()260   map_ptr_type&       _map_ptr()           { return t_map; }
_map_ptr()261   const map_ptr_type& _map_ptr() const     { return t_map; }
_dict_key()262   dict_key_type&       _dict_key()         { return t_dict_key; }
_dict_key()263   const dict_key_type& _dict_key() const   { return t_dict_key; }
_raw_object()264   raw_object&         _raw_object()        { return t_raw_object; }
_raw_object()265   const raw_object&   _raw_object() const  { return t_raw_object; }
_raw_bencode()266   raw_bencode&        _raw_bencode()       { return t_raw_bencode; }
_raw_bencode()267   const raw_bencode&  _raw_bencode() const { return t_raw_bencode; }
_raw_string()268   raw_string&         _raw_string()        { return t_raw_string; }
_raw_string()269   const raw_string&   _raw_string() const  { return t_raw_string; }
_raw_list()270   raw_list&           _raw_list()          { return t_raw_list; }
_raw_list()271   const raw_list&     _raw_list() const    { return t_raw_list; }
_raw_map()272   raw_map&            _raw_map()           { return t_raw_map; }
_raw_map()273   const raw_map&      _raw_map() const     { return t_raw_map; }
274 
275   union pod_types {
276     value_type    t_value;
277     raw_object    t_raw_object;
278     raw_bencode   t_raw_bencode;
279     raw_string    t_raw_string;
280     raw_list      t_raw_list;
281     raw_map       t_raw_map;
282   };
283 
284   union {
285     pod_types     t_pod;
286 
287     value_type    t_value;
288     string_type   t_string;
289     list_type     t_list;
290     map_type*     t_map;
291     dict_key_type t_dict_key;
292     raw_object    t_raw_object;
293     raw_bencode   t_raw_bencode;
294     raw_string    t_raw_string;
295     raw_list      t_raw_list;
296     raw_map       t_raw_map;
297   };
298 
299 #else
300   // #error "WTF we're testing C++11 now."
301 
_value()302   value_type&         _value()             { return reinterpret_cast<value_type&>(t_pod); }
_value()303   const value_type&   _value() const       { return reinterpret_cast<const value_type&>(t_pod); }
_string()304   string_type&        _string()            { return reinterpret_cast<string_type&>(t_string); }
_string()305   const string_type&  _string() const      { return reinterpret_cast<const string_type&>(t_string); }
_list()306   list_type&          _list()              { return reinterpret_cast<list_type&>(t_list); }
_list()307   const list_type&    _list() const        { return reinterpret_cast<const list_type&>(t_list); }
_map()308   map_type&           _map()               { return *reinterpret_cast<map_ptr_type&>(t_pod); }
_map()309   const map_type&     _map() const         { return *reinterpret_cast<const map_ptr_type&>(t_pod); }
_map_ptr()310   map_ptr_type&       _map_ptr()           { return reinterpret_cast<map_ptr_type&>(t_pod); }
_map_ptr()311   const map_ptr_type& _map_ptr() const     { return reinterpret_cast<const map_ptr_type&>(t_pod); }
_dict_key()312   dict_key_type&       _dict_key()         { return reinterpret_cast<dict_key_type&>(t_pod); }
_dict_key()313   const dict_key_type& _dict_key() const   { return reinterpret_cast<const dict_key_type&>(t_pod); }
_raw_object()314   raw_object&         _raw_object()        { return reinterpret_cast<raw_object&>(t_pod); }
_raw_object()315   const raw_object&   _raw_object() const  { return reinterpret_cast<const raw_object&>(t_pod); }
_raw_bencode()316   raw_bencode&        _raw_bencode()       { return reinterpret_cast<raw_bencode&>(t_pod); }
_raw_bencode()317   const raw_bencode&  _raw_bencode() const { return reinterpret_cast<const raw_bencode&>(t_pod); }
_raw_string()318   raw_string&         _raw_string()        { return reinterpret_cast<raw_string&>(t_pod); }
_raw_string()319   const raw_string&   _raw_string() const  { return reinterpret_cast<const raw_string&>(t_pod); }
_raw_list()320   raw_list&           _raw_list()          { return reinterpret_cast<raw_list&>(t_pod); }
_raw_list()321   const raw_list&     _raw_list() const    { return reinterpret_cast<const raw_list&>(t_pod); }
_raw_map()322   raw_map&            _raw_map()           { return reinterpret_cast<raw_map&>(t_pod); }
_raw_map()323   const raw_map&      _raw_map() const     { return reinterpret_cast<const raw_map&>(t_pod); }
324 
325   union pod_types {
326     value_type    t_value;
327     map_type*     t_map;
328     char          t_raw_object[sizeof(raw_object)];
329   };
330 
331   union {
332     pod_types t_pod;
333     char      t_string[sizeof(string_type)];
334     char      t_list[sizeof(list_type)];
335     char      t_dict_key[sizeof(dict_key_type)];
336   };
337 #endif
338 };
339 
340 inline
Object(const Object & b)341 Object::Object(const Object& b) {
342   m_flags = b.m_flags & (mask_type | mask_public);
343 
344   switch (type()) {
345   case TYPE_NONE:
346   case TYPE_RAW_BENCODE:
347   case TYPE_RAW_STRING:
348   case TYPE_RAW_LIST:
349   case TYPE_RAW_MAP:
350   case TYPE_VALUE:       t_pod = b.t_pod; break;
351   case TYPE_STRING:      new (&_string()) string_type(b._string()); break;
352   case TYPE_LIST:        new (&_list()) list_type(b._list()); break;
353   case TYPE_MAP:         _map_ptr() = new map_type(b._map()); break;
354   case TYPE_DICT_KEY:
355     new (&_dict_key().first) string_type(b._dict_key().first);
356     _dict_key().second = new Object(*b._dict_key().second); break;
357   }
358 }
359 
360 inline Object
create_empty(type_type t)361 Object::create_empty(type_type t) {
362   switch (t) {
363   case TYPE_RAW_BENCODE: return create_raw_bencode();
364   case TYPE_RAW_STRING:  return create_raw_string();
365   case TYPE_RAW_LIST:    return create_raw_list();
366   case TYPE_RAW_MAP:     return create_raw_map();
367   case TYPE_VALUE:       return create_value();
368   case TYPE_STRING:      return create_string();
369   case TYPE_LIST:        return create_list();
370   case TYPE_MAP:         return create_map();
371   case TYPE_DICT_KEY:    return create_dict_key();
372   case TYPE_NONE:
373   default: return torrent::Object();
374   }
375 }
376 
377 inline Object
object_create_raw_bencode_c_str(const char str[])378 object_create_raw_bencode_c_str(const char str[]) {
379   return Object::create_raw_bencode(raw_bencode(str, strlen(str)));
380 }
381 
382 // TODO: These do not preserve the flag...
383 
384 Object object_create_normal(const raw_bencode& obj) LIBTORRENT_EXPORT;
385 Object object_create_normal(const raw_list& obj) LIBTORRENT_EXPORT;
386 Object object_create_normal(const raw_map& obj) LIBTORRENT_EXPORT;
object_create_normal(const raw_string & obj)387 inline Object object_create_normal(const raw_string& obj) { return torrent::Object(obj.as_string()); }
388 
389 inline Object
create_dict_key()390 Object::create_dict_key() {
391   Object tmp;
392   tmp.m_flags = TYPE_DICT_KEY;
393   new (&tmp._dict_key()) dict_key_type();
394   tmp._dict_key().second = new Object();
395   return tmp;
396 }
397 
398 inline Object
create_raw_bencode(raw_bencode obj)399 Object::create_raw_bencode(raw_bencode obj) {
400   Object tmp; tmp.m_flags = TYPE_RAW_BENCODE; new (&tmp._raw_bencode()) raw_bencode(obj); return tmp;
401 }
402 
403 inline Object
create_raw_string(raw_string obj)404 Object::create_raw_string(raw_string obj) {
405   Object tmp; tmp.m_flags = TYPE_RAW_STRING; new (&tmp._raw_string()) raw_string(obj); return tmp;
406 }
407 
408 inline Object
create_raw_list(raw_list obj)409 Object::create_raw_list(raw_list obj) {
410   Object tmp; tmp.m_flags = TYPE_RAW_LIST; new (&tmp._raw_list()) raw_list(obj); return tmp;
411 }
412 
413 inline Object
create_raw_map(raw_map obj)414 Object::create_raw_map(raw_map obj) {
415   Object tmp; tmp.m_flags = TYPE_RAW_MAP; new (&tmp._raw_map()) raw_map(obj); return tmp;
416 }
417 
418 inline Object
object_create_normal(const Object & obj)419 object_create_normal(const Object& obj) {
420   switch (obj.type()) {
421   case Object::TYPE_RAW_BENCODE: return object_create_normal(obj.as_raw_bencode());
422   case Object::TYPE_RAW_STRING:  return object_create_normal(obj.as_raw_string());
423   case Object::TYPE_RAW_LIST:    return object_create_normal(obj.as_raw_list());
424   case Object::TYPE_RAW_MAP:     return object_create_normal(obj.as_raw_map());
425   default: return obj;
426   }
427 }
428 
429 inline std::string
object_create_string(const torrent::Object & obj)430 object_create_string(const torrent::Object& obj) {
431   switch (obj.type()) {
432   case Object::TYPE_RAW_BENCODE: return obj.as_raw_bencode().as_raw_string().as_string();
433   case Object::TYPE_RAW_STRING:  return obj.as_raw_string().as_string();
434   default: return obj.as_string();
435   }
436 }
437 
438 template <typename ForwardIterator>
439 inline Object
create_list_range(ForwardIterator first,ForwardIterator last)440 Object::create_list_range(ForwardIterator first, ForwardIterator last) {
441   Object tmp; tmp.m_flags = TYPE_LIST; new (&tmp._list()) list_type(first, last); return tmp;
442 }
443 
444 inline void
clear()445 Object::clear() {
446   switch (type()) {
447   case TYPE_STRING:   _string().~string_type(); break;
448   case TYPE_LIST:     _list().~list_type(); break;
449   case TYPE_MAP:      delete _map_ptr(); break;
450   case TYPE_DICT_KEY: delete _dict_key().second; _dict_key().~dict_key_type(); break;
451   default: break;
452   }
453 
454   // Only clear type?
455   m_flags = TYPE_NONE;
456 }
457 
458 inline void
swap_same_type(Object & left,Object & right)459 Object::swap_same_type(Object& left, Object& right) {
460   std::swap(left.m_flags, right.m_flags);
461 
462   switch (left.type()) {
463   case Object::TYPE_STRING:   left._string().swap(right._string()); break;
464   case Object::TYPE_LIST:     left._list().swap(right._list()); break;
465   case Object::TYPE_DICT_KEY:
466     std::swap(left._dict_key().first, right._dict_key().first);
467     std::swap(left._dict_key().second, right._dict_key().second); break;
468   default: std::swap(left.t_pod, right.t_pod); break;
469   }
470 }
471 
swap(Object & left,Object & right)472 inline void swap(Object& left, Object& right) { left.swap(right); }
473 
474 inline bool
object_equal(const Object & left,const Object & right)475 object_equal(const Object& left, const Object& right) {
476   if (left.type() != right.type())
477     return false;
478 
479   switch (left.type()) {
480   case Object::TYPE_NONE:        return true;
481   case Object::TYPE_VALUE:       return left.as_value() == right.as_value();
482   case Object::TYPE_STRING:      return left.as_string() == right.as_string();
483   default: return false;
484   }
485 }
486 
487 }
488 
489 #endif
490