/*
* tokenutils.h
*
* This file is part of NEST.
*
* Copyright (C) 2004 The NEST Initiative
*
* NEST 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.
*
* NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOKENUTILS_H
#define TOKENUTILS_H
#include "token.h"
#include "sliexceptions.h"
#include "namedatum.h"
#include <string>
#include "config.h"
/**
* @defgroup TokenHandling Handling classes Token and Dictionary.
*
* Accessing the underlying vales of class Token and Dictionary
* entries can be a somewhat tricky issue, depending on how the data
* type is actually implemented. The programmer needs detailed
* knowledge of the implementation (which usually involves an
* intermediate class which is derived from the generic class Datum.)
* However, the programmer in almost all cases is only interested in
* how to get and modify the underlying fundamental C++-types.
*
* The utility functions described in this group aim at simplifying
* the access to the underlying values by providing template
* specializations for each fundamental C++-type. The programmer can
* simply specify the fundamental C++-type to handle, while the
* implementation details are hidden.
*
* @note
* Some of the utility functions described here have since been superceded
* by new type conversion operators in class Token (see there). These
* operators allow to use class Token directly at positions, where a
* fundamental C++-datatype is required. Together with the indexing
* operator for class Dictionary, it all boils down to
* comprehensive calls like the following:
* @code
* int myvar = dict["myentry"];
* dict["entry2"] = 23;
* Token1 = Token2 + 1
* @endcode
* @note
* It is left to the programmer's choice what method to use. It is
* recommendable to use the (implicit) type conversion operators where
* their operation is obvious to the reader of the source code.
* Sometimes using the type conversion operators tends to obscure the
* meaning of code. In these cases, the programmer is kindly asked to
* comment on the code, or to use the more explicit template functions
* described in this group.
* @note
* R. Kupper, 24-09-2003
*/
/**
* @defgroup TokenUtils How to access the value contained in a Token.
* @ingroup TokenHandling
*
* Class Token defines the standard user interface for accessing SLI
* Datum types from tokens (see there). However, this user interface returns
* objects of class Datum, from which the actual value would still need to be
* extracted. The utilitiy functions described in this group shortcut
* this step and provide direct access to the underlying fundamental
* values contained in a token.
*/
/** getValue provides easy read-access to a Token's contents.
getValue returns the value of the Datum contained inside the Token.
\ingroup TokenUtils
The general getValue function assumes that the datum was directly
derived from a C++ type (most probably some container or stream).
All other cases will be handled by specialization of this template.
For example, AggregateDatum types are directly derived from a C++ type.
\verbatim
SLI Datum derived from C++ type
------------------------------------------
BoolDatum Name
HandleDatum DatumHandle (whatever that might be...)
LiteralDatum Name
NameDatum Name
ParserDatum Parser
StringDatum string
SymbolDatum Name
(What else?)
\endverbatim
Hence, getValue may be used in the following ways:
\verbatim
call can be used on Token containing SLI-type
--------------------------------------------------------------------
Name getValue<Name> {Bool|Literal|Name|Symbol}Datum
DatumHandle
getValue<DatumHandle> HandleDatum
Parser getValue<Parser> ParserDatum
string getValue<string> StringDatum
\endverbatim
The following specialized variants of getValue() can be used in addition:
\verbatim
call can be used on Token containing SLI-type
---------------------------------------------------------------------------------
long GetValue<long> IntegerDatum
double GetValue<double> DoubleDatum
bool GetValue<bool> BoolDatum
string GetValue<string> NameDatum
string GetValue<string> LiteralDatum
string GetValue<string> SymbolDatum
vector<long> GetValue<vector<long> > ArrayDatum
vector<double> GetValue<vector<double> > ArrayDatum
valarray<long> GetValue<valarray<long> > ArrayDatum
valarray<double> GetValue<valarray<double> > ArrayDatum
\endverbatim
What about the rest? (ElementFactoryDatum, el_prtdatum, FunctionDatum,
GenericDatum, NumericDatum, lockPTRDatum, ReferenceDatum, SmartPtrDatum,
TrieDatum)
@throws TypeMismatch The specified fundamental datatype does not
match the Token's contents, or a template specialization for this
type is missing.
**/
template <typename FT>
FT getValue(const Token &t)
{
FT *value = dynamic_cast<FT *>(t.datum());
if (value == NULL)
{
throw TypeMismatch();
}
return *value;
}
/** setValue provides easy write-access to a Token's contents.
setValue updates the value of the Datum contained inside the Token.
\ingroup TokenUtils
setValue(Token, value) can be called on the same value/Datum pairs getValue
handles. Note that the template parameter to setValue does not need to be
specified explicitely, as it can be derived from the second argument.
@throws TypeMismatch The specified fundamental datatype does not
match the Token's contents, or a template specialization for this
type is missing.
**/
template <typename FT>
void setValue(const Token &t, FT const &value)
{
FT *old = dynamic_cast<FT *>(t.datum());
if (old == NULL)
{
throw TypeMismatch();
}
*old = value;
}
/** Create a new Token from a fundamental data type.
Specify the desired Datum type as the second template parameter!
@ingroup TokenUtils
**/
template <typename FT, class D>
Token newToken2(FT const &value)
{
Token t(new D(value));
// this is for typechecking reasons:
getValue<FT>(t);
return t;
}
/** Create a new Token from a fundamental data type.
This template is specialized for the most fundamental types. If it
does not work, use newToken2() and specify the Datum type explicitely.
@ingroup TokenUtils
**/
template <typename FT>
Token newToken(FT const &value)
{
return newToken2<FT,NameDatum>(value);
}
// specializations below this line: -----------------------
template<>
long getValue<long>(const Token&);
template<>
void setValue<long>(const Token&, long const &value);
template<>
Token newToken<long>(long const &value);
template<>
double getValue<double>(const Token&);
template<>
void setValue<double>(const Token&, double const &value);
template<>
float getValue<float>(const Token&);
template<>
void setValue<float>(const Token&, float const &value);
template<>
Token newToken<double>(double const &value);
template<>
bool getValue<bool>(const Token&);
template<>
void setValue<bool>(const Token&, bool const &value);
template<>
Token newToken<bool>(bool const &value);
// These will handle StringDatum, NameDatum,
// LiteralDatum and SymbolDatum tokens:
template<>
std::string getValue<std::string>(const Token&);
template<>
void setValue<std::string>(const Token&, std::string const &value);
template<>
Token newToken<std::string>(std::string const &value);
// To get NameDatum, LiteralDatum or SymbolDatum tokens from a string,
// use newToken2<FT,D> instead (e.g. newToken2<string,LiteralDatum>);
// These will convert homogeneous int arrays to vectors:
template<>
std::vector<long> getValue<std::vector<long> >(const Token&);
template<>
void setValue<std::vector<long> >(const Token&, std::vector<long> const &value);
template<>
Token newToken<std::vector<long> >(std::vector<long> const &value);
// These will convert homogeneous double arrays to vectors:
template<>
std::vector<double> getValue<std::vector<double> >(const Token&);
template<>
void setValue<std::vector<double> >(const Token&, std::vector<double> const &value);
template<>
Token newToken<std::vector<double> >(std::vector<double> const &value);
// These will convert homogeneous int arrays to valarrays:
template<>
std::valarray<long> getValue<std::valarray<long> >(const Token&);
template<>
void setValue<std::valarray<long> >(const Token&, std::valarray<long> const &value);
template<>
Token newToken<std::valarray<long> >(std::valarray<long> const &value);
// These will convert homogeneous double arrays to valarrays:
template<>
std::valarray<double> getValue<std::valarray<double> >(const Token&);
template<>
void setValue<std::valarray<double> >(const Token&, std::valarray<double> const &value);
template<>
Token newToken<std::valarray<double> >(std::valarray<double> const &value);
#endif