kolibrios/contrib/media/updf/include/lispobject.h
right-hearted 4f7ee97ec9 uPDF with buttons
git-svn-id: svn://kolibrios.org@4680 a494cfbc-eb01-0410-851d-a64ba20cac60
2014-03-22 21:00:40 +00:00

235 lines
7.3 KiB
C++

/** \file lispobject.h
* Implementation of basic LispObject, which is the base class for
* anything that can be put in a linked list.
*
* class LispObject. This class implements one lisp object, which is a
* abstract class containing reference counting and a next pointer.
* derive from this to implement specific types of list elements.
* The local class LispPtr implements automatic garbage collection
* through reference counting.
*
*/
#ifndef __lispobject_h__
#define __lispobject_h__
#include "yacasbase.h"
#include "refcount.h"
#include "lispstring.h"
#include "genericobject.h"
#ifdef YACAS_DEBUG
#define DBG_(xxx) xxx
#else
#define DBG_(xxx) /*xxx*/
#endif
class LispObject;
class BigNumber;
/** class LispPtr. A LispPtr is a smart pointer to a LispObject.
* It does the reference counting, and consequent destruction if needed.
* LispPtr is used in LispObject as a pointer to the next object; and
* LispPtr::GoNext() advances one step in this LispObject::Nixed() chain.
* Diverse built-in functions use LispPtr to hold temporary values.
*/
typedef RefPtr<LispObject> LispPtr;
/** \class LispPtrArray is similar to LispPtr, but implements an array
* of pointers to objects.
*/
typedef CArrayGrower<LispPtr, ArrOpsCustomObj<LispPtr> > LispPtrArray;
#ifdef YACAS_DEBUG
void IncNrObjects();
void DecNrObjects();
#else
#define IncNrObjects()
#define DecNrObjects()
#endif
// Should we DecNrObjects by the delete, or in the destructor?
// Put a DecNrObjects_xxx() macro in both places, and CHOOSE here.
#define DecNrObjects_delete() DECNROBJECTS_CHOOSE(DecNrObjects(),)
#define DecNrObjects_destructor() DECNROBJECTS_CHOOSE(,DecNrObjects())
#define DECNROBJECTS_CHOOSE(bydelete,bydestructor) bydestructor
template <int> struct Undefined;
template <> struct Undefined<1>{};
/** class LispObject is the base object class that can be put in
* linked lists. It either has a pointer to a string, obtained through
* String(), or it is a holder for a sublist, obtainable through SubList(),
* or it is a generic object, in which case Generic() returns non-NULL.
* Only one of these three functions should return a non-NULL value.
* It is a reference-counted object. LispPtr handles the reference counting.
*/
class LispObject : public YacasBase
{
public:
inline LispPtr& Nixed();
public: //Derivables
virtual ~LispObject();
/** Return string representation, or NULL if the object doesn't have one.
* the string representation is only relevant if the object is a
* simple atom. This method returns NULL by default.
*/
virtual LispString * String() { return NULL; }
/** If this object is a list, return a pointer to it.
* Default behaviour is to return NULL.
*/
virtual LispPtr* SubList() { return NULL; }
virtual GenericClass* Generic() { return NULL; }
/** If this is a number, return a BigNumber representation
*/
virtual BigNumber* Number(LispInt aPrecision) { return NULL; }
virtual LispObject* Copy() = 0;
/** Return a pointer to extra info. This allows for annotating
* an object. Returns NULL by default.
* LispObject's implementation of this handles almost all derived classes.
*/
virtual LispObject* ExtraInfo() { return NULL; }
virtual LispObject* SetExtraInfo(LispObject* aData) = 0;
public:
LispInt Equal(LispObject& aOther);
inline LispInt operator==(LispObject& aOther);
inline LispInt operator!=(LispObject& aOther);
DBG_( LispChar * iFileName; )
DBG_( LispInt iLine; )
inline void SetFileAndLine(LispChar * aFileName, LispInt aLine)
{
DBG_( iFileName = aFileName; )
DBG_( iLine = aLine; )
}
protected:
inline LispObject() :
#ifdef YACAS_DEBUG
iFileName(NULL),iLine(0),
#endif // YACAS_DEBUG
iNext(),iReferenceCount()
{
IncNrObjects();
DBG_( iFileName = NULL; )
DBG_( iLine = 0; )
}
inline LispObject(const LispObject& other) :
#ifdef YACAS_DEBUG
iFileName(other.iFileName),iLine(other.iLine),
#endif // YACAS_DEBUG
iNext(),iReferenceCount()
{
IncNrObjects();
}
inline LispObject& operator=(const LispObject& other)
{
#ifdef YACAS_DEBUG
iFileName = other.iFileName;
iLine = other.iLine;
#endif // YACAS_DEBUG
IncNrObjects();
return *this;
}
private:
LispPtr iNext;
public:
ReferenceCount iReferenceCount;
};
template <class T>
class WithExtraInfo : public T
{
public:
WithExtraInfo(T& aT, LispObject* aData = 0) : T(aT), iExtraInfo(aData) {}
WithExtraInfo(const WithExtraInfo& other) : T(other), iExtraInfo(other.iExtraInfo) {}
virtual LispObject* ExtraInfo() { return iExtraInfo; }
virtual LispObject* SetExtraInfo(LispObject* aData) { iExtraInfo = aData; return this; }
virtual LispObject* Copy()
{
if (!iExtraInfo.ptr()) return T::Copy();
return NEW WithExtraInfo(*this, iExtraInfo->Copy());
}
private:
LispPtr iExtraInfo;
};
template <class T, class U = LispObject>
class ObjectHelper : public U
{
protected:
typedef ObjectHelper ASuper; // for use by the derived class
ObjectHelper() {}
ObjectHelper(const ObjectHelper& other) : U(other) {}
virtual ~ObjectHelper() = 0; // so we're abstract
virtual LispObject* SetExtraInfo(LispObject* aData)
{
if (!aData) return this;
//T * pT = dynamic_cast<T*>(this); LISPASSERT(pT);
LispObject * pObject = NEW WithExtraInfo<T>(*static_cast<T*>(this), aData);
return pObject;
}
};
template <typename T, class U>
inline ObjectHelper<T,U>::~ObjectHelper() {}
/**
* class LispIterator works almost like LispPtr, but doesn't enforce
* reference counting, so it should be faster. Use LispIterator
* (instead of LispPtr) to traverse a lisp expression non-destructively.
*/
class LispIterator : public YacasBase
{
public:
// ala TEMPLATE CLASS iterator
//typedef forward_iterator_tag iterator_category;
typedef LispPtr value_type;
typedef int /*ptrdiff_t*/ difference_type;
typedef LispPtr* pointer;
typedef LispPtr& reference;
public:
LispIterator() : _Ptr(0) {} // construct with null node pointer
LispIterator(pointer ptr) : _Ptr(ptr) {} // construct with node pointer
/*non-standard*/ LispIterator(reference ref) : _Ptr(&ref) {} // construct with node reference
reference operator*() const { return (*(_Ptr)); } // return designated value
pointer operator->() const { return (_Ptr); } // return pointer to class object
inline LispIterator& operator++() // preincrement
{
//precondition: _Ptr != NULL
LISPASSERT(_Ptr != NULL);
//expand: _Ptr = _Nextnode(_Ptr);
LispObject * pObj = _Ptr->operator->();
_Ptr = pObj ? &(pObj->Nixed()) : NULL;
return (*this);
}
LispIterator operator++(int) { LispIterator _Tmp = *this; ++*this; return (_Tmp); } // postincrement
bool operator==(const LispIterator& other) const { return (_Ptr == other._Ptr); } // test for iterator equality
bool operator!=(const LispIterator& other) const { return (!(*this == other)); } // test for iterator inequality
// The following operators are not used yet, and would need to be tested before used.
//LispIterator& operator--() { _Ptr = _Prevnode(_Ptr); return (*this); } // predecrement
//LispIterator operator--(int) { LispIterator _Tmp = *this; --*this; return (_Tmp); } // postdecrement
protected:
pointer _Ptr; // pointer to node
public:
inline LispObject* getObj() const { return (*_Ptr).operator->(); }
};
#include "lispobject.inl"
#endif