Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:44:52

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