added Growable and enhanced StrBase

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

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