To elaborate further on my proposal from last night, a particle bundle would look like the following (incorporating some unrelated proposed changes)
class XYZBundle { static FloatKey kx_, ky_, kz_; public: XYZBundle(Particle*p): p_(p){} static bool is_instance(Particle *p) { return p->has_attribute(kx_) && p->has_attribute(ky_) && p- >has_attribute(kz_); } typedef std::auto_ptr<XYZBundle> Pointer; Pointer cast(Pointer *p) { if (!is_instance(p)) return Pointer(); else return Pointer(new XYZBundle(p)); }
// either static XYZBundle::Pointer initialize(Particle *p) { p->add_attribute(kx_, 0); p->add_attribute(ky_, 0); p->add_attribute(kz_, 0); return Pointer(new XYZBundle(p)); } // or static XYZBundle::Pointer initialize(Particle *p, Float x, Float y, Float z) { p->add_attribute(kx_, x); p->add_attribute(ky_, y); p->add_attribute(kz_, z); return Pointer(new XYZBundle(p)); } Float get_x() const { return p->get_attribute(kx_); } void set_x(Float x) const { return p->set_attribute(kx_, x); } // etc };
The user class XYZBundle::Pointer xyzp= XYZBundle::initialize(p) to add the right fields or XYZBundle::Pointer xyzp= XYZBundle::cast(p) to use.
I am a bit uncomfortable about the faking aspect of the design especially without working reference counting. Since Bundles don't need to get passed back and forth from python, we could make the reference counting work. It might be better to just allocate Bundles on the stack. This removes a memory management issue at the cost of eliminating the possibility of using a NULL pointer to signify failure. So things would have to look more like
class XYZBundle { static FloatKey kx_, ky_, kz_; public: XYZBundle(Particle*p): p_(p){if (!is_instance(p)) p_=NULL;}
bool get_is_valid() const {return p_ != NULL;}
static bool is_instance(Particle *p) { return p->has_attribute(kx_) && p->has_attribute(ky_) && p- >has_attribute(kz_); }
// either static XYZBundle initialize(Particle *p) { IMP_assert(!is_instance(p)); p->add_attribute(kx_, 0); p->add_attribute(ky_, 0); p->add_attribute(kz_, 0); return XYZBundle(p); } // or static XYZBundle::Pointer initialize(Particle *p, Float x, Float y, Float z) { IMP_assert(!is_instance(p)); p->add_attribute(kx_, x); p->add_attribute(ky_, y); p->add_attribute(kz_, z); return XYZBundle(p); } Float get_x() const { return p->get_attribute(kx_); } void set_x(Float x) const { return p->set_attribute(kx_, x); } // etc };
the the user calls XYZBundle xyzb(p); and xyzb.is_valid() to manipulate a Particle and XYZBundle xyzb= XYZBundle::initialize(p); to initialize.