/* TYPED-COUNTER.hpp - maintain a set of type based contexts Copyright (C) Lumiera.org 2009, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file typed-counter.hpp ** Creating series of type-based contexts. ** The idea is to get a "slot" for any given type, so we can build ** tables or families of implementations based on these types. Each of ** those "slots" can be addressed by a distinct (compile time) type, but ** at the same time holds a numeric ID (runtime assigned on demand). This ** setup allows to bridge between metaprogramming and (runtime) dispatcher tables. ** ** Each such series of type-id-slots is associated to a distinct usage context. ** Those usage contexts are discerned by the template parameter \c CX. Each of ** these usage contexts uses a separate numbering scheme on his own, i.e. every ** new type encountered at runtime gets the next higher ID number (slot). ** @warning the actual ID numbers depend on the sequence of first encountering ** a given type. If this sequence isn't reproducible between runs, then ** also the generated type-IDs aren't reproducible. Thus its advisable ** \em not to rely on any specific numeric value here, but always just ** access the service through the type slots. ** @note Locking is based on a class lock per usage context, but a lock needs ** only be acquired to allocate a new ID number (double checked locking). ** Thus lock contention is considered not to be a problem, yet we need ** actually to verify this by real measurements (as of 2011) ** @todo 2010 ... this is the first, preliminary version of a facility, ** which is expected to get quite important for custom allocation management. ** ** @see typed-counter-test.cpp ** @see TypedAllocationManager ** @see AllocationCluster (custom allocation scheme using a similar idea inline) ** */ #ifndef LIB_TYPED_COUNTER_H #define LIB_TYPED_COUNTER_H #include "lib/error.hpp" #include "lib/sync-classlock.hpp" #include namespace lib { typedef size_t IxID; //////////////////////TICKET #863 using std::vector; /** * Provide type-IDs for a specific context. * This facility allows to access a numeric ID for each * given distinct type. Type-IDs may be used e.g. for * dispatcher tables or for custom allocators. * The type-IDs generated here are not completely global though. * Rather, they are tied to a specific type context, e.g. a class * implementing a custom allocator. These typed contexts are * considered to be orthogonal and independent of each other. */ template class TypedContext { static IxID lastGeneratedTypeID; public: static IxID newTypeID (IxID& typeID) { ClassLock synchronised; if (!typeID) typeID = ++lastGeneratedTypeID; return typeID; } /** type-ID */ template class ID { static IxID typeID; public: static IxID get() { if (typeID) return typeID; else return newTypeID(typeID); } }; }; /** storage for the type-ID generation mechanism */ template IxID TypedContext::lastGeneratedTypeID (0); /** table holding all the generated type-IDs */ template template IxID TypedContext::ID::typeID (0); /** * Helper providing a set of counters, each tied to a specific type. */ class TypedCounter : public Sync<> { mutable vector counters_; template IxID slot() const { IxID typeID = TypedContext::ID::get(); if (size() < typeID) counters_.resize (typeID); ENSURE (counters_.capacity() >= typeID); return (typeID - 1); } public: TypedCounter() { counters_.reserve(5); // pre-allocated 5 slots } template long get() const { Lock sync(this); return counters_[slot()]; } template long inc() { Lock sync(this); return ++counters_[slot()]; } template long dec() { Lock sync(this); return --counters_[slot()]; } /* == diagnostics == */ size_t size() const { return counters_.size(); } bool empty() const { return counters_.empty();} }; } // namespace lib #endif