Ok, at least one person said they were interested in seeing my idea for an
equation toolkit, so here goes... The files a few hundred lines, so
hopefully that's ok for this group. If I've exceed some message size, I'm
sorry in advance...
======== e.cpp (client code) follows =========
#include "equation.h"
#include "equation_enable_macros.h"
int main()
{
equation::Equation a;
a = _y + _z;
std::cout << a(_y is 5, _z is 10) << std::endl;
a = _x + 8 * (_y - _z);
std::cout << a(_x is 2, _y is 3, _z is -9000.9) << std::endl;
return 0;
}
======== equation.h follows (the real work) =========
// Copyright Stephen Gross 2006
#ifndef api_equation
#define api_equation
#include <string>
#include <iostream>
#include <map>
#include "boost/function.hpp"
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/bind.hpp"
namespace equation {
class ArgTable
{
typedef std::map MapType;
public:
ArgTable & setArg(const std::string & name, double val)
{
my_map[name] = val;
return *this;
}
virtual double getArg (const std::string & name) const
{
MapType::const_iterator f = my_map.find(name);
if(f == my_map.end())
{
std::cout << "Error: Equation requested argument '" << name << "'
which was not given." << std::endl;
exit(0);
}
else
{
return f->second;
}
}
private:
MapType my_map;
};
class ArgTableReporter : public ArgTable
{
public:
virtual double getArg(const std::string & name) const
{
my_last_var = name;
return 0;
}
const std::string & getLastVar() const { return my_last_var; }
private:
mutable std::string my_last_var;
};
///
/// Represents an Equation, simply put.
///
/// The idea here is that, for any Equation that takes named arguments ("x",
"y", etc.) and manipulates them
/// arithmetically, such an Equation can in fact be encapsulated in an
Equation instance.
///
///
class Equation
{
public:
typedef boost::function1 FunctorType;
/// @name Constructors
//@{
Equation() : my_ftr(boost::lambda::constant(0)) { ; }
Equation(const Equation & other) : my_ftr(other.my_ftr) { }
template<typename T> Equation(const T & t) : my_ftr(t) { }
//@}
/// @name The underlying function that invokes the functor:
//@{
double go (const ArgTable & args) const { return my_ftr(args); }
//@}
/// @name operator()
//@{
double operator() () { return go(ArgTable()); }
template<typename A1>
double operator() (const A1 & a1, double v1) const
{
ArgTable args;
ArgTableReporter names;
a1(names); args.setArg(names.getLastVar(), v1);
return go(args);
}
template
double operator() (const A1 & a1, double v1, const A2 & a2, double v2)
const
{
ArgTable args;
ArgTableReporter names;
a1(names); args.setArg(names.getLastVar(), v1);
a2(names); args.setArg(names.getLastVar(), v2);
return go(args);
}
template
double operator() (const A1 & a1, double v1, const A2 & a2, double v2,
const A3 & a3, double v3) const
{
ArgTable args;
ArgTableReporter names;
a1(names); args.setArg(names.getLastVar(), v1);
a2(names); args.setArg(names.getLastVar(), v2);
a3(names); args.setArg(names.getLastVar(), v3);
return go(args);
}
template
double operator() (const A1 & a1, double v1, const A2 & a2, double v2,
const A3 & a3, double v3, const A4 & a4, double v4) const
{
ArgTable args;
ArgTableReporter names;
a1(names); args.setArg(names.getLastVar(), v1);
a2(names); args.setArg(names.getLastVar(), v2);
a3(names); args.setArg(names.getLastVar(), v3);
a4(names); args.setArg(names.getLastVar(), v4);
return go(args);
}
//@}
private:
FunctorType my_ftr;
};
namespace Private {
class Sigma
{
public:
Sigma() : my_start(0), my_stop(0), my_iter(boost::lambda::constant(0.0))
{ }
Sigma(double start, double stop, const Equation & eq) :
my_start((int)start), my_stop((int)stop), my_iter(eq) { }
Sigma(const Sigma & other) : my_start(other.my_start),
my_stop(other.my_stop), my_iter(other.my_iter) { }
Sigma& operator=(const Sigma & other)
{
if(this != &other)
{
my_start = other.my_start;
my_stop = other.my_stop;
my_iter = other.my_iter;
}
return *this;
}
double go (const ArgTable & args) const
{
ArgTable newargs = args;
double result = 0.0;
for(int i = my_start; i <= my_stop; ++i)
{
newargs.setArg("i", (double)i);
result += my_iter.go(newargs);
}
return result;
}
private:
int my_start;
int my_stop;
Equation my_iter;
};
///
/// Helper struct so that unary math functions can be easily macro-ified for
constructing Equations.
struct UnaryFunc
{
UnaryFunc(double (*fn) (double), const Equation::FunctorType & arg_getter)
: my_fn(fn), my_arg_getter(arg_getter) { }
UnaryFunc(double (*fn) (double), double v) : my_fn(fn),
my_arg_getter(boost::lambda::constant(v)) { }
UnaryFunc(const UnaryFunc & other) : my_fn(other.my_fn),
my_arg_getter(other.my_arg_getter) { }
UnaryFunc& operator=(const UnaryFunc & other) { if(this != &other) { my_fn
= other.my_fn; my_arg_getter = other.my_arg_getter; } return *this; }
double go(const ArgTable & args) const { return (*my_fn)
(my_arg_getter(args)); }
double (*my_fn) (double);
Equation::FunctorType my_arg_getter;
};
///
/// Helper struct so that binary math functions can be easily macro-ified
for construction Equations.
struct BinaryFunc
{
BinaryFunc(
double (*fn) (double, double),
const Equation::FunctorType & arg1_getter,
const Equation::FunctorType & arg2_getter) :
my_fn(fn), my_arg1_getter(arg1_getter), my_arg2_getter(arg2_getter)
{ }
BinaryFunc(
double (*fn) (double, double),
double arg1,
const Equation::FunctorType & arg2_getter) :
my_fn(fn), my_arg1_getter(boost::lambda::constant(arg1)),
my_arg2_getter(arg2_getter) { }
BinaryFunc(
double (*fn) (double, double),
const Equation::FunctorType & arg1_getter,
double arg2) :
my_fn(fn), my_arg1_getter(arg1_getter),
my_arg2_getter(boost::lambda::constant(arg2)) { }
BinaryFunc(
double (*fn) (double, double),
double arg1,
double arg2) :
my_fn(fn), my_arg1_getter(boost::lambda::constant(arg1)),
my_arg2_getter(boost::lambda::constant(arg2)) { }
BinaryFunc(const BinaryFunc & other) : my_fn(other.my_fn),
my_arg1_getter(other.my_arg1_getter), my_arg2_getter(other.my_arg2_getter)
{ }
BinaryFunc& operator=(const BinaryFunc & other)
{
if(this != &other)
{
my_fn = other.my_fn;
my_arg1_getter = other.my_arg1_getter;
my_arg2_getter = other.my_arg2_getter;
}
return *this;
}
double go(const ArgTable & args) const
{
return (*my_fn) (my_arg1_getter(args), my_arg2_getter(args));
}
double (*my_fn) (double, double);
Equation::FunctorType my_arg1_getter;
Equation::FunctorType my_arg2_getter;
};
} // End namespace Private
} // End namespace equation
#define VAR(name) boost::lambda::bind<double>(&equation::ArgTable::getArg,
boost::lambda::_1, std::string(#name))
#define EQ(name) boost::lambda::bind<double>(&equation::Equation::go, &name,
boost::lambda::_1)
#endif
=========== equation_enable_macros.h follows ============
#ifndef api_equation_enable_macros
#define api_equation_enable_macros
// Disable macros now available:
#undef api_equation_disable_macros
#define is ,
#define _a VAR(a)
#define _b VAR(b)
#define _c VAR(c)
#define _d VAR(d)
#define _e VAR(e)
#define _f VAR(f)
#define _g VAR(g)
#define _h VAR(h)
#define _i VAR(i)
#define _j VAR(j)
#define _k VAR(k)
#define _l VAR(l)
#define _m VAR(m)
#define _n VAR(n)
#define _o VAR(o)
#define _p VAR(p)
#define _q VAR(q)
#define _r VAR(r)
#define _s VAR(s)
#define _t VAR(t)
#define _u VAR(u)
#define _v VAR(v)
#define _w VAR(w)
#define _x VAR(x)
#define _y VAR(y)
#define _z VAR(z)
#define _sigma(start, stop, iter) boost::lambda::bind<double>
(&equation::Private::Sigma::go, equation::Private::Sigma (start,
stop, iter), boost::lambda::_1)
#define _sqrt(x) boost::lambda::bind<double>
(&equation::Private::UnaryFunc::go, equation::Private::UnaryFunc (&sqrt,
x), boost::lambda::_1)
#define _pow(x, y) boost::lambda::bind<double>
(&equation::Private::BinaryFunc::go, equation::Private::BinaryFunc (&pow,
x, y), boost::lambda::_1)
#endif
========= end of code snippets ==============