mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
2280 lines
45 KiB
C++
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
|