diff --git a/qse/include/qse/Exception.hpp b/qse/include/qse/Exception.hpp index 7a7ed57e..3f0ce7c6 100644 --- a/qse/include/qse/Exception.hpp +++ b/qse/include/qse/Exception.hpp @@ -28,6 +28,9 @@ #ifndef _QSE_EXCEPTION_HPP_ #define _QSE_EXCEPTION_HPP_ +/// \file +/// Provides the Exception class. + #include #include @@ -35,6 +38,7 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// +/// The Exception class implements the exception object. class QSE_EXPORT Exception { public: diff --git a/qse/include/qse/Growable.hpp b/qse/include/qse/Growable.hpp new file mode 100644 index 00000000..c9556393 --- /dev/null +++ b/qse/include/qse/Growable.hpp @@ -0,0 +1,108 @@ +/* + * $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_GROWABLE_HPP_ +#define _QSE_GROWABLE_HPP_ + +/// \file +/// Provides classes for handling size growth including buffer growth. + +#include +#include + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +/// +/// The GrowthPolicy class is an abstract class that defines the behavior of +/// growth policy. +/// +class QSE_EXPORT GrowthPolicy +{ +public: + virtual ~GrowthPolicy () {} + + /// + /// A subclass must implement this function to return a new size over + /// the existing size \a current. + /// + virtual qse_size_t getNewSize (qse_size_t current) const = 0; +}; + +/// +/// The PercentageGrowthPolicy class calculates a new size incremented by +/// the configured percentage over the existing size. +/// +class QSE_EXPORT PercentageGrowthPolicy: public GrowthPolicy +{ +public: + PercentageGrowthPolicy (int percentage = 0): _percentage(percentage) {} + + qse_size_t getNewSize (qse_size_t current) const + { + // TODO: better way to handle overflow? + qse_size_t new_size = current + ((current * this->_percentage) / 100); + if (new_size < current) new_size = QSE_TYPE_MAX(qse_size_t); + return new_size; + } + +protected: + int _percentage; +}; + +/// +/// The Growable class implements common functions to get and set growth policy. +/// The class of an object that needs to grow the buffer or something similar +/// can inherit this class and utilize the policy set. The interface is designed +/// to remember the pointer to the policy to minimize memory use. This requires +/// the policy to outlive the life of the target object set with the policy. +/// +class QSE_EXPORT Growable +{ +public: + Growable (const GrowthPolicy* p = QSE_NULL): _growth_policy(p) {} + + const GrowthPolicy* getGrowthPolicy () const + { + return this->_growth_policy; + } + + void setGrowthPolicy (const GrowthPolicy* p) + { + this->_growth_policy = p; + } + +protected: + const GrowthPolicy* _growth_policy; +}; + + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// + +#endif diff --git a/qse/include/qse/Hashable.hpp b/qse/include/qse/Hashable.hpp index 6541c6e5..2a1b37b8 100644 --- a/qse/include/qse/Hashable.hpp +++ b/qse/include/qse/Hashable.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_HASHABLE_HPP_ #define _QSE_HASHABLE_HPP_ +/// \file +/// Privides the Hashable interface class. + #include #include @@ -34,11 +37,16 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// +/// The Hashable class is an abstract class that provides interface required +/// by a hasable object. In addtion, it provides static hash calculation +/// functions for convenience. +/// class QSE_EXPORT Hashable { public: virtual ~Hashable () {} + /// A class of an hashable object must implement this function. virtual qse_size_t getHashCode () const = 0; static qse_size_t getHashCode (qse_size_t init, const qse_char_t* str) @@ -87,6 +95,8 @@ public: return n; } + /// The getHashCode() function calculates a hash value of a byte stream + /// pointed to by \a data of the length \a size. static qse_size_t getHashCode (const void* data, qse_size_t size) { return Hashable::getHashCode (0, data, size); diff --git a/qse/include/qse/Makefile.am b/qse/include/qse/Makefile.am index 8aaf4744..7b455aae 100644 --- a/qse/include/qse/Makefile.am +++ b/qse/include/qse/Makefile.am @@ -8,7 +8,7 @@ pkginclude_HEADERS = \ if ENABLE_CXX pkginclude_HEADERS += \ - Types.hpp Hashable.hpp Uncopyable.hpp RefCounted.hpp \ + Types.hpp Growable.hpp Hashable.hpp Uncopyable.hpp RefCounted.hpp \ Exception.hpp Cstr.hpp endif diff --git a/qse/include/qse/Makefile.in b/qse/include/qse/Makefile.in index 7316dceb..e94d8776 100644 --- a/qse/include/qse/Makefile.in +++ b/qse/include/qse/Makefile.in @@ -51,7 +51,7 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @ENABLE_CXX_TRUE@am__append_1 = \ -@ENABLE_CXX_TRUE@ Types.hpp Hashable.hpp Uncopyable.hpp RefCounted.hpp \ +@ENABLE_CXX_TRUE@ Types.hpp Growable.hpp Hashable.hpp Uncopyable.hpp RefCounted.hpp \ @ENABLE_CXX_TRUE@ Exception.hpp Cstr.hpp subdir = include/qse @@ -94,8 +94,8 @@ am__can_run_installinfo = \ esac am__pkginclude_HEADERS_DIST = conf-msw.h conf-os2.h conf-dos.h \ conf-vms.h conf-mac.h conf-inf.h types.h macros.h pack1.h \ - unpack.h Types.hpp Hashable.hpp Uncopyable.hpp RefCounted.hpp \ - Exception.hpp Cstr.hpp + unpack.h Types.hpp Growable.hpp Hashable.hpp Uncopyable.hpp \ + RefCounted.hpp Exception.hpp Cstr.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/RefCounted.hpp b/qse/include/qse/RefCounted.hpp index 25b93017..a59da055 100644 --- a/qse/include/qse/RefCounted.hpp +++ b/qse/include/qse/RefCounted.hpp @@ -27,6 +27,11 @@ #ifndef _QSE_REFCOUNTED_HPP_ #define _QSE_REFCOUNTED_HPP_ + +/// \file +/// Defines a class that can be used to implement a class of a reference +/// counted object. + #include ///////////////////////////////// diff --git a/qse/include/qse/Types.hpp b/qse/include/qse/Types.hpp index 1e14e8f3..da9f98b5 100644 --- a/qse/include/qse/Types.hpp +++ b/qse/include/qse/Types.hpp @@ -31,7 +31,7 @@ #include /// \file -/// This file defines a class containg aliases to various QSE types. +/// 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 b772bb82..a3f59644 100644 --- a/qse/include/qse/Uncopyable.hpp +++ b/qse/include/qse/Uncopyable.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_UNCOPYABLE_HPP_ #define _QSE_UNCOPYABLE_HPP_ +/// \file +/// Provides the Uncopyable class. + #include #include diff --git a/qse/include/qse/cmn/Array.hpp b/qse/include/qse/cmn/Array.hpp index f348b983..d5391cf6 100644 --- a/qse/include/qse/cmn/Array.hpp +++ b/qse/include/qse/cmn/Array.hpp @@ -27,7 +27,7 @@ #ifndef _QSE_CMN_ARRAY_HPP_ #define _QSE_CMN_ARRAY_HPP_ -#include +#include #include ///////////////////////////////// @@ -45,15 +45,22 @@ struct ArrayPositioner struct ArrayResizer { - qse_size_t operator() (qse_size_t current) const + qse_size_t operator() (qse_size_t current, const GrowthPolicy* gp) const { if (current <= 0) current = 1; - return (current < 5000)? (current + current): - (current < 50000)? (current + (current / 2)): - (current < 100000)? (current + (current / 4)): - (current < 150000)? (current + (current / 8)): - (current + (current / 16)); + if (gp) + { + return gp->getNewSize (current); + } + else + { + return (current < 5000)? (current + current): + (current < 50000)? (current + (current / 2)): + (current < 100000)? (current + (current / 4)): + (current < 150000)? (current + (current / 8)): + (current + (current / 16)); + } } }; @@ -61,7 +68,7 @@ struct ArrayResizer /// The Array class provides a dynamically resized array. /// template , typename RESIZER = ArrayResizer > -class Array: public Mmged +class Array: public Mmged, public Growable { public: typedef Array SelfType; @@ -152,7 +159,7 @@ protected: { // copy-construct each element. new((QSE::Mmgr*)QSE_NULL, &tmp[index]) T(srcbuf[index]); - this->positioner (tmp[index], index); + this->_positioner (tmp[index], index); } } catch (...) @@ -162,7 +169,7 @@ protected: while (index > 0) { --index; - this->positioner (tmp[index], INVALID_INDEX); + this->_positioner (tmp[index], INVALID_INDEX); tmp[index].~T (); } ::operator delete (tmp, this->getMmgr()); @@ -179,13 +186,13 @@ protected: // no value exists in the given position. // i can copy-construct the value. new((QSE::Mmgr*)QSE_NULL, &this->buffer[index]) T(value); - this->positioner (this->buffer[index], index); + this->_positioner (this->buffer[index], index); } else { // there is an old value in the position. this->buffer[index] = value; - this->positioner (this->buffer[index], index); + this->_positioner (this->buffer[index], index); } } @@ -196,7 +203,7 @@ protected: for (qse_size_t i = this->count; i > 0; ) { --i; - this->positioner (this->buffer[i], INVALID_INDEX); + this->_positioner (this->buffer[i], INVALID_INDEX); this->buffer[i].~T (); } @@ -251,7 +258,7 @@ public: /// const int& t = a[2]; /// printf ("%lu\n", (unsigned long int)a.getIndex(t)); // print 2 /// \endcode - qse_size_t getIndex (const T& v) + qse_size_t getIndex (const T& v) const { if (&v >= &this->buffer[0] && &v < &this->buffer[this->count]) { @@ -308,7 +315,7 @@ public: { // the position to add the element is beyond the // capacity. resize the buffer. - qse_size_t new_capa = this->resizer (this->capacity); + qse_size_t new_capa = this->_resizer (this->capacity, this->getGrowthPolicy()); if (index < new_capa) this->setCapacity (new_capa); @@ -319,7 +326,7 @@ public: { // the array is already full. // insertion requires at least one more slot - qse_size_t new_capa = this->resizer (this->capacity); + qse_size_t new_capa = this->_resizer (this->capacity, this->getGrowthPolicy()); this->setCapacity (new_capa); } @@ -339,7 +346,7 @@ public: for (qse_size_t i = this->count; i < index; i++) { new((QSE::Mmgr*)QSE_NULL, &this->buffer[i]) T(); - this->positioner (this->buffer[i], i); + this->_positioner (this->buffer[i], i); } } @@ -355,7 +362,7 @@ public: { QSE_ASSERT (index < this->count); this->buffer[index] = value; - this->positioner (this->buffer[index], index); + this->_positioner (this->buffer[index], index); return index; } @@ -396,14 +403,14 @@ public: // 2. operator assignment. // 1. destruct followed by copy construct - //this->positioner (this->buffer[j], INVALID_INDEX); + //this->_positioner (this->buffer[j], INVALID_INDEX); //this->buffer[j].~T(); //new((QSE::Mmgr*)QSE_NULL, &this->buffer[j]) T(this->buffer[i]); - //this->positioner (this->buffer[j], j); + //this->_positioner (this->buffer[j], j); // 2. operator assignment this->buffer[j] = this->buffer[i]; - this->positioner (this->buffer[j], j); + this->_positioner (this->buffer[j], j); j++; i++; } @@ -411,7 +418,7 @@ public: // call the destructor of deleted elements. while (j < this->count) { - this->positioner (this->buffer[j], INVALID_INDEX); + this->_positioner (this->buffer[j], INVALID_INDEX); this->buffer[j].~T (); j++; } @@ -463,7 +470,7 @@ public: for (qse_size_t i = size; i < this->count; ++i) { // call the destructor of the items - this->positioner (this->buffer[i], INVALID_INDEX); + this->_positioner (this->buffer[i], INVALID_INDEX); this->buffer[i].~T (); } @@ -476,7 +483,7 @@ public: { // use the default contructor to set the value. new((QSE::Mmgr*)QSE_NULL, &this->buffer[i]) T(); - this->positioner (this->buffer[i], i); + this->_positioner (this->buffer[i], i); } this->count = size; @@ -514,7 +521,7 @@ public: } } - // The compact() function + /// The compact() function removes the unused space in the buffer. void compact () { this->setCapacity (this->size); @@ -581,25 +588,25 @@ public: while (index < nk) { this->buffer[index] = this->buffer[index + n]; - this->positioner (this->buffer[index], index); + this->_positioner (this->buffer[index], index); index += n; } if (index == last) break; this->buffer[index] = this->buffer[index - nk]; - this->positioner (this->buffer[index], index); + this->_positioner (this->buffer[index], index); index -= nk; } this->buffer[last] = c; - this->positioner (this->buffer[last], last); + this->_positioner (this->buffer[last], last); first++; } } protected: - POSITIONER positioner; - RESIZER resizer; + POSITIONER _positioner; + RESIZER _resizer; qse_size_t count; qse_size_t capacity; diff --git a/qse/include/qse/cmn/BinaryHeap.hpp b/qse/include/qse/cmn/BinaryHeap.hpp index 38fc3f0a..047f5a7e 100644 --- a/qse/include/qse/cmn/BinaryHeap.hpp +++ b/qse/include/qse/cmn/BinaryHeap.hpp @@ -27,10 +27,48 @@ #ifndef _QSE_CMN_BINARYHEAP_HPP_ #define _QSE_CMN_BINARYHEAP_HPP_ +/// \file +/// Provides a binary heap implementation. /// -/// This file provides a binary heap implementation. -/// In the heap, each node is greater than or equal to its BinaryHeap +/// \includelineno bh01.cpp +/// + +#include + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +// greater-than comparator +template +struct BinaryHeapComparator +{ + // this can be used to build a max heap + bool operator() (const T& v1, const T& v2) const + { + return v1 > v2; + } +}; + +template +struct BinaryHeapPositioner +{ + void operator() (T& v, qse_size_t index) const + { + // do nothing + } +}; + +typedef ArrayResizer BinaryHeapResizer; + +#define QSE_BINARY_HEAP_UP(x) (((x) - 1) / 2) +#define QSE_BINARY_HEAP_LEFT(x) ((x) * 2 + 1) +#define QSE_BINARY_HEAP_RIGHT(x) ((x) * 2 + 2) + /// +/// The BinaryHeap class is a template class that implements a binary heap. +/// +/// \code /// #include /// #include /// @@ -66,40 +104,8 @@ /// /// return 0; /// } -/// - -#include - -///////////////////////////////// -QSE_BEGIN_NAMESPACE(QSE) -///////////////////////////////// - -// greater-than comparator -template -struct BinaryHeapComparator -{ - // this can be used to build a max heap - bool operator() (const T& v1, const T& v2) const - { - return v1 > v2; - } -}; - -template -struct BinaryHeapPositioner -{ - void operator() (T& v, qse_size_t index) const - { - // do nothing - } -}; - -typedef ArrayResizer BinaryHeapResizer; - -#define QSE_BINARY_HEAP_UP(x) (((x) - 1) / 2) -#define QSE_BINARY_HEAP_LEFT(x) ((x) * 2 + 1) -#define QSE_BINARY_HEAP_RIGHT(x) ((x) * 2 + 2) - +/// \endcode +/// template , typename POSITIONER = BinaryHeapPositioner, typename RESIZER = BinaryHeapResizer > class BinaryHeap: protected Array { @@ -117,13 +123,11 @@ public: INVALID_INDEX = ParentType::INVALID_INDEX }; - BinaryHeap (qse_size_t capacity = DEFAULT_CAPACITY): - ParentType (QSE_NULL, capacity) + BinaryHeap (qse_size_t capacity = DEFAULT_CAPACITY): ParentType (QSE_NULL, capacity) { } - BinaryHeap (Mmgr* mmgr, qse_size_t capacity = DEFAULT_CAPACITY): - ParentType (mmgr, capacity) + BinaryHeap (Mmgr* mmgr, qse_size_t capacity = DEFAULT_CAPACITY): ParentType (mmgr, capacity) { } @@ -144,23 +148,42 @@ public: return *this; } - using ParentType::isEmpty; - using ParentType::getSize; - using ParentType::getCapacity; - using ParentType::getIndex; - using ParentType::clear; - using ParentType::compact; + /// The isEmpty() function returns true if the binary heap contains no + /// item and false otherwise. + bool isEmpty() const { return ParentType::isEmpty(); } + /// The getSize() function returns the number of items in the binary heap. + qse_size_t getSize() const { return ParentType::getSize(); } + + /// The getCapacity() function returns the capacity of the internal buffer + /// of the binary heap. + qse_size_t getCapacity() const { return ParentType::getCapacity(); } + + /// The getIndex() function returns the index of an item reference \a v. + qse_size_t getIndex (const T& v) const { return ParentType::getIndex(v); } + + /// The clear() function returns all items. + void clear (bool purge_buffer = false) { ParentType::clear (purge_buffer); } + + /// The compact() function restructures the internal buffer to the size + /// that is just large enough to hold the existing items. + void compact() { ParentType::compact (); } + + /// The operator[] function returns the constant reference to the item + /// at the specified \a index. const T& operator[] (qse_size_t index) const { return ParentType::getValueAt (index); } + /// The getValueAt() function returns the constant reference to the item + /// at the specified \a index. const T& getValueAt (qse_size_t index) const { return ParentType::getValueAt (index); } + /// The insert() function adds a new item \a value to the binary heap. qse_size_t insert (const T& value) { qse_size_t index = this->count; @@ -172,6 +195,8 @@ public: return this->sift_up(index); } + /// The update() function changes the item at the specified \a index + /// to a new item \a value. qse_size_t update (qse_size_t index, const T& value) { T old = this->buffer[index]; @@ -181,6 +206,7 @@ public: return (this->greater_than(value, old))? this->sift_up(index): this->sift_down(index); } + /// The remove() function removes an item at the specified \a index. void remove (qse_size_t index) { QSE_ASSERT (index < this->count); diff --git a/qse/include/qse/cmn/HashList.hpp b/qse/include/qse/cmn/HashList.hpp index c6ee4f45..e21def12 100644 --- a/qse/include/qse/cmn/HashList.hpp +++ b/qse/include/qse/cmn/HashList.hpp @@ -27,7 +27,11 @@ #ifndef _QSE_CMN_HASHLIST_HPP_ #define _QSE_CMN_HASHLIST_HPP_ +/// \file +/// Provides a hash list template class. + #include +#include #include ///////////////////////////////// @@ -54,13 +58,22 @@ struct HashListEqualer struct HashListResizer { - qse_size_t operator() (qse_size_t current) const + qse_size_t operator() (qse_size_t current, const GrowthPolicy* gp) const { - return (current < 5000)? (current + current): - (current < 50000)? (current + (current / 2)): - (current < 100000)? (current + (current / 4)): - (current < 150000)? (current + (current / 8)): - (current + (current / 16)); + if (current <= 0) current = 1; + + if (gp) + { + return gp->getNewSize (current); + } + else + { + return (current < 5000)? (current + current): + (current < 50000)? (current + (current / 2)): + (current < 100000)? (current + (current / 4)): + (current < 150000)? (current + (current / 8)): + (current + (current / 16)); + } } }; @@ -77,7 +90,7 @@ struct HashListResizer /// this->nodes[hc * 2 + 1] ponits to the last node. template , typename EQUALER = HashListEqualer, typename RESIZER = HashListResizer > -class HashList: public Mmged +class HashList: public Mmged, public Growable { public: typedef LinkedList DatumList; @@ -313,7 +326,7 @@ protected: qse_size_t hc, head, tail; Node* np; - hc = this->hasher(datum) % this->node_capacity; + hc = this->_hasher(datum) % this->node_capacity; head = hc << 1; tail = head + 1; np = this->nodes[head]; @@ -322,7 +335,7 @@ protected: do { T& t = np->value; - if (this->equaler (datum, t)) return np; + if (this->_equaler (datum, t)) return np; if (np == this->nodes[tail]) break; np = np->getNextNode (); } @@ -450,7 +463,7 @@ public: qse_size_t hc, head, tail; Node* np; - hc = this->hasher(datum) % this->node_capacity; + hc = this->_hasher(datum) % this->node_capacity; head = hc << 1; tail = head + 1; np = this->nodes[head]; @@ -459,7 +472,7 @@ public: do { T& t = np->value; - if (this->equaler (datum, t)) + if (this->_equaler (datum, t)) { if (injected) *injected = false; if (mode <= -1) return QSE_NULL; // failure @@ -476,7 +489,7 @@ public: if (datum_list->getSize() >= threshold) { this->rehash (); - hc = this->hasher(datum) % this->node_capacity; + hc = this->_hasher(datum) % this->node_capacity; head = hc << 1; tail = head + 1; } @@ -521,7 +534,7 @@ public: qse_size_t hc, head, tail; Node* np; - hc = this->hasher(datum) % this->node_capacity; + hc = this->_hasher(datum) % this->node_capacity; head = hc << 1; tail = head + 1; np = this->nodes[head]; @@ -530,7 +543,7 @@ public: do { T& t = np->value; - if (this->equaler (datum, t)) + if (this->_equaler (datum, t)) { if (this->nodes[head] == this->nodes[tail]) { @@ -602,31 +615,36 @@ public: this->datum_list->clear (clear_mpool); } - /// The getIterator() function returns an interator. /// - /// \code - /// struct IntHasher - /// { - /// qse_size_t operator() (int v) { return v; } - /// }; - /// typedef QSE::HashList IntList; + /// The getIterator() function returns an iterator. You can use + /// the iterator to loop over items in the hash list. /// - /// IntList hl; - /// IntList::Iterator it; + /// \code{.cpp} + /// struct IntHasher + /// { + /// qse_size_t operator() (int v) { return v; } + /// }; + /// typedef QSE::HashList IntList; /// - /// hl.insert (10); - /// hl.insert (150); - /// hl.insert (200); - /// for (it = hl.getIterator(); it.isLegit(); it++) - /// { - /// printf ("%d\n", *it); - /// } + /// IntList hl; + /// IntList::Iterator it; + /// + /// hl.insert (10); + /// hl.insert (150); + /// hl.insert (200); + /// for (it = hl.getIterator(); it.isLegit(); it++) + /// { + /// printf ("%d\n", *it); + /// } /// \endcode + /// Iterator getIterator (qse_size_t index = 0) { return this->datum_list->getIterator (index); } + /// The getConstIterator() function returns an iterator that emits the + /// constant reference to an item. ConstIterator getConstIterator (qse_size_t index = 0) const { return this->datum_list->getConstIterator (index); @@ -639,9 +657,9 @@ protected: mutable qse_size_t threshold; qse_size_t load_factor; - HASHER hasher; - EQUALER equaler; - RESIZER resizer; + HASHER _hasher; + EQUALER _equaler; + RESIZER _resizer; void rehash () { @@ -653,8 +671,8 @@ protected: // Using the memory pool block size of 0 is OK because the nodes // to be inserted are yielded off the original list and inserted // without new allocation. - //SelfType temp (this->getMmgr(), this->resizer(this->node_capacity), this->load_factor, mpool.getBlockSize()); - SelfType temp (this->getMmgr(), this->resizer(this->node_capacity), this->load_factor, 0); + //SelfType temp (this->getMmgr(), this->_resizer(this->node_capacity), this->load_factor, mpool.getBlockSize()); + SelfType temp (this->getMmgr(), this->_resizer(this->node_capacity, this->getGrowthPolicy()), this->load_factor, 0); Node* p = this->datum_list->getHeadNode(); while (p) { @@ -668,7 +686,7 @@ protected: // get the hash code using the new capacity qse_size_t hc, head, tail; - hc = this->hasher(pp->value) % temp.node_capacity; + hc = this->_hasher(pp->value) % temp.node_capacity; head = hc << 1; tail = head + 1; // insert the detached node to the new temporary list @@ -726,7 +744,7 @@ protected: { T& t = np->value; - qse_size_t hc = this->hasher(t) % new_node_capa; + qse_size_t hc = this->_hasher(t) % new_node_capa; qse_size_t head = hc << 1; qse_size_t tail = head + 1; diff --git a/qse/include/qse/cmn/HashTable.hpp b/qse/include/qse/cmn/HashTable.hpp index e0571077..e00087f5 100644 --- a/qse/include/qse/cmn/HashTable.hpp +++ b/qse/include/qse/cmn/HashTable.hpp @@ -27,6 +27,10 @@ #ifndef _QSE_CMN_HASHTABLE_HPP_ #define _QSE_CMN_HASHTABLE_HPP_ +/// \file +/// Provides a hash table template class. + + #include #include diff --git a/qse/include/qse/cmn/Mpool.hpp b/qse/include/qse/cmn/Mpool.hpp index 144078e9..7fa21660 100644 --- a/qse/include/qse/cmn/Mpool.hpp +++ b/qse/include/qse/cmn/Mpool.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_CMN_MPOOL_HPP_ #define _QSE_CMN_MPOOL_HPP_ +/// \file +/// Provides the Mpool class. + #include #include @@ -34,9 +37,10 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// -// -// allocator for fixed-size data -// +/// +/// The Mpool class implements an memory allocator for fixed-sized data. +/// It is similar to #qse_fma_t in functionality. +/// class QSE_EXPORT Mpool: public Uncopyable, public Mmged { @@ -52,8 +56,14 @@ public: qse_size_t block_size = DEFAULT_BLOCK_SIZE); ~Mpool (); + /// The allocate() function returns the pointer to the memory chunk of the + /// configured datum size. It returns #QSE_NULL upon failure. void* allocate (); + + /// The dispose() function frees the memory chunk pointed to by \a ptr. void dispose (void* ptr); + + /// The dispose() function frees all memory chunks allocated in the pool. void dispose (); bool isEnabled () const diff --git a/qse/include/qse/cmn/RedBlackTable.hpp b/qse/include/qse/cmn/RedBlackTable.hpp index 2d249e3a..14cdf582 100644 --- a/qse/include/qse/cmn/RedBlackTable.hpp +++ b/qse/include/qse/cmn/RedBlackTable.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_CMN_REDBLACKTABLE_HPP_ #define _QSE_CMN_REDBLACKTABLE_HPP_ +/// \file +/// Provides the RedBlackTable class. + #include #include @@ -48,6 +51,10 @@ struct RedBlackTableComparator }; +/// +/// The RedBlackTable class extends the RedBlackTree class to maintain the +/// pair of a key and a value. +/// template > class RedBlackTable: public Mmged { diff --git a/qse/include/qse/cmn/RedBlackTree.hpp b/qse/include/qse/cmn/RedBlackTree.hpp index 7c6046d5..1ad53f4b 100644 --- a/qse/include/qse/cmn/RedBlackTree.hpp +++ b/qse/include/qse/cmn/RedBlackTree.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_CMN_REDBLACKTREE_HPP_ #define _QSE_CMN_REDBLACKTREE_HPP_ +/// \file +/// Provides the RedBlackTree class. + #include #include @@ -300,7 +303,7 @@ protected: }; -/// +/// The RedBlackTree class implements the red-black tree data structure. /// /// A node is either red or black. /// The root is black. @@ -308,6 +311,8 @@ protected: /// Every red node must have two black child nodes. /// Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes. /// +/// \sa RedBlackTable, qse_rbt_t +/// template > class RedBlackTree: public Mmged { diff --git a/qse/include/qse/cmn/ScopedPtr.hpp b/qse/include/qse/cmn/ScopedPtr.hpp index 7828bdc1..4d1c002f 100644 --- a/qse/include/qse/cmn/ScopedPtr.hpp +++ b/qse/include/qse/cmn/ScopedPtr.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_CMN_SCOPEDPTR_HPP_ #define _QSE_CMN_SCOPEDPTR_HPP_ +/// \file +/// Provides the ScopedPtr template class. + #include #include diff --git a/qse/include/qse/cmn/SharedPtr.hpp b/qse/include/qse/cmn/SharedPtr.hpp index 838f5cc1..98b3e895 100644 --- a/qse/include/qse/cmn/SharedPtr.hpp +++ b/qse/include/qse/cmn/SharedPtr.hpp @@ -27,6 +27,9 @@ #ifndef _QSE_CMN_SHAREDPTR_HPP_ #define _QSE_CMN_SHAREDPTR_HPP_ +/// \file +/// Provides the SharedPtr template class. + #include #include diff --git a/qse/include/qse/cmn/StrBase.hpp b/qse/include/qse/cmn/StrBase.hpp index c6438904..d13e4e92 100644 --- a/qse/include/qse/cmn/StrBase.hpp +++ b/qse/include/qse/cmn/StrBase.hpp @@ -27,7 +27,9 @@ #ifndef _QSE_CMN_STRBASE_HPP_ #define _QSE_CMN_STRBASE_HPP_ + #include +#include #include #include @@ -45,7 +47,7 @@ protected: typedef StrBaseData SelfType; - StrBaseData (Mmgr* mmgr, qse_size_t capacity, const CHAR_TYPE* str, qse_size_t offset, qse_size_t size): + StrBaseData (Mmgr* mmgr, qse_size_t capacity, const CHAR_TYPE* str, qse_size_t size): buffer (QSE_NULL) // set buffer to QSE_NULL here in case operator new rasises an exception { if (capacity < size) capacity = size; @@ -59,7 +61,7 @@ protected: //} this->capacity = capacity; - this->size = this->opset.copy (this->buffer, str + offset, size); + this->size = this->opset.copy (this->buffer, str, size); QSE_ASSERT (this->size == size); } @@ -91,12 +93,12 @@ public: protected: SelfType* copy (Mmgr* mmgr) { - return new(mmgr) SelfType (mmgr, this->capacity, this->buffer, 0, this->size); + return new(mmgr) SelfType (mmgr, this->capacity, this->buffer, this->size); } SelfType* copy (Mmgr* mmgr, qse_size_t capacity) { - return new(mmgr) SelfType (mmgr, capacity, this->buffer, 0, this->size); + return new(mmgr) SelfType (mmgr, capacity, this->buffer, this->size); } #if 0 @@ -127,15 +129,22 @@ protected: struct StrBaseResizer { - qse_size_t operator() (qse_size_t current, qse_size_t desired) const + qse_size_t operator() (qse_size_t current, qse_size_t desired, const GrowthPolicy* gp) const { qse_size_t new_size; - new_size = (current < 5000)? (current + current): - (current < 50000)? (current + (current / 2)): - (current < 100000)? (current + (current / 4)): - (current < 150000)? (current + (current / 8)): - (current + (current / 16)); + if (gp) + { + new_size = gp->getNewSize (current); + } + else + { + new_size = (current < 5000)? (current + current): + (current < 50000)? (current + (current / 2)): + (current < 100000)? (current + (current / 4)): + (current < 150000)? (current + (current / 8)): + (current + (current / 16)); + } if (new_size < desired) new_size = desired; return new_size; @@ -143,7 +152,7 @@ struct StrBaseResizer }; template -class StrBase: public Mmged, public Hashable +class StrBase: public Mmged, public Hashable, public Growable { public: enum @@ -152,75 +161,58 @@ public: INVALID_INDEX = ~(qse_size_t)0 }; -/* - class GrowthPolicy - { - public: - enum Type - { - ABSOLUTE, - PERCENT - }; - - GrowthPolicy (Type type = ABSOLUTE, qse_size_t value = 0): type (type), value (value) {} - - Type type; - qse_size_t value; - }; -*/ - typedef StrBase SelfType; typedef StrBaseData StringItem; /// The StrBase() function creates an empty string with the default memory manager. StrBase (): Mmged(QSE_NULL) { - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(DEFAULT_CAPACITY), QSE_NULL, 0, 0); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(DEFAULT_CAPACITY), (const CHAR_TYPE*)QSE_NULL, 0); this->ref_item (); } /// The StrBase() function creates an empty string with a memory manager \a mmgr. StrBase (Mmgr* mmgr): Mmged(mmgr) { - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(DEFAULT_CAPACITY), QSE_NULL, 0, 0); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(DEFAULT_CAPACITY), (const CHAR_TYPE*)QSE_NULL, 0); this->ref_item (); } StrBase (qse_size_t capacity): Mmged(QSE_NULL) { - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(capacity), QSE_NULL, 0, 0); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(capacity), (const CHAR_TYPE*)QSE_NULL, 0); this->ref_item (); } StrBase (Mmgr* mmgr, qse_size_t capacity): Mmged(mmgr) { - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(capacity), QSE_NULL, 0, 0); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(capacity), (const CHAR_TYPE*)QSE_NULL, 0); this->ref_item (); } StrBase (const CHAR_TYPE* str): Mmged(QSE_NULL) { - qse_size_t len = this->opset.getLength(str); - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(len), str, 0, len); + qse_size_t len = this->_opset.getLength(str); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(len), str, len); this->ref_item (); } StrBase (Mmgr* mmgr, const CHAR_TYPE* str): Mmged(mmgr) { qse_size_t len = this->_opset.getLength(str); - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(len), str, 0, len); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(len), str, len); this->ref_item (); } - StrBase (const CHAR_TYPE* str, qse_size_t offset, qse_size_t size): Mmged(QSE_NULL) + StrBase (const CHAR_TYPE* str, qse_size_t size): Mmged(QSE_NULL) { - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(size), str, offset, size); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(size), str, size); this->ref_item (); } - StrBase (Mmgr* mmgr, const CHAR_TYPE* str, qse_size_t offset, qse_size_t size): Mmged(mmgr) + StrBase (Mmgr* mmgr, const CHAR_TYPE* str, qse_size_t size): Mmged(mmgr) { - this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(size), str, offset, size); + this->_item = new(this->getMmgr()) StringItem (this->getMmgr(), this->round_capacity(size), str, size); this->ref_item (); } @@ -264,7 +256,6 @@ public: return *this; } -#if 0 SelfType& operator= (const CHAR_TYPE* str) { if (this->_item->buffer != str) @@ -278,10 +269,9 @@ public: SelfType& operator= (const CHAR_TYPE c) { this->clear (); - this->insert (0, &c, 0, 1); + this->insert (0, &c, 1); return *this; } -#endif protected: void ref_item () const @@ -312,6 +302,14 @@ protected: this->ref_item (); } + void possess_data (qse_size_t capacity) const + { + StringItem* t = this->_item->copy (this->getMmgr(), capacity); + this->deref_item (); + this->_item = t; + this->ref_item (); + } + public: qse_size_t getSize () const @@ -390,11 +388,23 @@ public: this->_item->buffer[index] = c; } + SelfType getSubstring (qse_size_t index) const + { + QSE_ASSERT (index < this->_item->size); + return SelfType (this->_item->buffer + index, this->_item->size - index); + } + + SelfType getSubstring (qse_size_t index, qse_size_t size) const + { + QSE_ASSERT (index + size <= this->_item->size); + return SelfType (this->_item->buffer + index, size); + } + // // TODO: comparison, hash, trim, case-converting, etc // utf-8 encoding/decoding // - void insert (qse_size_t index, const CHAR_TYPE* str, qse_size_t offset, qse_size_t size) + void insert (qse_size_t index, const CHAR_TYPE* str, qse_size_t size) { if (size <= 0) return; if (index >= this->_item->size) index = this->_item->size; @@ -404,8 +414,7 @@ public: // finally calls n.insert(index. n.this->_item->buffer, 0, n.this->_item->size), // if n is not shared and should be copied, calling deref to it // immediately after it's copied will destroy n.data refered to by - // str/offset/size. So the deref must be called after copying is - // done. + // str/size. So the deref must be called after copying is done. // StringItem* old_item = QSE_NULL; @@ -434,7 +443,7 @@ public: CHAR_TYPE* p = this->_item->buffer + index; this->_opset.move (p + size, p, this->_item->size - index); - this->_opset.move (p, str + offset, size); + this->_opset.move (p, str, size); this->_item->buffer[new_size] = NULL_CHAR; this->_item->size = new_size; @@ -443,28 +452,28 @@ public: void insert (qse_size_t index, const CHAR_TYPE* str) { - this->insert (index, str, 0, this->_opset.getLength(str)); + this->insert (index, str, this->_opset.getLength(str)); } void insert (qse_size_t index, const CHAR_TYPE c) { - this->insert (index, &c, 0, 1); + this->insert (index, &c, 1); } void insert (qse_size_t index, const SelfType& str, qse_size_t offset, qse_size_t size) { QSE_ASSERT (offset + size <= str._item->size); - this->insert (index, str._item->buffer, offset, size); + this->insert (index, str._item->buffer + offset, size); } void insert (qse_size_t index, const SelfType& str) { - this->insert (index, str._item->buffer, 0, str._item->size); + this->insert (index, str._item->buffer, str._item->size); } - void prepend (const CHAR_TYPE* str, qse_size_t offset, qse_size_t size) + void prepend (const CHAR_TYPE* str, qse_size_t size) { - this->insert (0, str, offset, size); + this->insert (0, str, size); } void prepend (const CHAR_TYPE* str) @@ -487,9 +496,9 @@ public: this->insert (0, str); } - void append (const CHAR_TYPE* str, qse_size_t offset, qse_size_t size) + void append (const CHAR_TYPE* str, qse_size_t size) { - this->insert (this->_item->size, str, offset, size); + this->insert (this->_item->size, str, size); } void append (const CHAR_TYPE* str) @@ -514,7 +523,7 @@ public: SelfType& operator+= (const SelfType& str) { - this->insert (this->_item->size, str._item->buffer, 0, str._item->size); + this->insert (this->_item->size, str._item->buffer, str._item->size); return *this; } @@ -526,7 +535,7 @@ public: SelfType& operator+= (const CHAR_TYPE c) { - this->insert (this->_item->size, &c, 0, 1); + this->insert (this->_item->size, &c, 1); return *this; } @@ -561,14 +570,17 @@ public: int n; qse_va_list save_ap; - if (this->_item->isShared()) + if (this->_item->isShared()) this->possess_data (); + + qse_size_t n = this->_opset.format (QSE_NULL, 0, fmt, ap); + if (n == (qse_size_t)-1) { - StringItem* t = this->_item->copy (); - this->_item->deref (); this->_item = t; this->_item->ref (); + // there's conversion error. + ???? } qse_va_copy (save_ap, ap); - while ((n = SelfType::opset.vsprintf (&this->_item->buffer[this->_item->size], this->_item->capacity - this->_item->size, fmt, ap)) <= -1) + while ((n = this->_opset.format (&this->_item->buffer[this->_item->size], this->_item->capacity - this->_item->size, fmt, ap)) <= -1) { this->_item->growBy (calc_new_inc_for_growth (0)); qse_va_copy (ap, save_ap); @@ -576,14 +588,12 @@ public: this->_item->size += n; } - #endif - - void update (const CHAR_TYPE* str, qse_size_t offset, qse_size_t size) + void update (const CHAR_TYPE* str, qse_size_t size) { this->clear (); - this->insert (0, str, offset, size); + this->insert (0, str, size); } /// The update() function updates the entire string by copying a new @@ -613,65 +623,70 @@ public: /// The update() function replaces a \a size substring staring from the \a offset /// with a new \a ssize string pointed to by \a str starign from the \a soffset. - void update (qse_size_t offset, qse_size_t size, const CHAR_TYPE* str, qse_size_t soffset, qse_size_t ssize) + void update (qse_size_t index, qse_size_t size, const CHAR_TYPE* str, qse_size_t ssize) { - this->remove (offset, size); - this->insert (offset, str, soffset, ssize); + this->remove (index, size); + this->insert (index, str, ssize); } - void update (qse_size_t offset, qse_size_t size, const CHAR_TYPE* str) + void update (qse_size_t index, qse_size_t size, const CHAR_TYPE* str) { - this->remove (offset, size); - this->insert (offset, str, 0, this->_opset.getLength(str)); + this->remove (index, size); + this->insert (index, str, this->_opset.getLength(str)); } - void update (qse_size_t offset, qse_size_t size, const SelfType& str, qse_size_t soffset, qse_size_t ssize) + void update (qse_size_t index, qse_size_t size, const SelfType& str, qse_size_t soffset, qse_size_t ssize) { - this->remove (offset, size); - this->insert (offset, str, soffset, ssize); + this->remove (index, size); + this->insert (index, str, soffset, ssize); } - void update (qse_size_t offset, qse_size_t size, const SelfType& str) + void update (qse_size_t index, qse_size_t size, const SelfType& str) { - this->remove (offset, size); - this->insert (offset, str); + this->remove (index, size); + this->insert (index, str); } - void remove (qse_size_t offset, qse_size_t size) + void remove (qse_size_t index, qse_size_t size) { if (size <= 0) return; - if (offset >= this->_item->size) return; - if (size > this->_item->size - offset) size = this->_item->size - offset; + if (index >= this->_item->size) return; + if (size > this->_item->size - index) size = this->_item->size - index; if (this->_item->isShared()) this->possess_data (); - CHAR_TYPE* p = this->_item->buffer + offset; + CHAR_TYPE* p = this->_item->buffer + index; // +1 for the terminating null. - this->_opset.move (p, p + size, this->_item->size - offset - size + 1); + this->_opset.move (p, p + size, this->_item->size - index - size + 1); this->_item->size -= size; } - void remvoe () - { - this->remove (0, this->_item->size); - } - void clear () { this->remove (0, this->_item->size); } - - void invert (qse_size_t offset, qse_size_t size) + /// The compact() function compacts the internal buffer to the length of + /// the actual string. + void compact () { - QSE_ASSERT (offset + size <= this->_item->size); + if (this->getSize() < this->getCapacity()) + { + // call possess_data() regardless of this->_item->isShared() + this->possess_data (this->getSize()); + } + } + + void invert (qse_size_t index, qse_size_t size) + { + QSE_ASSERT (index + size <= this->_item->size); if (this->_item->isShared()) this->possess_data (); CHAR_TYPE c; - qse_size_t i = offset + size; - for (qse_size_t j = offset; j < --i; j++) + qse_size_t i = index + size; + for (qse_size_t j = index; j < --i; j++) { c = this->_item->buffer[j]; this->_item->buffer[j] = this->_item->buffer[i]; @@ -684,18 +699,6 @@ public: this->invert (0, this->_item->size); } - SelfType getSubstring (qse_size_t offset) const - { - QSE_ASSERT (offset < this->_item->size); - return SelfType (this->_item->buffer, offset, this->_item->size - offset); - } - - SelfType getSubstring (qse_size_t offset, qse_size_t size) const - { - QSE_ASSERT (offset + size <= this->_item->size); - return SelfType (this->_item->buffer, offset, size); - } - qse_size_t findIndex (qse_size_t index, const CHAR_TYPE* str, qse_size_t offset, qse_size_t size) const { if (size == 0) return index; @@ -749,6 +752,7 @@ public: return p1 - this->_item->buffer; } + qse_size_t findIndex (qse_size_t index, const CHAR_TYPE* str) const { return this->findIndex (index, str, 0, this->_opset.getLength(str)); @@ -896,8 +900,8 @@ public: return this->findLastIndex (this->_item->size - 1, c); } - /// The replace() function finds a substring \a str1 and replace it by - /// a new string \a str2. + /// The replace() function finds all occurrences of a substring \a str1 + /// and replace them by a new string \a str2. void replace (qse_size_t index, const CHAR_TYPE* str1, const CHAR_TYPE* str2) { qse_size_t len1 = this->_opset.getLength(str1); @@ -928,53 +932,43 @@ public: this->replace (0, str1, str2); } -#if 0 bool beginsWith (const CHAR_TYPE* str) const { - qse_size_t idx = 0; - while (*str != NULL_CHAR) - { - if (idx >= this->_item->size) return false; - if (this->_item->buffer[idx] != *str) return false; - idx++; str++; - } - return true; + return this->_opset.beginsWith(this->_item->buffer, this->_item->size, str); } bool beginsWith (const CHAR_TYPE* str, const qse_size_t len) const { - const CHAR_TYPE* end = str + len; - qse_size_t idx = 0; - - while (str < end) - { - if (idx >= this->_item->size) return false; - if (this->_item->buffer[idx] != *str) return false; - idx++; str++; - } - return true; + return this->_opset.beginsWith(this->_item->buffer, this->_item->size, str, len); } - qse_size_t touppercase () + bool endsWith (const CHAR_TYPE* str) const { - if (this->_item->isShared()) this->possess_data(); - return SelfType::touppercase (this->_item->buffer); + return this->_opset.endsWith(this->_item->buffer, this->_item->size, str); } - qse_size_t tolowercase () + bool endsWith (const CHAR_TYPE* str, const qse_size_t len) const + { + return this->_opset.endsWith(this->_item->buffer, this->_item->size, str, len); + } + + void trim () { if (this->_item->isShared()) this->possess_data (); - return SelfType::tolowercase (this->_item->buffer); + this->_item->size = this->_opset.trim(this->_item->buffer, this->_item->size, true, true); } - qse_size_t trim () + void trimLeft () { if (this->_item->isShared()) this->possess_data (); - this->_item->size = SelfType::trim (this->_item->buffer); - return this->_item->size; + this->_item->size = this->_opset.trim(this->_item->buffer, this->_item->size, true, false); } -#endif + void trimRight () + { + if (this->_item->isShared()) this->possess_data (); + this->_item->size = this->_opset.trim(this->_item->buffer, this->_item->size, false, true); + } protected: mutable StringItem* _item; @@ -989,38 +983,11 @@ private: ~((qse_size_t)DEFAULT_CAPACITY - (qse_size_t)1); } -#if 0 - qse_size_t calc_new_inc_for_growth (qse_size_t desired_inc) - { - qse_size_t inc ; - - - /* - switch (this->growth_policy.type) - { - case GrowthPolicy::PERCENT: - inc = (this->_item->size * this->growth_policy.value) / 100; - break; - - case GrowthPolicy::ABSOLUTE: - inc = this->growth_policy.value; - break; - - default: - inc = DEFAULT_CAPACITY; - break; - } - */ - - if (inc <= 0) inc = 1; - if (inc < desired_inc) inc = desired_inc; - return this->round_capacity (inc); - } -#endif - qse_size_t adjust_new_capacity (qse_size_t new_desired_capacity) { - return this->round_capacity(this->_resizer(this->_item->capacity, new_desired_capacity)); + qse_size_t new_capacity = this->_resizer(this->_item->capacity, new_desired_capacity, this->getGrowthPolicy()); + new_capacity = this->round_capacity(new_capacity); + return new_capacity; } }; diff --git a/qse/include/qse/cmn/String.hpp b/qse/include/qse/cmn/String.hpp index 3e1fe3f4..03a8d094 100644 --- a/qse/include/qse/cmn/String.hpp +++ b/qse/include/qse/cmn/String.hpp @@ -27,6 +27,12 @@ #ifndef _QSE_CMN_STRING_HPP_ #define _QSE_CMN_STRING_HPP_ +/// \file +/// Provides the String, WcString, McString classes. +/// +/// \includelineno str02.cpp +/// + #include #include #include @@ -63,19 +69,117 @@ struct WcStringOpset qse_size_t getLength (const qse_wchar_t* str) const { - return qse_strlen(str); + return qse_wcslen(str); + } + + bool beginsWith (const qse_wchar_t* str, qse_size_t len, const qse_wchar_t* sub) const + { + return qse_wcsxbeg (str, len, sub) != QSE_NULL; + } + + bool beginsWith (const qse_wchar_t* str, qse_size_t len, const qse_wchar_t* sub, qse_size_t sublen) const + { + return qse_wcsxnbeg (str, len, sub, sublen) != QSE_NULL; + } + + bool endsWith (const qse_wchar_t* str, qse_size_t len, const qse_wchar_t* sub) const + { + return qse_wcsxend (str, len, sub) != QSE_NULL; + } + + bool endsWith (const qse_wchar_t* str, qse_size_t len, const qse_wchar_t* sub, qse_size_t sublen) const + { + return qse_wcsxnend (str, len, sub, sublen) != QSE_NULL; + } + + qse_size_t trim (qse_wchar_t* str, qse_size_t len, bool left, bool right) const + { + qse_wchar_t* ptr; + qse_size_t xlen = len; + int flags = 0; + + if (left) flags |= QSE_WCSTRMX_LEFT; + if (right) flags |= QSE_WCSTRMX_RIGHT; + ptr = qse_wcsxtrmx (str, &xlen, flags); + this->move (str, ptr, xlen); + str[xlen] = QSE_WT('\0'); + + return xlen; } }; -//struct MbStringOpset -//{ -//}; +struct MbStringOpset +{ + qse_size_t copy (qse_mchar_t* dst, const qse_mchar_t* src, qse_size_t ssz) const + { + return qse_mbsncpy(dst, src, ssz); + } + + qse_size_t move (qse_mchar_t* dst, const qse_mchar_t* src, qse_size_t ssz) const + { + // this one doesn't insert terminating null + qse_memmove (dst, src, ssz * QSE_SIZEOF(*dst)); + return ssz; + } + + // compare two strings of the same length + int compare (const qse_mchar_t* str1, const qse_mchar_t* str2, qse_size_t len) const + { + return qse_mbsxncmp(str1, len, str2, len); + } + + // compare a length-bound string with a null-terminated string. + int compare (const qse_mchar_t* str1, qse_size_t len, const qse_mchar_t* str2) const + { + return qse_mbsxcmp(str1, len, str2); + } + + qse_size_t getLength (const qse_mchar_t* str) const + { + return qse_mbslen(str); + } + + bool beginsWith (const qse_mchar_t* str, qse_size_t len, const qse_mchar_t* sub) const + { + return qse_mbsxbeg (str, len, sub) != QSE_NULL; + } + + bool beginsWith (const qse_mchar_t* str, qse_size_t len, const qse_mchar_t* sub, qse_size_t sublen) const + { + return qse_mbsxnbeg (str, len, sub, sublen) != QSE_NULL; + } + + bool endsWith (const qse_mchar_t* str, qse_size_t len, const qse_mchar_t* sub) const + { + return qse_mbsxend (str, len, sub) != QSE_NULL; + } + + bool endsWith (const qse_mchar_t* str, qse_size_t len, const qse_mchar_t* sub, qse_size_t sublen) const + { + return qse_mbsxnend (str, len, sub, sublen) != QSE_NULL; + } + + qse_size_t trim (qse_mchar_t* str, qse_size_t len, bool left, bool right) const + { + qse_mchar_t* ptr; + qse_size_t xlen = len; + int flags = 0; + + if (left) flags |= QSE_MBSTRMX_LEFT; + if (right) flags |= QSE_MBSTRMX_RIGHT; + ptr = qse_mbsxtrmx (str, &xlen, flags); + this->move (str, ptr, xlen); + str[xlen] = QSE_MT('\0'); + + return xlen; + } +}; typedef StrBase WcString; -//typedef StrBase MbString; +typedef StrBase MbString; #if defined(QSE_CHAR_IS_MCHAR) - //typedef MbString String; + typedef MbString String; #else typedef WcString String; #endif diff --git a/qse/samples/cmn/str02.cpp b/qse/samples/cmn/str02.cpp index 2a788a6a..4189e2be 100644 --- a/qse/samples/cmn/str02.cpp +++ b/qse/samples/cmn/str02.cpp @@ -29,10 +29,54 @@ void t1 () //z->invert(); - qse_printf (QSE_T("[%s] [%c] capa=%d len=%d\n"), x.getBuffer(), x[0], (int)x.getCapacity(), (int)x.getLength()); - qse_printf (QSE_T("[%s] [%c] capa=%d len=%d\n"), z->getBuffer(), (*z)[0], (int)z->getCapacity(), (int)z->getLength()); + qse_printf (QSE_T("x: [%s] [%c] capa=%d len=%d\n"), x.getBuffer(), x[0u], (int)x.getCapacity(), (int)x.getLength()); + qse_printf (QSE_T("z: [%s] [%c] capa=%d len=%d\n"), z->getBuffer(), (*z)[0u], (int)z->getCapacity(), (int)z->getLength()); qse_printf (QSE_T("%d %d\n"), (int)z->findIndex (0, QSE_T("K")), (int)z->findLastIndex (0, QSE_T("K"))); + qse_printf (QSE_T("%d %d %d\n"), z->beginsWith (QSE_T("ok.ok")), z->beginsWith (QSE_T("ok.okX")), z->endsWith (QSE_T("string"))); + + //////////////////////////////////////////////////// + QSE::String t(QSE_T(" hello world good ")); + t.trim (); + QSE_ASSERT (t.getLength() == 20); + qse_printf (QSE_T("t: [%s] %d\n"), t.getBuffer(), t.getLength()); + + t = QSE_T(" come on and join me "); + QSE_ASSERT (t.getLength() == 24); + t.trimLeft (); + QSE_ASSERT (t.getLength() == 22); + qse_printf (QSE_T("t: [%s] %d\n"), t.getBuffer(), t.getLength()); + t = QSE_T(" come on and join me "); + t.trimRight (); + QSE_ASSERT (t.getLength() == 21); + qse_printf (QSE_T("t: [%s] %d\n"), t.getBuffer(), t.getLength()); + + //////////////////////////////////////////////////// + QSE::String q (z->getSubstring (4, 10)); + QSE_ASSERT (q.getLength() == 10); + QSE_ASSERT (q.getCharAt(0) == z->getCharAt(4)); + qse_printf (QSE_T("q: [%s] %d\n"), q.getBuffer(), q.getLength()); + q = z->getSubstring (z->getLength() - 5); + QSE_ASSERT (q.getLength() == 5); + qse_printf (QSE_T("q: [%s] %d\n"), q.getBuffer(), q.getLength()); + + + QSE::PercentageGrowthPolicy gp(1); + QSE::String g1(128), g2(128); + QSE_ASSERT (g1.getCapacity() == 128); + QSE_ASSERT (g2.getCapacity() == 128); + QSE_ASSERT (g1.getLength() == 0); + QSE_ASSERT (g2.getLength() == 0); + g2.setGrowthPolicy (&gp); + for (int i = 0; i < 1500; i++) + { + g1.append (i); + g2.append (i); + } + qse_printf (QSE_T("g1: %d %d g2: %d %d\n"), (int)g1.getCapacity(), (int)g1.getLength(), (int)g2.getCapacity(), (int)g2.getLength()); + g1.compact(); + g2.compact(); + qse_printf (QSE_T("g1: %d %d g2: %d %d\n"), (int)g1.getCapacity(), (int)g1.getLength(), (int)g2.getCapacity(), (int)g2.getLength()); } qse_printf (QSE_T("-----------------\n")); @@ -40,14 +84,20 @@ void t1 () } +void t2() +{ + QSE::MbString x(QSE_MT("this is a string")); + qse_printf (QSE_T("x: [%hs] %d %d\n"), x.getBuffer(), (int)x.getCapacity(), (int)x.getLength()); +} + int main () { - - qse_openstdsios (); t1 (); qse_printf (QSE_T("=================\n")); + t2 (); + qse_printf (QSE_T("=================\n")); qse_closestdsios (); return 0;