1 #ifndef s11n_SERIALIZE_HPP_INCLUDED 2 #define s11n_SERIALIZE_HPP_INCLUDED 3 //////////////////////////////////////////////////////////////////////// 4 // serialize.hpp: 5 // 6 // Defines the core de/serialize() functions (and close friends). 7 // 8 // License: Public Domain 9 // Author: stephan@s11n.net 10 //////////////////////////////////////////////////////////////////////// 11 12 #include <stdexcept> 13 14 15 //////////////////////////////////////////////////////////////////////////////// 16 // NO DEPS ON s11n_node.hpp ALLOWED! 17 //////////////////////////////////////////////////////////////////////////////// 18 19 namespace s11n { 20 21 22 namespace Detail { 23 /*** 24 s11n_api_marshaler is the internal API marshaller 25 for s11n. See the lib manual for full 26 details. Client code is not expected to use or 27 specialize this class, but theoretically some 28 cases may call for doing so. In s11n versions 29 prior to 1.0.x, specializing this type was 30 sometimes useful for handling client-side 31 template types, but this is no longer necessary 32 nor encouraged. 33 34 In the default implementation, s11n_traits<NodeT,SerializableT> 35 is used to marshal the de/serialize() calls. 36 37 Changed in 1.1.3: 38 39 - NodeType template param was moved from the static 40 functions to the class. 41 42 - Moved class from anonymous namespace into s11n::Detail. 43 */ 44 template <typename NodeType,typename SerializableT> 45 struct s11n_api_marshaler 46 { 47 /** 48 Same as SerializableT. 49 */ 50 typedef SerializableT serializable_type; 51 52 typedef NodeType node_type; 53 54 /** 55 Returns s11n_traits<serializable_type>::serialize_functor()( dest, src ). 56 57 This implementation sets dest's class name to 58 s11n_traits<SerializableT>::class_name(&src), which 59 is only guaranteed to work properly for monomorphic 60 types and base-most types of Serialization 61 hierarchies (i.e., the registered 62 bases). Polymorphic Serializable subtypes should 63 set this class name themselves, or via their 64 s11n_traits::class_name() specialization, both 65 described in the library manual. 66 67 */ 68 static bool serialize( node_type &dest, const serializable_type & src ); 69 70 /** 71 Returns s11n_traits<SerializableT>::deserialize_functor()(src,dest). 72 */ 73 static bool deserialize( const node_type & src, serializable_type & dest ); 74 }; 75 76 /** 77 A specialization to handle pointer types the same as 78 reference/value types. It simply translates the pointers 79 into references. 80 */ 81 template <typename NodeType,typename SerializableT> 82 struct s11n_api_marshaler<NodeType,SerializableT *> 83 { 84 /** 85 The SerializableT templatized type, minus any 86 pointer part. 87 */ 88 typedef SerializableT serializable_type; 89 90 typedef NodeType node_type; 91 92 /** 93 Convenience typedef: this class' quasi-parent type. 94 */ 95 typedef s11n_api_marshaler<node_type,serializable_type> parent_type; 96 97 /** 98 Returns parent_type::serialize( dest, *src ); 99 100 src must be a valid pointer, else false is returned. 101 */ 102 static bool serialize( node_type &dest, const serializable_type * const & src ); 103 104 /** 105 Returns parent_type::deserialize( src, *dest ); 106 107 dest must be a valid pointer, else false is returned. 108 109 Reminder to self: if we dupe the code from 110 deserialize(const N&,ST *&), we could 111 potentially provide support for passing a 112 reference to a null pointer here. No need, 113 though, since the public s11n API already 114 provides that. 115 */ 116 static bool deserialize( const node_type & src, serializable_type * & dest ); 117 }; 118 } // namespace Detail 119 120 121 /** 122 Serializes src to target using the default API marshaling 123 mechanism. 124 125 On success it always returns true, else false. 126 127 If a the underlying operation throws, it will pass on the 128 exception. 129 */ 130 template <typename DataNodeType, typename SerializableT> 131 bool serialize( DataNodeType & target, const SerializableT & src ); 132 133 /** 134 Calls s11n_traits<SerializableType>::cleanup_functor()(s). 135 136 This function is declared as no-throw because of its 137 logical role in the destruction process, and dtors are 138 normally prohibited from throwing. Any exceptions caught by 139 this function are silently ignored (a warning might go out 140 to a debug channel, probably cerr, but don't rely on it). 141 142 SerializableType requirements: 143 144 - Must be a Serializable. Specifically, it must have an 145 s11n_traits specialization installed. 146 147 - s11n_traits<SerializableType>::cleanup_functor must be 148 known to work properly for SerializableType. This is core 149 to the whole cleanup functionality, which is core to 150 protecting against leaks in the face of errors. 151 152 Technically, if the type can be delete()d without leaking 153 pointers, it's safe for use with this function, but this 154 function SHOULD NOT be used as general cleanup tool. It is 155 ONLY intended to be used with REGISTERED Serializables. 156 157 This function guarantees not to leak when "cleaning up" 158 containers holding unmanaged pointers as long as the 159 associated cleanup_functors do their part. The model is 160 such that once a cleanup_functor is in place for a given 161 type, this function will inherently walk it and invoke the 162 cleanup rules, which includes freeing any pointers along 163 the way. 164 165 Added in 1.1.3. 166 */ 167 template <typename SerializableType> 168 void cleanup_serializable( SerializableType & s ) throw(); 169 170 /** 171 This overload provides cleanup handling for pointer 172 types. This simplifies many algorithms over using 173 s11n_traits<SerializableType>::cleanup_functor directly, as 174 the algorithms do not need to care if they're using 175 pointer-qualified types or not in order to clean them up 176 properly. 177 178 SerializableType requirements are as for the non-pointered 179 variant of this function, plus: 180 181 - delete aSerializableTypeInstance; must be well-formed and 182 must neither throw nor invoke undefined behaviour. (Did 183 you realize that "neither" is an exception to English's 184 "i-before-e" rule?) 185 186 This function does nothing if s is null, otherwise it calls 187 cleanup_serializable(*s), deletes s, then assigns it to 0. 188 189 Postcondition: (0 == s) 190 191 Added in 1.1.3. 192 */ 193 template <typename SerializableType> 194 void cleanup_serializable( SerializableType * & s ) throw(); 195 196 197 /** 198 Intended for use with for_each(), this type cleans up 199 Serializables using cleanup_serializable(). 200 201 Usage: 202 203 std::for_each( container.begin(), container.end(), cleaner_upper() ); 204 205 where the container is parameterized to hold Serializables. 206 207 Provided that the contained type(s) conform to 208 cleanup_ptr's requirements, this will recursively clean up 209 sub-sub-...subcontainers. 210 211 Note that Serializable containers should have a cleanup 212 functor installed as part of their registration, making 213 this class unnecessary for most cases: simply calling 214 cleanup_serializable() will recursively walk/clean such 215 containers. The underlying cleanup algos might use this 216 type, however (at least one of them does). 217 218 Added in 1.1.3. 219 */ 220 struct cleaner_upper 221 { 222 /** 223 Calls cleanup_serializable<T>(t) 224 */ 225 template <typename T> operator ()s11n::cleaner_upper226 void operator()( T & t ) throw() 227 { 228 cleanup_serializable<T>( t ); 229 } 230 /** 231 Calls cleanup_serializable<T>(t). 232 */ 233 template <typename T> operator ()s11n::cleaner_upper234 void operator()( T * & t ) throw() 235 { 236 cleanup_serializable<T>( t ); 237 } 238 }; 239 240 241 /** 242 An auto_ptr-like type intended to simplify 243 pointer/exception safety in some deserialization algorithms 244 by providing a way to completely and safely destroy 245 partially-deserialized objects. 246 247 SerializableT must either have an explicit s11n_traits 248 specialization installed or work properly with the default 249 functor provided by s11n_traits::cleanup_functor. In 250 practice, this means that types which manage the memory of 251 their contained pointers are safe to work with the default, 252 whereas the cleanup of unmanaged child pointers (e.g., std 253 containers) requires a proper specialization. 254 255 Note that this type does not have copy/assignment ctors, 256 due to the conventional constness of their right-hand 257 sides: use the swap() or take() members to take over a 258 pointer. 259 260 Added in 1.1.3. 261 */ 262 template <typename SerializableT> 263 struct cleanup_ptr 264 { 265 public: 266 typedef SerializableT cleaned_type; 267 private: 268 cleaned_type * m_ptr; 269 cleanup_ptr & operator=( const cleanup_ptr & ); // Not Implemented 270 cleanup_ptr( const cleanup_ptr & ); // Not Implemented cleanups11n::cleanup_ptr271 void cleanup() throw() 272 { 273 if( this->m_ptr ) 274 { 275 cleanup_serializable<cleaned_type>( this->m_ptr ); 276 } 277 } 278 public: 279 /** 280 Constructs an object pointing to nothing. 281 */ cleanup_ptrs11n::cleanup_ptr282 cleanup_ptr() throw() : m_ptr(0) 283 { 284 } 285 /** 286 Transfers ownership of p to this object. 287 */ cleanup_ptrs11n::cleanup_ptr288 cleanup_ptr( cleaned_type * p ) throw() : m_ptr(p) 289 { 290 } 291 292 /** 293 Uses s11n::cleanup_serializable<cleaned_type>() 294 to free up up this->get(). 295 */ ~cleanup_ptrs11n::cleanup_ptr296 ~cleanup_ptr() throw() 297 { 298 this->cleanup(); 299 } 300 /** 301 Dereferences this object's pointed-to object. If 302 this object does not point to anything it throws a 303 std::runtime_error with an informative what() 304 message explaining the error. 305 */ operator *s11n::cleanup_ptr306 cleaned_type & operator*() 307 { 308 if( ! this->m_ptr ) 309 { 310 throw std::runtime_error("Attempt to dereference a null pointer via s11n::cleanup_ptr<>::operator*()" ); 311 } 312 return *this->m_ptr; 313 } 314 315 /** 316 Returns the same as get(). 317 */ operator ->s11n::cleanup_ptr318 cleaned_type * operator->() throw() 319 { 320 return this->m_ptr; 321 } 322 323 /** 324 Returns this object's pointed-to object without 325 transfering ownership. 326 */ gets11n::cleanup_ptr327 cleaned_type * get() throw() 328 { 329 return this->m_ptr; 330 } 331 332 /** 333 Transfers ownership of p to this object. This 334 member takes the place of copy/assign operators, 335 since those conventionally take a const right-hand 336 argument. 337 338 Destroys the object this object pointed to before 339 taking over ownership. 0 is a legal value for p. 340 341 If (p == this->get()) then this function does 342 nothing. 343 344 Postcondition: p == this->get() 345 */ takes11n::cleanup_ptr346 void take( cleaned_type * p ) throw() 347 { 348 if( p != this->m_ptr ) 349 { 350 this->cleanup(); 351 this->m_ptr = p; 352 } 353 } 354 355 /** 356 Transfers ownership of this->get() to the 357 caller. 358 359 Postcondition: 0 == this->get() 360 */ releases11n::cleanup_ptr361 cleaned_type * release() throw() 362 { 363 cleaned_type * x = this->m_ptr; 364 this->m_ptr = 0; 365 return x; 366 } 367 368 /** 369 Cleans up any pointed-to object and points this 370 object at 0. Does nothing if this object points 371 to no object. 372 373 Postcondition: 0 == this->get() 374 */ cleans11n::cleanup_ptr375 void clean() throw() 376 { 377 this->take( 0 ); 378 } 379 380 /** 381 Swaps ownership of pointers with rhs. 382 */ swaps11n::cleanup_ptr383 void swap( cleanup_ptr & rhs ) throw() 384 { 385 cleaned_type * x = this->m_ptr; 386 this->m_ptr = rhs.m_ptr; 387 rhs.m_ptr = x; 388 } 389 }; 390 391 392 /** 393 Deserializes target from src using the default API marshaling 394 mechanism. Returns true on success. 395 396 On error it returns false or passes on an exception. In 397 either case, target might be in an undefined state, and may 398 need manual interaction to free up resources (e.g., a list 399 of pointers might have some pointers which need to be 400 cleaned up during exception handling). The exact definition 401 of its state after a failure is specified by the algorithm 402 which deserializes the target (as defined via 403 s11n_traits<DeserializableT>::deserialize_functor). 404 */ 405 template <typename DataNodeType, typename DeserializableT> 406 bool deserialize( const DataNodeType & src, DeserializableT & target ); 407 408 409 /** 410 Like the standard form of deserialize(), but if passed a 411 null pointer, it attempts to classload the class and assign 412 the passed-in pointer to it. If passed a non-null target 413 then it behaves as if target were a reference, simply 414 passing on the target after dereferencing it. 415 416 For example: 417 418 <pre> 419 T * t = 0; 420 deserialize<NodeType,T>( mynode, t ); 421 // t will be non-0 if it worked. 422 423 T * x = new X; 424 if( deserialize<NodeType,T>( mynode, x ) ) 425 { 426 // x is now populated exactly as if we had called: 427 // deserialize<NodeType,T>( mynode, *x ); 428 } 429 </pre> 430 431 To get the class name, the algorithm first tries 432 node_traits<DataNodeType>::class_name(src). If it cannot 433 load a class using that name, it tries 434 s11n_traits<DeserializableT>::class_name(target). 435 436 Underlying calls to s11n::cl::classload() and serialization 437 proxies may throw. If they do, the exception is passed on 438 to the caller. 439 440 If passed a null pointer and this function fails, target is 441 not modified. If deserialization fails, any 442 internally-created (DeserializableT*) is deallocated using 443 cleanup_serializable(). If passed a non-null pointer and 444 the function fails, behaviour is as for the non-pointer 445 variant of deserialize() - target may or may not be in a 446 defined state, as defined by the specific proxy algorithm. 447 448 449 Added in s11n version 1.1.3. 450 451 */ 452 template <typename DataNodeType, typename DeserializableT> 453 bool deserialize( const DataNodeType & src, DeserializableT * & target ); 454 455 /** 456 Identical to deserialize(const 457 DataNodeType&,DeserializableT*&) except that it works on a 458 cleanup_ptr<>. The target may be empty (pointing to zero): 459 if it is then dynamic loading is attempted, as described 460 in the docs for the non-cleanup_ptr variant of this 461 function. 462 463 Returns true if deserialization to the target succeeds, 464 else false. If it returns false, target.get() still points 465 to the same object it did when function was called (which 466 may be 0). Whether or not the contained object is modified 467 on deserialization failure depends on the underlying 468 algorithm used to deserialize it. 469 */ 470 template <typename DataNodeType, typename DeserializableT> 471 bool deserialize( const DataNodeType & src, cleanup_ptr<DeserializableT> & target ); 472 473 /** 474 Tries to deserialize a DeserializableT from src, using 475 <code>s11n_traits<DeserializableT>::factory_type()(node_traits<DataNodeType>::class_name(src))</code> 476 to create a new DeserializableT. 477 478 DeserializableT may not be a pointer-qualified type. 479 480 On error it returns 0 or propagates on an exception, 481 otherwise returns a pointer to a new object, which the 482 caller takes ownership of. 483 484 As of 1.1.3, this function relies on 485 s11n::cleanup_serializable() in order to be able to specify 486 what happens to the internally allocated object if 487 deserialization fails. That function is called on the 488 object before this function returns if deserialization 489 fails. 490 491 Prior to 1.1.3 this function would leak if this function 492 failed and if DeserializableT contained unmanaged pointers 493 (even indirectly, via sub-containment), such as in 494 list<int*> or list<map<int,string*>>. 495 */ 496 template <typename DataNodeType, typename DeserializableT> 497 DeserializableT * deserialize( const DataNodeType & src ); 498 499 500 /** 501 Clones an arbitrary SerializableType using its 502 DataNodeType serialization implementation. 503 504 Returns a clone of tocp, or returns 0 on error. 505 The caller owns the returned pointer. 506 507 This copy is polymorphism-safe as long as all participating 508 Serializables (re)implement the appropriate de/serialize 509 operations, similarly to as they would do for a copy ctor 510 or classical Clone() member function. 511 512 Tip: s11n_clone() is a convenient way to test new 513 de/serialize functions, e.g., for new Serializables, 514 because if it works then deserializing from streams/files 515 will also work. This function takes SerializableType 516 through the whole de/serialize process except for i/o, 517 including classloading. 518 519 This function was renamed from clone() in version 1.1. 520 521 Exceptions and errors: 522 523 This function may return 0 or throw on an error, as 524 dictated by serialize() and then deserialize() (in that 525 order). Thus safety guarantees are defined in terms 526 of those operations. 527 */ 528 template <typename DataNodeType, typename SerializableType> 529 SerializableType * s11n_clone( const SerializableType & tocp ); 530 531 /** 532 "Casts" t1 to t2 using serialization. This will work 533 whenever t1 and t2 are "semantically compatible", whatever 534 that really means. It can be used, e.g., to copy a 535 list<int> to a vector<double>, provided both 536 types have been proxied. In practice, this means: if Type1 537 and Type2 both use the same, or compatible, de/ser 538 algorithms, they are s11n_cast-able to one another. 539 540 Note that in the case of containers, the pointerness of the 541 contained types is irrelevant: this works on both, thus 542 a list<int> can be "cast" to a vector<double*>. 543 544 As usual for a failed deserialization, if it returns false 545 then t2 may be in an undefined state. There is no guaranty, 546 however, that t2's deserialize operator will ever be 547 called, as the serialization of t1 must first succeed 548 for that to happen. 549 550 Type2 may not currently be a pointer type, but Type1 may 551 be. This will be fixed someday (when someone complains). 552 553 Exceptions and errors: 554 555 On error this function will return false or propagate 556 an exception, as dictated by serialize() and then 557 deserialize() (in that order). 558 559 If Type1 and Type2 are not guaranteed to be monomorphic or 560 base-most Serializable types, then it is good practice to 561 explicitely specify them as templatized parameters, and not 562 rely on implicit type selection, which might choose the 563 wrong type (not the base-most one, which is what s11n is 564 "keyed" to), which will mean that s11n "can't find" the 565 registration code for the type. 566 */ 567 template <typename NodeType, typename Type1, typename Type2> 568 bool s11n_cast( const Type1 & t1, Type2 & t2 ); 569 570 571 } // namespace s11n 572 573 #include <s11n.net/s11n/serialize.tpp> // implementations for above-declared code 574 575 576 #endif // s11n_SERIALIZE_HPP_INCLUDED 577