Boost logo

Boost Users :

From: Sergey Sadovnikov (flex_ferrum_at_[hidden])
Date: 2008-07-11 11:05:41


Hello All,

Would there be any interest in another C++ properties implementation?
I know that boost sandbox already contains properties library. But I
could offer yet another implementation of such library with some advantages
like this:
 - Simple properties set initialization. Only one call from the
 constructor:

   class SomeClass
   {
   public:
         //...
         SomeClass() : properties__(this) {/*...*/}
         //...
   };

 - Many kins of properties. Now implemented:
   Simple properties similar to datamembers.
   Properties bindable to getter/setter methods of container class.
   Properties bindable to arbitrary methods.
   Index properties with up to three levels of indirection.

 - Properties could be "abstract" and need implementation in derived
 classes

 - In-place initialization of simple properties. For example:
         PROPERTY_I(int, ContainerSize, 10)

 - Generic runtime access to the properties via names:
         SomeClassWithProps c;

         int val;
         c.properties__.invoke_get("ContainerSize", var(val) =
         boost::lambda::_1);

         c.properties__.invoke_set("ContainerSize", 20);

 - Runtime enumeration of properties:
   // Property visitor function
   template<typename P>
   void PropertyEnumerator(const std::string& propertyName, P
      SomeClassWithProps::* propInfo)
   {
        //...
   ]

   // Properties enumeration:
   SomeClassWithProps::properties__::enum_s(PropertyEnumerator);

 - Simple serialization of properties:
   template<typename Ar>
   void serialize(Ar& ar, const unsigned int ver)
   {
        ar & properties__;
   }

 - Quite simple definition in class. A piece of code from real
 project:
// Example of abstract properties definition in the base class:
class IPlayerCraft : public IAirObject
{
public:

        IPlayerCraft() : properties__(this) {;}
        virtual ~IPlayerCraft(){}

        // Craft status
        enum ECRAFTSTATUS
        {
                csREADY =0,
                csFLYING,
                csREPAIRING,
                csREFUELING,
                csREARMING,
                csTRANSFERING,
                csMAXCOUNT
        };

        PROPERTIES(IPlayerCraft,
                // Craft name
                ABSTRACT_RW_PROPERTY(std::wstring, Name)
                // Static craft info
                ABSTRACT_RO_PROPERTY(SCraftInfo const*, Info)
                // Craft home base
                ABSTRACT_RO_PROPERTY(IBase const*, HomeBase)
                // Is craft on the base?
                ABSTRACT_RO_PROPERTY(bool, IsOnTheBase)
                // Craft status
                ABSTRACT_RO_PROPERTY(ECRAFTSTATUS, Status)
                // Current craft speed
                ABSTRACT_RO_PROPERTY(TPARAM, Speed)
                // Craft weapon
                ABSTRACT_INDEX_PROPERTY(IItem*, CraftWeapon, 1, (CraftSlotCoord))
                // Craft weapon ammo
                ABSTRACT_RO_INDEX_PROPERTY(TPARAM, CraftWeaponAmmo, 1, (CraftSlotCoord))
        );
        //...
};

// Implementation class
class PlayerCraft : public IPlayerCraft
{
public:
        PlayerCraft(SCraftInfo const*, Player* player);
        ~PlayerCraft();

        PROPERTIES(PlayerCraft,
                IMPLEMENT_PROPERTY(IPlayerCraft, PROPERTY(std::wstring, Name))
                IMPLEMENT_PROPERTY(IPlayerCraft, PROPERTY(SCraftInfo const*, Info))
                IMPLEMENT_PROPERTY(IPlayerCraft, RO_PROPERTY(IBase const*, HomeBase, GetHomeBase))
                IMPLEMENT_PROPERTY(IPlayerCraft, PROPERTY(bool, IsOnTheBase))
                IMPLEMENT_PROPERTY(IPlayerCraft, PROPERTY_I(ECRAFTSTATUS, Status, csTRANSFERING))
                IMPLEMENT_PROPERTY(IPlayerCraft, PROPERTY_I(TPARAM, Speed, 0))
                IMPLEMENT_PROPERTY(IPlayerCraft, INDEX_PROPERTY(IItem*, CraftWeapon, 1, (CraftSlotCoord), GetCraftWeapon, SetCraftWeapon))
                IMPLEMENT_PROPERTY(IPlayerCraft, RO_INDEX_PROPERTY(TPARAM, CraftWeaponAmmo, 1, (CraftSlotCoord), GetCraftWeaponAmmo))
        );

        // ...
        IBase const* GetHomeBase() const {return m_HomeBase;}
private:
        // ...
        IItem* GetCraftWeapon(int slotId) const;
        void SetCraftWeapon(int slotId, IItem* weapon);
        TPARAM GetCraftWeaponAmmo(int slotId) const;
};

As you can see, properties definition based on boost::preprocessor.
It allows to implement quite complex background (with many special
abilities) for quite simple front-end.

It is assumed what access to the properties in many cases is same as
access to the datamember:
PlayerCraft craft;

std::string craft_name = craft.Name;

//...
IItem* weapon = craft.CraftWeapon[1];

And there is special access form needs in some cases:
craft.Name();
or
craft.Name.get();

If there is an interest in such properties implementation I could
start prepare code for formal library review.

-- 
Best Regards,
 Sergey                          mailto:flex_ferrum_at_[hidden]

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net