/***********************************************************************
* fstring.h - Unicode string class with UTF-8 support *
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2012-2019 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
* as published by the Free Software Foundation; either version 3 of *
* the License, or (at your option) any later version. *
* *
* The Final Cut 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program. If not, see *
* . *
***********************************************************************/
/* Standalone class
* ════════════════
*
* ▕▔▔▔▔▔▔▔▔▔▏
* ▕ FString ▏
* ▕▁▁▁▁▁▁▁▁▁▏
*/
#ifndef FSTRING_H
#define FSTRING_H
#if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
#error "Only can be included directly."
#endif
#include
#include
#include
#include // for read errno
#include
#include
#include
#include // need for va_list, va_start and va_end
#include // need for vsprintf
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "final/fc.h"
#include "final/ftypes.h"
namespace finalcut
{
// class forward declaration
class FString;
// Global typedef
typedef std::vector FStringList;
//----------------------------------------------------------------------
// class FString
//----------------------------------------------------------------------
class FString
{
public:
// Typedef
typedef const wchar_t* const_iterator;
typedef wchar_t* iterator;
// Constructors
FString () = default;
explicit FString (int);
explicit FString (std::size_t);
FString (std::size_t, wchar_t);
FString (const FString&); // implicit conversion copy constructor
FString (FString&&); // implicit conversion move constructor
FString (const std::wstring&); // implicit conversion constructor
FString (const wchar_t[]); // implicit conversion constructor
FString (const std::string&); // implicit conversion constructor
FString (const char[]); // implicit conversion constructor
FString (fc::SpecialCharacter); // implicit conversion constructor
FString (const wchar_t); // implicit conversion constructor
FString (const char); // implicit conversion constructor
// Destructor
virtual ~FString ();
// Overloaded operators
FString& operator = (const FString&);
FString& operator = (FString&&);
const FString& operator += (const FString&);
const FString operator + (const FString&);
const FString operator + (const wchar_t);
const FString operator + (const char);
FString& operator << (const FString&);
FString& operator << (fc::SpecialCharacter);
FString& operator << (const wchar_t);
FString& operator << (const char);
template ::value
|| std::is_floating_point::value
, int>::type = 0 >
FString& operator << (const NumT);
const FString& operator >> (FString&);
const FString& operator >> (std::wstring&);
const FString& operator >> (std::string&);
const FString& operator >> (wchar_t&);
const FString& operator >> (char&);
const FString& operator >> (sInt16&);
const FString& operator >> (uInt16&);
const FString& operator >> (sInt32&);
const FString& operator >> (uInt32&);
const FString& operator >> (sInt64&);
const FString& operator >> (uInt64&);
const FString& operator >> (double&);
const FString& operator >> (float&);
template
wchar_t& operator [] (const IndexT);
template
const wchar_t& operator [] (const IndexT) const;
const FString& operator () ();
bool operator < (const FString&) const;
template
bool operator < (const CharT&) const;
bool operator <= (const FString&) const;
template
bool operator <= (const CharT&) const;
bool operator == (const FString&) const;
template
bool operator == (const CharT&) const;
bool operator != (const FString&) const;
template
bool operator != (const CharT&) const;
bool operator >= (const FString&) const;
template
bool operator >= (const CharT&) const;
bool operator > (const FString&) const;
template
bool operator > (const CharT&) const;
operator const char* () const { return c_str(); }
// Accessor
virtual const FString getClassName();
// inquiries
bool isNull() const;
bool isEmpty() const;
// Methods
std::size_t getLength() const;
std::size_t getUTF8length() const;
std::size_t capacity() const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
wchar_t front() const;
wchar_t back() const;
template
FString& sprintf (const FString&, Args&&...);
FString clear();
const wchar_t* wc_str() const;
wchar_t* wc_str();
const char* c_str() const;
char* c_str();
const std::string toString() const;
FString toLower() const;
FString toUpper() const;
sInt16 toShort() const;
uInt16 toUShort() const;
int toInt() const;
uInt toUInt() const;
long toLong() const;
uLong toULong() const;
float toFloat() const;
double toDouble() const;
FString ltrim() const;
FString rtrim() const;
FString trim() const;
FString left (std::size_t) const;
FString right (std::size_t) const;
FString mid (std::size_t, std::size_t) const;
FStringList split (const FString&);
FString& setString (const FString&);
template
FString& setNumber (NumT, int = getPrecision());
FString& setNumber (sInt64);
FString& setNumber (uInt64);
FString& setNumber (lDouble, int = getPrecision());
template
FString& setFormatedNumber (NumT, char = nl_langinfo(THOUSEP)[0]);
FString& setFormatedNumber (sInt64, char = nl_langinfo(THOUSEP)[0]);
FString& setFormatedNumber (uInt64, char = nl_langinfo(THOUSEP)[0]);
const FString& insert (const FString&, int);
const FString& insert (const FString&, std::size_t);
FString replace (const FString&, const FString&);
FString replaceControlCodes() const;
FString expandTabs (int = 8) const;
FString removeDel() const;
FString removeBackspaces() const;
const FString& overwrite (const FString&, int);
const FString& overwrite (const FString&, std::size_t = 0);
const FString& remove (std::size_t, std::size_t);
bool includes (const FString&) const;
private:
// Constants
static constexpr uInt FWDBUFFER = 15;
static constexpr uInt INPBUFFER = 200;
static constexpr uInt CHAR_SIZE = sizeof(wchar_t); // bytes per character
// Methods
void initLength (std::size_t);
void _assign (const wchar_t[]);
void _insert (std::size_t, const wchar_t[]);
void _insert (std::size_t, std::size_t, const wchar_t[]);
void _remove (std::size_t, std::size_t);
char* wc_to_c_str (const wchar_t[]) const;
wchar_t* c_to_wc_str (const char[]) const;
wchar_t* extractToken (wchar_t*[], const wchar_t[], const wchar_t[]);
// Data members
wchar_t* string{nullptr};
std::size_t length{0};
std::size_t bufsize{0};
mutable char* c_string{nullptr};
static wchar_t null_char;
static const wchar_t const_null_char;
// Friend Non-member operator functions
friend const FString operator + (const FString&, const FString&);
friend const FString operator + (const FString&, const wchar_t);
friend const FString operator + (const std::wstring&, const FString&);
friend const FString operator + (const wchar_t[], const FString&);
friend const FString operator + (const std::string&, const FString&);
friend const FString operator + (const char[], const FString&);
friend const FString operator + (const wchar_t, const FString&);
friend const FString operator + (const char, const FString&);
friend const FString operator + (const FString&, const char);
friend std::ostream& operator << (std::ostream&, const FString&);
friend std::istream& operator >> (std::istream&, FString& s);
friend std::wostream& operator << (std::wostream&, const FString&);
friend std::wistream& operator >> (std::wistream&, FString&);
};
// FString inline functions
//----------------------------------------------------------------------
template ::value
|| std::is_floating_point::value
, int>::type >
inline FString& FString::operator << (const NumT val)
{
FString numstr(FString().setNumber(val));
_insert (length, numstr.length, numstr.string);
return *this;
}
//----------------------------------------------------------------------
template
inline wchar_t& FString::operator [] (const IndexT pos)
{
if ( isNegative(pos) || pos > IndexT(length) )
throw std::out_of_range(""); // Invalid index position
if ( std::size_t(pos) == length )
return null_char;
return string[std::size_t(pos)];
}
//----------------------------------------------------------------------
template
inline const wchar_t& FString::operator [] (const IndexT pos) const
{
if ( isNegative(pos) || pos > IndexT(length) )
throw std::out_of_range(""); // Invalid index position
if ( std::size_t(pos) == length )
return const_null_char;
return string[std::size_t(pos)];
}
//----------------------------------------------------------------------
template
inline bool FString::operator < (const CharT& s) const
{
const FString tmp(s);
return *this < tmp;
}
//----------------------------------------------------------------------
template
inline bool FString::operator <= (const CharT& s) const
{
const FString tmp(s);
return *this <= tmp;
}
//----------------------------------------------------------------------
template
inline bool FString::operator == (const CharT& s) const
{
const FString tmp(s);
return *this == tmp;
}
//----------------------------------------------------------------------
template
inline bool FString::operator != (const CharT& s) const
{
const FString tmp(s);
return *this != tmp;
}
//----------------------------------------------------------------------
template
inline bool FString::operator >= (const CharT& s) const
{
const FString tmp(s);
return *this >= tmp;
}
//----------------------------------------------------------------------
template
inline bool FString::operator > (const CharT& s) const
{
const FString tmp(s);
return *this > tmp;
}
//----------------------------------------------------------------------
inline const FString FString::getClassName()
{ return "FString"; }
//----------------------------------------------------------------------
inline bool FString::isNull() const
{ return ! string; }
//----------------------------------------------------------------------
inline bool FString::isEmpty() const
{ return ( ! string ) || ( ! *string ); }
//----------------------------------------------------------------------
inline std::size_t FString::getLength() const
{ return length; }
//----------------------------------------------------------------------
inline std::size_t FString::capacity() const
{ return ( length > 0 ) ? bufsize - 1 : 0; }
//----------------------------------------------------------------------
inline FString::iterator FString::begin()
{ return string; }
//----------------------------------------------------------------------
inline FString::iterator FString::end()
{ return string + length; }
//----------------------------------------------------------------------
inline FString::const_iterator FString::begin() const
{ return string; }
//----------------------------------------------------------------------
inline FString::const_iterator FString::end() const
{ return string + length; }
//----------------------------------------------------------------------
inline wchar_t FString::front() const
{
assert ( ! isEmpty() );
return string[0];
}
//----------------------------------------------------------------------
inline wchar_t FString::back() const
{
assert( ! isEmpty() );
return string[length - 1];
}
//----------------------------------------------------------------------
template
inline FString& FString::sprintf (const FString& format, Args&&... args)
{
static constexpr int BUFSIZE = 4096;
wchar_t buf[BUFSIZE]{};
if ( format.isEmpty() )
{
clear();
return *this;
}
std::swprintf ( buf, BUFSIZE, format.wc_str()
, std::forward(args)... );
_assign(buf);
return *this;
}
//----------------------------------------------------------------------
template
inline FString& FString::setNumber (NumT num, int precision)
{
if ( std::is_floating_point::value )
return setNumber (lDouble(num), precision);
if ( isNegative(num) )
return setNumber (sInt64(num));
return setNumber (uInt64(num));
}
//----------------------------------------------------------------------
template
inline FString& FString::setFormatedNumber (NumT num, char separator)
{
if ( isNegative(num) )
return setFormatedNumber (sInt64(num), separator);
return setFormatedNumber (uInt64(num), separator);
}
} // namespace finalcut
#endif // FSTRING_H