nestopia/source/win32/NstString.hpp

2280 lines
45 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_STRING_H
#define NST_STRING_H
#pragma once
#include <cstdlib>
#include <cstring>
#include <cwchar>
#include <cmath>
#include "NstMain.hpp"
namespace Nestopia
{
namespace String
{
class Base
{
template<typename T>
static bool ToUnsigned(const T* NST_RESTRICT,uint,uint&);
template<typename T> static void AppendSigned(T&,int);
template<typename T> static void AppendUnsigned(T&,uint);
static int Compare(const char*,int,const char*,int);
static int Compare(const wchar_t*,int,const wchar_t*,int);
static int CompareCase(const char*,int,const char*,int);
static int CompareCase(const wchar_t*,int,const wchar_t*,int);
protected:
enum
{
MAX_INT_LENGTH = 12,
MAX_FLT_LENGTH = 24
};
template<typename T> static T* Remove(T*,T);
static bool Trim(char*);
static bool Trim(wchar_t*);
static uint GetAbsolutePath(const char*,char*,uint);
static uint GetAbsolutePath(const wchar_t*,wchar_t*,uint);
template<typename T> static T* FromUnsigned(T (&)[MAX_INT_LENGTH],uint);
template<typename T> static T* FromSigned(T (&)[MAX_INT_LENGTH],int);
static uint FromDouble(char (&)[MAX_FLT_LENGTH],double,uint);
static uint FromDouble(wchar_t (&)[MAX_FLT_LENGTH],double,uint);
template<typename T> static void AssignSigned(T&,int);
template<typename T> static void AssignUnsigned(T&,uint);
template<typename T,typename U>
static bool ConvertToUnsigned(const T&,U&);
static uint Length(const char* str)
{
return std::strlen( str );
}
static uint Length(const wchar_t* str)
{
return std::wcslen( str );
}
static void Copy(char* NST_RESTRICT a,const char* NST_RESTRICT b,uint n)
{
std::memcpy( a, b, n );
}
static void Copy(wchar_t* NST_RESTRICT a,const wchar_t* NST_RESTRICT b,uint n)
{
std::wmemcpy( a, b, n );
}
static void Copy(wchar_t* NST_RESTRICT a,const char* NST_RESTRICT b,uint n)
{
for (uint i=0; i < n; ++i)
a[i] = b[i];
}
static void Copy(char* NST_RESTRICT a,const wchar_t* NST_RESTRICT b,uint n)
{
for (uint i=0; i < n; ++i)
a[i] = b[i];
}
static void Move(char* a,const char* b,uint n)
{
std::memmove( a, b, n );
}
static void Move(wchar_t* a,const wchar_t* b,uint n)
{
std::wmemmove( a, b, n );
}
template<typename T>
static const typename T::Type* GetPtr(const T& t)
{
return t.Ptr();
}
template<typename T>
static const T* GetPtr(T* const& t)
{
return t;
}
template<typename T>
static const T* GetPtr(const T* const& t)
{
return t;
}
template<typename T,uint N>
static const T* GetPtr(const T (&t)[N])
{
return t;
}
template<typename T>
static uint GetLength(const T& t)
{
return t.Length();
}
template<typename T>
static uint GetLength(T* const& t)
{
return Length(t);
}
template<typename T>
static uint GetLength(const T* const& t)
{
return Length(t);
}
template<typename T,uint N>
static uint GetLength(const T (&t)[N])
{
return Length(t);
}
template<typename T,typename U>
static bool Equal(const T& t,const U& u)
{
return t.Length() == u.Length() && !Compare( t.Ptr(), t.Length(), u.Ptr(), u.Length() );
}
template<typename T,typename U>
static bool Equal(const T& t,const U*& u)
{
return !Compare( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U>
static bool Equal(const T& t,const U* const& u)
{
return !Compare( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U,uint N>
static bool Equal(const T& t,const U (&u)[N])
{
return !Compare( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U>
static bool CaseEqual(const T& t,const U& u)
{
return t.Length() == u.Length() && !CompareCase( t.Ptr(), t.Length(), u.Ptr(), u.Length() );
}
template<typename T,typename U>
static bool CaseEqual(const T& t,const U*& u)
{
return !CompareCase( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U>
static bool CaseEqual(const T& t,const U* const& u)
{
return !CompareCase( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U,uint N>
static bool CaseEqual(const T& t,const U (&u)[N])
{
return !CompareCase( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U>
static int Compare(const T& t,const U& u)
{
return Compare( t.Ptr(), t.Length(), u.Ptr(), u.Length() );
}
template<typename T,typename U>
static int Compare(const T& t,const U*& u)
{
return Compare( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U>
static int Compare(const T& t,const U* const& u)
{
return Compare( t.Ptr(), t.Length(), u, -1 );
}
template<typename T,typename U,uint N>
static int Compare(const T& t,const U (&u)[N])
{
return Compare( t.Ptr(), t.Length(), u, -1 );
}
static bool Wide(const char*,uint)
{
return false;
}
static bool Wide(const wchar_t* t,uint n)
{
for (uint i=0; i < n; ++i)
{
if (t[i] > 0xFF)
return true;
}
return false;
}
template<typename T,typename U>
static void Append(T& t,const U& u)
{
t.Append( GetPtr(u), GetLength(u) );
}
template<typename T>
static void Append(T& t,char c)
{
const typename T::Type v = c;
t.Append( &v, 1 );
}
template<typename T>
static void Append(T& t,wchar_t c)
{
t.Append( &c, 1 );
}
template<typename T> static void Append(T& t,int i) { AppendSigned ( t, i ); }
template<typename T> static void Append(T& t,uint i) { AppendUnsigned ( t, i ); }
template<typename T> static void Append(T& t,schar i) { AppendSigned ( t, i ); }
template<typename T> static void Append(T& t,uchar i) { AppendUnsigned ( t, i ); }
template<typename T> static void Append(T& t,short i) { AppendSigned ( t, i ); }
template<typename T> static void Append(T& t,ushort i) { AppendUnsigned ( t, i ); }
template<typename T> static void Append(T& t,long i) { AppendSigned ( t, i ); }
template<typename T> static void Append(T& t,ulong i) { AppendUnsigned ( t, i ); }
};
template<typename T>
T* Base::FromUnsigned(T (&buffer)[MAX_INT_LENGTH],uint number)
{
number &= 0xFFFFFFFF;
T* it = buffer + MAX_INT_LENGTH-1;
*it = '\0';
do
{
*--it = '0' + number % 10;
}
while (number /= 10);
return it;
}
template<typename T>
T* Base::FromSigned(T (&buffer)[MAX_INT_LENGTH],const int number)
{
uint value = (number >= 0 ? number : -number) & 0x7FFFFFFFU;
T* it = buffer + MAX_INT_LENGTH-1;
*it = '\0';
do
{
*--it = '0' + value % 10;
}
while (value /= 10);
if (number < 0)
*--it = '-';
return it;
}
template<typename T>
void Base::AssignUnsigned(T& t,const uint i)
{
typename T::Type buffer[MAX_INT_LENGTH];
const typename T::Type* const offset = FromUnsigned( buffer, i );
t.Assign( offset, buffer + MAX_INT_LENGTH-1 - offset );
}
template<typename T>
void Base::AssignSigned(T& t,const int i)
{
typename T::Type buffer[MAX_INT_LENGTH];
const typename T::Type* const offset = FromSigned( buffer, i );
t.Assign( offset, buffer + MAX_INT_LENGTH-1 - offset );
}
template<typename T>
void Base::AppendUnsigned(T& t,const uint i)
{
typename T::Type buffer[MAX_INT_LENGTH];
const typename T::Type* const offset = FromUnsigned( buffer, i );
t.Append( offset, buffer + MAX_INT_LENGTH-1 - offset );
}
template<typename T>
void Base::AppendSigned(T& t,const int i)
{
typename T::Type buffer[MAX_INT_LENGTH];
const typename T::Type* const offset = FromSigned( buffer, i );
t.Append( offset, buffer + MAX_INT_LENGTH-1 - offset );
}
template<typename T>
bool Base::ToUnsigned(const T* NST_RESTRICT string,const uint length,uint& result)
{
result = 0;
if (length)
{
bool neg = false;
uint base = 10;
uint maxvalue = 0xFFFFFFFF / 10;
const T* end = string + length;
switch (*string)
{
case '-': neg = true;
case '+': ++string; break;
case '0':
if (++string != end)
{
base = 16;
maxvalue = 0xFFFFFFFF / 16;
const T digit = *string++;
if (digit == 'x' || digit == 'X')
break;
else
return false;
}
else
{
return true;
}
}
if (string != end)
{
uint value = 0;
do
{
const T digit = *string++;
uint num;
if (digit >= '0' && digit <= '9')
{
num = digit - '0';
}
else if (digit >= 'A' && digit <= 'F' && base == 16)
{
num = digit - 'A' + 10;
}
else if (digit >= 'a' && digit <= 'f' && base == 16)
{
num = digit - 'a' + 10;
}
else
{
return false;
}
if (value < maxvalue || (value == maxvalue && num <= 0xFFFFFFFFU % base))
value = value * base + num;
else
return false;
}
while (string != end);
result = neg ? uint(-int(value)) : value;
return true;
}
}
return false;
}
template<typename T,typename U>
bool Base::ConvertToUnsigned(const T& string,U& value)
{
uint u;
const bool r = ToUnsigned( string.Ptr(), string.Length(), u );
value = U(u);
return r;
}
template<typename T>
T* Base::Remove(T* string,const T c)
{
T* p;
for (p=string; *string; ++string)
{
if (*string != c)
*p++ = *string;
}
*p = '\0';
return p;
}
template<typename T=wchar_t,bool I=false>
class Generic : protected Base
{
public:
typedef T Type;
enum
{
TYPE_SIZE = sizeof(Type)
};
protected:
const Type* string;
uint length;
static const Type empty;
enum DoNothing {NOP};
Generic(DoNothing) {}
public:
Generic()
: string(&empty), length(0) {}
Generic(const Type* t,uint l)
: string(t), length(l) { NST_ASSERT( t ); }
template<typename U>
Generic(const U& t)
: string(Base::GetPtr(t)), length(Base::GetLength(t)) {}
template<typename U>
Generic& operator = (const U& t)
{
string = Base::GetPtr(t);
length = Base::GetLength(t);
return *this;
}
template<typename U>
bool operator >> (U& t) const
{
return Base::ConvertToUnsigned( *this, t );
}
uint Length() const
{
return length;
}
bool Empty() const
{
return !length;
}
const Type& Front() const
{
NST_ASSERT( length );
return string[0];
}
const Type& Back() const
{
NST_ASSERT( length );
return string[length-1];
}
bool NullTerminated() const
{
return string[length] == '\0';
}
const Type* Ptr() const
{
return string;
}
const Type& operator [] (uint i) const
{
return string[i];
}
bool Wide() const
{
return Base::Wide( Ptr(), Length() );
}
Generic operator () (uint p) const
{
NST_ASSERT( p <= length );
return Generic( string + p, length - p );
}
Generic operator () (uint p,uint l) const
{
NST_ASSERT( p + l <= length );
return Generic( string + p, l );
}
template<typename U>
bool Equal(const U& t) const
{
return Base::CaseEqual( *this, t );
}
template<typename U> bool operator == (const U& t) const { return Base::Equal( *this, t ); }
template<typename U> bool operator != (const U& t) const { return !Base::Equal( *this, t ); }
template<typename U> bool operator < (const U& t) const { return Base::Compare( *this, t ) < 0; }
template<typename U> bool operator <= (const U& t) const { return Base::Compare( *this, t ) <= 0; }
template<typename U> bool operator > (const U& t) const { return Base::Compare( *this, t ) > 0; }
template<typename U> bool operator >= (const U& t) const { return Base::Compare( *this, t ) >= 0; }
};
template<typename T,bool I>
const T Generic<T,I>::empty = '\0';
template<typename T>
class Generic<T,true> : public Generic<T,false>
{
typedef Generic<T,false> Parent;
void Copy(const Generic&);
T buffer[Parent::MAX_INT_LENGTH];
void SetValue(int number)
{
Parent::string = Base::FromSigned( buffer, number );
Parent::length = buffer + Parent::MAX_INT_LENGTH-1 - Parent::string;
}
void SetValue(uint number)
{
Parent::string = Base::FromUnsigned( buffer, number );
Parent::length = buffer + Parent::MAX_INT_LENGTH-1 - Parent::string;
}
public:
Generic(const Generic& g)
: Generic<T,false>(Parent::NOP)
{
Copy( g );
}
template<typename U>
Generic(const U& t)
: Generic<T,false>(t) {}
Generic(T c)
: Generic<T,false>(Parent::NOP)
{
Parent::string = buffer;
Parent::length = 1;
buffer[0] = c;
buffer[1] = '\0';
}
Generic( schar i ) : Generic<T,false>(Parent::NOP) { SetValue( int (i) ); }
Generic( uchar i ) : Generic<T,false>(Parent::NOP) { SetValue( uint (i) ); }
Generic( short i ) : Generic<T,false>(Parent::NOP) { SetValue( int (i) ); }
Generic( ushort i ) : Generic<T,false>(Parent::NOP) { SetValue( uint (i) ); }
Generic( int i ) : Generic<T,false>(Parent::NOP) { SetValue( int (i) ); }
Generic( uint i ) : Generic<T,false>(Parent::NOP) { SetValue( uint (i) ); }
Generic( long i ) : Generic<T,false>(Parent::NOP) { SetValue( int (i) ); }
Generic( ulong i ) : Generic<T,false>(Parent::NOP) { SetValue( uint (i) ); }
Generic& operator = (const Generic& g)
{
Copy( g );
return *this;
}
template<typename U>
Generic& operator = (const U& t)
{
Parent::operator = (t);
return *this;
}
Generic& operator = (T c)
{
Parent::string = buffer;
Parent::length = 1;
buffer[0] = c;
buffer[1] = '\0';
return *this;
}
Generic& operator = ( schar i ) { SetValue( int (i) ); return *this; }
Generic& operator = ( uchar i ) { SetValue( uint (i) ); return *this; }
Generic& operator = ( short i ) { SetValue( int (i) ); return *this; }
Generic& operator = ( ushort i ) { SetValue( uint (i) ); return *this; }
Generic& operator = ( int i ) { SetValue( int (i) ); return *this; }
Generic& operator = ( uint i ) { SetValue( uint (i) ); return *this; }
Generic& operator = ( long i ) { SetValue( int (i) ); return *this; }
Generic& operator = ( ulong i ) { SetValue( uint (i) ); return *this; }
};
template<typename T=wchar_t>
class Num : public Generic<T,true>
{
public:
Num(uint v)
: Generic<T,true>(v) {}
Num(int v)
: Generic<T,true>(v) {}
Num& operator = (uint v)
{
Generic<T,true>::operator = (v);
return *this;
}
Num& operator = (int v)
{
Generic<T,true>::operator = (v);
return *this;
}
};
template<typename T>
void Generic<T,true>::Copy(const Generic& g)
{
Generic::length = g.length;
if (g.string < g.buffer || g.string >= g.buffer + Generic::MAX_INT_LENGTH)
{
Generic::string = g.string;
}
else
{
Generic::string = buffer + (g.string - g.buffer);
Base::Copy( buffer, g.buffer, Generic::MAX_INT_LENGTH );
}
}
template<typename T>
class Sub : protected Base
{
public:
typedef typename T::Type Type;
enum
{
TYPE_SIZE = sizeof(Type)
};
template<typename U>
void Assign(const U* NST_RESTRICT,uint);
protected:
T& string;
uint offset;
uint length;
public:
Sub(T& t,uint o)
: string(t), offset(o), length(t.Length() - offset)
{
NST_ASSERT( offset + length <= string.Length() );
}
Sub(T& t,uint o,uint l)
: string(t), offset(o), length(l)
{
NST_ASSERT( offset + length <= string.Length() );
}
template<typename U>
Sub& operator = (const U& t)
{
Assign( Base::GetPtr(t), Base::GetLength(t) );
return *this;
}
Sub& operator = (Type c)
{
Assign( &c, 1 );
return *this;
}
Sub& operator = (int i) { Base::AssignSigned ( *this, i ); return *this; }
Sub& operator = (uint i) { Base::AssignUnsigned ( *this, i ); return *this; }
Sub& operator = (schar i) { Base::AssignSigned ( *this, i ); return *this; }
Sub& operator = (uchar i) { Base::AssignUnsigned ( *this, i ); return *this; }
Sub& operator = (short i) { Base::AssignSigned ( *this, i ); return *this; }
Sub& operator = (ushort i) { Base::AssignUnsigned ( *this, i ); return *this; }
Sub& operator = (long i) { Base::AssignSigned ( *this, i ); return *this; }
Sub& operator = (ulong i) { Base::AssignUnsigned ( *this, i ); return *this; }
template<typename U>
bool operator >> (U& t) const
{
return Base::ConvertToUnsigned( *this, t );
}
void Clear()
{
if (const uint n = length)
{
length = 0;
string.Erase( offset, n );
}
}
uint Length() const
{
return length;
}
bool Empty() const
{
return !length;
}
Type* Ptr()
{
return string.Ptr() + offset;
}
const Type* Ptr() const
{
return string.Ptr() + offset;
}
Type& operator [] (uint i)
{
NST_ASSERT( i < length );
return string[offset+i];
}
const Type& operator [] (uint i) const
{
NST_ASSERT( i < length );
return string[offset+i];
}
Type& Front()
{
NST_ASSERT( length );
return string[offset];
}
const Type& Front() const
{
NST_ASSERT( length );
return string[offset];
}
Type& Back()
{
NST_ASSERT( length );
return string[offset+length-1];
}
const Type& Back() const
{
NST_ASSERT( length );
return string[offset+length-1];
}
bool Wide() const
{
return Base::Wide( Ptr(), Length() );
}
Generic<Type> operator () (uint p) const
{
NST_ASSERT( p <= length );
return Generic<Type>( string.Ptr() + offset + p, length - p );
}
Generic<Type> operator () (uint p,uint l) const
{
NST_ASSERT( p + l <= length );
return Generic<Type>( string.Ptr() + offset + p, l );
}
template<typename U>
bool Equal(const U& t) const
{
return Base::CaseEqual( *this, t );
}
template<typename U> bool operator == (const U& t) const { return Base::Equal( *this, t ); }
template<typename U> bool operator != (const U& t) const { return !Base::Equal( *this, t ); }
template<typename U> bool operator < (const U& t) const { return Base::Compare( *this, t ) < 0; }
template<typename U> bool operator <= (const U& t) const { return Base::Compare( *this, t ) <= 0; }
template<typename U> bool operator > (const U& t) const { return Base::Compare( *this, t ) > 0; }
template<typename U> bool operator >= (const U& t) const { return Base::Compare( *this, t ) >= 0; }
};
template<typename T> template<typename U>
void Sub<T>::Assign(const U* const NST_RESTRICT t,const uint n)
{
const uint l = length;
length = n;
string.Erase( offset, l );
string.Insert( offset, t, n );
}
template<uint N,typename T=wchar_t>
class Stack : Base
{
public:
typedef T Type;
typedef Sub< Stack<N,Type> > SubString;
enum
{
TYPE_SIZE = sizeof(Type),
MAX_LENGTH = N
};
template<typename U> void Assign(const U* NST_RESTRICT,uint);
template<typename U> void Append(const U* NST_RESTRICT,uint);
template<typename U> void Insert(const uint,const U* NST_RESTRICT,uint);
void Erase(uint,uint);
private:
template<typename U> void Assign(const U* NST_RESTRICT);
template<typename U> void Append(const U* NST_RESTRICT);
enum
{
STACK_LENGTH = (N + 4U) & ~3U
};
uint length;
Type string[STACK_LENGTH];
public:
Stack()
: length(0)
{
*string = '\0';
}
Stack(const Stack& t)
{
Assign( t.Ptr(), t.Length() );
}
template<typename U>
Stack(const U* u,uint n)
{
Assign( u, n );
}
template<typename U>
Stack(const U& t)
{
Assign( t.Ptr(), t.Length() );
}
template<typename U>
Stack(const U* const& t)
{
Assign( t );
}
template<typename U>
Stack(U* const& t)
{
Assign( t );
}
template<typename U,uint C>
Stack(const U (&t)[C])
{
Assign( t );
}
Stack& operator = (const Stack& t)
{
Assign( t.Ptr(), t.Length() );
return *this;
}
template<typename U>
Stack& operator = (const U& t)
{
Assign( t.Ptr(), t.Length() );
return *this;
}
template<typename U>
Stack& operator = (const U* const& t)
{
Assign( t );
return *this;
}
template<typename U>
Stack& operator = (U* const& t)
{
Assign( t );
return *this;
}
template<typename U,uint C>
Stack& operator = (const U (&t)[C])
{
Assign( t );
return *this;
}
template<typename U>
Stack& operator << (const U& t)
{
Base::Append( *this, t );
return *this;
}
template<typename U>
bool operator >> (U& t) const
{
return Base::ConvertToUnsigned( *this, t );
}
uint Length() const
{
return length;
}
bool Empty() const
{
return !length;
}
Type* Ptr()
{
return string;
}
const Type* Ptr() const
{
return string;
}
Type& operator [] (uint i)
{
NST_ASSERT( i < MAX_LENGTH );
return string[i];
}
const Type& operator [] (uint i) const
{
NST_ASSERT( i < MAX_LENGTH );
return string[i];
}
Type& At(uint i)
{
NST_ASSERT( i < MAX_LENGTH );
return string[i];
}
const Type& At(uint i) const
{
NST_ASSERT( i < MAX_LENGTH );
return string[i];
}
Type& Front()
{
NST_ASSERT( length );
return string[0];
}
const Type& Front() const
{
NST_ASSERT( length );
return string[0];
}
Type& Back()
{
NST_ASSERT( length );
return string[length-1];
}
const Type& Back() const
{
NST_ASSERT( length );
return string[length-1];
}
void Clear()
{
length = 0;
*string = 0;
}
bool Wide() const
{
return Base::Wide( Ptr(), Length() );
}
uint Validate()
{
length = Base::Length(string);
return length;
}
void Resize(uint n)
{
NST_ASSERT( n <= MAX_LENGTH );
string[length=n] = '\0';
}
void ShrinkTo(uint n)
{
Resize( n );
}
void Remove(const Type c)
{
length = Base::Remove( string, c ) - string;
}
void Trim()
{
if (Base::Trim( string ))
Validate();
}
Generic<Type> operator () (uint p) const
{
NST_ASSERT( p <= length );
return Generic<Type>( string + p, length - p );
}
Generic<Type> operator () (uint p,uint l) const
{
NST_ASSERT( p + l <= length );
return Generic<Type>( string + p, l );
}
SubString operator () (uint p)
{
NST_ASSERT( p <= length );
return SubString( *this, p, length - p );
}
SubString operator () (uint p,uint l)
{
NST_ASSERT( p + l <= length );
return SubString( *this, p, l );
}
template<typename U>
bool Equal(const U& t) const
{
return Base::CaseEqual( *this, t );
}
template<typename U> bool operator == (const U& t) const { return Base::Equal( *this, t ); }
template<typename U> bool operator != (const U& t) const { return !Base::Equal( *this, t ); }
template<typename U> bool operator < (const U& t) const { return Base::Compare( *this, t ) < 0; }
template<typename U> bool operator <= (const U& t) const { return Base::Compare( *this, t ) <= 0; }
template<typename U> bool operator > (const U& t) const { return Base::Compare( *this, t ) > 0; }
template<typename U> bool operator >= (const U& t) const { return Base::Compare( *this, t ) >= 0; }
};
template<uint N,typename T> template<typename U>
void Stack<N,T>::Assign(const U* const NST_RESTRICT t)
{
NST_ASSERT( Base::Length(t) <= MAX_LENGTH );
uint i = ~0U;
Type c;
do
{
++i;
string[i] = c = t[i];
}
while (c);
length = i;
}
template<uint N,typename T> template<typename U>
void Stack<N,T>::Assign(const U* const NST_RESTRICT t,const uint n)
{
NST_ASSERT( t && n <= MAX_LENGTH );
length = n;
Base::Copy( string, t, n );
string[n] = '\0';
}
template<uint N,typename T> template<typename U>
void Stack<N,T>::Append(const U* const NST_RESTRICT t)
{
NST_ASSERT( length + Base::Length(t) <= MAX_LENGTH );
uint i = length - 1;
Type c;
do
{
++i;
string[i] = c = t[i];
}
while (c);
length = i;
}
template<uint N,typename T> template<typename U>
void Stack<N,T>::Append(const U* const NST_RESTRICT t,const uint n)
{
NST_ASSERT( t && length + n <= MAX_LENGTH );
Type* const offset = string + length;
length += n;
Base::Copy( offset, t, n );
offset[n] = '\0';
}
template<uint N,typename T>
void Stack<N,T>::Erase(const uint p,const uint n)
{
NST_ASSERT( p + n <= length );
const uint l = length;
length -= n;
Base::Move( string + p, string + p + n, (l + 1) - (p + n) );
}
template<uint N,typename T> template<typename U>
void Stack<N,T>::Insert(const uint pos,const U* const NST_RESTRICT t,const uint n)
{
NST_ASSERT( length + n <= MAX_LENGTH );
if (n)
{
const uint p = length;
length += n;
Base::Move( string + pos + n, string + pos, p + 1 - pos );
Base::Copy( string + pos, t, n );
}
}
template<typename T=wchar_t>
class Heap : public Base
{
public:
typedef T Type;
typedef Sub< Heap<Type> > SubString;
enum
{
TYPE_SIZE = sizeof(Type)
};
template<typename U> void Assign(const U* NST_RESTRICT,uint);
template<typename U> void Append(const U* NST_RESTRICT,uint);
template<typename U> void Insert(uint,const U* NST_RESTRICT,uint);
void Reserve(uint);
void Resize(uint);
void Defrag();
void Destroy();
void Erase(uint,uint);
Heap& Import(cstring,bool=false);
Heap& Import(wcstring,bool=false);
private:
template<typename U> void Init(const U* NST_RESTRICT,uint);
template<typename U> void Assign(const U* NST_RESTRICT);
template<typename U> void Append(const U* NST_RESTRICT);
Type* string;
uint length;
uint capacity;
static Type empty[4];
template<typename U>
void Copy(const U* const NST_RESTRICT t,const uint n)
{
NST_ASSERT( t );
Base::Copy( string, t, n );
string[n] = '\0';
}
public:
Heap()
: string(empty), length(0), capacity(0)
{
NST_ASSERT( !*empty );
}
Heap(const Heap& t)
{
Init( t.Ptr(), t.Length() );
}
template<typename U>
Heap(const U& t)
{
Init( Base::GetPtr(t), Base::GetLength(t) );
}
template<typename U>
Heap(const U* t,uint n)
{
Init( t, n );
}
~Heap()
{
if (capacity)
std::free( string );
}
Heap& operator = (const Heap& t)
{
Assign( t.Ptr(), t.Length() );
return *this;
}
template<typename U>
Heap& operator = (const U& t)
{
Assign( Base::GetPtr(t), Base::GetLength(t) );
return *this;
}
template<typename U>
Heap& operator << (const U& t)
{
Base::Append( *this, t );
return *this;
}
template<typename U>
bool operator >> (U& t) const
{
return Base::ConvertToUnsigned( *this, t );
}
template<typename U>
void Insert(const uint pos,const U& t)
{
Insert( pos, Base::GetPtr(t), Base::GetLength(t) );
}
void ShrinkTo(uint n)
{
NST_ASSERT( capacity >= n );
string[length = n] = '\0';
}
void Clear()
{
string[length = 0] = '\0';
}
uint Validate()
{
length = Base::Length(string);
return length;
}
void Remove(const Type c)
{
length = Base::Remove( string, c ) - string;
}
void Trim()
{
if (Base::Trim( string ))
Validate();
}
uint Length() const
{
return length;
}
uint Capacity() const
{
return capacity;
}
bool Empty() const
{
return !length;
}
Type* Ptr()
{
return string;
}
const Type* Ptr() const
{
return string;
}
Type& operator [] (uint i)
{
return string[i];
}
const Type& operator [] (uint i) const
{
return string[i];
}
Type& At(uint i)
{
return string[i];
}
const Type& At(uint i) const
{
return string[i];
}
Type& Front()
{
NST_ASSERT( length );
return string[0];
}
const Type& Front() const
{
NST_ASSERT( length );
return string[0];
}
Type& Back()
{
NST_ASSERT( length );
return string[length-1];
}
const Type& Back() const
{
NST_ASSERT( length );
return string[length-1];
}
bool Wide() const
{
return Base::Wide( Ptr(), Length() );
}
Generic<Type> operator () (uint p) const
{
NST_ASSERT( p <= length );
return Generic<Type>( string + p, length - p );
}
Generic<Type> operator () (uint p,uint l) const
{
NST_ASSERT( p + l <= length );
return Generic<Type>( string + p, l );
}
SubString operator () (uint p)
{
NST_ASSERT( p <= length );
return SubString( *this, p, length - p );
}
SubString operator () (uint p,uint l)
{
NST_ASSERT( p + l <= length );
return SubString( *this, p, l );
}
uint FindFirstOf(const Type c,const uint length)
{
for (uint i=0; i < length; ++i)
if (string[i] == c)
return i;
return length;
}
uint FindFirstOf(const Type c)
{
return FindFirstOf( c, length );
}
uint FindFirstNotOf(const Type c,const uint length)
{
for (uint i=0; i < length; ++i)
if (string[i] != c)
return i;
return length;
}
uint FindLastOf(const Type c,const uint length)
{
for (uint i=length; i; )
if (string[--i] == c)
return i;
return length;
}
uint FindLastNotOf(const Type c,const uint length)
{
for (uint i=length; i; )
if (string[--i] != c)
return i;
return length;
}
SubString FirstOf(Type c)
{
uint first = FindFirstOf(c,length);
return SubString( *this, first, length - first );
}
template<typename U> bool operator == (const U& t) const { return Base::Equal( *this, t ); }
template<typename U> bool operator != (const U& t) const { return !Base::Equal( *this, t ); }
template<typename U> bool operator < (const U& t) const { return Base::Compare( *this, t ) < 0; }
template<typename U> bool operator <= (const U& t) const { return Base::Compare( *this, t ) <= 0; }
template<typename U> bool operator > (const U& t) const { return Base::Compare( *this, t ) > 0; }
template<typename U> bool operator >= (const U& t) const { return Base::Compare( *this, t ) >= 0; }
};
template<typename T>
typename Heap<T>::Type Heap<T>::empty[4] = {'\0','\0','\0','\0'};
template<typename T> template<typename U>
void Heap<T>::Init(const U* const NST_RESTRICT t,const uint n)
{
NST_ASSERT( t && !*empty );
if (0 != (capacity = length = n))
{
string = static_cast<Type*>(std::malloc( (n+1) * TYPE_SIZE ));
Copy( t, n );
}
else
{
string = empty;
}
}
template<typename T>
void Heap<T>::Reserve(const uint n)
{
if (capacity < n)
{
uint prev = capacity;
capacity = n;
string = static_cast<Type*>(std::realloc( prev ? string : NULL, (n+1) * TYPE_SIZE ));
string[length] = '\0';
}
}
template<typename T>
void Heap<T>::Resize(uint n)
{
Reserve( n );
string[length = n] = '\0';
}
template<typename T>
void Heap<T>::Destroy()
{
if (capacity)
{
length = capacity = 0;
Type* tmp = string;
string = empty;
std::free( tmp );
}
}
template<typename T> template<typename U>
void Heap<T>::Assign(const U* NST_RESTRICT t,const uint n)
{
length = n;
if (capacity < n)
{
uint prev = capacity;
capacity = n;
string = static_cast<Type*>(std::realloc( prev ? string : NULL, (capacity+1) * TYPE_SIZE ));
}
Copy( t, n );
}
template<typename T> template<typename U>
void Heap<T>::Assign(const U* NST_RESTRICT t)
{
Assign( t, Base::Length(t) );
}
template<typename T> template<typename U>
void Heap<T>::Append(const U* NST_RESTRICT t,const uint n)
{
length += n;
if (capacity < length)
{
uint prev = capacity;
capacity = length * 2;
string = static_cast<Type*>(std::realloc( prev ? string : NULL, (capacity+1) * TYPE_SIZE ));
}
Base::Copy( string + length - n, t, n );
string[length] = '\0';
}
template<typename T> template<typename U>
void Heap<T>::Append(const U* NST_RESTRICT t)
{
Append( t, Base::Length(t) );
}
template<typename T> template<typename U>
void Heap<T>::Insert(const uint pos,const U* const NST_RESTRICT t,const uint n)
{
if (n)
{
if (capacity >= length + n)
{
Base::Move( string + pos + n, string + pos, length + 1 - pos );
}
else
{
capacity = length + n * 2;
Type* const next = static_cast<Type*>(std::malloc( (capacity+1) * TYPE_SIZE ));
Base::Copy( next, string, pos );
Base::Copy( next + pos + n, string + pos, length + 1 - pos );
if (string != empty)
std::free( string );
string = next;
}
length += n;
Base::Copy( string + pos, t, n );
}
}
template<typename T>
void Heap<T>::Erase(const uint p,const uint n)
{
NST_ASSERT( p + n <= length );
const uint l = length;
length -= n;
Base::Move( string + p, string + p + n, (l + 1) - (p + n) );
}
template<typename T>
void Heap<T>::Defrag()
{
if (capacity != length)
{
capacity = length;
if (capacity)
{
string = static_cast<Type*>(std::realloc( string, (capacity+1) * TYPE_SIZE ));
}
else
{
Type* tmp = string;
string = empty;
std::free( tmp );
}
}
}
template<typename T=wchar_t>
class Path : public Heap<T>
{
typedef Heap<T> Parent;
typedef Generic<T> Any;
typedef typename Heap<T>::SubString Sub;
public:
Path() {}
Path(Any,Any,Any=Any());
Path(const Path& p)
: Parent(static_cast<const Parent&>(p)) {}
template<typename U>
Path(const U& t)
: Parent(t) {}
Path& operator = (const Path& t)
{
Parent::operator = (static_cast<const Parent&>(t));
return *this;
}
template<typename U>
Path& operator = (const U& t)
{
Parent::operator = (t);
return *this;
}
template<typename U>
Path& operator << (const U& t)
{
Parent::operator << (t);
return *this;
}
void Set(Any,Any,Any=Any());
void MakePretty(bool=false);
Path& MakeAbsolute(bool=false);
bool FileExists() const;
bool FileProtected() const;
bool DirectoryExists() const;
static const Path Compact(Any,uint);
private:
static bool Compact(T*,const T*,uint);
uint FindDirectory() const;
void FindExtension(uint (&)[2]) const;
uint FindArchive() const;
void FindFileInArchive(uint (&)[2]) const;
static uint ExtensionId(const T* NST_RESTRICT,uint);
class DirectorySub : public Sub
{
public:
DirectorySub(Path& path,uint length)
: Sub( path, 0, length ) {}
void operator = (Any);
void operator += (Any);
void operator -= (uint);
};
class ExtensionSub : public Sub
{
public:
ExtensionSub(Path& path,uint pos,uint length)
: Sub( path, pos, length ) {}
void Assign(const T* NST_RESTRICT,uint);
void Clear();
template<typename U>
void operator = (const U& t)
{
Assign( Base::GetPtr(t), Base::GetLength(t) );
}
uint Id() const
{
return ExtensionId( Sub::Ptr(), Sub::Length() );
}
};
class ConstExtensionSub : public Any
{
public:
ConstExtensionSub(const T* string,uint length)
: Any( string, length ) {}
uint Id() const
{
return ExtensionId( Any::Ptr(), Any::Length() );
}
};
class ArchiveFileSub : public Any
{
public:
ArchiveFileSub(const T* string,uint length)
: Any( string, length ) {}
const Any File() const
{
for (uint i=Any::length; i; )
{
switch (Any::string[--i])
{
case '\\':
case '/': return Any( Any::string + i + 1, Any::length - (i + 1) );
}
}
return *this;
}
};
public:
DirectorySub Directory()
{
return DirectorySub( *this, FindDirectory() );
}
const Any Directory() const
{
return Any( Parent::Ptr(), FindDirectory() );
}
Sub File()
{
return Sub( *this, FindDirectory() );
}
const Any File() const
{
uint p = FindDirectory();
return Any( Parent::Ptr() + p, Parent::Length() - p );
}
ExtensionSub Extension()
{
uint p[2];
FindExtension( p );
return ExtensionSub( *this, p[0], p[1] );
}
const ConstExtensionSub Extension() const
{
uint p[2];
FindExtension( p );
return ConstExtensionSub( Parent::Ptr() + p[0], p[1] );
}
const Any Archive() const
{
return Any( Parent::Ptr(), FindArchive() );
}
ArchiveFileSub FileInArchive() const
{
uint p[2];
FindFileInArchive( p );
return ArchiveFileSub( Parent::Ptr() + p[0], p[1] );
}
ArchiveFileSub Target() const
{
const ArchiveFileSub archive( FileInArchive() );
if (archive.Length())
return archive;
return ArchiveFileSub( Parent::Ptr(), Parent::Length() );
}
};
template<typename T>
Path<T>::Path(const Any dir,const Any file,const Any ext)
{
Set( dir, file, ext );
}
template<typename T>
void Path<T>::Set(const Any dir,const Any file,const Any ext)
{
Parent::Clear();
Reserve( dir.Length() + file.Length() + ext.Length() );
Directory() = dir;
File() = file;
if (ext.Length())
Extension() = ext;
}
template<typename T>
void Path<T>::MakePretty(const bool checkSlash)
{
if (Parent::Length())
{
if
(
Parent::Length() >= 3 &&
Parent::At(0) >= 'a' &&
Parent::At(0) <= 'z' &&
Parent::At(1) == ':' &&
(Parent::At(2) == '\\' || Parent::At(2) == '/')
)
(*this)[0] -= ('a'-'A');
if (checkSlash && Parent::Back() != '\\' && Parent::Back() != '/')
(*this) << '\\';
}
}
template<typename T>
Path<T>& Path<T>::MakeAbsolute(const bool checkSlash)
{
Heap<T> buffer;
buffer.Reserve( 255 );
buffer.Resize( Parent::GetAbsolutePath( Parent::Ptr(), buffer.Ptr(), 255+1 ) );
if (buffer.Length() > 255+1)
{
Parent::GetAbsolutePath( Parent::Ptr(), buffer.Ptr(), buffer.Length() );
buffer.ShrinkTo( buffer.Length() - 1 );
}
if (checkSlash && Parent::Length() && Parent::Back() != '\\' && Parent::Back() != '/')
buffer << '\\';
*this = buffer;
return *this;
}
template<typename T>
uint Path<T>::FindDirectory() const
{
for (uint i=Parent::Length(); i; )
{
switch (Parent::At(--i))
{
case '\\':
case '/': return i + 1;
case '>': while (i && Parent::At(--i) != '<'); break;
}
}
return 0;
}
template<typename T>
void Path<T>::FindExtension(uint (&p)[2]) const
{
p[1] = Parent::Length();
for (uint i=Parent::Length(); i; )
{
switch (Parent::At(--i))
{
case '.':
p[0] = i + 1;
p[1] -= p[0];
return;
case '\\':
case '/':
i = 0;
break;
case '>':
while (i && Parent::At(--i) != '<');
if (i && Parent::At(i-1) == ' ')
--i;
p[1] = i;
break;
}
}
p[0] = p[1];
p[1] = 0;
}
template<typename T>
uint Path<T>::FindArchive() const
{
for (uint i=Parent::Length(); i; )
{
if (Parent::At(--i) == '>')
{
while (i)
{
if (Parent::At(--i) == '<')
{
if (i && Parent::At(i-1) == ' ')
--i;
return i;
}
}
break;
}
}
return 0;
}
template<typename T>
void Path<T>::FindFileInArchive(uint (&p)[2]) const
{
for (uint i=Parent::Length(); i; )
{
if (Parent::At(--i) == '>')
{
p[1] = i;
while (i)
{
if (Parent::At(--i) == '<')
{
p[0] = i + 1;
p[1] -= p[0];
return;
}
}
break;
}
}
p[0] = Parent::Length();
p[1] = 0;
}
template<typename T>
uint Path<T>::ExtensionId(const T* const NST_RESTRICT string,uint length)
{
uint id = 0;
if (length)
{
if (length > 4)
length = 4;
for (uint i=0; i < length; ++i)
{
const T c = string[i];
uint v;
if (c >= 'a' && c <= 'z')
{
v = c;
}
else if (c >= 'A' && c <= 'Z')
{
v = c - 'A' + 'a';
}
else if (c >= '0' && c <= '9')
{
v = c;
}
else
{
return 0;
}
id |= v << (8 * i);
}
}
return id;
}
template<typename T>
void Path<T>::DirectorySub::operator = (const Any t)
{
Sub::Clear();
if (t.Length())
{
Sub::string.Insert( 0, t.Ptr(), t.Length() );
Sub::length = t.Length();
if (t.Back() != '\\' && t.Back() != '/')
{
const T c = '\\';
Sub::string.Insert( Sub::length++, &c, 1 );
}
}
}
template<typename T>
void Path<T>::DirectorySub::operator += (const Any t)
{
if (t.Length())
{
Sub::string.Insert( Sub::length, t.Ptr(), t.Length() );
Sub::length += t.Length();
if (t.Back() != '\\' && t.Back() != '/')
{
const T c = '\\';
Sub::string.Insert( Sub::length++, &c, 1 );
}
}
}
template<typename T>
void Path<T>::DirectorySub::operator -= (uint subs)
{
if (subs && Sub::length && (Sub::Back() == '\\' || Sub::Back() == '/'))
{
uint i = Sub::length - 1;
uint p = ~0U;
do
{
if (Sub::string.At(--i) == '\\' || Sub::string.At(i) == '/')
{
p = i;
if (!--subs)
break;
}
}
while (i);
if (p != ~0U)
{
const uint n = Sub::length;
Sub::length = ++p;
Sub::string.Erase( p, n - p );
}
}
}
template<typename T>
void Path<T>::ExtensionSub::Clear()
{
const uint dot = (Sub::offset && Sub::string[Sub::offset-1] == '.');
const uint n = Sub::length;
Sub::length = 0;
Sub::string.Erase( Sub::offset -= dot, n + dot );
}
template<typename T>
void Path<T>::ExtensionSub::Assign(const T* NST_RESTRICT t,uint n)
{
Clear();
if (n)
{
if (*t == '.')
{
++t;
--n;
}
if (n)
{
Sub::length = n;
const T c = '.';
Sub::string.Insert( Sub::offset++, &c, 1 );
Sub::string.Insert( Sub::offset, t, n );
}
}
}
template<typename T>
const Path<T> Path<T>::Compact(const Any t,const uint maxLength)
{
Path path;
if (t.Length())
{
path.Reserve( maxLength );
if (Compact( path.Ptr(), Path<>(t).Ptr(), maxLength ))
path.Validate();
else
path.Clear();
}
return path;
}
template<typename T=wchar_t>
class Hex
{
public:
typedef T Type;
enum
{
TYPE_SIZE = sizeof(Type)
};
private:
Type buffer[12];
const Type* const string;
const uint length;
void Convert(uint,uint);
public:
Hex(const uint b,const uint v,const bool n0x=false)
:
string(n0x ? buffer + 2 : buffer),
length(n0x ? b/4 : 2+b/4)
{
NST_ASSERT( b == 8 || b == 16 || b == 32 );
Convert( v, 2+b/4 );
}
const Type* Ptr() const
{
return string;
}
uint Length() const
{
return length;
}
};
template<typename T>
void Hex<T>::Convert(uint number,const uint length)
{
Type* it = buffer + length;
*it = '\0';
static const Type lut[] =
{
'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'
};
do
{
*--it = lut[number % 16];
number /= 16;
}
while (it != buffer + 2);
*--it = 'x';
*--it = '0';
}
template<typename T=wchar_t>
class Real : Base
{
public:
typedef T Type;
enum
{
TYPE_SIZE = sizeof(Type)
};
Real(double,uint=1,bool=false);
private:
static bool Fraction(double v)
{
return std::modf( v, &v );
}
Type buffer[24];
const uint length;
public:
const Type* Ptr() const
{
return buffer;
}
uint Length() const
{
return length;
}
};
template<typename T>
Real<T>::Real(double v,uint d,bool p)
: length( Base::FromDouble( buffer, v, p || (d > 1 && Fraction(v)) ? d : 1 )) {}
}
typedef String::Heap<wchar_t> HeapString;
typedef String::Generic<wchar_t> GenericString;
typedef String::Generic<wchar_t,true> ValueString;
typedef String::Hex<wchar_t> HexString;
typedef String::Real<wchar_t> RealString;
typedef String::Path<wchar_t> Path;
}
#endif