/* * C++ support code for Tock programs * Copyright (C) 2007, 2008 University of Kent * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ //To get the UINT8_MAX etc macros in C++: #define __STDC_LIMIT_MACROS #include class StopException { public: std::string reason; inline StopException(const std::string& _reason) : reason(_reason) { } }; #define occam_stop(pos, nargs, format, args...) \ do { \ fprintf(stderr, "Program stopped at %s: " format "\n", pos, ##args); \ throw StopException(""); \ } while (0) #define BACKEND_CPPCSP #define Channel int #include "tock_support.h" #include #include #include #include #include #include #include #include #include inline unsigned TimeDiffHelper(unsigned now,unsigned waitFor) { //If waitFor is in the 2^31 before now, it is in the past: if (now - waitFor < 2147483648) { //if we have wrapped round between waitFor and now, we actually want to return a minus-one: if ((waitFor >= 2147483648) && (now < 2147483648)) { return (unsigned)(int)(-1); } else { return 0; } } else { //It is in the future. If we will wrap round before getting there, return one: if ((now >= 2147483648) && (waitFor < 2147483648)) { return 1; } else { return 0; } } } class StreamWriter : public csp::CSProcess { private: std::ostream& out; csp::Chanin in; protected: virtual void run() { try { uint8_t c; while (true) { in >> c; out << c; } out.flush(); } catch (csp::PoisonException& e) { in.poison(); } } public: inline StreamWriter(std::ostream& _out,const csp::Chanin& _in) : out(_out),in(_in) { } }; //For tieing together chained tuples: template inline boost::tuple tie10(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, T10 t10) { return boost::tuple (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); } inline std::pair< boost::array , unsigned > tockDims(const unsigned d0) { boost::array r; r[0] = d0; return std::pair< boost::array , unsigned >(r,d0 == 0 ? 0 : 1); } /* Generates functions like this: inline std::pair< boost::array , unsigned > tockDims(const unsigned d0,const unsigned d1,const unsigned d2) { boost::array r; r[0] = d0; r[1] = d1; r[2] = d2; return std::pair< boost::array , unsigned >(r,d1 * d2); } */ #define TOCKDIMS_ARGS(___z,NUM,___data) ,const unsigned d##NUM #define TOCKDIMS_ASSIGN(___z,NUM,___data) r[ NUM ] = d##NUM ; #define TOCKDIMS_MULT(___z,NUM,___data) * d##NUM #define TOCKDIMS(___z,NUM,___data) inline std::pair< boost::array,unsigned> tockDims(\ const unsigned d0 BOOST_PP_REPEAT_FROM_TO(1,NUM,TOCKDIMS_ARGS,0) ) { \ boost::array r; BOOST_PP_REPEAT(NUM,TOCKDIMS_ASSIGN,0) \ return std::pair< boost::array , unsigned >(r,1 BOOST_PP_REPEAT_FROM_TO(1,NUM,TOCKDIMS_MULT,0) ); } //Up to 12 dimensions: BOOST_PP_REPEAT_FROM_TO(2,12,TOCKDIMS,0) template < typename T, unsigned DIMS > class tockArrayView { T* realArray; boost::array dims; //dims[1] * dims[2] * dims[3] ... //If DIMS is 0 or 1, totalSubDim will be 1 unsigned totalSubDim; template inline void operator=(const U&) {} inline tockArrayView(T* _realArray,const boost::array& _biggerDims,unsigned _totalSubDim) : realArray(_realArray),totalSubDim(_totalSubDim) { memcpy(dims.c_array(),_biggerDims.data() + 1,sizeof(unsigned) * DIMS); } friend class tockArrayView; //TODO change the other methods so we can feed a string in here (the Meta) to report to occam_stop inline void correctDimsRetype(const unsigned totalSourceBytes) { if (totalSubDim == 0 || dims[0] == 0) { //Can only happen if one of the dimensions is zero, i.e. unknown //We must find this dimension and calculate it: unsigned zeroDim; unsigned totalDim = 1; for (unsigned i = 0;i < DIMS;i++) { if (dims[i] == 0) zeroDim = i; else totalDim *= dims[i]; } //Check it fits exactly: if ((totalSourceBytes / totalDim) % sizeof(T) != 0) { occam_stop ("", 3, "invalid size for RETYPES/RESHAPES (%d does not divide into %d)", (totalSourceBytes / totalDim), sizeof(T)); } //Set the size of the unknown dimension: dims[zeroDim] = (totalSourceBytes / totalDim) / sizeof(T); totalSubDim = (totalDim * dims[zeroDim]) / dims[0]; } } public: inline tockArrayView() : realArray(NULL) { dims.assign(0); totalSubDim = 0; } inline tockArrayView(const tockArrayView& v) : realArray(v.realArray), dims(v.dims), totalSubDim(v.totalSubDim) { } inline tockArrayView(T* _realArray,const std::pair< boost::array , unsigned >& _dims) : realArray(_realArray),dims(_dims.first),totalSubDim(_dims.second) { } inline tockArrayView(std::vector::type>& _vec,const std::pair< boost::array , unsigned >& _dims) : realArray(_vec.empty() ? NULL : &(_vec.at(0))),dims(_dims.first),totalSubDim(_dims.second) { } //The retyping constructors have their parameters in the other order to the same-type functions above, //to avoid ambiguities between retyping and same types (especially when const is involved): template inline tockArrayView(const std::pair< boost::array , unsigned >& _dims,U* _realArray) : realArray(reinterpret_cast(_realArray)),dims(_dims.first),totalSubDim(_dims.second) { //Assume it's a single U item: correctDimsRetype(sizeof(U)); } //Retyping, same number of dims: template inline tockArrayView(const std::pair< boost::array , unsigned >& _dims,const tockArrayView& tav) : realArray(reinterpret_cast(tav.data())),dims(_dims.first),totalSubDim(_dims.second) { correctDimsRetype(tav.size() * sizeof(U)); } inline tockArrayView operator[] (const unsigned index) const { return tockArrayView(realArray + (totalSubDim * index),dims,DIMS <= 1 ? 1 : (totalSubDim / dims[1])); } inline tockArrayView sliceFor(const unsigned amount) const { return sliceFromFor(0,amount); } inline tockArrayView sliceFrom(const unsigned index) const { return sliceFromFor(index,dims[0] - index); } inline tockArrayView sliceFromFor(const unsigned index,const unsigned amount) const { boost::array sliceDims = dims; sliceDims[0] = amount; return tockArrayView(realArray + (totalSubDim * index),std::make_pair(sliceDims,totalSubDim)); } inline T* data() const { return realArray; } inline const boost::array& getDims() const { return dims; } inline unsigned getTotalSubDim() const { return totalSubDim; } inline unsigned size() const { return dims[0] * totalSubDim; } inline unsigned extent(const unsigned dim) const { return dims[dim]; } inline operator tockArrayView() const { return tockArrayView((const T*)realArray,std::make_pair(dims,totalSubDim)); } }; template class tockArrayView { T* realArray; inline tockArrayView(T* _realArray,boost::array,unsigned) : realArray(_realArray) { } friend class tockArrayView; public: //Should only be used on arrays with zero dimensions: inline T& access() const { return *realArray; } }; class tockSendableArrayOfBytes { private: unsigned n; ///This is not as horrific as it looks - it is never used as a way to get rid of the const tag on the same pointer, only one field is used at a time. union { const void* sp; void* dp; }; public: ///For the sender: inline explicit tockSendableArrayOfBytes(const void* p) : n(0),sp(p) { } ///Also for the sender: template inline explicit tockSendableArrayOfBytes(const tockArrayView& arr) : n(0),sp(arr.data()) { } ///For the receiver: inline tockSendableArrayOfBytes(unsigned _n,void* p) : n(_n),dp(p) { } //Also for the receiver: template inline explicit tockSendableArrayOfBytes(unsigned _n, const tockArrayView& arr) : n(_n),dp(arr.data()) { } inline void operator=(const tockSendableArrayOfBytes& _src) { //We use the receiver's byte count: memcpy(dp,_src.sp,n); } }; inline void tockSendInt(const csp::Chanout& c, unsigned int n) { c << tockSendableArrayOfBytes(&n); } inline void tockRecvInt(const csp::Chanin& c, unsigned int* p) { tockSendableArrayOfBytes d(sizeof(unsigned int),p); c >> d; } template class tockSendableArray { private: tockSendableArrayOfBytes aob; public: template inline explicit tockSendableArray(const tockArrayView& arr) : aob(N*sizeof(T),arr.data()) { } template inline explicit tockSendableArray(const tockArrayView& arr) : aob(arr.data()) { } }; template inline void tockSendArray(const csp::Chanout< tockSendableArray >& out,const tockArrayView& arr) { out << tockSendableArray(arr); } template inline void tockRecvArray(const csp::Chanin< tockSendableArray >& in,const tockArrayView& arr) { tockSendableArray tsa(arr); in >> tsa; } template inline void tockSendArray(const csp::Chanout< tockSendableArray >& out,const tockArrayView& arr) { out << tockSendableArray(arr); } inline void tockSendArrayOfBytes(const csp::Chanout& c, const tockSendableArrayOfBytes& b) { c << b; } inline void tockRecvArrayOfBytes(const csp::Chanin& c, const tockSendableArrayOfBytes& _b) { //We can't read into the const parameter, so we copy it into a non-const version and read into that. //The copying will preserve the pointer inside, so it doesn't cause any problems: tockSendableArrayOfBytes b(_b); c >> b; } template inline void tockInitChanArray(T* pointTo,T** pointFrom,int count) { for (int i = 0;i < count;i++) pointFrom[i] = &(pointTo[i]); } class StreamWriterByteArray : public csp::CSProcess { private: std::ostream& out; csp::Chanin in; protected: virtual void run() { try { uint8_t c; while (true) { tockSendableArrayOfBytes aob(1,&c); in >> aob; out << c; } out.flush(); } catch (csp::PoisonException& e) { in.poison(); } } public: inline StreamWriterByteArray(std::ostream& _out,const csp::Chanin& _in) : out(_out),in(_in) { } }; template class tockList { private: mutable std::list data; public: inline tockList() { } inline explicit tockList(const T& t) { data.push_back(t); } inline tockList& operator()(const T& t) { data.push_back(t); return *this; } typedef typename std::list::iterator iterator; inline iterator beginSeqEach() { return data.begin(); } inline iterator limitIterator() { return data.end(); } inline void endSeqEach() { } inline void remove(const iterator& _it) { data.erase(_it); } //TODO add beginParEach //TODO add functions for concatenation //By default the class acts like a mobile thing: inline void operator=(const tockList& _rhs) { data.clear(); data.swap(_rhs.data); } class derefTockList { private: tockList* ref; public: inline explicit derefTockList(tockList* _ref) : ref(_ref) { } //If you dereference both sides, you get a proper copy-assignment: void operator=(const derefTockList& _rhs) { ref->data = _rhs.ref->data; } }; derefTockList operator*() { return derefTockList(this); } };