/**
* @file lib.BaseString.hpp
* @author Sergey Baigudin, sergey@baigudin.software
* @copyright 2017-2022, Sergey Baigudin, Baigudin Software
*/
#ifndef LIB_BASESTRING_HPP_
#define LIB_BASESTRING_HPP_
#include "lib.AbstractBaseString.hpp"
namespace eoos
{
namespace lib
{
/**
* @class BaseString<T,L,R,A>
* @brief Static base string class.
*
* Primary template implements the static string class.
*
* @tparam T A data type of string characters.
* @tparam L A maximum number of string characters, or 0 for dynamic allocation.
* @tparam R A character traits.
* @tparam A A heap memory allocator class.
*/
template <typename T, int32_t L, class R = CharTrait<T>, class A = Allocator>
class BaseString : public AbstractBaseString<T,R,A>
{
typedef AbstractBaseString<T,R,A> Parent;
public:
using Parent::isConstructed;
using Parent::convert;
/**
* @brief Constructor.
*/
BaseString()
: AbstractBaseString<T,R,A>() {
bool_t const isConstructed( construct() );
setConstructed( isConstructed );
}
/**
* @brief Constructor.
*
* @param source A source object interface.
*/
BaseString(api::String<T> const& source)
: AbstractBaseString<T,R,A>() {
bool_t const isConstructed( construct( source.getChar() ) );
setConstructed( isConstructed );
}
/**
* @brief Constructor.
*
* @param source A source character string.
*/
BaseString(T const* const source)
: AbstractBaseString<T,R,A>() {
bool_t const isConstructed( construct( source ) );
setConstructed( isConstructed );
}
/**
* @brief Constructor.
*
* @param value A source numerical value.
* @param base A numerical base used to represent a value as this string.
*/
explicit BaseString(int32_t const value, Number::Base const base = Number::BASE_10)
: AbstractBaseString<T,R,A>() {
bool_t isConstructed( construct() );
if( isConstructed )
{
isConstructed = convert(value, base);
}
setConstructed( isConstructed );
}
/**
* @brief Destructor.
*/
virtual ~BaseString()
{
}
/**
* @copydoc eoos::Object::Object(Object const&)
*/
BaseString(BaseString const& obj) ///< SCA MISRA-C++:2008 Justified Rule 12-8-1
: AbstractBaseString<T,R,A>(obj) {
bool_t const isConstructed( construct( obj.getChar() ) );
setConstructed( isConstructed );
}
/**
* @copydoc eoos::Object::operator=(Object const&)
*/
BaseString& operator=(BaseString const& obj)
{
if( isConstructed() && (this != &obj) )
{
copyRaw3(str_, obj.str_, L);
Parent::operator=(obj);
}
return *this;
}
#if EOOS_CPP_STANDARD >= 2011
/**
* @copydoc eoos::Object::Object(Object&&)
*/
BaseString(BaseString&& obj) noexcept
: AbstractBaseString<T,R,A>( move(obj) ) {
copyRaw3(str_, obj.str_, L);
}
/**
* @copydoc eoos::Object::operator=(Object&&)
*/
BaseString& operator=(BaseString&& obj) & noexcept
{
if( isConstructed() && (this != &obj) )
{
copyRaw3(str_, obj.str_, L);
Parent::operator=( move(obj) );
}
return *this;
}
#endif // EOOS_CPP_STANDARD >= 2011
/**
* @copydoc eoos::api::Collection::getLength()
*/
virtual size_t getLength() const
{
size_t length( 0U );
if( isConstructed() )
{
// @todo Rework here not to calculate length, but take it form a class member.
length = getLengthRaw(str_);
}
return length;
}
/**
* @copydoc eoos::api::String::getChar()
*/
virtual T const* getChar() const
{
T const* str( NULLPTR );
if( isConstructed() )
{
str = str_;
}
return str;
}
protected:
using Parent::setConstructed;
using Parent::getLengthRaw;
using Parent::copyRaw3;
using Parent::concatenateRaw3;
using Parent::isEqualRaw2;
private:
/**
* @copydoc eoos::lib::AbstractBaseString::copyRaw(T const*)
*/
virtual bool_t copyRaw(T const* const str)
{
bool_t res( false );
if( isConstructed() && (str != NULLPTR) )
{
copyRaw3(str_, str, L);
res = true;
}
return res;
}
/**
* @copydoc eoos::lib::AbstractBaseString::concatenate(T const*)
*/
virtual bool_t concatenateRaw(T const* const str)
{
bool_t res( false );
if( isConstructed() && (str != NULLPTR) )
{
concatenateRaw3(str_, str, L);
res = true;
}
return res;
}
/**
* @copydoc eoos::lib::AbstractBaseString::isEqualToRaw(T const*)
*/
virtual bool_t isEqualToRaw(T const* const str) const
{
bool_t res( false );
if( isConstructed() && (str != NULLPTR) )
{
res = isEqualRaw2(str_, str);
}
return res;
}
/**
* @brief Constructs this object.
*
* @param str A string to be copied on construction.
* @return True if this object has been constructed successfully.
*/
bool_t construct(T const* const str = NULLPTR)
{
str_[0] = R::getTerminator();
bool_t res( false );
do
{
if( !isConstructed() )
{
break;
}
res = ( str == NULLPTR ) ? true : copyRaw(str);
} while(false);
return res;
}
/**
* @brief The buffer of characters of this string.
*/
T str_[L + 1];
};
#ifdef EOOS_ENABLE_DYNAMIC_HEAP_MEMORY
/**
* @class BaseString<T,0,R,A>
* @brief Dynamic base string class.
*
* Partial specialization of the template implements the dynamic string class.
*
* @tparam T Data type of string characters.
* @tparam R A character traits.
* @tparam A Heap memory allocator class.
*/
template <typename T, class R, class A>
class BaseString<T,0,R,A> : public AbstractBaseString<T,R,A>
{
typedef AbstractBaseString<T,R,A> Parent;
public:
using Parent::isConstructed;
using Parent::convert;
/**
* @brief Constructor.
*/
BaseString()
: AbstractBaseString<T,R,A>()
, len_(0)
, str_(NULLPTR){
bool_t const isConstructed( construct() );
setConstructed( isConstructed );
}
/**
* @brief Constructor.
*
* @param source A source object interface.
*/
BaseString(api::String<T> const& source)
: AbstractBaseString<T,R,A>()
, len_(0)
, str_(NULLPTR){
bool_t const isConstructed( construct( source.getChar() ) );
setConstructed( isConstructed );
}
/**
* @brief Constructor.
*
* @param source A source character string.
*/
BaseString(T const* const source)
: AbstractBaseString<T,R,A>()
, len_(0)
, str_(NULLPTR){
bool_t const isConstructed( construct( source ) );
setConstructed( isConstructed );
}
/**
* @brief Constructor.
*
* @param value A source numerical value.
* @param base A numerical base used to represent a value as this string.
*/
explicit BaseString(int32_t const value, Number::Base const base = Number::BASE_10)
: AbstractBaseString<T,R,A>()
, len_(0)
, str_(NULLPTR){
bool_t isConstructed( construct() );
if( isConstructed )
{
isConstructed = convert(value, base);
}
setConstructed( isConstructed );
}
/**
* @brief Destructor.
*/
virtual ~BaseString()
{
free();
}
/**
* @copydoc eoos::Object::Object(Object const&)
*/
BaseString(BaseString const& obj) ///< SCA MISRA-C++:2008 Justified Rule 12-8-1
: AbstractBaseString<T,R,A>(obj)
, len_(0)
, str_(NULLPTR){
bool_t const isConstructed( construct( obj.getChar() ) );
setConstructed( isConstructed );
}
/**
* @copydoc eoos::Object::operator=(Object const&)
*/
BaseString& operator=(BaseString const& obj)
{
if( isConstructed() && (this != &obj) )
{
static_cast<void>( copyRaw( obj.getChar() ) );
Parent::operator=(obj);
}
return *this;
}
#if EOOS_CPP_STANDARD >= 2011
/**
* @copydoc eoos::Object::Object(Object&&)
*/
BaseString(BaseString&& obj) noexcept
: AbstractBaseString<T,R,A>( move(obj) )
, len_(obj.len_)
, str_(obj.str_){
obj.clean();
}
/**
* @copydoc eoos::Object::operator=(Object&&)
*/
BaseString& operator=(BaseString&& obj) & noexcept
{
if( isConstructed() && (this != &obj) )
{
free();
len_ = obj.len_;
str_ = obj.str_;
obj.clean();
Parent::operator=( move(obj) );
}
return *this;
}
#endif // EOOS_CPP_STANDARD >= 2011
/**
* @copydoc eoos::api::Collection::getLength()
*/
virtual size_t getLength() const
{
size_t length( 0U );
if( isConstructed() )
{
// @todo Rework here not to calculate length, but take it form a class member.
length = getLengthRaw(str_);
}
return length;
}
/**
* @copydoc eoos::api::String::getChar()
*/
virtual T const* getChar() const
{
T const* str( NULLPTR );
if( isConstructed() )
{
str = str_;
}
return str;
}
protected:
using Parent::setConstructed;
using Parent::getLengthRaw;
using Parent::copyRaw3;
using Parent::concatenateRaw3;
using Parent::isEqualRaw2;
private:
/**
* @copydoc eoos::lib::AbstractBaseString::copyRaw(T const*)
*/
virtual bool_t copyRaw(T const* const str)
{
bool_t res( false );
if( isConstructed() && (str != NULLPTR) )
{
size_t const length( getLengthRaw(str) );
bool_t isPrepared( prepareCopy(length) );
if( isPrepared )
{
copyRaw3(str_, str, len_);
res = true;
}
}
return res;
}
/**
* @copydoc eoos::lib::AbstractBaseString::concatenate(T const*)
*/
virtual bool_t concatenateRaw(T const* const str)
{
bool_t res( false );
if( isConstructed() && (str != NULLPTR) )
{
size_t const length( getLength() + getLengthRaw(str) );
bool_t isPrepared( prepareConcatenate(length) );
if( isPrepared )
{
concatenateRaw3(str_, str, len_);
res = true;
}
}
return res;
}
/**
* @copydoc eoos::lib::AbstractBaseString::isEqualToRaw(T const*)
*/
virtual bool_t isEqualToRaw(T const* const str) const
{
bool_t res( false );
if( isConstructed() && (str != NULLPTR) )
{
res = isEqualRaw2(str_, str);
}
return res;
}
/**
* @brief Constructs this object.
*
* @param str A string to be copied on construction.
* @return True if this object has been constructed successfully.
*/
bool_t construct(T const* const str = NULLPTR)
{
bool_t res( false );
do
{
if( !isConstructed() )
{
break;
}
size_t length( LENGTH_ON_CONSTRUCTION );
if( str != NULLPTR )
{
length = getLengthRaw(str);
}
bool_t isAllocated( allocate(length) );
if( !isAllocated )
{
break;
}
res = ( str == NULLPTR ) ? true : copyRaw(str);
} while(false);
return res;
}
/**
* @brief Prepare this string for a new length to copy.
*
* @param length A number of string characters.
* @return True if the the string is prepared.
*/
bool_t prepareCopy(size_t length)
{
bool_t res(true);
if( !isFit(length) )
{
free();
res = allocate(length);
}
return res;
}
/**
* @brief Prepare this string for a new length to copy.
*
* @param length A number of string characters.
* @return True if the the string is prepared.
*/
bool_t prepareConcatenate(size_t length)
{
bool_t res(true);
if( !isFit(length) )
{
// @todo Refactor this implementation to make it be more clear.
T* const str( str_ );
size_t const len( len_ );
clean();
res = allocate(length);
if( res )
{
copyRaw3(str_, str, len);
}
A::free(str);
}
return res;
}
/**
* @brief Allocates memory for a string.
*
* @param length A number of string characters.
* @return True if the context has been allocated successfully.
*/
bool_t allocate(size_t const length)
{
bool_t res( false );
if( (str_ == NULLPTR) && (length != 0U) )
{
size_t const size( calculateSize(length) );
T* const string( reinterpret_cast<T*>( A::allocate(size) ) );
if(string != NULLPTR)
{
str_ = string;
len_ = length;
str_[0] = R::getTerminator();
res = true;
}
}
return res;
}
/**
* @brief Frees this contex.
*/
void free()
{
if(str_ != NULLPTR)
{
A::free(str_);
str_ = NULLPTR;
len_ = 0U;
}
}
/**
* @brief Cleans this contex.
*/
void clean()
{
str_ = NULLPTR;
len_ = 0U;
}
/**
* @brief Returns size in byte for a string length.
*
* @param len A number of string characters.
* @return Size in byte for a passed string.
*/
static size_t calculateSize(size_t len)
{
return (len * sizeof(T)) + sizeof(T);
}
/**
* @brief Tests if a passed length fits to allocated available length.
*
* @param len A number of string characters.
* @return True if this length will be fit successfully.
*/
bool_t isFit(size_t len) const ///< SCA MISRA-C++:2008 Justified Rule 2-10-2
{
return len <= len_;
}
/**
* @brief Lenght of the buffer of characters on construction.
*
* @note Cannot be zero.
*/
static const size_t LENGTH_ON_CONSTRUCTION = 7U;
/**
* @brief Lenght of the buffer of characters of this string.
*/
size_t len_;
/**
* @brief The buffer of characters of this string.
*
* @todo Refactor this to be array on construction,
* and if new assigned string is more than LENGTH_ON_CONSTRUCTION,
* allocate a new array dynamically. To implement this approach and
* reduce size of the class object, revise using a `union` type.
*/
T* str_;
};
#endif // EOOS_ENABLE_DYNAMIC_HEAP_MEMORY
/**
* @brief Concatenates two strings.
*
* @param source1 A source object 1.
* @param source2 A source object 2.
* @return This string object with the concatenated strings.
*/
template <typename T, int32_t L, class R, class A>
inline BaseString<T,L,R,A> operator+(BaseString<T,L,R,A> const& source1, BaseString<T,L,R,A> const& source2)
{
BaseString<T,L,R,A> string(source1);
string += source2;
return string;
}
/**
* @brief Concatenates two strings.
*
* @param source1 A source object 1.
* @param source2 A source object interface 2.
* @return This string object with the concatenated strings.
*/
template <typename T, int32_t L, class R, class A>
inline BaseString<T,L,R,A> operator+(BaseString<T,L,R,A> const& source1, api::String<T> const& source2)
{
BaseString<T,L,R,A> string(source1);
string += source2;
return string;
}
/**
* @brief Concatenates two strings.
*
* @param source1 A source object interface 1.
* @param source2 A source object 2.
* @return This string object with the concatenated strings.
*/
template <typename T, int32_t L, class R, class A>
inline BaseString<T,L,R,A> operator+(api::String<T> const& source1, BaseString<T,L,R,A> const& source2)
{
BaseString<T,L,R,A> string(source1);
string += source2;
return string;
}
/**
* @brief Concatenates two strings.
*
* @param source1 A source object 1.
* @param source2 A source character string 2.
* @return This string object with the concatenated strings.
*/
template <typename T, int32_t L, class R, class A>
inline BaseString<T,L,R,A> operator+(BaseString<T,L,R,A> const& source1, T const* const source2)
{
BaseString<T,L,R,A> string(source1);
string += source2;
return string;
}
/**
* @brief Concatenates two strings.
*
* @param source1 A source character string 1.
* @param source2 A source object 2.
* @return This string object with the concatenated strings.
*/
template <typename T, int32_t L, class R, class A>
inline BaseString<T,L,R,A> operator+(T const* const source1, BaseString<T,L,R,A> const& source2)
{
BaseString<T,L,R,A> string(source1);
string += source2;
return string;
}
} // namespace lib
} // namespace eoos
#endif // LIB_BASESTRING_HPP_