Browse Source

more styling

master
Joshua Moerman 13 years ago
parent
commit
5f4032eca0
  1. 42
      Attractor.cpp
  2. 2
      Attractor.hpp
  3. 44
      AttractorKernel.cpp
  4. 16
      AttractorKernel.hpp
  5. 6
      Canvas.cpp
  6. 44
      Canvas.hpp
  7. 12
      Logger.hpp
  8. 2
      Projector.cpp
  9. 15
      defines.hpp
  10. 2
      kernels/Logistic.cpp
  11. 2
      kernels/Lorenz3D.cpp
  12. 12
      kernels/Polynomial.cpp
  13. 2
      kernels/PolynomialA3D.cpp
  14. 6
      kernels/Unravel3D.cpp
  15. 4
      ostream_helpers.h
  16. 7719
      pngwriter/pngwriter.cc
  17. 1285
      pngwriter/pngwriter.h
  18. 26
      projectors/Normalizer.cpp
  19. 6
      projectors/Projection.cpp
  20. 550
      stfu/stf.cpp
  21. 718
      stfu/stf.hpp

42
Attractor.cpp

@ -21,7 +21,7 @@ Attractor::Attractor(const std::string& filename) : kernel(0), projector(0) {
projector = Projector::createProjector(system.getChild(system.getValue("Projector")), system);
}
Attractor::~Attractor(){
Attractor::~Attractor() {
delete kernel;
}
@ -29,7 +29,7 @@ Attractor::~Attractor(){
// this should probably done in the projector section
void Attractor::init_range() {
// stabilize attractor
for ( unsigned int i = 0; i < 100000; i++ ) {
for(unsigned int i = 0; i < 100000; i++) {
iterate();
}
}
@ -41,22 +41,22 @@ bool Attractor::is_chaos() {
Single point attractor
Lyapunov exponent
*/
/*
double sum = 0;
for ( unsigned int i = 0; i < dim; i++ ) {
const double dist = 0; //new_point[i] - point[i];
sum += dist*dist;
}
if ( sum >= 1.0e7 ) {
// big change => Escaping
return false;
}
if ( sum <= 1.0e-7 ) {
// small change => singularity
return false;
}
return true;
*/
/*
double sum = 0;
for ( unsigned int i = 0; i < dim; i++ ) {
const double dist = 0; //new_point[i] - point[i];
sum += dist*dist;
}
if ( sum >= 1.0e7 ) {
// big change => Escaping
return false;
}
if ( sum <= 1.0e-7 ) {
// small change => singularity
return false;
}
return true;
*/
return true;
}
@ -65,7 +65,7 @@ void Attractor::iterate() {
}
void Attractor::plot() {
const double * point = kernel->vector();
const double* point = kernel->vector();
projector->plot(point);
}
@ -75,9 +75,9 @@ void Attractor::plot() {
*/
void Attractor::output() {
const unsigned int dimension = kernel->getDimension();
const double * point = kernel->vector();
const double* point = kernel->vector();
for ( unsigned int i = 0; i < dimension; i++ ) {
for(unsigned int i = 0; i < dimension; i++) {
LogMoreInfo("%f, ", point[i]);
}
LogMoreInfo("\n");

2
Attractor.hpp

@ -10,7 +10,7 @@ class AttractorKernel;
class Attractor {
private:
AttractorKernel * kernel;
AttractorKernel* kernel;
public:

44
AttractorKernel.cpp

@ -15,11 +15,11 @@
#pragma mark memory
AttractorKernel::AttractorKernel(const unsigned int dimension, const unsigned int numberOfParameters) :
numberOfParameters(numberOfParameters), dimension(dimension){
numberOfParameters(numberOfParameters), dimension(dimension) {
try {
allocate();
} catch (std::exception& e) {
} catch(std::exception& e) {
LogError("Couldn't construct Attractorkernel: %s\n", e.what());
dealloc();
}
@ -30,17 +30,17 @@ numberOfParameters(numberOfParameters), dimension(dimension){
}
AttractorKernel::~AttractorKernel(){
AttractorKernel::~AttractorKernel() {
dealloc();
}
void AttractorKernel::allocate(){
void AttractorKernel::allocate() {
parameters = new double[numberOfParameters];
vectorNew = new double[dimension];
vectorOld = new double[dimension];
}
void AttractorKernel::dealloc(){
void AttractorKernel::dealloc() {
delete[] vectorOld;
vectorOld = NULL;
delete[] vectorNew;
@ -54,30 +54,30 @@ void AttractorKernel::dealloc(){
// NOTE: inlining these functions (with the keyword inline) improves performance by at most 1% (tested)
double & AttractorKernel::operator[](const unsigned int index){
double& AttractorKernel::operator[](const unsigned int index) {
return parameters[index];
}
double const & AttractorKernel::operator[](const unsigned int index) const{
double const& AttractorKernel::operator[](const unsigned int index) const {
return parameters[index];
}
unsigned int AttractorKernel::getNumberOfParameters() const{
unsigned int AttractorKernel::getNumberOfParameters() const {
return numberOfParameters;
}
#pragma mark -
#pragma mark vector
double const * AttractorKernel::vector() const{
double const* AttractorKernel::vector() const {
return vectorNew;
}
double const * AttractorKernel::previousVector() const{
double const* AttractorKernel::previousVector() const {
return vectorOld;
}
unsigned int AttractorKernel::getDimension() const{
unsigned int AttractorKernel::getDimension() const {
return dimension;
}
@ -90,9 +90,9 @@ unsigned int AttractorKernel::getDimension() const{
#include "kernels/PolynomialA3D.hpp"
#include "kernels/Unravel3D.hpp"
AttractorKernel * AttractorKernel::createAttractorKernel(stfu::node& attractor){
AttractorKernel* AttractorKernel::createAttractorKernel(stfu::node& attractor) {
AttractorKernel * myAttractor = NULL;
AttractorKernel* myAttractor = NULL;
// reading basic stuff
const std::string attractorType = attractor.getValue("type");
@ -108,30 +108,30 @@ AttractorKernel * AttractorKernel::createAttractorKernel(stfu::node& attractor){
// depending on type, make the formula object
if ( attractorType == "lorenz" ){
if ( dimension == 3 ) {
if(attractorType == "lorenz") {
if(dimension == 3) {
myAttractor = new Lorenz3D();
} else {
LogError("something wrong\n");
exit(37);
}
} else if ( attractorType == "polynomial" ) {
} else if(attractorType == "polynomial") {
const std::string attractorOrde = attractor.getValue("orde");
const unsigned int orde = atoi(attractorOrde.c_str());
LogMoreInfo(" Orde: %d\n", orde);
myAttractor = new Polynomial(dimension, orde);
} else if ( attractorType == "polynomial a" ) {
if ( dimension == 3 ) {
} else if(attractorType == "polynomial a") {
if(dimension == 3) {
myAttractor = new PolynomialA3D();
} else {
LogError("something wrong\n");
exit(37);
}
} else if ( attractorType == "logistic" ) {
} else if(attractorType == "logistic") {
myAttractor = new Logistic(dimension);
} else if ( attractorType == "unravel" ) {
if ( dimension == 3 ) {
} else if(attractorType == "unravel") {
if(dimension == 3) {
myAttractor = new Unravel3D();
} else {
LogError("something wrong\n");
@ -146,7 +146,7 @@ AttractorKernel * AttractorKernel::createAttractorKernel(stfu::node& attractor){
// read parameters
const unsigned int numberOfParameters = myAttractor->getNumberOfParameters();
for ( unsigned int i = 0; i < numberOfParameters; i++ ) {
for(unsigned int i = 0; i < numberOfParameters; i++) {
stfu::node attractorParameters = attractor.getChild("parameters");
(*myAttractor)[i] = atof(attractorParameters.getValue(i).c_str());
LogMoreInfo(" Parameter %d set to %f, ", i, (*myAttractor)[i]);

16
AttractorKernel.hpp

@ -13,9 +13,9 @@ protected:
// biggest type first, this will reduce sizeof(AttractorKernel)
// size is now 40 (when the unsigned int are in front, it was 48)
double * parameters;
double * vectorNew;
double * vectorOld;
double* parameters;
double* vectorNew;
double* vectorOld;
unsigned int numberOfParameters;
unsigned int dimension;
@ -26,23 +26,23 @@ protected:
public:
// parameters are stored in a array of doubles
double & operator[](const unsigned int index);
double const & operator[](const unsigned int index) const;
double& operator[](const unsigned int index);
double const& operator[](const unsigned int index) const;
unsigned int getNumberOfParameters() const;
// iterate his formula, implemented by subclasses
virtual void operator()() = 0;
// getter functions for teh resulta (can't be used as setters)
double const * vector() const;
double const * previousVector() const;
double const* vector() const;
double const* previousVector() const;
unsigned int getDimension() const;
// dtor, should be virtual for subclasses to be deleted
virtual ~AttractorKernel();
// factory function
static AttractorKernel * createAttractorKernel(stfu::node& attractorKernel);
static AttractorKernel* createAttractorKernel(stfu::node& attractorKernel);
};

6
Canvas.cpp

@ -1,3 +1,3 @@
#include "Canvas.hpp"
// lol
#include "Canvas.hpp"
// lol

44
Canvas.hpp

@ -1,22 +1,22 @@
#ifndef CANVAS_HPP
#define CANVAS_HPP
class Canvas {
protected:
unsigned int dimension;
Canvas (const unsigned int dimension) : dimension (dimension) {};
public:
unsigned int getDimension() const { return dimension; };
virtual ~Canvas() {};
virtual void clear() = 0;
virtual void plot (const double * normalizedPosition) = 0;
virtual void output_file (const char * filename) const = 0;
};
#endif // CANVAS_HPP
#ifndef CANVAS_HPP
#define CANVAS_HPP
class Canvas {
protected:
unsigned int dimension;
Canvas(const unsigned int dimension) : dimension(dimension) {};
public:
unsigned int getDimension() const { return dimension; };
virtual ~Canvas() {};
virtual void clear() = 0;
virtual void plot(const double* normalizedPosition) = 0;
virtual void output_file(const char* filename) const = 0;
};
#endif // CANVAS_HPP

12
Logger.hpp

@ -1,8 +1,8 @@
#ifndef LOGGER_HPP_INCLUDED
#define LOGGER_HPP_INCLUDED
#ifndef LOGGER_HPP_INCLUDED
#define LOGGER_HPP_INCLUDED
#include <cstdio>
extern int verbose;
#define LogDebug(s, ...) \
@ -17,6 +17,6 @@ extern int verbose;
#define LogError(s, ...) \
if ( verbose >= 0 ) { printf("%s, %d: ", __FILE__, __LINE__); printf(s, ##__VA_ARGS__); }
#endif // LOGGER_HPP_INCLUDED
#endif // LOGGER_HPP_INCLUDED

2
Projector.cpp

@ -18,7 +18,7 @@ Projector::Projector(unsigned int inputDimension, unsigned int outputDimension)
std::fill_n(projectedPoint, outputDimension, 0.0);
}
Projector::~Projector(){
Projector::~Projector() {
deallocate();
}

15
defines.hpp

@ -1,13 +1,12 @@
#define DEFAULT_ATTRACTOR_FILE "attractors/testUnravel.stf"
#ifdef UNI_BUILD
#warning Building for the RU, are you sure?
#define DEFAULT_WIDTH 8000
#define DEFAULT_HEIGHT 8000
#define DEFAULT_ITERATIONS 4200000000
#warning Building for the RU, are you sure?
#define DEFAULT_WIDTH 8000
#define DEFAULT_HEIGHT 8000
#define DEFAULT_ITERATIONS 4200000000
#else
#define DEFAULT_WIDTH 800
#define DEFAULT_HEIGHT 800
#define DEFAULT_ITERATIONS 1000000
#define DEFAULT_WIDTH 800
#define DEFAULT_HEIGHT 800
#define DEFAULT_ITERATIONS 1000000
#endif

2
kernels/Logistic.cpp

@ -36,7 +36,7 @@ void Logistic::init() {
void Logistic::operator()() {
std::swap(vectorNew, vectorOld);
for ( unsigned int i = 0; i < dimension; i++ ) {
for(unsigned int i = 0; i < dimension; i++) {
vectorNew[i] = parameters[i]*vectorOld[i]*(1.0 - vectorOld[i]);
}
}

2
kernels/Lorenz3D.cpp

@ -6,7 +6,7 @@
#pragma mark ctors
Lorenz3D::Lorenz3D():
AttractorKernel(3, 4){
AttractorKernel(3, 4) {
init();
}

12
kernels/Polynomial.cpp

@ -12,7 +12,7 @@
unsigned int calculateNumberOfParameters(const unsigned int dimension, const unsigned int orde) {
double n_coef = orde + 1;
for (unsigned int i = 2; i <= dimension; i++) {
for(unsigned int i = 2; i <= dimension; i++) {
n_coef = n_coef*(orde + i)/(i - 1);
}
@ -25,10 +25,10 @@ unsigned int calculateNumberOfParameters(const unsigned int dimension, const uns
#pragma mark ctors
Polynomial::Polynomial():
AttractorKernel(3, calculateNumberOfParameters(3, 2)), orde(2){}
AttractorKernel(3, calculateNumberOfParameters(3, 2)), orde(2) {}
Polynomial::Polynomial(const unsigned int dimension, const unsigned int orde):
AttractorKernel(dimension, calculateNumberOfParameters(dimension, orde)), orde(orde){}
AttractorKernel(dimension, calculateNumberOfParameters(dimension, orde)), orde(orde) {}
#pragma mark -
@ -38,7 +38,7 @@ void Polynomial::operator()() {
std::swap(vectorNew, vectorOld);
unsigned int m = 0;
for ( unsigned int i = 0; i < dimension; i++ ) {
for(unsigned int i = 0; i < dimension; i++) {
vectorNew[i] = parameters[m];
m++;
@ -48,12 +48,12 @@ void Polynomial::operator()() {
void Polynomial::recur(unsigned int curr_dimension, unsigned int prev_i, unsigned int n, unsigned int& m, double prev_product) {
double product;
for (unsigned int i = prev_i; i < dimension; i++) {
for(unsigned int i = prev_i; i < dimension; i++) {
product = prev_product * vectorOld[i];
vectorNew[curr_dimension] += parameters[m] * product;
m++;
if (n < orde) {
if(n < orde) {
recur(curr_dimension, i, n+1, m, product);
}
}

2
kernels/PolynomialA3D.cpp

@ -14,7 +14,7 @@
#pragma mark ctors
PolynomialA3D::PolynomialA3D():
AttractorKernel(3, 3){}
AttractorKernel(3, 3) {}
#pragma mark -

6
kernels/Unravel3D.cpp

@ -7,7 +7,7 @@
#pragma mark ctors
Unravel3D::Unravel3D():
AttractorKernel(3, 7){}
AttractorKernel(3, 7) {}
#pragma mark -
@ -22,9 +22,9 @@ void Unravel3D::operator()() {
const double dist = vectorNew[0]*vectorNew[0] + vectorNew[1]*vectorNew[1] + vectorNew[2]*vectorNew[2];
if ( dist > parameters[6]*parameters[6] ) {
if(dist > parameters[6]*parameters[6]) {
const double sqrtDist = std::sqrt(dist);
const double p = 1.0 - parameters[6] * ( static_cast<int> ( sqrtDist / parameters[6] ) + 1.0 ) / sqrtDist;
const double p = 1.0 - parameters[6] * (static_cast<int>(sqrtDist / parameters[6]) + 1.0) / sqrtDist;
vectorNew[0] *= p;
vectorNew[1] *= p;
vectorNew[2] *= p;

4
ostream_helpers.h

@ -1,4 +1,4 @@
#ifndef OSTREAM_HELPERS_HPP
#ifndef OSTREAM_HELPERS_HPP
#define OSTREAM_HELPERS_HPP
#include <iterator>
@ -9,7 +9,7 @@
std::ostream& operator<<(std::ostream& os, AttractorKernel const& x) {
const unsigned int dimension = x.getDimension();
const double * point = x.vector();
const double* point = x.vector();
std::copy(point, point+dimension, std::ostream_iterator<double>(os, ", "));
return os;

7719
pngwriter/pngwriter.cc

File diff suppressed because it is too large

1285
pngwriter/pngwriter.h

File diff suppressed because it is too large

26
projectors/Normalizer.cpp

@ -9,7 +9,7 @@ Normalizer::Normalizer(unsigned int dimension) : Projector(dimension, dimension)
try {
allocate();
} catch (std::exception& e) {
} catch(std::exception& e) {
LogError("Couldn't construct Normalizer (Projector): %s\n", e.what());
deallocate();
}
@ -23,13 +23,13 @@ Normalizer::~Normalizer() {
deallocate();
}
void Normalizer::allocate(){
void Normalizer::allocate() {
range_min = new double[outputDimension];
range_max = new double[outputDimension];
offset = new double[outputDimension];
}
void Normalizer::deallocate(){
void Normalizer::deallocate() {
delete[] range_min;
range_min = 0;
delete[] range_max;
@ -41,12 +41,12 @@ void Normalizer::deallocate(){
#pragma mark -
#pragma mark plot
void Normalizer::project(const double * point) {
for ( unsigned int i = 0; i < inputDimension; ++i ) {
void Normalizer::project(const double* point) {
for(unsigned int i = 0; i < inputDimension; ++i) {
projectedPoint[0] = point[0]*factor + offset[0];
}
if(!ready){
if(!ready) {
static unsigned int state = 0;
switch(state) {
@ -70,16 +70,16 @@ void Normalizer::project(const double * point) {
#pragma mark setting up
void Normalizer::init_range() {
for ( unsigned int i = 0; i < outputDimension; i++ ) {
for(unsigned int i = 0; i < outputDimension; i++) {
range_min[i] = range_max[i] = projectedPoint[i];
}
}
void Normalizer::update_range() {
for ( unsigned int i = 0; i < outputDimension; i++ ) {
if ( projectedPoint[i] < range_min[i] ) {
for(unsigned int i = 0; i < outputDimension; i++) {
if(projectedPoint[i] < range_min[i]) {
range_min[i] = projectedPoint[i];
} else if ( projectedPoint[i] > range_max[i] ) {
} else if(projectedPoint[i] > range_max[i]) {
range_max[i] = projectedPoint[i];
}
}
@ -87,16 +87,16 @@ void Normalizer::update_range() {
void Normalizer::finish_range() {
factor = 2.0 / (range_max[0] - range_min[0]);
for ( unsigned int i = 1; i < outputDimension; i++ ) {
for(unsigned int i = 1; i < outputDimension; i++) {
double dist = range_max[i] - range_min[i];
if ( factor * dist > 2.0 ) {
if(factor * dist > 2.0) {
factor = 2.0 / dist;
//teh_size = canvas->size[i];
LogDebug("Crap for dimension %d\n", i);
}
}
for ( unsigned int i = 0; i < outputDimension; i++ ) {
for(unsigned int i = 0; i < outputDimension; i++) {
offset[i] = -0.5*factor*(range_min[i] + range_max[i]);
}
}

6
projectors/Projection.cpp

@ -1,10 +1,10 @@
#include "Projection.hpp"
Projection::Projection(unsigned int inputDimension, unsigned int outputDimension) : Projector(inputDimension, outputDimension){
Projection::Projection(unsigned int inputDimension, unsigned int outputDimension) : Projector(inputDimension, outputDimension) {
}
void Projection::project(const double* point){
for ( unsigned int i = 0; i < inputDimension; ++i){
void Projection::project(const double* point) {
for(unsigned int i = 0; i < inputDimension; ++i) {
projectedPoint[i] = point[i];
}
}

550
stfu/stf.cpp

@ -1,275 +1,275 @@
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <typeinfo>
#include "stf.hpp"
namespace stfu{
std::ostream &operator<< (std::ostream &out, const node &root) {
root.write(out);
return out;
}
bool operator<< (const char *filename, const node &root){
return root.write(filename);
}
bool operator<< (std::ofstream &out, const node &root) {
return root.write(out);
}
bool operator>> (std::istream &in, node &root) {
return root.read(in);
}
bool operator>> (const char *filename, node &root) {
return root.read(filename);
}
const std::string &node::getValue(const std::string &name, size_t index) const throw (std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
/*Function is const, but shouldn't be called on const objects since it returns a nonconst-reference to a member*/
std::string &node::getValue(const std::string &name, size_t index) throw (std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
std::string &node::addValue(const std::string &name) {
return values.insert(std::pair<std::string, std::string>(name, std::string()))->second;
}
std::string &node::value(const std::string &name, size_t index) {
try {
return getValue(name, index);
} catch (std::out_of_range &e) {
//it doesn't exist: create it
return addValue(name);
}
}
void node::removeValue(const std::string &name, size_t index) throw (std::out_of_range) {
values.erase(get_indexed_it(values, name, index));
return;
}
void node::renameValue(const std::string &oldName, const std::string &newName, size_t index) {
addValue(newName) = value(oldName, index);
removeValue(oldName, index);
}
const node &node::getChild(const std::string &name, size_t index) const throw (std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node &node::getChild(const std::string &name, size_t index) throw (std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node &node::addChild(const std::string &name) {
return children.insert(std::pair<std::string, node>(name, node()))->second;
}
node &node::addChild(const std::string &name, node &newNode) {
return children.insert(std::pair<std::string, node>(name, newNode))->second;
}
node &node::child(const std::string &name, size_t index) {
//if there's no such child, add one
try {
return getChild(name, index);
} catch (std::out_of_range &e) {
//it doesn't exist: create it
return addChild(name);
}
}
void node::renameChild(const std::string &oldName, const std::string &newName, size_t index) {
node copy = child(oldName, index);
removeChild(oldName, index);
addChild(newName) = copy;
}
void node::removeChild(const std::string &name, size_t index) throw (std::out_of_range) {
children.erase(get_indexed_it(children, name, index));
return;
}
bool node::read(const char *filename) {
std::ifstream f(filename);
if (!f.good()) return false;
bool success = read(f);
f.close();
return success;
}
bool node::read(std::istream &in) {
while (1) {
in >> std::ws; //Skip whitespace
//if end of node is reached, return
if (in.peek() == '}') {
in.ignore();
return true;
}
if (in.eof()) {
return true; //End of the file is reached
}
std::string name;
char type; // '{' or '"'
streamRead(in, name, ':'); //Read name (all chars before ':')
type = streamSkip(in,"\"{"); //Skip everything until '{' or '"'
switch (type) {
//in case of value
case '"': {
std::string value;
while (1) {
if (streamRead(in, value, '"') == 0) { //Read to the closing-"
return false;
}
if (in.peek() == '"') {
in.ignore();
value += '"';
continue;
} else {
break;
}
}
this->values.insert(std::pair<std::string,std::string>(name, value));
break;
}
//in case of child
case '{': {
node sub;
if (!sub.read(in)) { //Recursively read the subnode
return false;
}
this->children.insert(std::pair<std::string,node>(name,sub));
break;
}
default:
return false;
}
}
}
/*Writes to a file using it's overloaded self*/
bool node::write(const char *filename) const {
std::ofstream f(filename);
if (!f.good()) {
return false;
}
bool success = write(f);
f.close();
return success;
}
// TODO (Nick#1#): Make write() not put unnamed values on a new line, children are okay.
bool node::write(std::ostream &out, size_t depth, std::string indent) const {
std::string indentation;
for (size_t i = 0; i < depth; i++) {
indentation += indent;
}
for (std::multimap<std::string, std::string>::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) {
//Escape all the '"' by adding a second '"'
std::string value(value_it->second);
size_t found = value.find('"');
//while there are more ", insert second "s
while (found != value.npos) {
value.insert(found, 1, '"');
found = value.find('"', found+2);
}
out << indentation << value_it->first << ": \"" << value << '"' << std::endl;
}
for (std::multimap<std::string, node>::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) {
out << indentation << child_it->first << ": {" << std::endl;
child_it->second.write(out, depth+1);
out << indentation << '}' << std::endl;
}
return true;
}
char node::streamSkip(std::istream &in, const std::string &delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while (in >> std::noskipws >> cur) {
if (delimiters.find_first_of(cur) != delimiters.npos) return cur;
}
return 0;
}
char node::streamRead(std::istream &in, std::string &out, const std::string &delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while (in >> std::noskipws >> cur) {
if (delimiters.find(cur) != delimiters.npos) return cur;
out += cur;
}
return 0;
}
char node::streamRead(std::istream &in, std::string &out, const char delimiter) {
char cur;
//Return if the current char is delimiter
while (in >> std::noskipws >> cur) {
if (delimiter == cur) return cur;
out += cur;
}
return 0;
}
}
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <typeinfo>
#include "stf.hpp"
namespace stfu {
std::ostream& operator<< (std::ostream& out, const node& root) {
root.write(out);
return out;
}
bool operator<< (const char* filename, const node& root) {
return root.write(filename);
}
bool operator<< (std::ofstream& out, const node& root) {
return root.write(out);
}
bool operator>> (std::istream& in, node& root) {
return root.read(in);
}
bool operator>> (const char* filename, node& root) {
return root.read(filename);
}
const std::string& node::getValue(const std::string& name, size_t index) const throw(std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
/*Function is const, but shouldn't be called on const objects since it returns a nonconst-reference to a member*/
std::string& node::getValue(const std::string& name, size_t index) throw(std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
std::string& node::addValue(const std::string& name) {
return values.insert(std::pair<std::string, std::string>(name, std::string()))->second;
}
std::string& node::value(const std::string& name, size_t index) {
try {
return getValue(name, index);
} catch(std::out_of_range& e) {
//it doesn't exist: create it
return addValue(name);
}
}
void node::removeValue(const std::string& name, size_t index) throw(std::out_of_range) {
values.erase(get_indexed_it(values, name, index));
return;
}
void node::renameValue(const std::string& oldName, const std::string& newName, size_t index) {
addValue(newName) = value(oldName, index);
removeValue(oldName, index);
}
const node& node::getChild(const std::string& name, size_t index) const throw(std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node& node::getChild(const std::string& name, size_t index) throw(std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node& node::addChild(const std::string& name) {
return children.insert(std::pair<std::string, node>(name, node()))->second;
}
node& node::addChild(const std::string& name, node& newNode) {
return children.insert(std::pair<std::string, node>(name, newNode))->second;
}
node& node::child(const std::string& name, size_t index) {
//if there's no such child, add one
try {
return getChild(name, index);
} catch(std::out_of_range& e) {
//it doesn't exist: create it
return addChild(name);
}
}
void node::renameChild(const std::string& oldName, const std::string& newName, size_t index) {
node copy = child(oldName, index);
removeChild(oldName, index);
addChild(newName) = copy;
}
void node::removeChild(const std::string& name, size_t index) throw(std::out_of_range) {
children.erase(get_indexed_it(children, name, index));
return;
}
bool node::read(const char* filename) {
std::ifstream f(filename);
if(!f.good()) return false;
bool success = read(f);
f.close();
return success;
}
bool node::read(std::istream& in) {
while(1) {
in >> std::ws; //Skip whitespace
//if end of node is reached, return
if(in.peek() == '}') {
in.ignore();
return true;
}
if(in.eof()) {
return true; //End of the file is reached
}
std::string name;
char type; // '{' or '"'
streamRead(in, name, ':'); //Read name (all chars before ':')
type = streamSkip(in,"\"{"); //Skip everything until '{' or '"'
switch(type) {
//in case of value
case '"': {
std::string value;
while(1) {
if(streamRead(in, value, '"') == 0) { //Read to the closing-"
return false;
}
if(in.peek() == '"') {
in.ignore();
value += '"';
continue;
} else {
break;
}
}
this->values.insert(std::pair<std::string,std::string>(name, value));
break;
}
//in case of child
case '{': {
node sub;
if(!sub.read(in)) { //Recursively read the subnode
return false;
}
this->children.insert(std::pair<std::string,node>(name,sub));
break;
}
default:
return false;
}
}
}
/*Writes to a file using it's overloaded self*/
bool node::write(const char* filename) const {
std::ofstream f(filename);
if(!f.good()) {
return false;
}
bool success = write(f);
f.close();
return success;
}
// TODO (Nick#1#): Make write() not put unnamed values on a new line, children are okay.
bool node::write(std::ostream& out, size_t depth, std::string indent) const {
std::string indentation;
for(size_t i = 0; i < depth; i++) {
indentation += indent;
}
for(std::multimap<std::string, std::string>::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) {
//Escape all the '"' by adding a second '"'
std::string value(value_it->second);
size_t found = value.find('"');
//while there are more ", insert second "s
while(found != value.npos) {
value.insert(found, 1, '"');
found = value.find('"', found+2);
}
out << indentation << value_it->first << ": \"" << value << '"' << std::endl;
}
for(std::multimap<std::string, node>::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) {
out << indentation << child_it->first << ": {" << std::endl;
child_it->second.write(out, depth+1);
out << indentation << '}' << std::endl;
}
return true;
}
char node::streamSkip(std::istream& in, const std::string& delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while(in >> std::noskipws >> cur) {
if(delimiters.find_first_of(cur) != delimiters.npos) return cur;
}
return 0;
}
char node::streamRead(std::istream& in, std::string& out, const std::string& delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while(in >> std::noskipws >> cur) {
if(delimiters.find(cur) != delimiters.npos) return cur;
out += cur;
}
return 0;
}
char node::streamRead(std::istream& in, std::string& out, const char delimiter) {
char cur;
//Return if the current char is delimiter
while(in >> std::noskipws >> cur) {
if(delimiter == cur) return cur;
out += cur;
}
return 0;
}
}

718
stfu/stf.hpp

@ -1,359 +1,359 @@
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <fstream>
#include <string>
#include <sstream>
#include <map>
#include <stdexcept>
#ifndef STFU_HPP
#define STFU_HPP
namespace stfu {
const static std::string not_found("search->No such child/value");
/*! \class node
* \brief A node in an STF tree.
* \author Maurice Bos
* \author Nick Overdijk
* \version 1.0
* \date 2009-04-25
*
* When you read an STF file through a node (with read() for example), this node will be the root node, without a name. See the examples for more information.
*/
class node {
/** Overloaded ostream's operator<< */
friend std::ostream &operator<< (std::ostream &out, const node &root);
/** Returns whether it was succesful or not*/
friend bool operator<< (std::ofstream &out, const node &root);
/** Acts like write(), but looks like this: "filename" << node */
friend bool operator<< (const char *filename, const node &root);
/** Overloaded istream's operator>> */
friend bool operator>> (std::istream &in, node &root);
/** Acts like read(), but looks like this: "filename" >> node */
friend bool operator>> (const char *filename, node &root);
public:
//@{
/** The values and children belonging to this node. To add, remove, do whatever: you CAN use these variables directly. To use indexing, use the member functions below*/
std::multimap<std::string, std::string> values;
std::multimap<std::string, node> children;
//@}
/**
Clears the whole node recursively.
*/
void clear() {
values.clear();
children.clear();
}
/**
Gets the std::string value from a variable
\param name The name of the value you wish to retrieve
\param index If there are more values with the same name, they are indexed. Here you can supply its indexnumber.
\return The retrieved value
*/
std::string &value(const std::string &name, size_t index = 0);
/**
Same as value(), but for unnamed values
\note same as value("", index)
\param index If there are more unnamed values, they are indexed. Here you can supply its indexnumber.
\return Same as value
*/
std::string &value(size_t index){
return value("", index);
}
/**
Creates and adds a value.
\param name The name of the value to be created
\return A reference to the value of the created value.
*/
std::string &addValue(const std::string &name = "");
/**
Const function for const objects to get a value. It's NOT possible to call value() on constant objects for value() isn't const.
\param name Name of the value to be retrieved
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a const std::string& to the value of value with the name and index specified
*/
const std::string &getValue(const std::string &name, size_t index) const throw (std::out_of_range);
/**
Same as getValue() const, but for unnamed values
\note same as getValue("", index) const
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
\return Returns a const std::string& to the value of value with the name and index specified
*/
const std::string &getValue(size_t index) const throw (std::out_of_range){
return getValue("", index);
}
/**
Same as getValue() const, but for non-const objects. The returned std::string& can safely be modified.
\param name Name of the value to be retrieved
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a std::string& to the value of value with the name and index specified
*/
std::string &getValue(const std::string &name, size_t index = 0) throw (std::out_of_range);
/**
Same as getValue(), but for unnamed values
\note same as getValue("", index)
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
\return Returns a std::string& to the value of value with the name and index specified
*/
std::string &getValue(size_t index) throw (std::out_of_range){
return getValue("", index);
}
/**
Removes a value. Surprise huh?
\param name Name of the value to be removed
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
*/
void removeValue(const std::string &name, size_t index = 0) throw (std::out_of_range);
/**
Removes an unnamed value.
\note same as removeValue("", index);
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
*/
void removeValue(size_t index) throw (std::out_of_range){
removeValue("", index);
}
/**
Renames a value.
\param oldName Name of the value to be renamed
\param newName The name that the oldName-value should have
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
*/
void renameValue(const std::string &oldName, const std::string &newName, size_t index = 0);
/**
Changes, adds or retrieves node
\param name The name of the child you wish to retrieve, change or add.
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return The retrieved node
If this index number is > the number of variables with that name, a new variable with that name is created with index = current number of same name variables + 1.
So say you have 4 variables named "tree", you call child("tree", 10), another tree gets made with index 5, NOT 10.
*/
node &child(const std::string &name, size_t index = 0);
/**
Same as child(), but for unnamed children.
\note same as child("", index)
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return The retrieved node
*/
node &child(size_t index = 0){
return child("", index);
}
/**
Guarranteed to add a child
\param name Name for the child
\return A reference to the created node
*/
node &addChild(const std::string &name = "");
/**
As addChild(name), but copies data from newChild as well.
\param name Name for the child
\param newChild Data to copy from the child.
\return A reference to the created node
*/
node &addChild(const std::string &name, node &newChild);
/**
As addChild(name, newChild), but without name, for unnamed children
\note same as addChild("", newChild);
\param newChild Data to copy from the child.
\return A reference to the created node
*/
node &addChild(node &newChild){
return addChild("", newChild);
}
/**
Const function for const objects to get a node. It's NOT possible to call child() for this, for child() isn't const.
\param name Name of the child to be retrieved
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a const node& to the node with the name and index specified
*/
const node &getChild(const std::string &name, size_t index = 0) const throw (std::out_of_range);
/**
Const function for const objects to get an unnamed const node&.
\note same as getChild("", index) const;
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return Returns a const node& to the node with the name and index specified
*/
const node &getChild(size_t index = 0) const throw (std::out_of_range){
return getChild("", index);
}
/**
Same as getChild() const, but for non-const objects. The returned child & can be modified
\param name Name of the child to be retrieved
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a node& to the node with the name and index specified
*/
node &getChild(const std::string &name, size_t index = 0) throw (std::out_of_range);
/**
Same as getChild() const, but for non-const objects.
\note same as getChild("", index);
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return Returns a node& to the node with the name and index specified
*/
node &getChild(size_t index = 0) throw (std::out_of_range){
return getChild("", index);
}
/**
Removes a child. Surprise huh?
\param name Name of the child to be removed
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
*/
void removeChild(const std::string &name, size_t index = 0) throw (std::out_of_range);
/**
As removeChild() for unnamed children.
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
*/
void removeChild(size_t index = 0) throw (std::out_of_range){
removeChild("", index);
}
/**
Renames a child.
\param oldName Name of the child to be renamed
\param newName The name that the oldName-child should have
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
*/
void renameChild(const std::string &oldName, const std::string &newName, size_t index = 0);
/**
Reads the STF from an istream
\return Returns whether it was succesful
*/
bool read(std::istream &in);
/**
Reads the STF from a file
\return Returns whether it was succesful
*/
bool read(const char *filename);
/**
Writes the STF to an ostream with optional indentation
\param out ostream to write to
\param depth how much indentation to start with
\param indent What std::string to use as indenation
\return Returns whether it was succesful
*/
bool write(std::ostream &out, size_t depth = 0, std::string indent = "\t") const;
/**
Writes to a file. Simply first opens a file and passes that ostream to itself.
\param filename File to write to
\return Returns whether it was succesful
*/
bool write(const char *filename) const;
private:
char streamRead(std::istream &in,std::string &out, const std::string &delim);
char streamRead(std::istream &in, std::string &out, const char delim);
char streamSkip(std::istream &in, const std::string &delim);
/*
returns a T2&, not a const T2&. The functions getValue/getChild make sure this will be done correctly for const objects
this function can NOT use get_indexed_it, because that function can't be const:
const_iterators can not be transformed into iterators, and the iterator is needed for erase(), which wants an iterator.
*/
template <typename T1, typename T2>
T2& get_indexed(const std::multimap<T1, T2> &container, const T1 &key, size_t index = 0) const throw (std::out_of_range) {
size_t count = container.count(key);
if (count != 0 && count-1 >= index) {
typename std::multimap<T1, T2>::const_iterator it = container.find(key);
while (index--) it++;
return const_cast<T2&>(it->second);
} else {
throw std::out_of_range((std::string)"get_indexed->"+"Element " + key + "doesn't exist!");
}
}
// template <typename T1, typename T2>
// typename multimap<T1, T2>::iterator get_indexed_it(multimap<T1, T2> &container, const T1 &key, size_t index = 0) throw (out_of_range) {
// size_t count = container.count(key);
//
// if (count != 0 && count-1 >= index) {
// typename multimap<T1, T2>::iterator it = container.find(key);
// while (index--) it++;
// return it;
// } else {
// throw out_of_range((std::string)"get_indexed_it->"+"Element " + key + "doesn't exist!");
// }
// }
template <typename Container, typename T>
typename Container::iterator get_indexed_it(Container& container, const T& key, size_t index = 0)
throw (std::out_of_range) {
typename Container::iterator it = container.find(key);
while (index-- && it != container.end() && it->first==key) it++;
if (it == container.end()) throw std::out_of_range("get_indexed_it(Container&, const T&, size_t)");
return it;
}
};
typedef std::pair<std::string, std::string> value;
typedef std::pair<std::string, node> child;
typedef std::multimap<std::string, std::string>::iterator valueiterator;
typedef std::multimap<std::string, node>::iterator childiterator;
}
#endif // STFU_HPP
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <fstream>
#include <string>
#include <sstream>
#include <map>
#include <stdexcept>
#ifndef STFU_HPP
#define STFU_HPP
namespace stfu {
const static std::string not_found("search->No such child/value");
/*! \class node
* \brief A node in an STF tree.
* \author Maurice Bos
* \author Nick Overdijk
* \version 1.0
* \date 2009-04-25
*
* When you read an STF file through a node (with read() for example), this node will be the root node, without a name. See the examples for more information.
*/
class node {
/** Overloaded ostream's operator<< */
friend std::ostream& operator<< (std::ostream& out, const node& root);
/** Returns whether it was succesful or not*/
friend bool operator<< (std::ofstream& out, const node& root);
/** Acts like write(), but looks like this: "filename" << node */
friend bool operator<< (const char* filename, const node& root);
/** Overloaded istream's operator>> */
friend bool operator>> (std::istream& in, node& root);
/** Acts like read(), but looks like this: "filename" >> node */
friend bool operator>> (const char* filename, node& root);
public:
//@{
/** The values and children belonging to this node. To add, remove, do whatever: you CAN use these variables directly. To use indexing, use the member functions below*/
std::multimap<std::string, std::string> values;
std::multimap<std::string, node> children;
//@}
/**
Clears the whole node recursively.
*/
void clear() {
values.clear();
children.clear();
}
/**
Gets the std::string value from a variable
\param name The name of the value you wish to retrieve
\param index If there are more values with the same name, they are indexed. Here you can supply its indexnumber.
\return The retrieved value
*/
std::string& value(const std::string& name, size_t index = 0);
/**
Same as value(), but for unnamed values
\note same as value("", index)
\param index If there are more unnamed values, they are indexed. Here you can supply its indexnumber.
\return Same as value
*/
std::string& value(size_t index) {
return value("", index);
}
/**
Creates and adds a value.
\param name The name of the value to be created
\return A reference to the value of the created value.
*/
std::string& addValue(const std::string& name = "");
/**
Const function for const objects to get a value. It's NOT possible to call value() on constant objects for value() isn't const.
\param name Name of the value to be retrieved
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a const std::string& to the value of value with the name and index specified
*/
const std::string& getValue(const std::string& name, size_t index) const throw(std::out_of_range);
/**
Same as getValue() const, but for unnamed values
\note same as getValue("", index) const
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
\return Returns a const std::string& to the value of value with the name and index specified
*/
const std::string& getValue(size_t index) const throw(std::out_of_range) {
return getValue("", index);
}
/**
Same as getValue() const, but for non-const objects. The returned std::string& can safely be modified.
\param name Name of the value to be retrieved
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a std::string& to the value of value with the name and index specified
*/
std::string& getValue(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
Same as getValue(), but for unnamed values
\note same as getValue("", index)
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
\return Returns a std::string& to the value of value with the name and index specified
*/
std::string& getValue(size_t index) throw(std::out_of_range) {
return getValue("", index);
}
/**
Removes a value. Surprise huh?
\param name Name of the value to be removed
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
*/
void removeValue(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
Removes an unnamed value.
\note same as removeValue("", index);
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
*/
void removeValue(size_t index) throw(std::out_of_range) {
removeValue("", index);
}
/**
Renames a value.
\param oldName Name of the value to be renamed
\param newName The name that the oldName-value should have
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
*/
void renameValue(const std::string& oldName, const std::string& newName, size_t index = 0);
/**
Changes, adds or retrieves node
\param name The name of the child you wish to retrieve, change or add.
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return The retrieved node
If this index number is > the number of variables with that name, a new variable with that name is created with index = current number of same name variables + 1.
So say you have 4 variables named "tree", you call child("tree", 10), another tree gets made with index 5, NOT 10.
*/
node& child(const std::string& name, size_t index = 0);
/**
Same as child(), but for unnamed children.
\note same as child("", index)
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return The retrieved node
*/
node& child(size_t index = 0) {
return child("", index);
}
/**
Guarranteed to add a child
\param name Name for the child
\return A reference to the created node
*/
node& addChild(const std::string& name = "");
/**
As addChild(name), but copies data from newChild as well.
\param name Name for the child
\param newChild Data to copy from the child.
\return A reference to the created node
*/
node& addChild(const std::string& name, node& newChild);
/**
As addChild(name, newChild), but without name, for unnamed children
\note same as addChild("", newChild);
\param newChild Data to copy from the child.
\return A reference to the created node
*/
node& addChild(node& newChild) {
return addChild("", newChild);
}
/**
Const function for const objects to get a node. It's NOT possible to call child() for this, for child() isn't const.
\param name Name of the child to be retrieved
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a const node& to the node with the name and index specified
*/
const node& getChild(const std::string& name, size_t index = 0) const throw(std::out_of_range);
/**
Const function for const objects to get an unnamed const node&.
\note same as getChild("", index) const;
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return Returns a const node& to the node with the name and index specified
*/
const node& getChild(size_t index = 0) const throw(std::out_of_range) {
return getChild("", index);
}
/**
Same as getChild() const, but for non-const objects. The returned child & can be modified
\param name Name of the child to be retrieved
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a node& to the node with the name and index specified
*/
node& getChild(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
Same as getChild() const, but for non-const objects.
\note same as getChild("", index);
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return Returns a node& to the node with the name and index specified
*/
node& getChild(size_t index = 0) throw(std::out_of_range) {
return getChild("", index);
}
/**
Removes a child. Surprise huh?
\param name Name of the child to be removed
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
*/
void removeChild(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
As removeChild() for unnamed children.
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
*/
void removeChild(size_t index = 0) throw(std::out_of_range) {
removeChild("", index);
}
/**
Renames a child.
\param oldName Name of the child to be renamed
\param newName The name that the oldName-child should have
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
*/
void renameChild(const std::string& oldName, const std::string& newName, size_t index = 0);
/**
Reads the STF from an istream
\return Returns whether it was succesful
*/
bool read(std::istream& in);
/**
Reads the STF from a file
\return Returns whether it was succesful
*/
bool read(const char* filename);
/**
Writes the STF to an ostream with optional indentation
\param out ostream to write to
\param depth how much indentation to start with
\param indent What std::string to use as indenation
\return Returns whether it was succesful
*/
bool write(std::ostream& out, size_t depth = 0, std::string indent = "\t") const;
/**
Writes to a file. Simply first opens a file and passes that ostream to itself.
\param filename File to write to
\return Returns whether it was succesful
*/
bool write(const char* filename) const;
private:
char streamRead(std::istream& in,std::string& out, const std::string& delim);
char streamRead(std::istream& in, std::string& out, const char delim);
char streamSkip(std::istream& in, const std::string& delim);
/*
returns a T2&, not a const T2&. The functions getValue/getChild make sure this will be done correctly for const objects
this function can NOT use get_indexed_it, because that function can't be const:
const_iterators can not be transformed into iterators, and the iterator is needed for erase(), which wants an iterator.
*/
template <typename T1, typename T2>
T2& get_indexed(const std::multimap<T1, T2> &container, const T1& key, size_t index = 0) const throw(std::out_of_range) {
size_t count = container.count(key);
if(count != 0 && count-1 >= index) {
typename std::multimap<T1, T2>::const_iterator it = container.find(key);
while(index--) it++;
return const_cast<T2&>(it->second);
} else {
throw std::out_of_range((std::string)"get_indexed->"+"Element " + key + "doesn't exist!");
}
}
// template <typename T1, typename T2>
// typename multimap<T1, T2>::iterator get_indexed_it(multimap<T1, T2> &container, const T1 &key, size_t index = 0) throw (out_of_range) {
// size_t count = container.count(key);
//
// if (count != 0 && count-1 >= index) {
// typename multimap<T1, T2>::iterator it = container.find(key);
// while (index--) it++;
// return it;
// } else {
// throw out_of_range((std::string)"get_indexed_it->"+"Element " + key + "doesn't exist!");
// }
// }
template <typename Container, typename T>
typename Container::iterator get_indexed_it(Container& container, const T& key, size_t index = 0)
throw(std::out_of_range) {
typename Container::iterator it = container.find(key);
while(index-- && it != container.end() && it->first==key) it++;
if(it == container.end()) throw std::out_of_range("get_indexed_it(Container&, const T&, size_t)");
return it;
}
};
typedef std::pair<std::string, std::string> value;
typedef std::pair<std::string, node> child;
typedef std::multimap<std::string, std::string>::iterator valueiterator;
typedef std::multimap<std::string, node>::iterator childiterator;
}
#endif // STFU_HPP