/// @file templates.hh /// @author Stefan Schmitt /// @version 1.0 /// @date 2003-07 /// /// Declares various class templates and template-like macros. #ifndef TEMPLATES_HH #define TEMPLATES_HH namespace EyeMind { /// Provide access to a single instance of CLASS. To be used in \c public: /// declaration section of a class. See also NO_COPYING. CLASS::I() will /// return a reference to the single instance. The instance is created when it /// is first needed and is automatically destroyed after main(). #define SINGLETON(CLASS) \ static CLASS& I() \ { \ static CLASS instance; \ return instance; \ } /// Companion to the SINGLETON macro, to be used in \c private: declaration. /// Prevents copying of an instance and can also be used without SINGLETON. /// You also need to declare the default constructor in the \c private: section /// for the SINGLETON scheme to work. #define NO_COPYING(CLASS) \ CLASS(const CLASS&);\ void operator=(const CLASS&){} }; // namespace EyeMind #include "base/constants.hh" namespace EyeMind { #ifdef EYEBOT #include "librobi/c-protos.h" #include "librobi/c-stubs.h" /// Poor man's exception. inline void OSPanicIf(bool expr, const char *msg) { // The const_cast is necessary because of some shortcomings in the // EyeBot library. OSPanic() does not alter the contents of the string // and even if it would, who cares? The system stops working anyway // since it's OSPanic()'s big time. if (expr) OSPanic(const_cast(msg)); } #else #warning OSPanicIf does nothing inline void OSPanicIf(bool expr, const char *msg){} #endif //EYEBOT /// Clips an int to min/max. inline int clip(int value, int min, int max) { if (value < min) return min; if (value > max) return max; return value; } /// Clips an unsigned to min/max. inline unsigned clip(unsigned value, unsigned min, unsigned max) { if (value < min) return min; if (value > max) return max; return value; } /// Clips a float to min/max. inline float clip(float value, float min, float max) { if (value < min) return min; if (value > max) return max; return value; } /// Default number of elements in Array collection. const unsigned DEFAULT_ARRAY_SIZE=8; /// Iterable pointer collection (lightweight, array-based, evil). /// /// Provides operators to add, remove, iterate and read elements, but there are /// no functions for altering the elements. The iteration is quite different /// to the STL containers, so watch out. /// /// @warning: Iteration is not thread-safe. Provide thread-safety in your user /// program by preventing task-switching around iteration calls (if needed). template class Array { private: unsigned pos; ///< Current iterator position. unsigned next; ///< Next element counter. T* data[size]; ///< Container for T. NO_COPYING(Array); ///< Prevent copying. public: /// Default constructor; initializes data members with NULL. Array(); /// @name Attribute manipulation functions. //@{ unsigned Pos(){ return pos; } ///< Returns curren iterator position. void Pos(unsigned i){ pos=i; } ///< Sets iterator position. unsigned Size(){ return size; } ///< Returns max size of Array. unsigned Count(){ return next; } ///< Returns element count. //@} /// Add T to Array. This operator changes the instance. You may not /// expect this from an addition operator, but since it is not possible /// to create a symmetry to the substraction operator it is implemented /// in this way. /// /// Note: The += and -= operators would not lead to symmetry, too. Array& operator+(T& e); /// Append T to Array. If the Array has reached the maximum size, a /// pointer to the first element is returned. /// @param e Reference to element to be appended. /// @returns Pointer to the removed element, NULL else. T* Append(T& e); /// Remove T at position \b i from Array. /// @param i Position of element to be removed /// @returns Removed T* /// /// This operator changes the instance. (see addition operator) T* operator-(const unsigned i); /// Remove T referenced by e from Array. /// @param e Reference to element to be removed. /// @returns Removed T* if found, NULL else. /// /// This operator changes the instance. (see addition operator) T* operator-(T& e); /// @name Iterator functions and operators. //@{ /// Initialize T iterator; returns first T*. T* Begin(); /// Initialize T reverse iterator; returns first T*. T* RBegin(); /// Iterate through Ts; prefix ++; returns next T*. T* operator++(); //prefix /// Iterate through Ts; postfix ++; returns next T*. T* operator++(int); //postfix /// Iterate reverse through Ts; prefix --; returns next T*. T* operator--(); //prefix /// Iterate reverse through Ts; postfix --; returns next T*. T* operator--(int); //postfix /// Indexing operator; returns T* at index i. T* operator[](unsigned i) const; //@} /// Find index of \b e in Array /// @param e Element to find /// @return Index of element if found, NOK else int Find(T& e); }; template Array::Array() { for (unsigned i = 0;i < size;i++) data[i] = NULL; pos = 0; next = 0; } template Array& Array::operator+(T& e) { OSPanicIf(next >= size, "Array full"); data[next] = &e; next++; return *this; // make chaining possible: Array+Element+Element+.. } template T* Array::Append(T& e) { T *temp = NULL; if (next < size) *this + e; else { temp = *this - 0; *this + e; } return temp; } template T* Array::operator-(unsigned i) { T* temp; if (i < size) { temp = data[i]; for (i = i; i < size; i++) data[i] = data[i + 1]; return temp; } else { return NULL; } } template T* Array::operator-(T& e) { int temp=Find(e); if (temp >= 0) return (*this - temp); else return NULL; } template T* Array::operator[](unsigned i) const { if (i < size) return data[i]; else return NULL; } template T* Array::Begin() { Pos(0); return data[pos]; } template T* Array::RBegin() { unsigned temp = next; if (temp > 0) --temp; Pos(temp); return data[pos]; } template T* Array::operator++() { ++pos; if (pos < size) return data[pos]; else return NULL; } template T* Array::operator++(int) { if (pos < size) { ++pos; return data[pos-1]; } else return NULL; } template T* Array::operator--() { // pos is unsigned, so decrementing it at 0 will make it UINT_MAX and // is thus never less than size (which has also a maximum of UINT_MAX) --pos; if (pos < size) return data[pos]; else return NULL; } template T* Array::operator--(int) { if (pos < size) { --pos; return data[pos+1]; } else return NULL; } template int Array::Find(T& e) { for(unsigned i = 0; i < next; ++i) if (data[i] == &e) return i; return NOK; } /// Iterable pointer collection (lightweight, linked-list-based). /// /// Provides operators to add, remove and iterate elements. /// /// @warning: Iteration is not thread-safe. Provide thread-safety in your user /// program by preventing task-switching around iteration calls (if needed). template class LinkedList { // the friend functions must (?) be defined here, not only declared. ugly, but // at least this does what it should /// Append T to LinkedList. /// This operator changes the instance. You may not expect this from an /// addition operator, but since it is not possible to create a symmetry to the /// substraction operator it is implemented in this way. /// /// Note: The += and -= operators would not lead to symmetry, too. friend LinkedList& operator+(LinkedList& l, T& e){ return l.Append(e); } /// Prepend T to LinkedList. /// This operator changes the instance. You may not expect this from an /// addition operator, but since it is not possible to create a symmetry to the /// substraction operator it is implemented in this way. /// /// Note: The += and -= operators would not lead to symmetry, too. friend LinkedList& operator+(T& e, LinkedList& l){ return l.Prepend(e); } private: /// Linked list type. struct LList { T* entity; LList* next; }; LList* first; ///< List anchor. LList* last; ///< Last element pointer. LList* pos; ///< Current iterator position. unsigned count; ///< Element counter. NO_COPYING(LinkedList); ///< Prevent copying. public: /// Default constructor; initializes data members. LinkedList(); /// Destructor; deletes all list elements, but nor the entities they /// are pointing to. ~LinkedList(); /// @name Attribute manipulation functions. //@{ unsigned Count(){ return count; } //@} /// Append a T to the end of the LinkedList. LinkedList& Append(T& e); /// Prepend a T to the start of the LinkedList. LinkedList& Prepend(T& e); /// Remove T referenced by e from LinkedList. /// @param e Reference to element to be removed. /// @returns Removed T* if found, NULL else. /// /// This operator changes the instance. (see addition operator) T* operator-(T& e); /// @name Iterator functions and operators //@{ /// Initialize T iterator; returns first T*. T* Begin(); /// @name Iterate through Ts; prefix ++; returns next T*. T* operator++(); //prefix /// @name Iterate through Ts; postfix ++; returns next T*. T* operator++(int); //postfix //@} }; template LinkedList::LinkedList() : first(NULL), last(NULL), pos(NULL), count(0) { } template LinkedList::~LinkedList() { LList* temp = first; while (temp) { LList* next = temp->next; delete temp; temp = next; }; } template LinkedList& LinkedList::Append(T& e) { LList* temp = new LList; temp->next = NULL; temp->entity = &e; if (first) last->next = temp; else // when creating the first element first = temp; last = temp; ++count; return *this; } template LinkedList& LinkedList::Prepend(T& e) { LList* temp = new LList; temp->next = first; temp->entity = &e; if (!last) // when creating the first element last = temp; first = temp; ++count; return *this; } template T* LinkedList::operator-(T& e) { // is list empty? if (first == NULL) return NULL; // is element to be removed the first one? if (first->entity == &e) { LList* temp = first; first = first->next; if (first == NULL) last = NULL; delete temp; --count; return &e; } // so the element is somewhere else in the list LList* prev = first; LList* temp = first->next; while (temp) { if (temp->entity == &e) { if (last == temp) // when removing last element last = prev; prev->next = temp->next; delete temp; --count; return &e; }; prev = temp; temp = temp->next; }; // not found return NULL; } template T* LinkedList::Begin() { pos = first; if (pos) return pos->entity; else return NULL; } template T* LinkedList::operator++() { if (pos) pos = pos->next; if (pos) return pos->entity; else return NULL; } template T* LinkedList::operator++(int) { LList* temp = pos; if (pos) pos = pos->next; if (temp) return temp->entity; else return NULL; } }; // namespace EyeMind #endif // TEMPLATES_HH