added Growable and enhanced StrBase

This commit is contained in:
hyung-hwan 2015-03-18 13:53:22 +00:00
parent c6d29bc9b6
commit c090a950c7
20 changed files with 629 additions and 295 deletions

View File

@ -28,6 +28,9 @@
#ifndef _QSE_EXCEPTION_HPP_
#define _QSE_EXCEPTION_HPP_
/// \file
/// Provides the Exception class.
#include <qse/types.h>
#include <qse/macros.h>
@ -35,6 +38,7 @@
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
/// The Exception class implements the exception object.
class QSE_EXPORT Exception
{
public:

View File

@ -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 <qse/types.h>
#include <qse/macros.h>
/////////////////////////////////
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

View File

@ -27,6 +27,9 @@
#ifndef _QSE_HASHABLE_HPP_
#define _QSE_HASHABLE_HPP_
/// \file
/// Privides the Hashable interface class.
#include <qse/types.h>
#include <qse/macros.h>
@ -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);

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@
#include <qse/macros.h>
/// \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)

View File

@ -27,6 +27,9 @@
#ifndef _QSE_UNCOPYABLE_HPP_
#define _QSE_UNCOPYABLE_HPP_
/// \file
/// Provides the Uncopyable class.
#include <qse/types.h>
#include <qse/macros.h>

View File

@ -27,7 +27,7 @@
#ifndef _QSE_CMN_ARRAY_HPP_
#define _QSE_CMN_ARRAY_HPP_
#include <qse/Types.hpp>
#include <qse/Growable.hpp>
#include <qse/cmn/Mmged.hpp>
/////////////////////////////////
@ -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 T, typename POSITIONER = ArrayPositioner<T>, typename RESIZER = ArrayResizer >
class Array: public Mmged
class Array: public Mmged, public Growable
{
public:
typedef Array<T,POSITIONER,RESIZER> 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;

View File

@ -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/cmn/Array.hpp>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
// greater-than comparator
template <typename T>
struct BinaryHeapComparator
{
// this can be used to build a max heap
bool operator() (const T& v1, const T& v2) const
{
return v1 > v2;
}
};
template <typename T>
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 <qse/cmn/BinaryHeap.hpp>
/// #include <stdio.h>
///
@ -66,40 +104,8 @@
///
/// return 0;
/// }
///
#include <qse/cmn/Array.hpp>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
// greater-than comparator
template <typename T>
struct BinaryHeapComparator
{
// this can be used to build a max heap
bool operator() (const T& v1, const T& v2) const
{
return v1 > v2;
}
};
template <typename T>
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 T, typename COMPARATOR = BinaryHeapComparator<T>, typename POSITIONER = BinaryHeapPositioner<T>, typename RESIZER = BinaryHeapResizer >
class BinaryHeap: protected Array<T,POSITIONER,RESIZER>
{
@ -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);

View File

@ -27,7 +27,11 @@
#ifndef _QSE_CMN_HASHLIST_HPP_
#define _QSE_CMN_HASHLIST_HPP_
/// \file
/// Provides a hash list template class.
#include <qse/Hashable.hpp>
#include <qse/Growable.hpp>
#include <qse/cmn/LinkedList.hpp>
/////////////////////////////////
@ -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 T, typename HASHER = HashListHasher<T>, typename EQUALER = HashListEqualer<T>, typename RESIZER = HashListResizer >
class HashList: public Mmged
class HashList: public Mmged, public Growable
{
public:
typedef LinkedList<T,EQUALER> 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<int,QSE::Mpool,IntHasher> 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<int,QSE::Mpool,IntHasher> 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;

View File

@ -27,6 +27,10 @@
#ifndef _QSE_CMN_HASHTABLE_HPP_
#define _QSE_CMN_HASHTABLE_HPP_
/// \file
/// Provides a hash table template class.
#include <qse/cmn/Association.hpp>
#include <qse/cmn/HashList.hpp>

View File

@ -27,6 +27,9 @@
#ifndef _QSE_CMN_MPOOL_HPP_
#define _QSE_CMN_MPOOL_HPP_
/// \file
/// Provides the Mpool class.
#include <qse/Uncopyable.hpp>
#include <qse/cmn/Mmged.hpp>
@ -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

View File

@ -27,6 +27,9 @@
#ifndef _QSE_CMN_REDBLACKTABLE_HPP_
#define _QSE_CMN_REDBLACKTABLE_HPP_
/// \file
/// Provides the RedBlackTable class.
#include <qse/cmn/Association.hpp>
#include <qse/cmn/RedBlackTree.hpp>
@ -48,6 +51,10 @@ struct RedBlackTableComparator
};
///
/// The RedBlackTable class extends the RedBlackTree class to maintain the
/// pair of a key and a value.
///
template <typename K, typename V, typename COMPARATOR = RedBlackTableComparator<K> >
class RedBlackTable: public Mmged
{

View File

@ -27,6 +27,9 @@
#ifndef _QSE_CMN_REDBLACKTREE_HPP_
#define _QSE_CMN_REDBLACKTREE_HPP_
/// \file
/// Provides the RedBlackTree class.
#include <qse/Types.hpp>
#include <qse/cmn/Mpool.hpp>
@ -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 <typename T, typename COMPARATOR = RedBlackTreeComparator<T> >
class RedBlackTree: public Mmged
{

View File

@ -27,6 +27,9 @@
#ifndef _QSE_CMN_SCOPEDPTR_HPP_
#define _QSE_CMN_SCOPEDPTR_HPP_
/// \file
/// Provides the ScopedPtr template class.
#include <qse/Uncopyable.hpp>
#include <qse/cmn/Mmgr.hpp>

View File

@ -27,6 +27,9 @@
#ifndef _QSE_CMN_SHAREDPTR_HPP_
#define _QSE_CMN_SHAREDPTR_HPP_
/// \file
/// Provides the SharedPtr template class.
#include <qse/cmn/Mmged.hpp>
#include <qse/RefCounted.hpp>

View File

@ -27,7 +27,9 @@
#ifndef _QSE_CMN_STRBASE_HPP_
#define _QSE_CMN_STRBASE_HPP_
#include <qse/Hashable.hpp>
#include <qse/Growable.hpp>
#include <qse/RefCounted.hpp>
#include <qse/cmn/Mmged.hpp>
@ -45,7 +47,7 @@ protected:
typedef StrBaseData<CHAR_TYPE,NULL_CHAR,OPSET,RESIZER> 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 <typename CHAR_TYPE, CHAR_TYPE NULL_CHAR, typename OPSET, typename RESIZER = StrBaseResizer>
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<CHAR_TYPE,NULL_CHAR,OPSET,RESIZER> SelfType;
typedef StrBaseData<CHAR_TYPE,NULL_CHAR,OPSET,RESIZER> 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;
}
};

View File

@ -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 <qse/cmn/StrBase.hpp>
#include <qse/cmn/str.h>
#include <qse/cmn/mem.h>
@ -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<qse_wchar_t, QSE_WT('\0'), WcStringOpset > WcString;
//typedef StrBase<qse_mchar_t, QSE_MT('\0'), MbStringOpset > MbString;
typedef StrBase<qse_mchar_t, QSE_MT('\0'), MbStringOpset > MbString;
#if defined(QSE_CHAR_IS_MCHAR)
//typedef MbString String;
typedef MbString String;
#else
typedef WcString String;
#endif

View File

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