CppCMS
|
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