added Growable and enhanced StrBase
This commit is contained in:
		@ -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,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;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user