#ifndef wOYVH4QhyaNIiefhP4sh9Osro2k #define wOYVH4QhyaNIiefhP4sh9Osro2k #include #include #include #include #include "simlimits.hpp" #include "template_helpers.hpp" // HINT: the template Ptr<> is defined in quant_types; it is an empty, // forbidden basecase anyway #include "quant_types.hpp" namespace PtrImpl { using boost::is_same; template struct Iter { Iter(IterPtr ptr) : ptr(ptr) {} Ptr operator* () const { return Ptr(ptr); } #define REL(op) bool operator op (Iter i) { return ptr op i.ptr; } REL(!=) REL(==) #undef REL Iter& operator++ () { ptr++; return *this; } Iter& operator-- () { ptr--; return *this; } IterPtr ptr; }; template struct Range { typedef Iter iter_t; // init range with raw begin/end ptr or the first and last element // to visit (DIFFERENT SEMANTICS!) Range(IterPtr p1, IterPtr p2) : p1(p1), p2(p2) {} Range(Ptr p1, Ptr p2) : p1(p1.raw), p2(p2.raw + 1) {} iter_t begin() const { return iter_t(p1); } iter_t end() const { return iter_t(p2); } IterPtr p1, p2; }; // we discriminate between storage and iter pointer to allow a zero // bit storage pointer while maintaining a conforming iteration // strategy template::least, typename IterPtr = typename boost::uint_value_t::least> struct Common { typedef StoragePtr ptr_t; typedef Range range_t; Common() = delete; //Common(const StoragePtr raw) : raw(raw) {} explicit Common(const IterPtr ptr) : raw(ptr) {} const StoragePtr operator() () const { return raw; } Ptr& operator++ () { raw++; return FORCE_CONV(Ptr, *this); } #define REL(op) bool operator op (Common const &i) const { return raw op i.raw; } REL(!=) REL(==) REL(<) REL(<=) REL(>) REL(>=) #undef REL static range_t all() { BOOST_STATIC_ASSERT((is_same::value)); return range_t(0, instanceCount); } // return instanceCount; different semantic for continuous and // discrete quants, so we use two identical function static constexpr IterPtr numInstances() { BOOST_STATIC_ASSERT((is_same::value)); return instanceCount; } static constexpr IterPtr maxInstances() { BOOST_STATIC_ASSERT((is_same::value)); return instanceCount; } StoragePtr raw; }; // we define the Common<>-instances later used to maintain // one-source-of-truth albeit circular dependencies typedef Common CommonSynapse; typedef Common CommonNeuron; } // NS //////////////////////////////////////////////////////////////////////////////// // CONTINOUS PROPERTIES //////////////////////////////////////////////////////////////////////////////// #define PTR_DEFAULT_CTOR \ explicit Ptr(const ptr_t raw) : Common(raw) {} template<> struct Ptr : PtrImpl::Common { Ptr() : Common(0) {} explicit Ptr(const uint64_t raw) : Common(0) { assert(raw == 0); } // #define REL(op) bool operator op (Ptr &i) { return raw op i.raw; } // REL(!=) // REL(==) // REL(<) REL(<=) // REL(>) REL(>=) // #undef REL inline PtrImpl::CommonNeuron::range_t childs() const; }; template<> struct Ptr : PtrImpl::CommonNeuron { PTR_DEFAULT_CTOR inline PtrImpl::CommonSynapse::range_t childs() const; }; template<> struct Ptr : PtrImpl::CommonSynapse { typedef boost::uint_value_t::least offset_t; PTR_DEFAULT_CTOR Ptr(const Ptr neuron, const offset_t synapse) : Common(neuron() * maxSynapsesPerNeuron + synapse) {} const Ptr extractNeuron() const { return Ptr(raw / maxSynapsesPerNeuron); } const offset_t extractSynapseOffset() const { return (raw % maxSynapsesPerNeuron); } }; // we have to declare childs()-functions after childs' Ptr<> inline PtrImpl::CommonNeuron::range_t Ptr::childs() const { return PtrImpl::CommonNeuron::range_t{ Ptr{0}, Ptr{maxNeurons - 1}}; } inline PtrImpl::CommonSynapse::range_t Ptr::childs() const { return PtrImpl::CommonSynapse::range_t{ Ptr{*this, 0}, Ptr{*this, maxSynapsesPerNeuron - 1}}; } //////////////////////////////////////////////////////////////////////////////// // DISCRETE PROPERTIES //////////////////////////////////////////////////////////////////////////////// template<> struct Ptr : PtrImpl::Common { PTR_DEFAULT_CTOR }; template<> struct Ptr : PtrImpl::Common { PTR_DEFAULT_CTOR }; template<> struct Ptr : PtrImpl::Common { PTR_DEFAULT_CTOR }; template<> struct Ptr : PtrImpl::Common { typedef boost::uint_value_t::least offset_t; PTR_DEFAULT_CTOR // HINT: offset refers to the topology table of the neuron // corresponding to the given spike, _not_ to the synpase offset of // the receiving neuron Ptr(const Ptr spike, const offset_t offset) : Common(spike() * maxSynapsesPerNeuron + offset) {} const Ptr extractSpike() const { return Ptr(raw / maxSynapsesPerNeuron); } }; // Stream I/O namespace std { #define GEN(T) \ ostream& operator<< (ostream &os, Ptr val) { return os << (uint64_t) val(); } GEN(Global) GEN(Neuron) GEN(Synapse) GEN(GlobalMsg) GEN(Spike) GEN(RandomSpike) GEN(SpikeArrival) #undef GEN } #endif // wOYVH4QhyaNIiefhP4sh9Osro2k