/*
* tokenarray.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 TOKENARRAY_H
#define TOKENARRAY_H
/*
Reference Counted Array class specialized on Token objects.
*/
#include <typeinfo>
#include <cstddef>
#include <vector>
#include <valarray>
#include "tarrayobj.h"
#include "sliexceptions.h"
// class Tokenarray uses reference counting and lazy evaluation.
// This means that only a pointer
// to the actual array representation, class TokenArrayObj, is stored.
// In most cases only this pointer is copied. Only when the array is
// to be modified, will the TokenArray be copied.
// class TokenArrayObj is the complete token array class without reference-
// counting and lazu evaluation. class TokenArray serves as a smart interface.
//
// Note, that after the use of non const member functions, iterators (i.e.
// Token *) may become invalid due to cloning or reallocation of the array
//
//
// gewaltig, July 18 1997
// _move member functions may invalidate their iterator arguments.
// These functions are most efficient if for the source (argument)
// TokenArray references()==1 holds and therfore no cloning has to
// be performed.
//
// can be optimized for the case references()>1 by only
// constructing the elements needed without proper clone()
//
// Diesmann, April 14 1998
class TokenArray
{
private:
TokenArrayObj* data;
bool clone(void)
{
if( data->references() > 1)
{
data->remove_reference();
data = new TokenArrayObj(*data);
return true;
}
else return false;
}
bool detach(void)
{
if( data->references() > 1)
{
data->remove_reference();
data = new TokenArrayObj();
return true;
}
else return false;
}
protected:
friend class TokenArrayObj;
friend class TokenStack;
operator TokenArrayObj() const
{ return *data; }
public:
TokenArray(void)
: data(new TokenArrayObj()) {};
explicit
TokenArray(size_t n, const Token &t = Token(), size_t alloc = 128)
: data( new TokenArrayObj(n,t,alloc)) {}
TokenArray(const TokenArray &a)
: data(a.data)
{ data->add_reference(); }
TokenArray(const TokenArrayObj &a)
: data( new TokenArrayObj(a)){}
TokenArray(const std::vector<size_t> &);
TokenArray(const std::vector<long> &);
TokenArray(const std::valarray<long> &);
TokenArray(const std::valarray<double> &);
TokenArray(const std::valarray<float> &);
TokenArray(const std::vector<double> &);
TokenArray(const std::vector<float> &);
virtual ~TokenArray()
{
data->remove_reference(); // this will dispose data if needed.
}
/**
* Return pointer to the first element.
*/
Token * begin() const
{
return data->begin();
}
/**
* Return pointer to next to last element.
*/
Token * end() const
{
return data->end();
}
/**
* Return number of elements in the array.
*/
size_t size(void) const
{
return data->size();
}
/**
* Return maximal number of elements that fit into the container.
*/
size_t capacity(void) const
{
return data->capacity();
}
// Note, in order to use the const version of operator[]
// through a pointer, it is in some cases necessary to
// use an explicit TokenArray const * pointer!
// Use the member function get(size_t) const to force
// constness.
Token & operator[](size_t i)
{
clone();
return (*data)[i];
}
const Token & operator[](size_t i) const
{
return (*data)[i];
}
const Token &get(long i) const
{
return data->get(i);
}
bool index_is_valid(long i) const
{
return data->index_is_valid(i);
}
void rotate(Token *t1, Token *t2, Token *t3)
{
size_t s1= t1 - data->begin();
size_t s2= t2 - data->begin();
size_t s3= t3 - data->begin();
clone();
Token *b=data->begin();
data->rotate(b+s1,b+s2,b+s3);
}
void rotate(long n);
// The following two members shrink and reserve do
// NOT invoke cloning, since they have no immediate
// consequences.
/**
* Reduce allocated space such that size()==capacity().
* Returns true if the array was resized and false otherwhise.
* If true is returned, all existing pointers into the array are
* invalidated.
*/
bool shrink(void)
{
return data->shrink();
}
/**
* Reserve space such that after the call the new capacity is n.
* Returns true, if the container was reallocated. In this case all
* existing pointers are invalidated.
*/
bool reserve(size_t n)
{
return data->reserve(n);
}
unsigned int references(void)
{
return data->references();
}
/**
* Resizes the container to size s.
* If the new size is larger than the old size, the new space is initialized with t.
*/
void resize(size_t s, const Token &t = Token())
{
clone(); data->resize(s,t);
}
// Insertion, deletion
void push_back(const Token &t)
{
clone(); data->push_back(t);
}
void push_back(Datum *d)
{
Token t(d);
clone(); data->push_back_move(t);
}
void push_back_move(Token &t)
{
clone(); data->push_back_move(t);
}
void push_back_dont_clone(Token &t)
{
data->push_back_move(t);
}
void assign_move(size_t i, Token &t) // 8.4.98 Diesmann
{
clone(); data->assign_move(data->begin()+i,t);
}
void assign_move(TokenArray &a, size_t i, size_t n)
{
clear(); // no cloning, because we overwrite everything
// This is slightly inefficient, because if a has references,
// cloning is more expensive than just copying the desired range.
if(a.references()==1)
data->assign_move(*(a.data), i,n);
else
data->assign(*(a.data), i,n);
}
void insert_move(size_t i, TokenArray &a) // 8.4.98 Diesmann
{
clone(); // make copy if others point to representation
a.clone(); // also for a because we are going to empy it
// assert(data->refs==1); // private copy
// assert(a.data->refs==1); // private copy
data->insert_move(i, *(a.data));
// the representations insert_move moves the
// the contens of all Tokens in a.data and marks it empty.
// assert(a.data->size()==0); // empty, but memory is still allocated incase
// it will be used again. data->clear() would
// free the memory. In any case the destructor
// finally frees the memory.
}
void insert_move(size_t i, Token &t)
{
clone();
data->insert_move(i,t);
}
void replace_move(size_t i, size_t n, TokenArray &a)
{
clone();
a.clone();
data->replace_move(i,n,*(a.data));
}
void append_move(TokenArray &a)
{
clone(); // make copy if others point to representation
a.clone(); // also for a because we are going to empy it
data->append_move(*(a.data));
}
void pop_back(void)
{
clone(); data->pop_back();
}
void clear(void)
{
erase();
}
void erase(void)
{
if(!detach())
erase(begin(),end());
}
void erase(Token * from, Token * to)
{
if(from != to)
{
size_t sf = from - data->begin();
size_t st = to - data->begin();
clone(); data->erase(data->begin()+sf, data->begin()+st);
}
}
void erase(size_t i, size_t n)
{
if(i<size() && n>0)
{
clone();
data->erase(i,n);
}
}
// Reduce the Array to the Range given by the iterators
void reduce(size_t i, size_t n)
{
if(i>0 || n<size())
{
clone();
data->reduce(i,n);
}
}
void reverse();
void swap(TokenArray &a)
{
std::swap(data,a.data);
}
const TokenArray & operator=(const TokenArray &);
const TokenArray & operator=(const std::vector<long> &);
const TokenArray & operator=(const std::vector<double> &);
const TokenArray & operator=(const std::valarray<long> &);
const TokenArray & operator=(const std::valarray<double> &);
bool operator==(const TokenArray &a) const
{
return *data == *a.data;
}
bool empty(void) const
{
return size()==0;
}
void info(std::ostream &) const;
/** Fill vectors with homogenous integer and double arrays */
void toVector(std::vector<size_t> &) const;
void toVector(std::vector<long> &) const;
void toVector(std::vector<double> &) const;
void toVector(std::vector<std::string> &) const;
void toValarray(std::valarray<long> &) const;
void toValarray(std::valarray<double> &) const;
bool valid(void) const; // check integrity
/** Exception classes */
// class TypeMismatch {};
class OutOfRange {};
};
inline
void TokenArray::reverse()
{
if(size()==0)
return;
clone();
Token *b = begin();
Token *e = end() -1;
while(b < e)
{
b->swap(*e);
++b; --e;
}
}
inline
void TokenArray::rotate(long n=1)
{
if (size() == 0 || n == 0)
return;
clone();
long rot = n % static_cast<long>(size());
rot = (rot < 0) ? rot+size() : rot;
std::rotate(begin(), begin()+rot, end());
}
std::ostream & operator<<(std::ostream& , const TokenArray&);
#ifdef TokenArray_H_DEBUG
#undef TokenArray_H_DEBUG
#undef NDEBUG
#endif
#endif