added Mpool and LinkedList

This commit is contained in:
2015-01-02 06:40:41 +00:00
parent 91e4e06318
commit 3b672857aa
15 changed files with 988 additions and 85 deletions

View File

@ -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 <qse/Types.hpp>
#include <xp/bas/MemoryPool.hpp>
#include <xp/bas/MemoryPoolable.hpp>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
template <typename T> class LinkedList;
template <typename T>
class LinkedListNode: protected MemoryPoolable
{
public:
friend class LinkedList<T>;
T value;
protected:
LinkedListNode<T>* next;
LinkedListNode<T>* prev;
public:
LinkedListNode<T>* getNext () { return this->next; }
const LinkedListNode<T>* getNext () const { return this->next; }
LinkedListNode<T>* getPrev () { return this->prev; }
const LinkedListNode<T>* getPrev () const { return this->prev; }
protected:
LinkedListNode () {}
LinkedListNode (const T& v): value(v) {}
void setNext (const LinkedListNode<T>* node)
{
this->next = node;
}
void setPrev (const LinkedListNode<T>* node)
{
this->prev = node;
}
};
///
/// The LinkedList<T> class provides a template for a doubly-linked list.
///
template <typename T> class LinkedList
{
public:
typedef LinkedListNode<T> 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<T>& 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<T>& operator= (const LinkedList<T>& 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<T>& 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<T>& 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<T>::*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 <typename T>
inline typename LinkedList<T>::Node* LinkedList<T>::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 <typename T>
inline typename LinkedList<T>::Node* LinkedList<T>::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

View File

@ -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

View File

@ -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/||"`;; \

View File

@ -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/Uncopyable.hpp>
/////////////////////////////////
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

View File

@ -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/cmn/Mpool.hpp>
/////////////////////////////////
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