/* * C++ support code for Tock programs * Copyright (C) 2007 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, format, args...) \ do { \ EXTERNAL_CALLN (fprintf, stderr, "Program stopped at %s: " format "\n", pos, ##args); \ SetErr (); \ throw StopException(""); \ } while (0) #define NO_CIFCCSP #include "tock_support.h" #include #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); } class tockAny : public boost::any { public: inline tockAny() {} inline tockAny(const tockAny& t) : boost::any(*(boost::any*)&t) { } template inline tockAny(T t) : boost::any(t) {} template inline operator T () const { return boost::any_cast(*this); } }; //Let's assume bool is an unsigned byte: #define occam_mostneg_tockBool 0 #define occam_mostpos_tockBool 255 class tockBool { private: bool b; public: inline tockBool() {} inline tockBool(bool _b) : b(_b) {} inline operator bool () const {return b;} inline void operator = (const bool& _b) {b = _b;} }; 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; inline void correctDimsRetype(const unsigned totalSourceBytes) { if (totalSubDim == 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]; } //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) { } //Retyping: template inline tockArrayView(U* _realArray,const std::pair< boost::array , unsigned >& _dims) : 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 tockArrayView& tav,const std::pair< boost::array , unsigned >& _dims) : 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)); } inline void updateFromVector(std::vector::type>& v) { realArray = v.empty() ? NULL : &(v.at(0)); } inline tockArrayView::type,DIMS> versionToSend() { return tockArrayView::type,DIMS>(const_cast::type*>(realArray),std::make_pair(dims,totalSubDim)); } inline const tockArrayView::type,DIMS> versionToSend() const { return tockArrayView::type,DIMS>(const_cast::type*>(realArray),std::make_pair(dims,totalSubDim)); } inline tockArrayView& operator=(const tockArrayView& tav) { //TODO investigate speeding up when T is primitive (maybe there's a boost class for that?) unsigned n = tav.size(); for (unsigned i = 0;i < n;i++) { realArray[i] = tav.realArray[i]; } dims = tav.dims; totalSubDim = tav.totalSubDim; return *this; } inline tockArrayView& operator=(const tockAny&) { //TODO later on } }; 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; } };