diff --git a/qse/include/qse/RefCounted.hpp b/qse/include/qse/RefCounted.hpp index e4447084..05103295 100644 --- a/qse/include/qse/RefCounted.hpp +++ b/qse/include/qse/RefCounted.hpp @@ -71,7 +71,6 @@ protected: mutable qse_size_t ref_count; }; - ///////////////////////////////// QSE_END_NAMESPACE(QSE) ///////////////////////////////// diff --git a/qse/include/qse/Types.hpp b/qse/include/qse/Types.hpp index 18efa4de..4f01c8ae 100644 --- a/qse/include/qse/Types.hpp +++ b/qse/include/qse/Types.hpp @@ -30,6 +30,9 @@ #include #include +/// \file +/// This file defines a class containg aliases to various QSE types. + ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// diff --git a/qse/include/qse/Uncopyable.hpp b/qse/include/qse/Uncopyable.hpp index b03e4d83..b772bb82 100644 --- a/qse/include/qse/Uncopyable.hpp +++ b/qse/include/qse/Uncopyable.hpp @@ -27,12 +27,16 @@ #ifndef _QSE_UNCOPYABLE_HPP_ #define _QSE_UNCOPYABLE_HPP_ -#include +#include +#include ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// +/// The Uncopyable class disallows an inheriting class to be assigned or +/// copied. + class QSE_EXPORT Uncopyable { public: @@ -48,5 +52,4 @@ private: QSE_END_NAMESPACE(QSE) ///////////////////////////////// - #endif diff --git a/qse/include/qse/awk/Awk.hpp b/qse/include/qse/awk/Awk.hpp index ae304ccb..105ce593 100644 --- a/qse/include/qse/awk/Awk.hpp +++ b/qse/include/qse/awk/Awk.hpp @@ -33,7 +33,7 @@ #include #include -/// @file +/// \file /// AWK Interpreter ///////////////////////////////// @@ -105,24 +105,24 @@ public: protected: /// - /// @name Error Handling + /// \name Error Handling /// - /// @{ + /// \{ /// /// The getErrorString() function returns a formatting string - /// for an error code @a num. You can override this function + /// for an error code \a num. You can override this function /// to customize an error message. You must include the same numbers /// of ${X}'s as the orginal formatting string. Their order may be /// different. The example below changes the formatting string for /// #QSE_AWK_ENOENT. - /// @code + /// \code /// const MyAwk::char_t* MyAwk::getErrorString (errnum_t num) const /// { /// if (num == QSE_AWK_ENOENT) return QSE_T("cannot find '${0}'"); /// return Awk::getErrorString (num); /// } - /// @endcode + /// \endcode /// virtual const char_t* getErrorString ( errnum_t num @@ -175,7 +175,7 @@ public: //protected: can't make it protected for borland void retrieveError (); void retrieveError (Run* run); - /// @} + /// \} protected: class NoSource; @@ -791,14 +791,14 @@ public: /// /// The isIndexed() function determines if a value is arrayed. - /// @return true if indexed, false if not. + /// \return true if indexed, false if not. /// bool isIndexed () const; /// /// The getIndexed() function gets a value at the given - /// index @a idx and sets it to @a val. - /// @return 0 on success, -1 on failure + /// index \a idx and sets it to \a val. + /// \return 0 on success, -1 on failure /// int getIndexed ( const Index& idx, ///< array index @@ -807,8 +807,8 @@ public: /// /// The getFirstIndex() function stores the first index of - /// an arrayed value into @a idx. - /// @return IndexIterator::END if the arrayed value is empty, + /// an arrayed value into \a idx. + /// \return IndexIterator::END if the arrayed value is empty, /// iterator that can be passed to getNextIndex() if not /// IndexIterator getFirstIndex ( @@ -816,10 +816,10 @@ public: ) const; /// - /// The getNextIndex() function stores into @a idx the next + /// The getNextIndex() function stores into \a idx the next /// index of an array value from the position indicated by - /// @a iter. - /// @return IndexIterator::END if the arrayed value is empty, + /// \a iter. + /// \return IndexIterator::END if the arrayed value is empty, /// iterator that can be passed to getNextIndex() if not /// IndexIterator getNextIndex ( @@ -882,40 +882,40 @@ public: /// /// The setGlobal() function sets the value of a global - /// variable identified by @a id - /// to @a v. - /// @return 0 on success, -1 on failure + /// variable identified by \a id + /// to \a v. + /// \return 0 on success, -1 on failure /// int setGlobal (int id, int_t v); /// /// The setGlobal() function sets the value of a global - /// variable identified by @a id - /// to @a v. - /// @return 0 on success, -1 on failure + /// variable identified by \a id + /// to \a v. + /// \return 0 on success, -1 on failure /// int setGlobal (int id, flt_t v); /// /// The setGlobal() function sets the value of a global - /// variable identified by @a id - /// to a string as long as @a len characters pointed to by - /// @a ptr. - /// @return 0 on success, -1 on failure + /// variable identified by \a id + /// to a string as long as \a len characters pointed to by + /// \a ptr. + /// \return 0 on success, -1 on failure /// int setGlobal (int id, const char_t* ptr, size_t len); /// /// The setGlobal() function sets a global variable - /// identified by @a id to a value @a v. - /// @return 0 on success, -1 on failure + /// identified by \a id to a value \a v. + /// \return 0 on success, -1 on failure /// int setGlobal (int id, const Value& v); /// /// The getGlobal() function gets the value of a global - /// variable identified by @a id and stores it in @a v. - /// @return 0 on success, -1 on failure + /// variable identified by \a id and stores it in \a v. + /// \return 0 on success, -1 on failure /// int getGlobal (int id, Value& v) const; @@ -930,8 +930,8 @@ public: operator awk_t* () const; /// - /// @name Basic Functions - /// @{ + /// \name Basic Functions + /// \{ /// /// The Awk() function creates an interpreter without fully @@ -946,7 +946,7 @@ public: /// /// The open() function initializes an interpreter. /// You must call this function before doing anything meaningful. - /// @return 0 on success, -1 on failure + /// \return 0 on success, -1 on failure /// int open (); @@ -957,11 +957,11 @@ public: /// /// The parse() function parses the source code read from the input - /// stream @a in and writes the parse tree to the output stream @a out. - /// To disable deparsing, you may set @a out to Awk::Source::NONE. - /// However, it is not allowed to specify Awk::Source::NONE for @a in. + /// stream \a in and writes the parse tree to the output stream \a out. + /// To disable deparsing, you may set \a out to Awk::Source::NONE. + /// However, it is not allowed to specify Awk::Source::NONE for \a in. /// - /// @return Run object on success, #QSE_NULL on failure + /// \return Run object on success, #QSE_NULL on failure /// Awk::Run* parse ( Source& in, ///< script to parse @@ -1002,15 +1002,15 @@ public: /// /// The loop() function executes the BEGIN block, pattern-action blocks, - /// and the END block. The return value is stored into @a ret. - /// @return 0 on succes, -1 on failure + /// and the END block. The return value is stored into \a ret. + /// \return 0 on succes, -1 on failure /// int loop ( Value* ret ///< return value holder ); /// - /// The call() function invokes a function named @a name. + /// The call() function invokes a function named \a name. /// int call ( const char_t* name, ///< function name @@ -1023,16 +1023,16 @@ public: /// The stop() function makes request to abort execution /// void stop (); - /// @} + /// \} /// - /// @name Configuration - /// @{ + /// \name Configuration + /// \{ /// /// /// The getTrait() function gets the current options. - /// @return current traits + /// \return current traits /// int getTrait () const; @@ -1045,7 +1045,7 @@ public: /// /// The setMaxDepth() function sets the maximum processing depth - /// for operations identified by @a ids. + /// for operations identified by \a ids. /// void setMaxDepth ( depth_t id, ///< depth identifier @@ -1054,18 +1054,18 @@ public: /// /// The getMaxDepth() function gets the maximum depth for an operation - /// type identified by @a id. + /// type identified by \a id. /// size_t getMaxDepth ( depth_t id ///< depth identifier ) const; /// - /// The addArgument() function adds an ARGV string as long as @a len + /// The addArgument() function adds an ARGV string as long as \a len /// characters pointed to - /// by @a arg. loop() and call() make a string added available + /// by \a arg. loop() and call() make a string added available /// to a script through ARGV. - /// @return 0 on success, -1 on failure + /// \return 0 on success, -1 on failure /// int addArgument ( const char_t* arg, ///< string pointer @@ -1073,10 +1073,10 @@ public: ); /// - /// The addArgument() function adds a null-terminated string @a arg. + /// The addArgument() function adds a null-terminated string \a arg. /// loop() and call() make a string added available to a script /// through ARGV. - /// @return 0 on success, -1 on failure + /// \return 0 on success, -1 on failure /// int addArgument ( const char_t* arg ///< string pointer @@ -1089,7 +1089,7 @@ public: /// /// The addGlobal() function registers an intrinsic global variable. - /// @return integer >= 0 on success, -1 on failure. + /// \return integer >= 0 on success, -1 on failure. /// int addGlobal ( const char_t* name ///< variable name @@ -1098,7 +1098,7 @@ public: /// /// The deleteGlobal() function unregisters an intrinsic global /// variable by name. - /// @return 0 on success, -1 on failure. + /// \return 0 on success, -1 on failure. /// int deleteGlobal ( const char_t* name ///< variable name @@ -1107,7 +1107,7 @@ public: /// /// The addGlobal() function returns the numeric ID of an intrinsic // global variable. - /// @return integer >= 0 on success, -1 on failure. + /// \return integer >= 0 on success, -1 on failure. /// int findGlobal ( const char_t* name ///> variable name @@ -1115,10 +1115,10 @@ public: /// /// The setGlobal() function sets the value of a global variable - /// identified by @a id. The @a id is either a value returned by + /// identified by \a id. The \a id is either a value returned by /// addGlobal() or one of the #gbl_id_t enumerators. It is not allowed /// to call this function prior to parse(). - /// @return 0 on success, -1 on failure + /// \return 0 on success, -1 on failure /// int setGlobal ( int id, ///< numeric identifier @@ -1127,10 +1127,10 @@ public: /// /// The getGlobal() function gets the value of a global variable - /// identified by @a id. The @a id is either a value returned by + /// identified by \a id. The \a id is either a value returned by /// addGlobal() or one of the #gbl_id_t enumerators. It is not allowed /// to call this function before parse(). - /// @return 0 on success, -1 on failure + /// \return 0 on success, -1 on failure /// int getGlobal ( int id, ///< numeric identifier @@ -1168,7 +1168,7 @@ public: int deleteFunction ( const char_t* name ///< function name ); - /// @} + /// \} Pipe::Handler* getPipeHandler () { @@ -1238,10 +1238,10 @@ public: protected: /// - /// @name Pipe I/O handlers + /// \name Pipe I/O handlers /// Pipe operations are achieved through the following functions /// if no external pipe handler is set with setPipeHandler(). - /// @{ + /// \{ /// The openPipe() function is a pure virtual function that must be /// overridden by a child class to open a pipe. It must return 1 @@ -1256,26 +1256,26 @@ protected: virtual ssize_t readPipe (Pipe& io, char_t* buf, size_t len); virtual ssize_t writePipe (Pipe& io, const char_t* buf, size_t len); virtual int flushPipe (Pipe& io); - /// @} + /// \} /// - /// @name File I/O handlers + /// \name File I/O handlers /// File operations are achieved through the following functions /// if no external file handler is set with setFileHandler(). - /// @{ + /// \{ /// virtual int openFile (File& io); virtual int closeFile (File& io); virtual ssize_t readFile (File& io, char_t* buf, size_t len); virtual ssize_t writeFile (File& io, const char_t* buf, size_t len); virtual int flushFile (File& io); - /// @} + /// \} /// - /// @name Console I/O handlers + /// \name Console I/O handlers /// Console operations are achieved through the following functions. /// if no external console handler is set with setConsoleHandler(). - /// @{ + /// \{ /// virtual int openConsole (Console& io); virtual int closeConsole (Console& io); @@ -1283,7 +1283,7 @@ protected: virtual ssize_t writeConsole (Console& io, const char_t* buf, size_t len); virtual int flushConsole (Console& io); virtual int nextConsole (Console& io); - /// @} + /// \} // primitive handlers virtual flt_t pow (flt_t x, flt_t y) = 0; diff --git a/qse/include/qse/awk/StdAwk.hpp b/qse/include/qse/awk/StdAwk.hpp index 9c9ab12a..9a4dcb9b 100644 --- a/qse/include/qse/awk/StdAwk.hpp +++ b/qse/include/qse/awk/StdAwk.hpp @@ -31,7 +31,7 @@ #include #include -/// @file +/// \file /// Standard AWK Interpreter ///////////////////////////////// diff --git a/qse/include/qse/cmn/LinkedList.hpp b/qse/include/qse/cmn/LinkedList.hpp new file mode 100644 index 00000000..e4984f13 --- /dev/null +++ b/qse/include/qse/cmn/LinkedList.hpp @@ -0,0 +1,583 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_CMN_LINKEDLIST_HPP_ +#define _QSE_CMN_LINKEDLIST_HPP_ + +#include +#include +#include + + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +template class LinkedList; + +template +class LinkedListNode: protected MemoryPoolable +{ +public: + friend class LinkedList; + + T value; + +protected: + LinkedListNode* next; + LinkedListNode* prev; + +public: + LinkedListNode* getNext () { return this->next; } + const LinkedListNode* getNext () const { return this->next; } + + LinkedListNode* getPrev () { return this->prev; } + const LinkedListNode* getPrev () const { return this->prev; } + +protected: + LinkedListNode () {} + LinkedListNode (const T& v): value(v) {} + + void setNext (const LinkedListNode* node) + { + this->next = node; + } + void setPrev (const LinkedListNode* node) + { + this->prev = node; + } +}; + +/// +/// The LinkedList class provides a template for a doubly-linked list. +/// +template class LinkedList +{ +public: + typedef LinkedListNode Node; + + enum + { + INVALID_INDEX = ~(qse_size_t)0 + }; + + ~LinkedList () + { + this->clearout (); + } + + LinkedList (qse_size_t mpb_size = 0): mp (QSE_SIZEOF(Node), mpb_size) + { + this->node_count = 0; + this->head_node = QSE_NULL; + this->tail_node = QSE_NULL; + } + + LinkedList (const LinkedList& ll): mp (ll.mp.datumSize(), ll.mp.blockSize()) + { + this->node_count = 0; + this->head_node = QSE_NULL; + this->tail_node = QSE_NULL; + for (Node* p = ll.head_node; p != QSE_NULL; p = p->next) + this->append (p->value); + } + + LinkedList& operator= (const LinkedList& ll) + { + this->clear (); + for (Node* p = ll.head_node; p != QSE_NULL; p = p->next) + this->append (p->value); + return *this; + } + + T& operator[] (qse_size_t index) + { + // same as getValueAt() + QSE_ASSERT (index < this->node_count); + Node* np = this->getNodeAt (index); + return np->value; + } + + const T& operator[] (qse_size_t index) const + { + // same as getValueAt() + QSE_ASSERT (index < this->node_count); + Node* np = this->getNodeAt (index); + return np->value; + } + + qse_size_t getMPBlockSize() const + { + return this->mp.blockSize(); + } + + bool isMPEnabled () const + { + return this->mp.isEnabled(); + } + + qse_size_t getSize () const + { + return this->node_count; + } + + bool isEmpty () const + { + return this->node_count == 0; + } + + bool contains (const T& value) const + { + return this->findFirstNode(value) != QSE_NULL; + } + + // insert an externally created node. + // may need to take extra care when using this method. + Node* insertNode (Node* pos, Node* node); + + // create a new node to hold the value and insert it. + Node* insertValue (Node* pos, const T& value) + { + Node* n = this->mp.isEnabled()? + (new(&mp) Node(value)): (new Node(value)); + return this->insertNode (pos, n); + } + + T& insert (Node* node, const T& value) + { + return this->insertValue(node, value)->value; + } + + T& insert (qse_size_t index, const T& value) + { + QSE_ASSERT (index <= node_count); + + if (index >= node_count) + { + // insert it at the back + return this->insert ((Node*)QSE_NULL, value); + } + + return this->insert (this->getNodeAt(index), value); + } + + T& prepend (const T& value) + { + return this->insert (this->head_node, value); + } + T& append (const T& value) + { + return this->insert ((Node*)QSE_NULL, value); + } + + Node* prependNode (Node* node) + { + return this->insertNode (head_node, node); + } + Node* appendNode (Node* node) + { + return this->insertNode ((Node*)QSE_NULL, node); + } + + Node* prependValue (const T& value) + { + return this->insertValue (this->head_node, value); + } + Node* appendValue (const T& value) + { + return this->insertValue ((Node*)QSE_NULL, value); + } + + void prependAll (const LinkedList& list) + { + Node* n = list.tail_node; + + if (&list == this) + { + Node* head = list.head_node; + while (n) + { + this->prepend (n->value); + if (n == head) break; + n = (Node*)n->prev; + } + } + else + { + while (n) + { + this->prepend (n->value); + n = (Node*)n->prev; + } + } + } + + void appendAll (const LinkedList& list) + { + Node* n = list.head_node; + + if (&list == this) + { + Node* tail = list.tail_node; + while (n) + { + this->append (n->value); + if (n == tail) break; + n = n->next; + } + } + else + { + while (n) + { + this->append (n->value); + n = n->next; + } + } + } + + // remove a node from the list without freeing it. + // take extra care when using this method as the node + // can be freed through the memory pool when the list is + // destructed if the memory pool is enabled. + Node* yield (Node* node, bool clear_links = true); + + // remove a node from the list and free it. + void remove (Node* node) + { + this->yield (node, false); + if (mp.isDisabled()) delete node; + else + { + node->~Node (); + #if defined(_MSC_VER) + node->operator delete (node, &mp); + #else + node->dispose (node, &mp); + #endif + } + } + + void remove (qse_size_t index) + { + QSE_ASSERT (index < node_count); + + Node* np = this->head_node; + while (index > 0) + { + np = np->next; + index--; + } + + this->remove (np); + } + + Node* yieldByValue (const T& value, bool clear_links = true) + { + Node* p = this->findFirstNode (value); + Node* p = this->findFirstNode (value); + if (p == QSE_NULL) return -1; + return this->yield (p, clear_links); + } + + qse_size_t removeByValue (const T& value) + { + Node* p = this->findFirstNode (value); + if (!p) return 0; + this->remove (p); + return 1; + } + + /// \return the number of items deleted + qse_size_t removeAllByValue (const T& value) + { + Node* p = this->findFirstNode (value); + if (!p) return 0; + + qse_size_t cnt = 0; + do + { + Node* tmp = p->next; + this->remove (p); + cnt++; + p = this->findFirstNode (value, tmp); + } + while (p); + + return cnt; + } + + void removeHead () + { + this->remove (this->head_node); + } + void removeTail () + { + this->remove (this->tail_node); + } + + Node* getHeadNode () const + { + return this->head_node; + } + + Node* getTailNode () const + { + return this->tail_node; + } + + Node* getNodeAt (qse_size_t index) const + { + QSE_ASSERT (index < this->node_count); + + register Node* np; + register qse_size_t cnt; + + if (index < (this->node_count >> 1)) + { + for (np = this->head_node, cnt = 0; cnt < index; np = np->next, cnt++) + { + QSE_ASSERT (np != QSE_NULL); + } + } + else + { + for (np = this->tail_node, cnt = this->node_count - 1; cnt > index; np = np->prev, cnt--) + { + QSE_ASSERT (np != QSE_NULL); + } + } + + return np; + } + + T& getValueAt (qse_size_t index) + { + // same as operator[] + QSE_ASSERT (index < this->node_count); + Node* np = this->getNodeAt (index); + return np->value; + } + + const T& getValueAt (qse_size_t index) const + { + // same as operator[] + QSE_ASSERT (index < this->node_count); + Node* np = this->getNodeAt (index); + return np->value; + } + + void setValueAt (qse_size_t index, const T& value) + { + QSE_ASSERT (index < this->node_count); + Node* np = this->getNodeAt (index); + np->value = value; + } + + Node* findFirstNode (const T& value) const + { + for (Node* p = this->head_node; p; p = p->next) + { + if (value == p->value) return p; + } + return QSE_NULL; + } + + Node* findLastNode (const T& value) const + { + for (Node* p = tail_node; p; p = p->prev) + { + if (value == p->value) return p; + } + return QSE_NULL; + } + + Node* findFirstNode (const T& value, Node* head) const + { + for (Node* p = head; p; p = p->next) + { + if (value == p->value) return p; + } + return QSE_NULL; + } + + Node* findLastNode (const T& value, Node* tail) const + { + for (Node* p = tail; p; p = p->prev) + { + if (value == p->value) return p; + } + return QSE_NULL; + } + + qse_size_t findFirstIndex (const T& value) const + { + qse_size_t index = 0; + for (Node* p = this->head_node; p; p = p->next) + { + if (value == p->value) return index; + index++; + } + return INVALID_INDEX; + } + + qse_size_t findLastIndex (const T& value) const + { + qse_size_t index = node_count; + for (Node* p = tail_node; p; p = p->prev) + { + index--; + if (value == p->value) return index; + } + return INVALID_INDEX; + } + + void clear () + { + Node* p, * saved; + + p = this->head_node; + while (p) + { + saved = p->next; + + if (this->mp.isDisabled()) delete p; + else + { + p->~Node (); + #if defined(_MSC_VER) + p->operator delete (p, &mp); + #else + p->dispose (p, &mp); + #endif + } + + this->node_count--; + p = saved; + } + + this->head_node = this->tail_node = QSE_NULL; + QSE_ASSERT (this->node_count == 0); + } + + void clearout () + { + this->clear (); + this->mp.dispose (); + } + + typedef int (LinkedList::*TraverseCallback) (Node* start, Node* cur); + + void traverse (TraverseCallback callback, Node* start) + { + Node* cur, * prev, * next; + + cur = start; + while (cur) + { + prev = cur->prev; + next = cur->next; + + int n = (this->*callback) (start, cur); + + if (n > 0) cur = next; + else if (n < 0) cur = prev; + else break; + } + } + +protected: + MemoryPool mp; + Node* head_node; + Node* tail_node; + qse_size_t node_count; +}; + +template +inline typename LinkedList::Node* LinkedList::insertNode (Node* pos, Node* node) +{ + if (pos == QSE_NULL) + { + if (this->node_count == 0) + { + QSE_ASSERT (head_node == QSE_NULL); + QSE_ASSERT (tail_node == QSE_NULL); + this->head_node = this->tail_node = node; + } + else + { + node->prev = this->tail_node; + this->tail_node->next = node; + this->tail_node = node; + } + } + else + { + node->next = pos; + node->prev = pos->prev; + if (pos->prev) pos->prev->next = node; + else this->head_node = node; + pos->prev = node; + } + + this->node_count++; + return n; +} + +template +inline typename LinkedList::Node* LinkedList::yield (Node* node, bool clear_links) +{ + QSE_ASSERT (node != QSE_NULL); + QSE_ASSERT (this->node_count > 0); + + if (node->next) + node->next->prev = node->next; + else + this->tail_node = node->prev; + + if (node->prev) + node->prev->next = node->next; + else + this->head_node = node->next; + + this->node_count--; + + if (clear_links) + { + node->next = QSE_NULL; + node->prev = QSE_NULL; + } + + return node; +} + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// + +#endif + + diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index 5b890f32..03f311db 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -50,6 +50,8 @@ pkginclude_HEADERS = \ xma.h if ENABLE_CXX -pkginclude_HEADERS += Mmgr.hpp StdMmgr.hpp Mmged.hpp +pkginclude_HEADERS += \ + Mmgr.hpp StdMmgr.hpp Mmged.hpp Mpool.hpp Mpoolable.hpp \ + LinkedList.hpp endif diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 307f916b..689e69a1 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -50,7 +50,10 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@ENABLE_CXX_TRUE@am__append_1 = Mmgr.hpp StdMmgr.hpp Mmged.hpp +@ENABLE_CXX_TRUE@am__append_1 = \ +@ENABLE_CXX_TRUE@ Mmgr.hpp StdMmgr.hpp Mmged.hpp Mpool.hpp Mpoolable.hpp \ +@ENABLE_CXX_TRUE@ LinkedList.hpp + subdir = include/qse/cmn DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in @@ -87,7 +90,8 @@ am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dir.h dll.h \ lda.h main.h map.h mb8.h mbwc.h mem.h mux.h nwad.h nwif.h \ nwio.h oht.h opt.h path.h pio.h pma.h rbt.h rex.h sck.h sio.h \ sll.h slmb.h str.h task.h time.h tio.h tmr.h tre.h uni.h uri.h \ - utf8.h xma.h Mmgr.hpp StdMmgr.hpp Mmged.hpp + utf8.h xma.h Mmgr.hpp StdMmgr.hpp Mmged.hpp Mpool.hpp \ + Mpoolable.hpp LinkedList.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ diff --git a/qse/include/qse/cmn/Mpool.hpp b/qse/include/qse/cmn/Mpool.hpp new file mode 100644 index 00000000..b9de66c9 --- /dev/null +++ b/qse/include/qse/cmn/Mpool.hpp @@ -0,0 +1,107 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_CMN_MPOOL_HPP_ +#define _QSE_CMN_MPOOL_HPP_ + +#include + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +// +// allocator for fixed-size data +// + +class Mpool: public Uncopyable +{ +public: + enum + { + DEFAULT_BLOCK_SIZE = 128 + }; + + Mpool ( + qse_size_t datum_size, + qse_size_t block_size = DEFAULT_BLOCK_SIZE); + ~Mpool (); + + void* allocate (); + void dispose (void* ptr); + void dispose (); + + inline bool isEnabled () const + { + return this->datum_size > 0 && this->block_size > 0; + } + inline bool isDisabled () const + { + return this->datum_size <= 0 || this->block_size <= 0; + } + + inline qse_size_t datumSize () const + { + return this->datum_size; + } + inline qse_size_t blockSize () const + { + return this->block_size; + } + inline void setBlockSize (qse_size_t blockSize) + { + this->block_size = blockSize; + } + +#if defined(QSE_DEBUG_MPOOL) + qse_size_t nalloc; + qse_size_t navail; +#endif + +protected: + struct Block + { + Block* next; + //qse_uint8_t data[0]; + }; + struct Chain + { + Chain* next; + }; + + Block* mp_blocks; + Chain* free_list; + qse_size_t datum_size; + qse_size_t block_size; + + void add_block (); +}; + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +//////////////////////////////// +#endif + diff --git a/qse/include/qse/cmn/Mpoolable.hpp b/qse/include/qse/cmn/Mpoolable.hpp new file mode 100644 index 00000000..d3965db7 --- /dev/null +++ b/qse/include/qse/cmn/Mpoolable.hpp @@ -0,0 +1,73 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_CMN_MPOOLABLE_HPP_ +#define _QSE_CMN_MPOOLABLE_HPP_ + +#include + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +class Mpoolable +{ +public: + typedef qse_size_t mp_size_t; + + inline void* operator new (mp_size_t size) + { + return ::operator new (size); + } + + inline void operator delete (void* ptr) + { + ::operator delete (ptr); + } + + inline void* operator new (mp_size_t /*size*/, Mpool* mp) + { + return mp->allocate (); + } + +#if defined(_MSC_VER) + void operator delete (void* ptr, Mpool* mp) + { + mp->dispose (ptr); + } +#else + inline void dispose (void* ptr, Mpool* mp) + { + mp->dispose (ptr); + } +#endif +}; + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// + +#endif diff --git a/qse/include/qse/http/http.h b/qse/include/qse/http/http.h index 1a6f8e2c..5142e602 100644 --- a/qse/include/qse/http/http.h +++ b/qse/include/qse/http/http.h @@ -27,7 +27,7 @@ #ifndef _QSE_HTTP_HTTP_H_ #define _QSE_HTTP_HTTP_H_ -/** @file +/** \file * This file provides basic data types and functions for the http protocol. */ @@ -131,7 +131,7 @@ enum qse_http_range_type_t typedef enum qse_http_range_type_t qse_http_range_type_t; /** * The qse_http_range_t type defines a structure that can represent - * a value for the @b Range: http header. + * a value for the \b Range: http header. * * If type is #QSE_HTTP_RANGE_NONE, this range is not valid. * @@ -141,10 +141,10 @@ typedef enum qse_http_range_type_t qse_http_range_type_t; * * You should adjust a range when the size that this range belongs to is * made known. See this code: - * @code + * \code * range.from = total_size - range.to; * range.to = range.to + range.from - 1; - * @endcode + * \endcode * * If type is #QSE_HTTP_RANGE_PROPER, 'from' and 'to' represents a proper range * where the value of 0 indicates the first byte. This doesn't require any diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index 211de1c4..7ef4c314 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -141,7 +141,7 @@ if ENABLE_CXX lib_LTLIBRARIES += libqsecmnxx.la libqsecmnxx_la_SOURCES = \ - Mmgr.cpp StdMmgr.cpp + Mmgr.cpp StdMmgr.cpp Mpool.cpp libqsecmnxx_la_LDFLAGS = -version-info 1:0:0 -no-undefined libqsecmnxx_la_LIBADD = diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 8d249d42..2ef65003 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -149,8 +149,9 @@ libqsecmn_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libqsecmn_la_LDFLAGS) $(LDFLAGS) -o $@ libqsecmnxx_la_DEPENDENCIES = -am__libqsecmnxx_la_SOURCES_DIST = Mmgr.cpp StdMmgr.cpp -@ENABLE_CXX_TRUE@am_libqsecmnxx_la_OBJECTS = Mmgr.lo StdMmgr.lo +am__libqsecmnxx_la_SOURCES_DIST = Mmgr.cpp StdMmgr.cpp Mpool.cpp +@ENABLE_CXX_TRUE@am_libqsecmnxx_la_OBJECTS = Mmgr.lo StdMmgr.lo \ +@ENABLE_CXX_TRUE@ Mpool.lo libqsecmnxx_la_OBJECTS = $(am_libqsecmnxx_la_OBJECTS) libqsecmnxx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ @@ -433,7 +434,7 @@ libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \ libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined libqsecmn_la_LIBADD = $(SOCKET_LIBS) $(QUADMATH_LIBS) @ENABLE_CXX_TRUE@libqsecmnxx_la_SOURCES = \ -@ENABLE_CXX_TRUE@ Mmgr.cpp StdMmgr.cpp +@ENABLE_CXX_TRUE@ Mmgr.cpp StdMmgr.cpp Mpool.cpp @ENABLE_CXX_TRUE@libqsecmnxx_la_LDFLAGS = -version-info 1:0:0 -no-undefined @ENABLE_CXX_TRUE@libqsecmnxx_la_LIBADD = @@ -515,6 +516,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Mmgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Mpool.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StdMmgr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alg-base64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alg-rand.Plo@am__quote@ diff --git a/qse/lib/cmn/Mpool.cpp b/qse/lib/cmn/Mpool.cpp new file mode 100644 index 00000000..a91159cf --- /dev/null +++ b/qse/lib/cmn/Mpool.cpp @@ -0,0 +1,127 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + + +// TODO: can i use QSE_MMGR_XXXXX instead of ::new and ::delete??? + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +Mpool::Mpool (qse_size_t datum_size, qse_size_t block_size) +{ + if (datum_size > 0 && datum_size < QSE_SIZEOF(void*)) + datum_size = QSE_SIZEOF(void*); + + this->mp_blocks = QSE_NULL; + this->free_list = QSE_NULL; + this->datum_size = datum_size; + this->block_size = block_size; +#if defined(QSE_DEBUG_MPOOL) + this->navail = 0; + this->nalloc = 0; +#endif +} +Mpool::~Mpool () +{ + this->dispose (); +} + +void* Mpool::allocate () +{ + if (this->datum_size <= 0 || this->block_size <= 0) return QSE_NULL; + + void* ptr = this->free_list; + if (!ptr) + { + this->add_block (); + ptr = this->free_list; + } + this->free_list = this->free_list->next; +#if defined(QSE_DEBUG_MPOOL) + this->navail--; +#endif + return ptr; +} + +void Mpool::dispose (void* ptr) +{ + ((Chain*)ptr)->next = this->free_list; + this->free_list = (Chain*)ptr; +#if defined(QSE_DEBUG_MPOOL) + this->navail++; +#endif +} + +void Mpool::dispose () +{ + Block* block = this->mp_blocks; + while (block) + { + Block* next = block->next; + ::delete[] block; + block = next; + } + + this->free_list = QSE_NULL; + this->mp_blocks = QSE_NULL; +#if defined(QSE_DEBUG_MPOOL) + this->navail = 0; + this->nalloc = 0; +#endif +} + +void Mpool::add_block () +{ + QSE_ASSERT (this->datum_size > 0 && this->block_size > 0); + + Block* block = (Block*)::new qse_uint8_t[ + QSE_SIZEOF(Block) + this->block_size * this->datum_size]; + + //this->free_list = (Chain*)block->data; + this->free_list = (Chain*)(block + 1); + Chain* ptr = this->free_list; + for (qse_size_t i = 0; i < this->block_size - 1; i++) + { + Chain* next = (Chain*)((qse_uint8_t*)ptr + this->datum_size); + ptr->next = next; + ptr = next; + } + ptr->next = QSE_NULL; + + block->next = this->mp_blocks; + this->mp_blocks = block; +#if defined(QSE_DEBUG_MPOOL) + this->navail += this->block_size; + this->nalloc += this->block_size; +#endif +} + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// diff --git a/qse/lib/sed/Sed.cpp b/qse/lib/sed/Sed.cpp index 24bf8532..39bc5cc2 100644 --- a/qse/lib/sed/Sed.cpp +++ b/qse/lib/sed/Sed.cpp @@ -36,7 +36,7 @@ QSE_BEGIN_NAMESPACE(QSE) int Sed::open () { sed = qse_sed_open (this->mmgr, QSE_SIZEOF(Sed*)); - if (sed == QSE_NULL) return -1; + if (!sed) return -1; *(Sed**)QSE_XTN(sed) = this; dflerrstr = qse_sed_geterrstr (sed); @@ -47,10 +47,10 @@ int Sed::open () void Sed::close () { - if (sed != QSE_NULL) + if (sed) { qse_sed_close (sed); - sed = QSE_NULL; + sed = QSE_NULL; } }