CppCMS
cppcms/archive_traits.h
00001 
00002 //                                                                             
00003 //  Copyright (C) 2008-2012  Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>     
00004 //                                                                             
00005 //  See accompanying file COPYING.TXT file for licensing details.
00006 //
00008 #ifndef CPPCMS_ARCHIVE_TRAITS_H
00009 #define CPPCMS_ARCHIVE_TRAITS_H
00010 
00011 #include <cppcms/serialization_classes.h>
00012 #include <cppcms/json.h>
00013 
00014 #include <booster/shared_ptr.h>
00015 #include <booster/intrusive_ptr.h>
00016 #include <booster/hold_ptr.h>
00017 #include <booster/clone_ptr.h>
00018 #include <booster/copy_ptr.h>
00019 
00020 #include <booster/traits/enable_if.h>
00021 #include <booster/traits/is_base_of.h>
00022 
00023 #include <memory>
00024 #include <iterator>
00025 #include <map>
00026 #include <vector>
00027 #include <list>
00028 #include <set>
00029 #include <sstream>
00030 
00032 
00033 namespace cppcms {
00034 
00035                 
00036         template<typename S>
00037         struct archive_traits<S,typename booster::enable_if<booster::is_base_of<serializable_base,S> >::type > {
00038                 static void save(serializable_base const &d,archive &a)
00039                 {
00040                         d.save(a);
00041                 }
00042                 static void load(serializable_base &d,archive &a)
00043                 {
00044                         d.load(a);
00045                 }
00046         };
00047 
00048         template<typename T>
00049         struct archive_traits<T const> {
00050                 static void save(T const &o,archive &a) 
00051                 {
00052                         archive_traits<T>::save(o,a);
00053                 }
00054                 static void load(T &o,archive &a)
00055                 {
00056                         archive_traits<T>::load(o,a);
00057                 }
00058         };
00059         
00060         template<>
00061         struct archive_traits<std::string> {
00062                 static void save(std::string const &o,archive &a) 
00063                 {
00064                         a.write_chunk(o.c_str(),o.size());
00065                 }
00066                 static void load(std::string &o,archive &a)
00067                 {
00068                         std::string res = a.read_chunk_as_string();
00069                         res.swap(o);
00070                 }
00071         };
00072 
00073         namespace details {
00074 
00075                 struct pod_data {
00076                         void *pointer;
00077                         size_t len;
00078                 };
00079 
00080                 struct const_pod_data {
00081                         void const *pointer;
00082                         size_t len;
00083                 };
00084 
00085                 inline archive &operator<<(archive &a,const_pod_data const &d)
00086                 {
00087                         a.write_chunk(d.pointer,d.len);
00088                         return a;
00089                 }
00090 
00091                 
00092                 inline archive &operator&(archive &a,pod_data const &d)
00093                 {
00094                         if(a.mode()==archive::load_from_archive)
00095                                 a.read_chunk(d.pointer,d.len);
00096                         else
00097                                 a.write_chunk(d.pointer,d.len);
00098                         return a;
00099                 }
00100                 inline archive &operator<<(archive &a,pod_data const &d)
00101                 {
00102                         a.write_chunk(d.pointer,d.len);
00103                         return a;
00104                 }
00105                 inline archive &operator>>(archive &a,pod_data const &d)
00106                 {
00107                         a.read_chunk(d.pointer,d.len);
00108                         return a;
00109                 }
00110 
00111         }
00112 
00113         template<typename T>
00114         details::pod_data as_pod(T &v)
00115         {
00116                 details::pod_data d = { &v , sizeof(v) };
00117                 return d;
00118         }
00119         
00120         template<typename T>
00121         details::const_pod_data as_pod(T const &v)
00122         {
00123                 details::const_pod_data d = { &v , sizeof(v) };
00124                 return d;
00125         }
00126         
00127 } // cppcms
00128 
00129 
00130 #define CPPCMS_TRIVIAL_ARCHIVE(Type)                            \
00131 namespace cppcms {                                              \
00132         template<>                                              \
00133         struct archive_traits<std::vector<Type> > {             \
00134                 typedef std::vector<Type> vec;                  \
00135                 static void save(vec const &v,archive &a)       \
00136                 {                                               \
00137                         void const *p=0;                        \
00138                         size_t len=                             \
00139                                 v.size()*sizeof(Type);          \
00140                         if(!v.empty())                          \
00141                                 p=&v.front();                   \
00142                         a.write_chunk(p,len);                   \
00143                 }                                               \
00144                 static void load(vec &v,archive &a)             \
00145                 {                                               \
00146                         size_t n=a.next_chunk_size() /          \
00147                                 sizeof(Type);                   \
00148                         v.clear();                              \
00149                         v.resize(n);                            \
00150                         void *p=0;                              \
00151                         if(!v.empty())                          \
00152                                 p=&v.front();                   \
00153                         a.read_chunk(p,n*sizeof(Type));         \
00154                 }                                               \
00155         };                                                      \
00156                                                                 \
00157         template<int n>                                         \
00158         struct archive_traits<Type[n]> {                        \
00159                 static void save(Type const d[n],archive &a)    \
00160                 {                                               \
00161                         a.write_chunk(&d[0],sizeof(Type)*n);    \
00162                 }                                               \
00163                 static void load(Type d[n],archive &a)          \
00164                 {                                               \
00165                         a.read_chunk(&d[0],sizeof(Type)*n);     \
00166                 }                                               \
00167         };                                                      \
00168         template<int n>                                         \
00169         struct archive_traits<Type const [n]> {                 \
00170                 static void save(Type const d[n],archive &a)    \
00171                 {                                               \
00172                         a.write_chunk(&d[0],sizeof(Type)*n);    \
00173                 }                                               \
00174         };                                                      \
00175                                                                 \
00176         template<>                                              \
00177         struct archive_traits<Type> {                           \
00178                 static void save(Type const d,archive &a)       \
00179                 {                                               \
00180                         a.write_chunk(&d,sizeof(d));            \
00181                 }                                               \
00182                 static void load(Type &d,archive &a)            \
00183                 {                                               \
00184                         a.read_chunk(&d,sizeof(d));             \
00185                 }                                               \
00186         };                                                      \
00187 } /* cppcms */                                          
00188 
00189 CPPCMS_TRIVIAL_ARCHIVE(char)
00190 CPPCMS_TRIVIAL_ARCHIVE(signed char)
00191 CPPCMS_TRIVIAL_ARCHIVE(unsigned char)
00192 CPPCMS_TRIVIAL_ARCHIVE(signed short)
00193 CPPCMS_TRIVIAL_ARCHIVE(unsigned short)
00194 CPPCMS_TRIVIAL_ARCHIVE(signed int)
00195 CPPCMS_TRIVIAL_ARCHIVE(unsigned int)
00196 CPPCMS_TRIVIAL_ARCHIVE(signed long)
00197 CPPCMS_TRIVIAL_ARCHIVE(unsigned long)
00198 CPPCMS_TRIVIAL_ARCHIVE(signed long long)
00199 CPPCMS_TRIVIAL_ARCHIVE(unsigned long long)
00200 CPPCMS_TRIVIAL_ARCHIVE(wchar_t)
00201 CPPCMS_TRIVIAL_ARCHIVE(float)
00202 CPPCMS_TRIVIAL_ARCHIVE(double)
00203 CPPCMS_TRIVIAL_ARCHIVE(long double)
00204 
00205 
00206 namespace cppcms {
00207 
00208         template<typename T,int size>
00209         struct archive_traits<T [size]> 
00210         {
00211                 static void save(T const d[size],archive &a)
00212                 {
00213                         for(int i=0;i<size;i++)
00214                                 archive_traits<T>::save(d[i],a);
00215                 }
00216                 static void load(T d[size],archive &a)
00217                 {
00218                         for(int i=0;i<size;i++)
00219                                 archive_traits<T>::load(d[i],a);
00220                 }
00221         };
00222 
00223         template<typename F,typename S>
00224         struct archive_traits<std::pair<F,S> > 
00225         {
00226                 static void save(std::pair<F,S> const &d,archive &a)
00227                 {
00228                         archive_traits<F>::save(d.first,a);
00229                         archive_traits<S>::save(d.second,a);
00230                 }
00231                 static void load(std::pair<F,S> &d,archive &a)
00232                 {
00233                         archive_traits<F>::load(d.first,a);
00234                         archive_traits<S>::load(d.second,a);
00235                 }
00236         };
00237 
00238         template<>
00239         struct archive_traits<json::value> {
00240                 static void save(json::value const &v,archive &a)
00241                 {
00242                         std::ostringstream ss;
00243                         v.save(ss);
00244                         std::string s=ss.str();
00245                         a.write_chunk(s.c_str(),s.size());
00246                 }
00247                 static void load(json::value &v,archive &a)
00248                 {
00249                         std::istringstream ss;
00250                         ss.str(a.read_chunk_as_string());
00251                         if(!v.load(ss,true)) {
00252                                 throw archive_error("Invalid json");
00253                         }
00254                 }
00255         };
00256 
00257         namespace details {
00258                 
00259                 template<typename T>
00260                 void archive_save_container(T const &v,archive &a)
00261                 {
00262                         typename T::const_iterator it;
00263                         typedef typename T::value_type value_type;
00264                         size_t n=v.size();
00265                         archive_traits<size_t>::save(n,a);
00266                         for(it=v.begin();it!=v.end();++it) {
00267                                 archive_traits<value_type>::save(*it,a);
00268                         }
00269                 }
00270 
00271                 template<typename T>
00272                 void archive_load_container(T &v,archive &a)
00273                 {
00274                         size_t n;
00275                         archive_traits<size_t>::load(n,a);
00276                         v.clear();
00277                         std::insert_iterator<T> it(v,v.begin());
00278                         typedef typename T::value_type value_type;
00279                         for(size_t i=0;i<n;i++) {
00280                                 value_type tmp;
00281                                 archive_traits<value_type>::load(tmp,a);
00282                                 *it++ = tmp;
00283                         }
00284                 }
00285         } // details
00286 
00287 
00288 
00289 } 
00290 
00291 #define CPPCMS_CONTAINER_ARCHIVE2(Type)                                 \
00292 namespace cppcms {                                                      \
00293         template<typename V1,typename V2>                               \
00294         struct archive_traits<Type<V1,V2> >                             \
00295         {                                                               \
00296                 typedef Type<V1,V2> cont;                               \
00297                 static void save(cont const &d,archive &a)              \
00298                 {                                                       \
00299                         details::archive_save_container<cont>(d,a);     \
00300                 }                                                       \
00301                 static void load(cont &v,archive &a)                    \
00302                 {                                                       \
00303                         size_t n;                                       \
00304                         archive_traits<size_t>::load(n,a);              \
00305                         v.clear();                                      \
00306                         typedef std::pair<V1,V2> pair_type;             \
00307                         for(size_t i=0;i<n;i++) {                       \
00308                                 pair_type tmp;                          \
00309                                 archive_traits<pair_type>::load(tmp,a); \
00310                                 v.insert(tmp);                          \
00311                         }                                               \
00312                 }                                                       \
00313         };                                                              \
00314 } /* cppcms */
00315         
00316 #define CPPCMS_CONTAINER_ARCHIVE(Type)                                  \
00317 namespace cppcms {                                                      \
00318         template<typename V>                                            \
00319         struct archive_traits<Type<V> >                                 \
00320         {                                                               \
00321                 static void save(Type<V> const &d,archive &a)           \
00322                 {                                                       \
00323                         details::archive_save_container<Type<V> >(d,a); \
00324                 }                                                       \
00325                 static void load(Type<V> &d,archive &a)                 \
00326                 {                                                       \
00327                         details::archive_load_container<Type<V> >(d,a); \
00328                 }                                                       \
00329         };                                                              \
00330 } /* cppcms */
00331 
00332 CPPCMS_CONTAINER_ARCHIVE(std::vector)
00333 CPPCMS_CONTAINER_ARCHIVE(std::list)
00334 CPPCMS_CONTAINER_ARCHIVE2(std::map)
00335 CPPCMS_CONTAINER_ARCHIVE2(std::multimap)
00336 CPPCMS_CONTAINER_ARCHIVE(std::set)
00337 CPPCMS_CONTAINER_ARCHIVE(std::multiset)
00338 
00339 #define CPPCMS_ARCHIVE_SMART_POINTER(SmartPtr)                  \
00340 namespace cppcms {                                              \
00341         template<typename V>                                    \
00342         struct archive_traits<SmartPtr<V> > {                   \
00343                 typedef SmartPtr<V> pointer;                    \
00344                 static void save(pointer const &d,archive &a)   \
00345                 {                                               \
00346                         char empty = d.get() == 0;              \
00347                         a.write_chunk(&empty,1);                \
00348                         if(!empty) {                            \
00349                                 archive_traits<V>::save(*d,a);  \
00350                         }                                       \
00351                 }                                               \
00352                 static void load(pointer &d,archive &a)         \
00353                 {                                               \
00354                         char empty;                             \
00355                         a.read_chunk(&empty,1);                 \
00356                         if(empty) {                             \
00357                                 d.reset();                      \
00358                         }                                       \
00359                         else {                                  \
00360                                 d.reset(new V());               \
00361                                 archive_traits<V>::load(*d,a);  \
00362                         }                                       \
00363                 }                                               \
00364         };                                                      \
00365 } /* cppcms */
00366 
00367 
00368 #define CPPCMS_ARCHIVE_INTRUSIVE_POINTER(SmartPtr)              \
00369 namespace cppcms {                                              \
00370         template<typename V>                                    \
00371         struct archive_traits<SmartPtr<V> > {                   \
00372                 typedef SmartPtr<V> pointer;                    \
00373                 static void save(pointer const &d,archive &a)   \
00374                 {                                               \
00375                         char empty = d.get() == 0;              \
00376                         a.write_chunk(&empty,1);                \
00377                         if(!empty) {                            \
00378                                 archive_traits<V>::save(*d,a);  \
00379                         }                                       \
00380                 }                                               \
00381                 static void load(pointer &d,archive &a)         \
00382                 {                                               \
00383                         char empty;                             \
00384                         a.read_chunk(&empty,1);                 \
00385                         if(empty) {                             \
00386                                 d = 0;                          \
00387                         }                                       \
00388                         else {                                  \
00389                                 d = new V();                    \
00390                                 archive_traits<V>::load(*d,a);  \
00391                         }                                       \
00392                 }                                               \
00393         };                                                      \
00394 } /* cppcms */
00395 
00396 
00397 
00398 
00399 CPPCMS_ARCHIVE_SMART_POINTER(booster::shared_ptr)
00400 CPPCMS_ARCHIVE_SMART_POINTER(booster::hold_ptr)
00401 CPPCMS_ARCHIVE_SMART_POINTER(booster::copy_ptr)
00402 CPPCMS_ARCHIVE_SMART_POINTER(booster::clone_ptr)
00403 CPPCMS_ARCHIVE_SMART_POINTER(std::auto_ptr)
00404 CPPCMS_ARCHIVE_INTRUSIVE_POINTER(booster::intrusive_ptr)
00405 
00406 
00407 
00409 
00410 
00411 #endif