/************************************************************************ Copyright Rice University, 2006 All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. **************************************************************************/ #ifndef __RVL_TOOLS_NEW_CONTENT_PACKAGE_ #define __RVL_TOOLS_NEW_CONTENT_PACKAGE_ #include "local.hh" #include "dejavu.hh" namespace RVL { // forward declaration template class ContentPackage; // rewrite of ADP's ContentPackage - now stores only a single // metadata object, which is supposed to be collective /** Helper function template to extract the size of a data array implicit in a MetaType object. No sensible default, so throws exception. Specializations provided for intrinsic integer MetaType (size_t, int, long, uint,...). Note - returns size of data in WORDS - DataType not being specified cannot convert to bytes here. */ template size_t getDataSize(MetaType const & md) { size_t t = md; return t; } /** Metadata types are not constant sized, so serialization requires a size function. Obvious specializations supplied for int types. note that return is size in BYTES. */ template size_t getMetaSize(MetaType const & md) { return sizeof(MetaType); } /** works for any fixed size data, eg. a struct with default-constructed members of fixed size */ template char * serialize(MetaType const & mt, size_t & len) { len = getMetaSize(mt); char * cbuf = new char[len]; memcpy(cbuf, (char *)(&mt), len); return cbuf; } /** Obvious implementation for int types - will need to be specialized for others. Will not compile for variable size metatypes for which default construction is not defined. */ template MetaType * deserialize(char * cbuf, size_t len) { // functional only for data of fixed size and // default construction - test this first MetaType * mt = new MetaType; if (len < getMetaSize(*mt)) { RVLException e; e<<"ERROR: deserialize[ContentPackage MetaType]\n"; e<<" asserted size of char buf too small to hold\n"; e<<" metadata object of this type\n"; throw e; } memcpy((char *)mt,cbuf,getMetaSize(*mt)); return mt; } /** serializes CP into two contiguous blocks: (1) serialized metadata, followed by (2) data array. */ template char * serialize(ContentPackage const & cp, size_t & len) { size_t mlen = 0; char * mbuf = serialize(cp.getMetadata(), mlen); size_t dlen = getDataSize(cp.getMetadata())*sizeof(DataType); len = mlen + dlen; char * cbuf = new char[len]; memcpy(cbuf,mbuf,mlen); memcpy(&(cbuf[mlen]),(char *)(cp.getData()),dlen); delete [] mbuf; return cbuf; } /** Assumes that serialized CP consists of two contiguous blocks: (1) serialized metadata, followed by (2) data array. */ template ContentPackage * deserialize(char * cbuf, size_t len) { try { MetaType * mt = deserialize(cbuf,len); int clen = getMetaSize(*mt) + getDataSize(*mt)*sizeof(DataType); if (len != clen) { RVLException e; e<<"ERROR: deserialize[ContentPackage]\n"; e<<" asserted size of char buffer appears to differ from that needed\n"; e<<" to store CP object of given type\n"; e<<" asserted size of char buffer = "< * cp = new ContentPackage; cp->initialize(*mt); delete mt; memcpy((char *)(cp->getData()), &(cbuf[getMetaSize(*mt)]),getDataSize(*mt)*sizeof(DataType) ); return cp; } catch (RVLException & e) { e<<"\ncalled from deserialize[ContentPackage]\n"; throw e; } } /** Helper template for implementation of standard write method. Will give sensible if minimal output. */ template ostream & writeMeta(MetaType const & md, ostream & e) { e< DataType * newData(MetaType & md) { return new DataType[getDataSize(md)]; } /** Helper template to delete data memory - paired with allocData. specialization permits other arrangements. */ template void deleteData(DataType ** d, MetaType ** md) { delete [] *d; *d=NULL; } /** A normal pairing of an array of data along with Metadata object. The only requirement on DataType: * must have static size - and object of type DataType must have * a definite size known at compile time - and possess a default * constructor which allocates a memory block of constant, * definite size - sizeof(DataType) must make sense, and actually * give the size in bytes of a word of type DataType. Essentially * the only possibilities are an intrinsic type or a struct made * out of intrinsic types or a struct made out of such structs * or... The only requirements on MetaType: * a deep copy constructor; * correct behaviour of the getDataSize() helper * function, if necessary by template specialization, returning * the size of the DataType array specified by a MetaType object. These assumptions are implicit in the presumption that all information necessary to initialize and define the behaviour of an object of this type is present in the MetaType data member and the DataType type specification.. This class follows the "initialization separate from instantiation" paradigm. The added flexibility is useful eg. in distributed computing - a recipient object can be constructed before the data it is to receive has been transmitted. Since the MetaType data member determines the size of the DataType array, the alternative paradigm would require some kind of auxiliary factory object. */ template class ContentPackage: public LocalDataContainer { private: mutable MetaType * md; mutable DataType * d; bool own; public: /** copy constructor - deep copy, assumes const word length for DataType returned by sizeof. */ ContentPackage(const ContentPackage & bin) : md(NULL), d(NULL), own(bin.own) { if (bin.md) { md = new MetaType(*(bin.md)); if (own) { // d = new DataType[getDataSize(*md)]; d=newData(*md); memcpy(d,bin.d,getDataSize(*md)*sizeof(DataType)); } else { d = bin.d; } } //cerr<<"CP copy constr: md = "<(*md,cerr); } /** main constructor */ ContentPackage() :md(NULL), d(NULL), own(true) { //cerr<<"CP main constr: md = "< * p = NULL, size_t start = 0) { if (md) return false; md = new MetaType(_md); //cerr<<"CP::initialize - md = "<(*md,cerr); if (p) { if (getDataSize(*md) <= p->getSize()-start) { d = &((p->getData())[start]); own = false; return true; } else { //cerr<<"warning: ContentPackage::initialize\n"; // cerr<<"attempted to build view of external LDC\n"; // cerr<<"of length "<(*md)<<" starting at word " // <getSize()<<"\n"; delete md; md=NULL; return false; } } else { // d = new DataType[getDataSize(*md)]; d=newData(*md); return true; } } /** initialization status query */ bool isInitialized() const { if (md) return true; return false; } /** assignment */ ContentPackage & operator=(ContentPackage const & src) { if (this != &src) { if (*md != *(src.md)) { RVLException e; e<<"Error: ContentPackage assignment op\n"; e<<"metadata of this differs from metadata of source\n"; throw e; } size_t n = getDataSize(*md); if (!d) d = new DataType[n]; memcpy(d,src.d,n*sizeof(DataType)); } return *this; } /** comparison */ bool operator==(ContentPackage const & a) const { if (this == &a) return true; if (*md != *(a.md)) return false; if (getSize() != a.getSize()) return false; for (size_t i=0;i const & a) const { return !operator==(a); } bool isCompatible(ContentPackage const & a) const { return (this->getMetadata() == a.getMetadata()); } /** access metadata, mutable */ MetaType & getMetadata() { if (!md) { RVLException e; e<<"Error: ContentPackage::getMetaData\n"; e<<"metadata not initialized yet\n"; throw e; } return *md; } /** access metadata, const */ MetaType const & getMetadata() const { if (!md) { RVLException e; e<<"Error: ContentPackage::getMetaData\n"; e<<"metadata not initialized yet\n"; throw e; } return *md; } /** access data array size */ size_t getSize() const { if (md) return getDataSize(*md); return 0; } /** access data, mutable */ DataType * getData() { if (!d) { RVLException e; e<<"Error: ContentPackage::getData\n"; e<<"data not initialized yet\n"; throw e; } return d; } /** access data, const */ DataType const * getData() const { if (!d) { RVLException e; e<<"Error: ContentPackage::getData\n"; e<<"data not initialized yet\n"; throw e; } return d; } ostream & write(ostream & str) const { str<<"ContentPackage LDC, MetaData = \n"; if (md) { writeMeta(*md,str); } else { str<<"(not initialized)\n"; } str<<" and data array\n"; for (size_t i=0;igetSize(); i++) { str<<" "<(d[i],str); } return str; } }; /** Copy function for CPs. Default implementation may be specialized for more subtle copies, eg. of windows into multidimensional arrays or sectors of unstructured meshes or... */ template void copyCP(Source const & in, Target & out) { try { size_t n = min(in.getSize(),out.getSize()); for (size_t i=0;i class PackageContainer: public DataContainer { protected: /** Sequential access to component CPs. Should return more=false when there are no more CPs to be returned, else true. Thus a typical use is bool more = true; while (more) { ContentPackage<...> const & cp = get(more); (do something) } Implementations should test for more=true and throw an exception if not, as an additional check. Since access is sequential, revisiting the contents of the PC requires a call to reset(). Child classes must store an internal CP buffer so that they can always return a ref to a CP. */ virtual ContentPackage & get(bool & more) = 0; virtual ContentPackage const & get(bool & more) const = 0; /** store the internal CP buffer - to allow for out-of-order execution (eg. in parallel), child classes can index into global storage using metadata attributes of their internal CP buffer. */ virtual void put() const = 0; /** restore PC to its original state. For out-of-core PCs this should seek the file pointer to BOF. */ virtual void reset() const = 0; public: PackageContainer() {} PackageContainer(PackageContainer const &) {} virtual ~PackageContainer() {} /** FO eval method - virtual to allow specialization in subclasses */ virtual void eval(FunctionObject & f, std::vector & x) { try { // cerr<<"pc: before reset\n"; // this->write(cerr); this->reset(); // cerr<<"pc: after reset\n"; // this->write(cerr); std::vector const *> pcx(x.size()); for (size_t i=0;i const *>(x[i]))) { RVLException e; e<<"Error: PackageContainer::eval(FO)\n"; e<<"at least one other arg is not a package container.\n"; for (size_t j=0;jwrite(e); } throw e; } // cannot alias input with output if (this == pcx[i]) { RVLException e; e<<"Error: PackageContainer::eval(FO)\n"; e<<"input argument "<reset(); } bool more = true; std::vector cpx(x.size()); // cerr<<"cp: size="<get\n"; // this->write(cerr); ContentPackage & cp = this->get(more); // cerr<<"cp->eval\n"; cp.eval(f,cpx); // cerr<<"this->put\n"; this->put(); } } catch (RVLException & e) { e<<"\ncalled from PackageContainer::eval(FO)\n"; throw e; } } /** FOR eval method - virtual to allow specialization in subclasses */ virtual void eval(FunctionObjectConstEval & f, vector & x) const { try { this->reset(); std::vector const *> pcx(x.size()); for (size_t i=0;i const *>(x[i]))) { RVLException e; e<<"Error: PackageContainer::eval(FOR)\n"; e<<"at least one other arg is not a package container.\n"; throw e; } pcx[i]->reset(); } bool more = true; std::vector cpx(x.size()); while (more) { ContentPackage const & cp = this->get(more); for (size_t i=0;i const>(&j,pcx); // if j has not changed value, then this is a non-aliased arg if (j==i) { cpx[i]=&(pcx[i]->get(more)); } // otherwise we've already seen it else { cpx[i] = cpx[j]; } } } cp.eval(f,cpx); } } catch (RVLException & e) { e<<"\ncalled from PackageContainer::eval(FOR)\n"; throw e; } } }; /** An almost-concrete factory class for PackageContainers, lacking only one protected and one public method to be complete. Added clone method because copying of children in classes owning one of these will require virtual construction. The comparison methods may not be sufficiently discriminatory for various applications, as they merely typecheck, So they are made virtual and can be overridden in child classes. */ template class PackageContainerFactory: public DataContainerFactory { protected: virtual PackageContainer * buildPC() const = 0; public: /** Typically implemnented by op new. */ virtual PackageContainerFactory * clone() const = 0; DataContainer * build() const { return buildPC(); } virtual bool compare( DataContainerFactory const & dcf) const { PackageContainerFactory const * ptr = NULL; if ((ptr = dynamic_cast< PackageContainerFactory const * >(&dcf))) return true; return false; } virtual bool isCompatible(DataContainer const & dc) const { PackageContainer const * ptr = NULL; if ((ptr = dynamic_cast< PackageContainer const * >(&dc))) return true; return false; } virtual ostream & write(ostream & str) const { str<<"PackageContainerFactory\n"; return str; } }; /** SingleDataContainer is a wrapper for a single ContentPackage, and is a child rather than a template specialization of PackageContainer. The additional attributes are server functions (get and put). Any number of replications of the ContentPackage may be served up; when the specified number have been served, get returns false.q */ template class SingleDataContainer: public PackageContainer { private: ContentPackage gd; mutable int nrep; int nrep0; protected: ContentPackage & get(bool & more) { nrep--; if (nrep<1) more = false; return gd; } ContentPackage const & get(bool & more) const { nrep--; if (nrep<1) more = false; return gd; } void put() const {} void reset() const { nrep=nrep0; } public: SingleDataContainer(int _nrep = 1) : PackageContainer(), gd(), nrep(_nrep), nrep0(nrep) {} SingleDataContainer(SingleDataContainer const & g) : PackageContainer(g), gd(g.gd), nrep(g.nrep), nrep0(g.nrep0) {} ~SingleDataContainer() {} void initialize(Metatype const & g) { gd.initialize(g); } Metatype const & getMetadata() const { if (gd.isInitialized()) return gd.getMetadata(); RVLException e; e<<"Error: SingleDataContainer::getMetadata\n"; e<<"cannot return reference to internal Metadata, as\n"; e<<"this is not initialized yet.\n"; throw e; } ostream & write(ostream & e) const { e<<"SingleDataContainer encapsulating ContentPackage object:\n"; gd.write(e); return e; } }; /** Factory class for SingleDataContainer. */ template class SingleDataContainerFactory: public PackageContainerFactory { private: int nrep; Metatype * g; protected: PackageContainer * buildPC() const { SingleDataContainer * gdc = new SingleDataContainer(nrep); if (g) { gdc->initialize(*g); return gdc; } else { RVLException e; e<<"Error: SingleDataContainerFactory::buildPC\n"; e<<"internal Metadata not initialized\n"; throw e; } } public: SingleDataContainerFactory(int _nrep=1): nrep(_nrep), g(NULL) {} SingleDataContainerFactory (SingleDataContainerFactory const & f) : nrep(f.nrep), g(NULL) { if (f.g) g=new Metatype(*(f.g)); } ~SingleDataContainerFactory() { if (g) delete g; } PackageContainerFactory * clone() const { if (g) { SingleDataContainerFactory * f = new SingleDataContainerFactory; f->initialize(*g); return f; } RVLException e; e<<"Error: SingleDataContainerFactory::clone\n"; e<<"cannot construct copy because not initialized\n"; throw e; } void initialize(Metatype const & _g) { g = new Metatype(_g); } bool compare( DataContainerFactory const & dcf) const { try { if (!g) { cerr<<"Warning: SingleDataContainerFactory::compare\n"; cerr<<"cannot compare uninitialized factory to others\n"; return false; } SingleDataContainerFactory const * dcfptr = NULL; if ((dcfptr = dynamic_cast const *>(dcfptr))) { if (!(dcfptr->g)) { cerr<<"Warning: GridDataContainerFactory::compare\n"; cerr<<"cannot compare this to uninitialized factory\n"; return false; } if ( *g == *(dcfptr->g)) return true; } } catch (RVLException & e) { e<<"\ncalled from SingleDataContainerFactory::compare\n"; throw e; } } bool isCompatible(DataContainer const & dc) const { try { if (!g) { cerr<<"Warning: SingleDataContainerFactory::isCompatible\n"; cerr<<"cannot decide compatibility for uninitialized factory\n"; return false; } SingleDataContainer const * dcptr = NULL; if ((dcptr = dynamic_cast const *>(&dc))) if (*g == dcptr->getMetadata()) return true; return false; } catch (RVLException & e) { e<<"\ncalled from GridDataContainerFactory::isCompatible\n"; throw e; } } ostream & write(ostream & str) const { str<<"SingleDataContainerFactory"; if (g) { str<<" using Metadata:\n"; g->write(str); } else { str<<" (uninitialized)\n"; } return str; } }; } #endif