User Tag List

Results 1 to 3 of 3

Thread: More abuses for the Template Factory Pattern. (c++)

  1. #1
    The Time-Loop Continues ZC Developer
    Gleeok's Avatar
    Join Date
    Apr 2007
    Posts
    4,815
    Mentioned
    259 Post(s)
    Tagged
    10 Thread(s)
    vBActivity - Stats
    Points
    12,933
    Level
    33
    vBActivity - Bars
    Lv. Percent
    23.44%

    More abuses for the Template Factory Pattern. (c++)

    One thing that I get really tired of doing is defining how Objects need to serialize (read/write) themselves to file; be it xml, binary, whatever. It's also error prone if you add something new to the Serialize() method, but forget to do the same (or wrongly do it) to the Deserialize() method. Worse is that we need to duplicate this code for each file type we want. In case you're new to files, you can't just say fwrite(f, this, sizeof*this)); because 90+% of the time the members are not POD type.

    The solution I came up with is very small, a single file, uses simple buffers and arrays, and is actually O(1) time. Considering what it does this is pretty good I think. (Looks at boost::serializer bloated nonsense)..

    Here it is:

    Code:
    struct AttributeAccessorInfo
    {
    public:
    	AttributeAccessorVariableType type;
    	const char* name;
    	int offset;
    
    	AttributeAccessorInfo() : type(VAR_TYPE_NONE), name(0), offset(0) {}
    	AttributeAccessorInfo( AttributeAccessorVariableType type, const char* name, int offset )
    		: type(type), name(name), offset(offset)
    	{}
    
    };
    
    
    class AttributeAccessorObjectTypeBase
    {
    public:
    	typedef fc::vector<AttributeAccessorInfo>	vec_type;
    
    	AttributeAccessorObjectTypeBase( const char* className ) : m_className(className) {}
    	virtual ~AttributeAccessorObjectTypeBase()
    	{}
    
    	void RegisterAttributeAccessor( const AttributeAccessorInfo& attrInfo );
    
    	NO_INLINE void SerializeObjectAttributesXml( const void* obj, XmlWriter* xml );
    	NO_INLINE void DeserializeObjectAttributesXml( void* obj, XmlReader* xml );
    
    	int OnReadAttributeInfoXml( void* obj, XmlReader* xml, const AttributeAccessorInfo& attr );
    	int OnWriteAttributeInfoXml( const void* obj, XmlWriter* xml, const AttributeAccessorInfo& attr );
    
    protected:
    	static int m_typeIdGenerator;
    
    	static int GenerateTypeId()
    	{
    		int currentVal = m_typeIdGenerator++;
    		return currentVal;
    	}
    
    	const char*	m_className;
    	vec_type	m_attributes;
    };
    
    
    template<class T>
    class AttributeAccessorObjectTypeInfo : public AttributeAccessorObjectTypeBase
    {
    public:
    	AttributeAccessorObjectTypeInfo( const char* className )
    		: AttributeAccessorObjectTypeBase(className)
    	{}
    
    	static int GetTypeId()
    	{
    		static int typeId = AttributeAccessorObjectTypeBase::GenerateTypeId();
    		return typeId;
    	}
    };
    
    
    class ObjectAttributeSerializerFactory
    {
    public:
    	enum : size_t
    	{
    		MaxBufferBytes = 512
    	};
    
    	typedef fc::fixed_tiny_vector<AttributeAccessorObjectTypeBase*, MaxBufferBytes / sizeof(AttributeAccessorObjectTypeBase*)> vec_type;
    	typedef fc::aligned_buffer<MaxBufferBytes, FC_ALIGNOF(AttributeAccessorObjectTypeBase*)> buffer_type;
    
    	ObjectAttributeSerializerFactory() :
    		m_factories(),
    		m_buffer(),
    		m_offset(0)
    	{
    	}
    
    	static ObjectAttributeSerializerFactory* GetInstance()
    	{
    		return &m_instance;
    	}
    
    	template <class T>
    	void RegisterAttribute( const AttributeAccessorInfo& attrInfo )
    	{
    		int registeredTypeId = AttributeAccessorObjectTypeInfo<T>::GetTypeId();
    		m_instance.m_factories[registeredTypeId]->RegisterAttributeAccessor(attrInfo);
    	}
    
    	template <class T>
    	void RegisterFactoryType( const char* className )
    	{
    		int registeredTypeId = AttributeAccessorObjectTypeInfo<T>::GetTypeId();
    		ASSERT((size_t)registeredTypeId <= m_factories.size());
    
    		// only register a new factory if typeId is a valid type.
    		if( (size_t)registeredTypeId == m_factories.size() )
    		{
    			ASSERT(m_offset <= MaxBufferBytes - sizeof(AttributeAccessorObjectTypeInfo<T>));
    
    			AttributeAccessorObjectTypeInfo<T>* p = new (m_buffer.buffer + m_offset) AttributeAccessorObjectTypeInfo<T>(className);
    			m_offset += sizeof(AttributeAccessorObjectTypeInfo<T>);
    			m_factories.push_back(p);
    		}
    	}
    
    	template <class T>
    	void SerializeObjectAttributesXml( const T* obj, XmlWriter* xml )
    	{
    		int registeredTypeId = AttributeAccessorObjectTypeInfo<T>::GetTypeId();
    		m_instance.m_factories[registeredTypeId]->SerializeObjectAttributesXml(obj, xml);
    	}
    
    	template <class T>
    	void DeserializeObjectAttributesXml( T* obj, XmlReader* xml )
    	{
    		int registeredTypeId = AttributeAccessorObjectTypeInfo<T>::GetTypeId();
    		m_instance.m_factories[registeredTypeId]->DeserializeObjectAttributesXml(obj, xml);
    	}
    
    
    private:
    	// There's zero point in having more than one instance
    	// of a factory that depends on compile-time constants
    	// and static template typeid generation.
    	static ObjectAttributeSerializerFactory m_instance;
    
    	vec_type		m_factories;
    	buffer_type		m_buffer;
    	size_t			m_offset;
    
    };
    
    
    #define REGISTER_ATTRIBUTE_FACTORY_TYPE(class_) \
    	ObjectAttributeSerializerFactory::GetInstance()->RegisterFactoryType<class_>(#class_)
    
    #define PUSH_ATTRIBUTE_NODE(class_, nodeName) \
    	ObjectAttributeSerializerFactory::GetInstance()->RegisterAttribute<class_> \
    		(AttributeAccessorInfo(VAR_TYPE_PUSH_NODE, nodeName, 0))
    
    #define POP_ATTRIBUTE_NODE(class_) \
    	ObjectAttributeSerializerFactory::GetInstance()->RegisterAttribute<class_> \
    		(AttributeAccessorInfo(VAR_TYPE_POP_NODE, "", 0))
    
    #define REGISTER_ATTRIBUTE(class_, type, name, var) \
    	ObjectAttributeSerializerFactory::GetInstance()->RegisterAttribute<class_> \
    		(AttributeAccessorInfo(type, name, offsetof(class_, var)))
    
    #define SERIALIZE_OBJECT_ATTRIBUTES_XML(obj, xml) \
    	ObjectAttributeSerializerFactory::GetInstance()->SerializeObjectAttributesXml(obj, xml)
    
    #define DESERIALIZE_OBJECT_ATTRIBUTES_XML(obj, xml) \
    	ObjectAttributeSerializerFactory::GetInstance()->DeserializeObjectAttributesXml(obj, xml)
    Now any classes we want to write to file we add a static "Register" method that looks like this:
    Code:
    void CharacterClass::RegisterObject()
    {
    	REGISTER_ATTRIBUTE_FACTORY_TYPE(CharacterClass);
    	REGISTER_ATTRIBUTE(CharacterClass, VAR_TYPE_STRING, "name", name);
    	REGISTER_ATTRIBUTE(CharacterClass, VAR_TYPE_STRING, "script", script);
    	REGISTER_ATTRIBUTE(CharacterClass, VAR_TYPE_STRING, "description", description);
    	//etc..
    }
    And that's how babies are made.

    ...yeah, I guess I haven't actually done anything worthwhile this week. :\
    This post contains the official Gleeok seal of approval. Look for these and other posts in an area near you.

  2. #2
    Octorok jeffythedragonslayer's Avatar
    Join Date
    Jan 2024
    Posts
    399
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    29
    Level
    2
    vBActivity - Bars
    Lv. Percent
    15.33%
    The bloated nonsense, for comparison: https://www.boost.org/doc/libs/1_84_...doc/index.html

  3. #3
    The Time-Loop Continues ZC Developer
    Gleeok's Avatar
    Join Date
    Apr 2007
    Posts
    4,815
    Mentioned
    259 Post(s)
    Tagged
    10 Thread(s)
    vBActivity - Stats
    Points
    12,933
    Level
    33
    vBActivity - Bars
    Lv. Percent
    23.44%
    Hah, I forgot about that (it got deleted) one. I always get a kick out of programming when things go sideways.

    Anyway, the project got majorly setback in 2014-15 and now it's in limbo. I just haven't got around to it, but I plan on releasing some tools and assets when I finish digging them up. The PSP unpacking tool was pretty nice: all the sfx/maps/tiles/sprites/etc from the PSP games are easy.

    Also R.I.P. Imzogelmo.
    This post contains the official Gleeok seal of approval. Look for these and other posts in an area near you.

  4. #4
    Octorok jeffythedragonslayer's Avatar
    Join Date
    Jan 2024
    Posts
    399
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    29
    Level
    2
    vBActivity - Bars
    Lv. Percent
    15.33%
    Quote Originally Posted by Gleeok View Post
    And that's how babies are made.

    ...yeah, I guess I haven't actually done anything worthwhile this week. :\
    That's OK because some people are dying to know:

    https://www.purezc.net/forums/index.php?showtopic=78601

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
About us
Armageddon Games is a game development group founded in 1997. We are extremely passionate about our work and our inspirations are mostly drawn from games of the 8-bit and 16-bit era.
Social