Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
//=========================================================================
// AbsReader.hh
//
// Template implementation of a factory pattern for reading objects from
// C++ streams. Derive a reader for your concrete inheritance hierarchy
// from the "DefaultReader" template (as illustrated by the examples
// provided with the package). Wrap your reader using the "StaticReader"
// template when the actual reading is performed to ensure that the reader
// factory is unique.
//
// The classes which can be read must implement the static "read" function
// which creates objects on the heap. The signature of this function is
//
// static ClassName* read(const ClassId& id, std::istream& is);
//
// In this function, the class id argument can be used to implement object
// versioning. The "read" method must always succeed. If it is unable to
// build the object, it must throw an exception which inherits from
// std::exception.
//
// I. Volobouev
// September 2010
//=========================================================================

#ifndef GENERS_ABSREADER_HH_
#define GENERS_ABSREADER_HH_

#include "Alignment/Geners/interface/IOException.hh"
#include <map>
#include <sstream>
#include <string>

#include "Alignment/Geners/interface/ClassId.hh"

namespace gs {
  template <class Base>
  struct AbsReader {
    virtual ~AbsReader() {}

    virtual Base *read(const ClassId &id, std::istream &in) const = 0;
  };

  template <class Base, class Derived>
  struct ConcreteReader : public AbsReader<Base> {
    ~ConcreteReader() override {}

    inline Derived *read(const ClassId &id, std::istream &in) const override {
      // Assume that Derived::read(id, in) returns a new object
      // of type "Derived" allocated on the heap
      return Derived::read(id, in);
    }
  };

  template <class Base>
  class DefaultReader : public std::map<std::string, AbsReader<Base> *> {
  public:
    typedef Base value_type;

    inline DefaultReader() : std::map<std::string, AbsReader<Base> *>() {}

    virtual ~DefaultReader() {
      for (typename std::map<std::string, AbsReader<Base> *>::iterator it = this->begin(); it != this->end(); ++it)
        delete it->second;
    }

    inline Base *read(const ClassId &id, std::istream &in) const {
      typename std::map<std::string, AbsReader<Base> *>::const_iterator it = this->find(id.name());
      if (it == this->end()) {
        std::ostringstream os;
        os << "In gs::DefaultReader::read: class \"" << id.name() << "\" is not mapped to a concrete reader";
        throw gs::IOInvalidArgument(os.str());
      }
      return it->second->read(id, in);
    }

    DefaultReader(const DefaultReader &) = delete;
    DefaultReader &operator=(const DefaultReader &) = delete;
  };

  // A trivial implementation of the Meyers singleton for use with reader
  // factories. Naturally, this assumes that all factories are independent
  // from each other (otherwise we are getting into trouble with undefined
  // singleton destruction order). Also, this particular code is not
  // thread-safe (but should become thread-safe in C++11 if I understand
  // static local initialization guarantees correctly).
  //
  // Assume that "Reader" is derived from "DefaultReader" and that it
  // publishes its base class as "Base".
  //
  template <class Reader>
  class StaticReader {
  public:
    typedef typename Reader::Base::value_type InheritanceBase;

    static const Reader &instance() {
      static const Reader obj;
      return obj;
    }

    template <class Derived>
    static void registerClass() {
      Reader &rd = const_cast<Reader &>(instance());
      const ClassId &id(ClassId::makeId<Derived>());
      delete rd[id.name()];
      rd[id.name()] = new ConcreteReader<InheritanceBase, Derived>();
    }

    // Disable the constructor
    StaticReader() = delete;
  };
}  // namespace gs

#endif  // GENERS_ABSREADER_HH_