added Growable and enhanced StrBase
This commit is contained in:
parent
c6d29bc9b6
commit
c090a950c7
@ -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:
|
||||
|
108
qse/include/qse/Growable.hpp
Normal file
108
qse/include/qse/Growable.hpp
Normal 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
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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/||"`;; \
|
||||
|
@ -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>
|
||||
|
||||
/////////////////////////////////
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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,23 +45,30 @@ 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;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
/// 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;
|
||||
|
@ -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;
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
|
||||
#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)
|
||||
|
||||
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);
|
||||
|
@ -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,7 +58,15 @@ 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
|
||||
{
|
||||
if (current <= 0) current = 1;
|
||||
|
||||
if (gp)
|
||||
{
|
||||
return gp->getNewSize (current);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (current < 5000)? (current + current):
|
||||
(current < 50000)? (current + (current / 2)):
|
||||
@ -62,6 +74,7 @@ struct HashListResizer
|
||||
(current < 150000)? (current + (current / 8)):
|
||||
(current + (current / 16));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// The HashList class provides a linked list where a data item can be accessed
|
||||
@ -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,9 +615,11 @@ public:
|
||||
this->datum_list->clear (clear_mpool);
|
||||
}
|
||||
|
||||
/// The getIterator() function returns an interator.
|
||||
///
|
||||
/// \code
|
||||
/// The getIterator() function returns an iterator. You can use
|
||||
/// the iterator to loop over items in the hash list.
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// struct IntHasher
|
||||
/// {
|
||||
/// qse_size_t operator() (int v) { return v; }
|
||||
@ -622,11 +637,14 @@ public:
|
||||
/// 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;
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
return this->_opset.beginsWith(this->_item->buffer, this->_item->size, str, len);
|
||||
}
|
||||
|
||||
while (str < end)
|
||||
bool endsWith (const CHAR_TYPE* str) const
|
||||
{
|
||||
if (idx >= this->_item->size) return false;
|
||||
if (this->_item->buffer[idx] != *str) return false;
|
||||
idx++; str++;
|
||||
}
|
||||
return true;
|
||||
return this->_opset.endsWith(this->_item->buffer, this->_item->size, str);
|
||||
}
|
||||
|
||||
qse_size_t touppercase ()
|
||||
bool endsWith (const CHAR_TYPE* str, const qse_size_t len) 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, len);
|
||||
}
|
||||
|
||||
qse_size_t tolowercase ()
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user