Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 11:56:19

0001 //
0002 // Top-level API for serializing and deserializing arbitrary classes
0003 //
0004 
0005 #ifndef GENERS_GENERICIO_HH_
0006 #define GENERS_GENERICIO_HH_
0007 
0008 #include <memory>
0009 
0010 #include "Alignment/Geners/interface/IOPointeeType.hh"
0011 #include "Alignment/Geners/interface/binaryIO.hh"
0012 
0013 #include "Alignment/Geners/interface/ArrayAdaptor.hh"
0014 #include "Alignment/Geners/interface/ClearIfPointer.hh"
0015 #include "Alignment/Geners/interface/StrippedType.hh"
0016 
0017 namespace gs {
0018   /**
0019 // Generic top-level function which can be used to write out
0020 // almost anything. Intended mainly for use inside "write"
0021 // methods of user-developed classes and templates. Returns
0022 // "true" if the argument item is successfully written out.
0023 */
0024   template <class Stream, class Item>
0025   inline bool write_item(Stream &os, const Item &item, const bool writeClassId = true) {
0026     char *ps = nullptr;
0027     return process_const_item<GenericWriter>(item, os, ps, writeClassId);
0028   }
0029 
0030   /**
0031 // A function for overwriting existing objects (which usually live
0032 // on the stack). This function actually skips couple levels of
0033 // indirection which would be generated by a call to "process_item".
0034 */
0035   template <class Stream, class Item>
0036   inline void restore_item(Stream &is, Item *item, const bool readClassId = true) {
0037     typedef std::vector<ClassId> State;
0038     assert(item);
0039     State state;
0040     const bool status = GenericReader<Stream, State, Item *, Int2Type<IOTraits<int>::ISPOINTER>>::process(
0041         item, is, &state, readClassId);
0042     if (is.fail())
0043       throw IOReadFailure("In gs::restore_item: input stream failure");
0044     if (!status)
0045       throw IOInvalidData("In gs::restore_item: invalid input stream data");
0046   }
0047 
0048   /**
0049 // Function for returning objects on the heap. This function
0050 // requires explicit specification of its first template
0051 // parameter, the type of the item to read. This function
0052 // either succeeds or throws an exception which inherits
0053 // from std::exception.
0054 */
0055   template <class Item, class Stream>
0056   inline std::unique_ptr<Item> read_item(Stream &is, const bool readClassId = true) {
0057     typedef std::vector<ClassId> State;
0058     Item *item = nullptr;
0059     State state;
0060     const bool status = GenericReader<Stream, State, Item *, Int2Type<IOTraits<int>::ISNULLPOINTER>>::process(
0061         item, is, &state, readClassId);
0062     std::unique_ptr<Item> ptr(item);
0063     if (is.fail())
0064       throw IOReadFailure("In gs::read_item: input stream failure");
0065     if (!status || item == nullptr)
0066       throw IOInvalidData("In gs::read_item: invalid input stream data");
0067     return ptr;
0068   }
0069 
0070   /**
0071 // Generic top-level function for writing arrays. Note that
0072 // the length of the array is not written out and that the
0073 // length must be known in advance in the scope from which
0074 // the companion function, "read_array", is called. "true"
0075 // is returned upon success, "false" on failure.
0076 */
0077   template <class Stream, class Item>
0078   inline bool write_array(Stream &os, Item *items, const std::size_t length) {
0079     char *ps = nullptr;
0080     return process_const_item<GenericWriter>(ArrayAdaptor<Item>(items, length), os, ps, false);
0081   }
0082 
0083   /**
0084 // Function for deserializing arrays. The length of the array
0085 // must be known in the scope from which this function is invoked.
0086 */
0087   template <class Stream, class Item>
0088   inline void read_array(Stream &is, Item *items, const std::size_t length) {
0089     typedef std::vector<ClassId> State;
0090     State state;
0091     ArrayAdaptor<Item> adap(items, length);
0092     const bool st = process_item<GenericReader>(adap, is, &state, false);
0093     if (is.fail())
0094       throw IOReadFailure("In gs::read_array: input stream failure");
0095     if (!st)
0096       throw IOInvalidData("In gs::read_array: invalid input stream data");
0097   }
0098 }  // namespace gs
0099 
0100 namespace gs {
0101   template <class Stream, class State, class Item, class Stage>
0102   struct GenericWriter2 : public GenericWriter<Stream, State, Item, Stage> {};
0103 
0104   template <class Stream, class State, class Item, class Stage>
0105   struct GenericReader2 : public GenericReader<Stream, State, Item, Stage> {};
0106 
0107   // The reader and writer templates should be specialized
0108   // (that is, their "process" function should be defined) using
0109   // the following processing stage types from "ProcessItem.hh":
0110   //
0111   // Int2Type<IOTraits<int>::ISPOD>                (+readIntoPtr)
0112   // InContainerHeader
0113   // InContainerFooter
0114   // InContainerSize
0115   // InPODArray
0116   // Int2Type<IOTraits<int>::ISWRITABLE>
0117   // Int2Type<IOTraits<int>::ISPOINTER>
0118   // Int2Type<IOTraits<int>::ISSHAREDPTR>
0119   // Int2Type<IOTraits<int>::ISPAIR>               (+readIntoPtr)
0120   // Int2Type<IOTraits<int>::ISSTRING>             (+readIntoPtr)
0121   //
0122   // In addition, the reader should be specialized for the following
0123   // types:
0124   //
0125   // InContainerCycle                              (process     only)
0126   // Int2Type<IOTraits<int>::ISSTDCONTAINER>       (readIntoPtr only)
0127   // Int2Type<IOTraits<int>::ISHEAPREADABLE>       (readIntoPtr only)
0128   // Int2Type<IOTraits<int>::ISPLACEREADABLE>      (readIntoPtr only)
0129   //
0130   // The resulting code is essentially one big compile-time state
0131   // machine with two main switching hubs: "process_item" function
0132   // from "ProcessItem.hh" and "process" function in GenericReader
0133   // template specialized for bare pointers.
0134   //
0135 
0136   //===================================================================
0137   //
0138   // Processing of a POD
0139   //
0140   //===================================================================
0141   template <class Stream, class State, class T>
0142   struct GenericWriter<Stream, State, T, Int2Type<IOTraits<int>::ISPOD>> {
0143     inline static bool process(const T &s, Stream &os, State *, const bool processClassId) {
0144       static const ClassId current(ClassId::makeId<T>());
0145       const bool status = processClassId ? current.write(os) : true;
0146       if (status)
0147         write_pod(os, s);
0148       return status && !os.fail();
0149     }
0150   };
0151 
0152   template <class Stream, class State, class T>
0153   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISPOD>> {
0154     inline static bool readIntoPtr(T *&ptr, Stream &str, State *, const bool processClassId) {
0155       std::unique_ptr<T> myptr;
0156       if (ptr == nullptr)
0157         myptr = std::unique_ptr<T>(new T());
0158       if (processClassId) {
0159         static const ClassId current(ClassId::makeId<T>());
0160         ClassId id(str, 1);
0161         current.ensureSameName(id);
0162       }
0163       read_pod(str, ptr ? ptr : myptr.get());
0164       if (str.fail())
0165         return false;
0166       if (ptr == nullptr)
0167         ptr = myptr.release();
0168       return true;
0169     }
0170 
0171     inline static bool process(T &s, Stream &os, State *st, const bool processClassId) {
0172       T *ps = &s;
0173       return readIntoPtr(ps, os, st, processClassId);
0174     }
0175   };
0176 
0177   //===================================================================
0178   //
0179   // Processing of a container header
0180   //
0181   //===================================================================
0182   template <class Stream, class State, class Container>
0183   struct GenericWriter<Stream, State, Container, InContainerHeader> {
0184     inline static bool process(const Container &, Stream &os, State *, const bool processClassId) {
0185       typedef typename Container::value_type T;
0186 
0187       static const ClassId current(ClassId::makeId<Container>());
0188       bool status = processClassId ? current.write(os) : true;
0189 
0190       // Maybe we do not have to write out the container class id,
0191       // but we do have to write out the item class id -- unless the
0192       // container is just an array of pods. Otherwise we might not
0193       // be able to read the container items back.
0194       if (status && !(IOTraits<T>::IsPOD && IOTraits<Container>::IsContiguous)) {
0195         static const ClassId itemId(ClassId::makeId<T>());
0196         status = itemId.write(os);
0197       }
0198       return status;
0199     }
0200   };
0201 
0202   template <class Stream, class State, class Container>
0203   struct GenericReader<Stream, State, Container, InContainerHeader> {
0204     inline static bool process(Container &a, Stream &is, State *state, const bool processClassId) {
0205       typedef typename Container::value_type T;
0206 
0207       if (processClassId) {
0208         static const ClassId current(ClassId::makeId<Container>());
0209         ClassId id(is, 1);
0210         current.ensureSameName(id);
0211       }
0212       a.clear();
0213       if (!(IOTraits<T>::IsPOD && IOTraits<Container>::IsContiguous)) {
0214         ClassId id(is, 1);
0215 
0216         // Remember the class id of the contained items.
0217         // We need to do this even if the id is invalid because
0218         // the id will be popped back when the "InContainerFooter"
0219         // stage is processed.
0220         state->push_back(id);
0221       }
0222       return true;
0223     }
0224   };
0225 
0226   //===================================================================
0227   //
0228   // Processing of a container footer
0229   //
0230   //===================================================================
0231   template <class Stream, class State, class Container>
0232   struct GenericWriter<Stream, State, Container, InContainerFooter> {
0233     inline static bool process(const Container &, Stream &, State *, bool) { return true; }
0234   };
0235 
0236   template <class Stream, class State, class Container>
0237   struct GenericReader<Stream, State, Container, InContainerFooter> {
0238     inline static bool process(Container &, Stream &, State *state, bool) {
0239       typedef typename Container::value_type T;
0240       if (!(IOTraits<T>::IsPOD && IOTraits<Container>::IsContiguous))
0241         state->pop_back();
0242       return true;
0243     }
0244   };
0245 
0246   //===================================================================
0247   //
0248   // Processing of container size
0249   //
0250   //===================================================================
0251   template <class Stream, class State, class Container>
0252   struct GenericWriter<Stream, State, Container, InContainerSize> {
0253     inline static bool process(const std::size_t &sz, Stream &os, State *, bool /* processClassId */) {
0254       write_pod(os, sz);
0255       return !os.fail();
0256     }
0257   };
0258 
0259   template <class Stream, class State, class Container>
0260   struct GenericReader<Stream, State, Container, InContainerSize> {
0261     inline static bool process(std::size_t &sz, Stream &is, State *, bool /* processClassId */) {
0262       read_pod(is, &sz);
0263       return !is.fail();
0264     }
0265   };
0266 
0267   //===================================================================
0268   //
0269   // Processing of data in contiguous POD containers
0270   //
0271   //===================================================================
0272   template <class Stream, class State, class ArrayLike>
0273   struct GenericWriter<Stream, State, ArrayLike, InPODArray> {
0274     inline static bool process(const ArrayLike &a, Stream &os, State *, bool) {
0275       const std::size_t len = a.size();
0276       write_pod(os, len);
0277       if (len)
0278         write_pod_array(os, &a[0], len);
0279       return !os.fail();
0280     }
0281   };
0282 
0283   template <class Stream, class State, class ArrayLike>
0284   struct GenericReader<Stream, State, ArrayLike, InPODArray> {
0285     inline static bool process(ArrayLike &a, Stream &s, State *, bool) {
0286       std::size_t len = 0;
0287       read_pod(s, &len);
0288       if (s.fail())
0289         return false;
0290       a.resize(len);
0291       if (!len)
0292         return true;
0293       read_pod_array(s, &a[0], len);
0294       return !s.fail();
0295     }
0296   };
0297 
0298   //===================================================================
0299   //
0300   // Processing of "writable" objects
0301   //
0302   //===================================================================
0303   template <class Stream, class State, class T>
0304   struct GenericWriter<Stream, State, T, Int2Type<IOTraits<int>::ISWRITABLE>> {
0305     inline static bool process(const T &s, Stream &os, State *, const bool processClassId) {
0306       return (processClassId ? s.classId().write(os) : true) && s.write(os) && !os.fail();
0307     }
0308   };
0309 
0310   template <class Stream, class State, class T>
0311   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISWRITABLE>> {
0312     inline static bool process(T &s, Stream &is, State *st, const bool processClassId) {
0313       typedef IOTraits<T> M;
0314       T *ps = &s;
0315       return GenericReader<Stream, State, T, Int2Type<M::Signature &(M::ISPLACEREADABLE | M::ISHEAPREADABLE)>>::
0316           readIntoPtr(ps, is, st, processClassId);
0317     }
0318   };
0319 
0320   //===================================================================
0321   //
0322   // Processing of bare pointers.
0323   //
0324   // The writer simply dereferences the pointer.
0325   //
0326   // In the reader, we want to read stuff into the pointee object,
0327   // or want to create an item on the heap if the pointer value is 0.
0328   //
0329   //===================================================================
0330   template <class Stream, class State, class Ptr>
0331   struct GenericWriter<Stream, State, Ptr, Int2Type<IOTraits<int>::ISPOINTER>> {
0332     inline static bool process(const Ptr &ptr, Stream &os, State *s, const bool processClassId) {
0333       // Can't have pointers to pointers. This is a design
0334       // decision which simplifies things considerably.
0335       typedef typename IOPointeeType<Ptr>::type Pointee;
0336       typedef IOTraits<Pointee> M;
0337       static_assert((M::Signature & (M::ISPOINTER | M::ISSHAREDPTR)) == 0, "can not write pointers to pointers");
0338 
0339       // Can't have NULL pointers either. But this
0340       // can be checked at run time only.
0341       assert(ptr);
0342       return process_const_item<GenericWriter2>(*ptr, os, s, processClassId);
0343     }
0344   };
0345 
0346   template <class Stream, class State, class Ptr>
0347   struct GenericReader<Stream, State, Ptr, Int2Type<IOTraits<int>::ISPOINTER>> {
0348     inline static bool process(Ptr &ptr, Stream &str, State *s, const bool processClassId) {
0349       // We need to figure out the type of the pointee
0350       // and make a swich depending on that type.
0351       // Note that the pointee itself can not be a pointer.
0352       typedef typename IOPointeeType<Ptr>::type Pointee;
0353       typedef IOTraits<Pointee> M;
0354       static_assert((M::Signature & (M::ISPOINTER | M::ISSHAREDPTR)) == 0, "can not read pointers to pointers");
0355 
0356       return GenericReader<
0357           Stream,
0358           State,
0359           Pointee,
0360           Int2Type<M::Signature &(M::ISPOD | M::ISSTDCONTAINER | M::ISHEAPREADABLE | M::ISPLACEREADABLE | M::ISPAIR |
0361                                   M::ISTUPLE | M::ISEXTERNAL | M::ISSTRING)>>::readIntoPtr(ptr, str, s, processClassId);
0362     }
0363   };
0364 
0365   template <class Stream, class State, class Ptr>
0366   struct GenericReader<Stream, State, Ptr, Int2Type<IOTraits<int>::ISNULLPOINTER>> {
0367     inline static bool process(Ptr &ptr, Stream &str, State *s, const bool processClassId) {
0368       // We need to figure out the type of the pointee
0369       // and make a swich depending on that type.
0370       // Note that the pointee itself can not be a pointer.
0371       typedef typename IOPointeeType<Ptr>::type Pointee;
0372       typedef IOTraits<Pointee> M;
0373       static_assert((M::Signature & (M::ISNULLPOINTER | M::ISSHAREDPTR)) == 0, "can not read pointers to pointers");
0374 
0375       return GenericReader<
0376           Stream,
0377           State,
0378           Pointee,
0379           Int2Type<M::Signature &(M::ISPOD | M::ISSTDCONTAINER | M::ISPUREHEAPREADABLE | M::ISPLACEREADABLE | M::ISPAIR |
0380                                   M::ISTUPLE | M::ISEXTERNAL | M::ISSTRING)>>::readIntoPtr(ptr, str, s, processClassId);
0381     }
0382   };
0383 
0384   //===================================================================
0385   //
0386   // Processing of shared pointers -- similar logic to pointers.
0387   // For the reader, handling of the shared pointer is reduced
0388   // to handling of a normal pointer with 0 value.
0389   //
0390   //===================================================================
0391   template <class Stream, class State, class Ptr>
0392   struct GenericWriter<Stream, State, Ptr, Int2Type<IOTraits<int>::ISSHAREDPTR>> {
0393     inline static bool process(const Ptr &ptr, Stream &os, State *s, const bool processClassId) {
0394       typedef typename Ptr::element_type Pointee;
0395       typedef IOTraits<Pointee> M;
0396       static_assert((M::Signature & (M::ISPOINTER | M::ISSHAREDPTR)) == 0, "can not write pointers to pointers");
0397       assert(ptr.get());
0398       return process_const_item<GenericWriter2>(*ptr, os, s, processClassId);
0399     }
0400   };
0401 
0402   template <class Stream, class State, class ShPtr>
0403   struct GenericReader<Stream, State, ShPtr, Int2Type<IOTraits<int>::ISSHAREDPTR>> {
0404     inline static bool process(ShPtr &a, Stream &str, State *s, const bool processClassId) {
0405       typedef typename ShPtr::element_type Pointee;
0406       typedef IOTraits<Pointee> M;
0407       static_assert((M::Signature & (M::ISPOINTER | M::ISSHAREDPTR)) == 0, "can not read pointers to pointers");
0408       Pointee *ptr = 0;
0409       const bool status = GenericReader<Stream, State, Pointee *, Int2Type<IOTraits<int>::ISNULLPOINTER>>::process(
0410           ptr, str, s, processClassId);
0411       if (status) {
0412         assert(ptr);
0413         a = std::shared_ptr<Pointee>(ptr);
0414         return true;
0415       } else {
0416         delete ptr;
0417         return false;
0418       }
0419     }
0420   };
0421 
0422   //===================================================================
0423   //
0424   // Processing of std::pair
0425   //
0426   //===================================================================
0427   template <class Stream, class State, class T>
0428   struct GenericWriter<Stream, State, T, Int2Type<IOTraits<int>::ISPAIR>> {
0429     inline static bool process(const T &s, Stream &os, State *st, const bool processClassId) {
0430       // Here is a little problem: in this scope "GenericWriter"
0431       // means GenericWriter<Stream, State, T,
0432       //                     Int2Type<IOTraits<int>::ISPAIR> >
0433       // However, we want to use the whole template, unspecialized.
0434       // This is why "GenericWriter2" is introduced: a copy of
0435       // "GenericWriter" via public inheritance.
0436       static const ClassId current(ClassId::makeId<T>());
0437       return (processClassId ? current.write(os) : true) &&
0438              process_const_item<GenericWriter2>(s.first, os, st, false) &&
0439              process_const_item<GenericWriter2>(s.second, os, st, false);
0440     }
0441   };
0442 
0443   template <class Stream, class State, class T>
0444   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISPAIR>> {
0445     inline static bool readIntoPtr(T *&ptr, Stream &str, State *s, const bool processClassId) {
0446       std::unique_ptr<T> myptr;
0447       if (ptr == 0) {
0448         myptr = std::unique_ptr<T>(new T());
0449         clearIfPointer(myptr.get()->first);
0450         clearIfPointer(myptr.get()->second);
0451       }
0452       std::vector<std::vector<ClassId>> itemIds;
0453       if (processClassId) {
0454         static const ClassId current(ClassId::makeId<T>());
0455         ClassId pairId(str, 1);
0456         current.ensureSameName(pairId);
0457         pairId.templateParameters(&itemIds);
0458         assert(itemIds.size() == 2U);
0459       } else {
0460         assert(!s->empty());
0461         s->back().templateParameters(&itemIds);
0462         if (itemIds.size() != 2U) {
0463           std::string err(
0464               "In gs::GenericReader::readIntoPtr: "
0465               "bad class id for std::pair on the "
0466               "class id stack: ");
0467           err += s->back().id();
0468           throw IOInvalidData(err);
0469         }
0470       }
0471       if (!(process_item<GenericReader2>((ptr ? ptr : myptr.get())->first, str, &itemIds[0], false) &&
0472             process_item<GenericReader2>((ptr ? ptr : myptr.get())->second, str, &itemIds[1], false)))
0473         return false;
0474       if (ptr == 0)
0475         ptr = myptr.release();
0476       return true;
0477     }
0478 
0479     inline static bool process(T &s, Stream &os, State *st, const bool processClassId) {
0480       T *ps = &s;
0481       return readIntoPtr(ps, os, st, processClassId);
0482     }
0483   };
0484 
0485   //===================================================================
0486   //
0487   // Processing of std::string
0488   //
0489   //===================================================================
0490   template <class Stream, class State>
0491   struct GenericWriter<Stream, State, std::string, Int2Type<IOTraits<int>::ISSTRING>> {
0492     inline static bool process(const std::string &s, Stream &os, State *, const bool processClassId) {
0493       static const ClassId current(ClassId::makeId<std::string>());
0494       const bool status = processClassId ? current.write(os) : true;
0495       if (status)
0496         write_string<char>(os, s);
0497       return status && !os.fail();
0498     }
0499   };
0500 
0501   template <class Stream, class State>
0502   struct GenericReader<Stream, State, std::string, Int2Type<IOTraits<int>::ISSTRING>> {
0503     inline static bool readIntoPtr(std::string *&ptr, Stream &is, State *, const bool processClassId) {
0504       std::unique_ptr<std::string> myptr;
0505       if (ptr == nullptr)
0506         myptr = std::make_unique<std::string>();
0507       if (processClassId) {
0508         static const ClassId current(ClassId::makeId<std::string>());
0509         ClassId id(is, 1);
0510         current.ensureSameName(id);
0511       }
0512       read_string<char>(is, ptr ? ptr : myptr.get());
0513       if (is.fail())
0514         return false;
0515       if (ptr == nullptr)
0516         ptr = myptr.release();
0517       return true;
0518     }
0519 
0520     inline static bool process(std::string &s, Stream &is, State *st, const bool processClassId) {
0521       std::string *ptr = &s;
0522       return readIntoPtr(ptr, is, st, processClassId);
0523     }
0524   };
0525 
0526   //===================================================================
0527   //
0528   // Processing of container readout
0529   //
0530   //===================================================================
0531   template <class Stream, class State, class Container>
0532   struct GenericReader<Stream, State, Container, InContainerCycle> {
0533   private:
0534     typedef typename Container::value_type item_type;
0535     typedef IOTraits<item_type> M;
0536 
0537     // Item is a simple pointer
0538     inline static bool process2(Container &obj, Stream &is, State *st, const std::size_t itemN, Int2Type<1>) {
0539       item_type ptr = 0;
0540       const bool status =
0541           GenericReader<Stream, State, item_type, Int2Type<IOTraits<int>::ISNULLPOINTER>>::process(ptr, is, st, true);
0542       if (status) {
0543         assert(ptr);
0544         InsertContainerItem<Container>::insert(obj, ptr, itemN);
0545       } else
0546         delete ptr;
0547       return status;
0548     }
0549 
0550     // Item is a shared pointer
0551     inline static bool process2(Container &obj, Stream &is, State *st, const std::size_t itemN, Int2Type<2>) {
0552       typedef typename item_type::element_type Pointee;
0553       Pointee *ptr = 0;
0554       const bool status =
0555           GenericReader<Stream, State, Pointee *, Int2Type<IOTraits<int>::ISNULLPOINTER>>::process(ptr, is, st, true);
0556       if (status) {
0557         assert(ptr);
0558         std::shared_ptr<Pointee> sptr(ptr);
0559         InsertContainerItem<Container>::insert(obj, sptr, itemN);
0560       } else
0561         delete ptr;
0562       return status;
0563     }
0564 
0565     // Item is heap-readable
0566     inline static bool process2(Container &obj, Stream &is, State *st, const std::size_t itemN, Int2Type<3>) {
0567       // No class id -- this is a member of a container
0568       assert(!st->empty());
0569       item_type *ptr = item_type::read(st->back(), is);
0570       if (ptr) {
0571         InsertContainerItem<Container>::insert(obj, *ptr, itemN);
0572         delete ptr;
0573       }
0574       return ptr;
0575     }
0576 
0577     // Item is not a pointer and not heap-readable.
0578     // Assume that it has a default constructor.
0579     inline static bool process2(Container &obj, Stream &is, State *st, const std::size_t itemN, Int2Type<4>) {
0580       typedef typename StrippedType<item_type>::type NCType;
0581       NCType item;
0582       NCType *pitem = &item;
0583       bool status =
0584           GenericReader<Stream, State, NCType *, Int2Type<IOTraits<int>::ISPOINTER>>::process(pitem, is, st, false);
0585       if (status)
0586         InsertContainerItem<Container>::insert(obj, item, itemN);
0587       return status;
0588     }
0589 
0590   public:
0591     inline static bool process(Container &obj, Stream &is, State *st, const std::size_t itemN) {
0592       // By default, we will assume that container starts empty.
0593       // Here, we need to produce a new item. There are 3 options:
0594       //   1) make it on the stack, insert a copy into the container
0595       //   2) make it on the heap, insert a copy, delete original
0596       //   3) the container contains pointers to begin with, so
0597       //      we make it on the stack and add a pointer to the container
0598       return process2(obj,
0599                       is,
0600                       st,
0601                       itemN,
0602                       Int2Type<M::IsPointer * 1 + M::IsSharedPtr * 2 + M::IsHeapReadable * 3 +
0603                                !(M::IsPointer || M::IsSharedPtr || M::IsHeapReadable) * 4>());
0604     }
0605   };
0606 
0607   //===================================================================
0608   //
0609   // Reading things when a pointer is given
0610   //
0611   //===================================================================
0612   template <class Stream, class State, class T>
0613   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISSTDCONTAINER>> {
0614     inline static bool readIntoPtr(T *&ptr, Stream &str, State *s, const bool processClassId) {
0615       if (ptr)
0616         return process_item<GenericReader2>(*ptr, str, s, processClassId);
0617       else {
0618         std::unique_ptr<T> myptr(new T());
0619         if (!process_item<GenericReader2>(*myptr, str, s, processClassId))
0620           return false;
0621         ptr = myptr.release();
0622         return true;
0623       }
0624     }
0625   };
0626 
0627   template <class Stream, class State, class T>
0628   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISHEAPREADABLE>> {
0629     inline static bool readIntoPtr(T *&ptr, Stream &str, State *s, const bool processClassId) {
0630       T *readback = 0;
0631       if (processClassId) {
0632         ClassId id(str, 1);
0633         readback = T::read(id, str);
0634       } else {
0635         assert(!s->empty());
0636         readback = T::read(s->back(), str);
0637       }
0638       if (readback) {
0639         if (ptr) {
0640           try {
0641             // We will assume here that the "read"
0642             // operation takes precedence over constness
0643             *const_cast<typename StrippedType<T>::type *>(ptr) = *readback;
0644           } catch (...) {
0645             delete readback;
0646             throw;
0647           }
0648           delete readback;
0649         } else
0650           ptr = readback;
0651       }
0652       return readback;
0653     }
0654   };
0655 
0656   template <class Stream, class State, class T>
0657   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISPUREHEAPREADABLE>> {
0658     inline static bool readIntoPtr(T *&ptr, Stream &str, State *s, const bool processClassId) {
0659       T *readback = nullptr;
0660       if (processClassId) {
0661         ClassId id(str, 1);
0662         readback = T::read(id, str);
0663       } else {
0664         assert(!s->empty());
0665         readback = T::read(s->back(), str);
0666       }
0667       if (readback) {
0668         assert(!ptr);
0669         ptr = readback;
0670       }
0671       return readback;
0672     }
0673   };
0674 
0675   template <class Stream, class State, class T>
0676   struct GenericReader<Stream, State, T, Int2Type<IOTraits<int>::ISPLACEREADABLE>> {
0677     inline static bool readIntoPtr(T *&ptr, Stream &str, State *s, const bool processClassId) {
0678       std::unique_ptr<T> myptr;
0679       if (ptr == 0)
0680         myptr = std::unique_ptr<T>(new T());
0681       if (processClassId) {
0682         ClassId id(str, 1);
0683         T::restore(id, str, ptr ? ptr : myptr.get());
0684       } else {
0685         assert(!s->empty());
0686         T::restore(s->back(), str, ptr ? ptr : myptr.get());
0687       }
0688       if (ptr == 0)
0689         ptr = myptr.release();
0690       return ptr;
0691     }
0692   };
0693 }  // namespace gs
0694 
0695 #endif  // GENERS_GENERICIO_HH_