LUMIERA.clone/src/lib/typed-counter.hpp
Ichthyostega fc488f3b56 extract a basic set of generic ID functions for #984
using the struct-scheme.hpp and the requirements for
EntryID as a guideline. The goal is to move EntryID
over into the support lib, which means we need to get rid
of all direct proc::asset dependencies. Thus, these generic
ID functions shall form a baseline implementation, while
asset::Struct may provide the previously used implementation
through specialisation -- so the behaviour of EntryID will
not change for the structural assets, but we'll get a more
sane and readable default implementation for all other types.
2015-08-16 01:35:29 +02:00

190 lines
5.4 KiB
C++

/*
TYPED-COUNTER.hpp - maintain a set of type based contexts
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
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 <vector>
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 CX>
class TypedContext
{
static IxID lastGeneratedTypeID;
public:
static IxID
newTypeID (IxID& typeID)
{
ClassLock<TypedContext> synchronised;
if (!typeID)
typeID = ++lastGeneratedTypeID;
return typeID;
}
/** type-ID */
template<typename TY>
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<class CX>
IxID TypedContext<CX>::lastGeneratedTypeID (0);
/** table holding all the generated type-IDs */
template<class CX>
template<typename TY>
IxID TypedContext<CX>::ID<TY>::typeID (0);
/**
* Helper providing a set of counters, each tied to a specific type.
*/
class TypedCounter
: public Sync<>
{
mutable vector<long> counters_;
template<typename TY>
IxID
slot() const
{
IxID typeID = TypedContext<TypedCounter>::ID<TY>::get();
if (size() < typeID)
counters_.resize (typeID);
ENSURE (counters_.capacity() >= typeID);
return (typeID - 1);
}
public:
TypedCounter()
{
counters_.reserve(5); // pre-allocated 5 slots
}
template<class X>
long
get() const
{
Lock sync(this);
return counters_[slot<X>()];
}
template<class X>
long
inc()
{
Lock sync(this);
return ++counters_[slot<X>()];
}
template<class X>
long
dec()
{
Lock sync(this);
return --counters_[slot<X>()];
}
/* == diagnostics == */
size_t size() const { return counters_.size(); }
bool empty() const { return counters_.empty();}
};
} // namespace lib
#endif