0,0 → 1,234 |
/** \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 |