A
alan
I have a set of classes, cell, cell_body, and cell_internal.
cell_internal is an abstract base class, intended to encapsulate
deferred computation.
cell is just a wrapped pointer around cell_body; this is the user's
interface to this code.
When a cell is created, it creates a cell_body and attaches a
shared_ptr member (value_) to the body. This shared_ptr should never
be changed; the cell can only have one cell_body during its lifetime.
The cell_body holds a pointer to a cell_internal; when the cell's
value is taken by the member get_value(), it calls cell_body's
get_value(), which calls cell_internal's virtual cell_value(). This
virtual cell_value then computes the correct value. Basically the
get_value() function performs the computation that has been deferred.
Copying a cell to a cell does not, in fact, copy the cell; instead,
the destination cell is "attached" to the source cell, so that
changing the value of one changes the value of the other. So:
cell<int> i, j;
i = j;
j = 1; //now i is also 1
Actually what is being attached are the cell_body's. A new
cell_internal derived class (cell_shadow) is created, whose virtual
get_value() simply calls the get_value() of the cell_body it is
constructed with.
I don't use cell_body directly because of the possibility of
temporaries. When a cell is destroyed, its cell_body may still
survive, for example when referred from a global variable.
I think I may need to do swap-copy, but I don't quite understand yet
where I need to put it.
/*
* */
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
/* cell_internal
* Interface to handle the deferred computation
* */
template<class T>
class cell_internal{
public:
virtual T get_value(void) const=0;
virtual ~cell_internal(){};
};
template<class T>
struct cell_internal_ptr{
typedef boost::shared_ptr< const cell_internal<T> > type;
};
/* cell_constant
* Handles constant numeric values
* */
template<class T>
class cell_constant: public cell_internal<T>{
T c_;
public:
cell_constant<T>(const T& v): c_(v) {};
T get_value(void) const {return c_;};
};
/* cell_body
* The actual cell structure
* */
template<class T>
class cell_body{
typename cell_internal_ptr<T>::type value_;
public:
cell_body(const cell_internal<T>* v): value_(v) {};
cell_body(const typename cell_internal_ptr<T>::type v): value_(v) {}
T get_value(void) const {
return value_->get_value();
};
void set(const cell_internal<T>* v){
value_.reset(v);
}
};
template<class T>
struct cell_body_ptr{
typedef boost::shared_ptr< const cell_body<T> > type;
};
/* cell_shadow
* Shadows a given cell_body
* */
template<class T>
class cell_shadow: public cell_internal<T>{
boost::shared_ptr< const cell_body<T> > var_;
public:
cell_shadow<T>(const cell_body<T>* v) : var_(v){};
cell_shadow<T>(const boost::shared_ptr< cell_body<T> >& v):
var_(v){};
T get_value(void) const {return var_->get_value();};
};
/* cell_op
* Handles a binary operation
* */
template<class T, class BinaryOperation>
class cell_op: public cell_internal<T>{
boost::shared_ptr< const cell_body<T> > lhs_;
boost::shared_ptr< const cell_body<T> > rhs_;
public:
cell_op<T, BinaryOperation>( const boost::shared_ptr< const
cell_body<T> >& lhs,
const boost::shared_ptr< const cell_body<T> >& rhs
) :
lhs_(lhs),
rhs_(rhs) { };
cell_op<T, BinaryOperation>( cell_body<T>* lhs, cell_body<T>* rhs):
lhs_(lhs),
rhs_(rhs) { };
T get_value(void) const {
return BinaryOperation()(lhs_->get_value(), rhs_->get_value());
};
};
/* cell_singelop
* Handles a unary operation
* */
//template<class T, class UnaryOperation>
//class cell_singleop: public cell_internal<T>{
//};
/* cell
* Acts as the user's interface to the cell_body
* Effectively just a wrapper around a pointer to the cell_body
* IMPORTANT. Each cell will have one, and only one, cell_body
* during its lifetime. A cell_body, however, may outlive its
* cell (for example if the cell is a local variable that is
* then used in the formula for a global variable - at the end
* of the function the local cell is destroyed, but the cell_body
* is retained via a cell_shadow by the formula for the global).
* */
template<class T>
class cell{
void set(const cell_internal<T>* v){
value_->set(v);
}
boost::shared_ptr< cell_body<T> > value_;
public:
cell<T>(const cell<T>& v){
value_.reset(new cell_body<T>(new cell_shadow<T>(v.value_)));
}
cell<T>(const T& v=T()){
value_.reset(new cell_body<T>(new cell_constant<T>(v)));
}
cell<T>(const typename cell_internal_ptr<T>::type& v){
value_.reset(new cell_body<T>(v));
}
cell<T>(const cell_internal<T>* v){
value_.reset(new cell_body<T>(v));
}
cell<T>& operator=(const cell<T>& v){
if(&v != this){
set(new cell_shadow<T>(v.value_));
}
}
cell<T>& operator=(const T& v){
set(new cell_constant<T>(v));
}
cell<T>& operator=(const typename cell_internal_ptr<T>::type& v){
set(&(*v));
}
cell<T> operator+(const cell<T>& rhs) const {
return cell<T>(
new cell_op<T, std:
lus<T> >(
value_,
rhs.value_
)
);
};
T get_value(void) const {return value_->get_value();}
};
template<class T>
inline cell<T> operator+(const cell<T>& lhs, const T& rhs){
return lhs + cell<T>(rhs);
}
template<class T>
inline cell<T> operator+(const T& lhs, const cell<T>& rhs){
return cell<T>(lhs) + rhs;
}
cell_internal is an abstract base class, intended to encapsulate
deferred computation.
cell is just a wrapped pointer around cell_body; this is the user's
interface to this code.
When a cell is created, it creates a cell_body and attaches a
shared_ptr member (value_) to the body. This shared_ptr should never
be changed; the cell can only have one cell_body during its lifetime.
The cell_body holds a pointer to a cell_internal; when the cell's
value is taken by the member get_value(), it calls cell_body's
get_value(), which calls cell_internal's virtual cell_value(). This
virtual cell_value then computes the correct value. Basically the
get_value() function performs the computation that has been deferred.
Copying a cell to a cell does not, in fact, copy the cell; instead,
the destination cell is "attached" to the source cell, so that
changing the value of one changes the value of the other. So:
cell<int> i, j;
i = j;
j = 1; //now i is also 1
Actually what is being attached are the cell_body's. A new
cell_internal derived class (cell_shadow) is created, whose virtual
get_value() simply calls the get_value() of the cell_body it is
constructed with.
I don't use cell_body directly because of the possibility of
temporaries. When a cell is destroyed, its cell_body may still
survive, for example when referred from a global variable.
I think I may need to do swap-copy, but I don't quite understand yet
where I need to put it.
/*
* */
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
/* cell_internal
* Interface to handle the deferred computation
* */
template<class T>
class cell_internal{
public:
virtual T get_value(void) const=0;
virtual ~cell_internal(){};
};
template<class T>
struct cell_internal_ptr{
typedef boost::shared_ptr< const cell_internal<T> > type;
};
/* cell_constant
* Handles constant numeric values
* */
template<class T>
class cell_constant: public cell_internal<T>{
T c_;
public:
cell_constant<T>(const T& v): c_(v) {};
T get_value(void) const {return c_;};
};
/* cell_body
* The actual cell structure
* */
template<class T>
class cell_body{
typename cell_internal_ptr<T>::type value_;
public:
cell_body(const cell_internal<T>* v): value_(v) {};
cell_body(const typename cell_internal_ptr<T>::type v): value_(v) {}
T get_value(void) const {
return value_->get_value();
};
void set(const cell_internal<T>* v){
value_.reset(v);
}
};
template<class T>
struct cell_body_ptr{
typedef boost::shared_ptr< const cell_body<T> > type;
};
/* cell_shadow
* Shadows a given cell_body
* */
template<class T>
class cell_shadow: public cell_internal<T>{
boost::shared_ptr< const cell_body<T> > var_;
public:
cell_shadow<T>(const cell_body<T>* v) : var_(v){};
cell_shadow<T>(const boost::shared_ptr< cell_body<T> >& v):
var_(v){};
T get_value(void) const {return var_->get_value();};
};
/* cell_op
* Handles a binary operation
* */
template<class T, class BinaryOperation>
class cell_op: public cell_internal<T>{
boost::shared_ptr< const cell_body<T> > lhs_;
boost::shared_ptr< const cell_body<T> > rhs_;
public:
cell_op<T, BinaryOperation>( const boost::shared_ptr< const
cell_body<T> >& lhs,
const boost::shared_ptr< const cell_body<T> >& rhs
) :
lhs_(lhs),
rhs_(rhs) { };
cell_op<T, BinaryOperation>( cell_body<T>* lhs, cell_body<T>* rhs):
lhs_(lhs),
rhs_(rhs) { };
T get_value(void) const {
return BinaryOperation()(lhs_->get_value(), rhs_->get_value());
};
};
/* cell_singelop
* Handles a unary operation
* */
//template<class T, class UnaryOperation>
//class cell_singleop: public cell_internal<T>{
//};
/* cell
* Acts as the user's interface to the cell_body
* Effectively just a wrapper around a pointer to the cell_body
* IMPORTANT. Each cell will have one, and only one, cell_body
* during its lifetime. A cell_body, however, may outlive its
* cell (for example if the cell is a local variable that is
* then used in the formula for a global variable - at the end
* of the function the local cell is destroyed, but the cell_body
* is retained via a cell_shadow by the formula for the global).
* */
template<class T>
class cell{
void set(const cell_internal<T>* v){
value_->set(v);
}
boost::shared_ptr< cell_body<T> > value_;
public:
cell<T>(const cell<T>& v){
value_.reset(new cell_body<T>(new cell_shadow<T>(v.value_)));
}
cell<T>(const T& v=T()){
value_.reset(new cell_body<T>(new cell_constant<T>(v)));
}
cell<T>(const typename cell_internal_ptr<T>::type& v){
value_.reset(new cell_body<T>(v));
}
cell<T>(const cell_internal<T>* v){
value_.reset(new cell_body<T>(v));
}
cell<T>& operator=(const cell<T>& v){
if(&v != this){
set(new cell_shadow<T>(v.value_));
}
}
cell<T>& operator=(const T& v){
set(new cell_constant<T>(v));
}
cell<T>& operator=(const typename cell_internal_ptr<T>::type& v){
set(&(*v));
}
cell<T> operator+(const cell<T>& rhs) const {
return cell<T>(
new cell_op<T, std:
value_,
rhs.value_
)
);
};
T get_value(void) const {return value_->get_value();}
};
template<class T>
inline cell<T> operator+(const cell<T>& lhs, const T& rhs){
return lhs + cell<T>(rhs);
}
template<class T>
inline cell<T> operator+(const T& lhs, const cell<T>& rhs){
return cell<T>(lhs) + rhs;
}