/** * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL-2 (see license file) */ #include #include #include #if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0 const size_t etk::String::m_sizeLocal = 64-sizeof(etk::Vector); #else const char* getStaticEmptyString() { static const char* tmp = "\0\0\0\0\0\0"; return tmp; } #endif etk::String::String(): m_data() { #if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0 static_assert(sizeof(etk::String) == ETK_ENABLE_INTERNAL_DATA_IN_STRING, "Wrong basic size of string"); //printf("size of string=%ld %ld %ld\n", uint64_t(sizeof(etk::String)), m_sizeLocal, uint64_t(sizeof(etk::Vector))); memset(m_localData, 0, sizeof(m_localData)); #else //m_data.resize(1, '\0'); #endif } etk::String::String(const etk::String& _obj) { #if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0 if (_obj.size() < sizeof(m_localData)) { if (_obj.m_data.size() != 0) { memcpy(m_localData, &_obj.m_data[0], _obj.m_data.size()); } else { memcpy(m_localData, _obj.m_localData, sizeof(m_localData)); } } else { m_data = _obj.m_data; } #else m_data = _obj.m_data; #endif } etk::String::String(const etk::String& _obj, size_t _pos, size_t _size) { if (_pos + _size >= _obj.size()) { _size = etk::String::npos; } if (_size != etk::String::npos) { #if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0 if (_size < sizeof(m_localData)) { if (_obj.m_data.size() != 0) { } else { } } else { resize(_size); for (size_t iii=0; iii<_size; ++iii) { m_data[iii] = _obj.m_data[_pos+iii]; } } #else resize(_size); for (size_t iii=0; iii<_size; ++iii) { m_data[iii] = _obj.m_data[_pos+iii]; } #endif return; } resize(_obj.size()-_pos); for (size_t iii=0; iii<_obj.size()-_pos; ++iii) { m_data[iii] = _obj.m_data[_pos+iii]; } } etk::String::String(const char* _obj) { if (_obj == null) { resize(0); return; } uint32_t size = strlen(_obj); /*if (size == 0) { return; }*/ resize(size); for (size_t iii=0; iii '%s'\n", size, _obj, &m_data[0]); } /* etk::String::String(const etk::String _obj) { resize(_obj.size()); for (size_t iii=0; iii<_obj.size(); ++iii) { m_data[iii] = _obj[iii]; } } */ etk::String::String(const char* _obj, size_t _size) { if ( _obj == null || _size == 0) { resize(0); return; } uint32_t size = strlen(_obj); if (_size < size) { size = _size; } resize(size); for (size_t iii=0; iii size()) { //TK_ERROR("Resize does not work correctly ... not added item"); return; } for (size_t iii=0; iii<_nbElement; iii++) { m_data[idElement+iii] = _item[iii]; } } void etk::String::popBack() { if(size() > 0) { resize(size()-1); } } char& etk::String::back() { return m_data[m_data.size()-2]; } const char& etk::String::back() const { return m_data[m_data.size()-2]; } void etk::String::reserve(size_t _size) { m_data.reserve(_size+1); } void etk::String::clear() { m_data.clear(); } void etk::String::insert(size_t _pos, const char* _item, size_t _nbElement) { if (_pos>size()) { //TK_WARNING(" can not insert Element at this position : " << _pos << " > " << size() << " add it at the end ... "); pushBack(_item, _nbElement); return; } size_t idElement = size(); // Request resize of the current buffer resize(size()+_nbElement); if (idElement>=size()) { //TK_ERROR("Resize does not work correctly ... not added item"); return; } // move current data (after the position) size_t sizeToMove = (idElement - _pos); if ( 0 < sizeToMove) { for (size_t iii=1; iii<=sizeToMove; iii++) { m_data[size()-iii] = m_data[idElement-iii]; } } // affectation of all input element for (size_t iii=0; iii<_nbElement; iii++) { m_data[_pos+iii] = _item[iii]; } } void etk::String::insert(size_t _pos, const char _item) { insert(_pos, &_item, 1); } void etk::String::insert(size_t _pos, const etk::String& _value) { insert(_pos, &_value[0], _value.size()); } void etk::String::erase(size_t _pos, size_t _nbElement) { if (_pos>size()) { //TK_ERROR(" can not Erase Len Element at this position : " << _pos << " > " << size()); return; } if (_pos+_nbElement>size()) { _nbElement = size() - _pos; } size_t idElement = size(); // move current data size_t sizeToMove = (idElement - (_pos+_nbElement)); if ( 0 < sizeToMove) { for (size_t iii=0; iii size()) { //TK_ERROR(" can not Erase Element at this position : " << _pos << " > " << size()); return; } if (_posEnd > size()) { _posEnd = size(); } size_t nbElement = size() - _pos; size_t tmpSize = size(); // move current data size_t sizeToMove = (tmpSize - (_pos+nbElement)); if (sizeToMove > 0) { for (size_t iii=0; iii= size()) { _posEnd = size(); } if (_posStart >= size()) { return out; } if (_posStart >= _posEnd) { return out; } out.pushBack(&m_data[_posStart], _posEnd-_posStart); return out; } const char* etk::String::c_str() const { if (m_data.size() == 0) { return getStaticEmptyString(); } return &m_data[0]; } etk::String::Iterator etk::String::position(size_t _pos) { return etk::String::Iterator(this, _pos); } const etk::String::Iterator etk::String::position(size_t _pos) const { return etk::String::Iterator(this, _pos); } etk::String::Iterator etk::String::begin() { return position(0); } const etk::String::Iterator etk::String::begin() const { return position(0); } etk::String::Iterator etk::String::end() { return position(size()); } const etk::String::Iterator etk::String::end() const { return position(size()); } void etk::String::resize(size_t _newSize, char _value) { if (_newSize == 0) { m_data.clear(); return; } size_t oldSize = m_data.size(); if (oldSize != 0) { m_data[m_data.size()-1] = _value; } m_data.resize(_newSize + 1, _value); // in all case ==> we have the last element that is '\0' m_data[_newSize] = '\0'; } bool etk::String::operator== (const etk::String& _obj) const { // check if it was the same pointer if( this == &_obj ) { return true; } // first step: check the size... if (m_data.size() != _obj.m_data.size()) { return false; } for (size_t iii=0; iii= 'A' && _value <= 'Z') { return char(int(_value) + int('a') - int('A')); } return _value; } char etk::toUpper(char _value) { if ( _value >= 'a' && _value <= 'z') { return char(int(_value) + int('A') - int('a')); } return _value; } etk::String etk::String::toLower() const { etk::String tmp(*this); for (auto &it: tmp) { it = etk::toLower(it); } return tmp; } etk::String& etk::String::lower() { for (auto &it: m_data) { it = etk::toLower(it); } return *this; } etk::String etk::String::toUpper() const { etk::String tmp(*this); for (auto &it: tmp) { it = etk::toUpper(it); } return tmp; } etk::String& etk::String::upper() { for (auto &it: m_data) { it = etk::toUpper(it); } return *this; } bool etk::String::endWith(const etk::String& _val, bool _caseSensitive) const { if (_val.size() == 0) { return false; } if (_val.size() > size()) { return false; } if (_caseSensitive == true) { for( int64_t iii=_val.size()-1, jjj=size()-1; iii>=0 && jjj>=0; iii--, jjj--) { if (m_data[jjj] != _val[iii]) { return false; } } return true; } for( int64_t iii=_val.size()-1, jjj=size()-1; iii>=0 && jjj>=0; iii--, jjj--) { if (etk::toLower(_val[iii]) != etk::toLower(m_data[jjj])) { return false; } } return true; } bool etk::String::startWith(const etk::String& _val, bool _caseSensitive) const { if (_val.size() == 0) { return false; } if (_val.size() > size()) { return false; } if (_caseSensitive == true) { for( size_t iii = 0; iii < _val.size(); iii++) { if (m_data[iii] != _val[iii]) { return false; } } return true; } for( size_t iii = 0; iii < _val.size(); iii++) { if (etk::toLower(_val[iii]) != etk::toLower(m_data[iii])) { return false; } } return true; } template <> long double etk::String::to() const { long double ret = 0; sscanf(c_str(), "%Lf", &ret); return ret; } template <> double etk::String::to() const { double ret = 0; sscanf(c_str(), "%lf", &ret); return ret; } template <> float etk::String::to() const { float ret = 0; sscanf(c_str(), "%f", &ret); return ret; } template <> int8_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%d", &ret); return ret; } template <> int16_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%d", &ret); return ret; } template <> int32_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%d", &ret); return ret; } template <> int64_t etk::String::to() const { int64_t ret = 0; #if ( defined(__TARGET_OS__Android) \ || defined(__TARGET_OS__Windows) \ || defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs)) sscanf(c_str(), "%lld", &ret); #else sscanf(c_str(), "%ld", &ret); #endif return ret; } template <> uint8_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%d", &ret); return ret; } template <> uint16_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%d", &ret); return ret; } template <> uint32_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%d", &ret); return ret; } template <> uint64_t etk::String::to() const { uint64_t ret = 0; #if ( defined(__TARGET_OS__Android) \ || defined(__TARGET_OS__Windows) \ || defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs)) sscanf(c_str(), "%llu", &ret); #else sscanf(c_str(), "%lu", &ret); #endif return ret; } #if defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs) template <> size_t etk::String::to() const { int ret = 0; sscanf(c_str(), "%u", &ret); return ret; } #endif template <> bool etk::String::to() const { if( compare("true", false) == true || compare("enable", false) == true || compare("yes", false) == true || compare("1") == true) { return true; } return false; } etk::Stream& etk::operator <<(etk::Stream& _os, const etk::String& _obj) { _os << _obj.c_str(); return _os; } void etk::sort(etk::Vector &_list) { etk::Vector tmpList(_list); _list.clear(); for(size_t iii=0; iii *_list[jjj]) { findPos = jjj+1; } } //TK_DEBUG("position="< &_list) { etk::Vector tmpList(_list); _list.clear(); for(size_t iii=0; iii _list[jjj]) { findPos = jjj+1; } } //TK_DEBUG("position="< bool from_string(etk::String& _variableRet, const etk::String& _value) { _variableRet = _value; return true; } template<> bool from_string(int8_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(int16_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(int32_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(int64_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(uint8_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(uint16_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(uint32_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(uint64_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } #if defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs) template<> bool from_string(size_t& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } #endif template<> bool from_string(float& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(double& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(long double& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } template<> bool from_string(bool& _variableRet, const etk::String& _value) { _variableRet = _value.to(); return true; } } template<> etk::String etk::toString(const bool& _val) { if (_val == true) { return "true"; } return "false"; } template<> etk::String etk::toString(const int8_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%d", _val); return tmpVal; } template<> etk::String etk::toString(const int16_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%d", _val); return tmpVal; } template<> etk::String etk::toString(const int32_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%d", _val); return tmpVal; } template<> etk::String etk::toString(const int64_t& _val) { char tmpVal[256]; #if ( defined(__TARGET_OS__Android) \ || defined(__TARGET_OS__Windows) \ || defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs)) sprintf(tmpVal, "%lld", _val); #else sprintf(tmpVal, "%ld", _val); #endif return tmpVal; } template<> etk::String etk::toString(const uint8_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%u", _val); return tmpVal; } template<> etk::String etk::toString(const uint16_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%u", _val); return tmpVal; } template<> etk::String etk::toString(const uint32_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%u", _val); return tmpVal; } template<> etk::String etk::toString(const uint64_t& _val) { char tmpVal[256]; #if ( defined(__TARGET_OS__Android) \ || defined(__TARGET_OS__Windows) \ || defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs)) sprintf(tmpVal, "%llu", _val); #else sprintf(tmpVal, "%lu", _val); #endif return tmpVal; } #if defined(__TARGET_OS__MacOs) \ || defined(__TARGET_OS__IOs) template<> etk::String etk::toString(const size_t& _val) { char tmpVal[256]; sprintf(tmpVal, "%zu", _val); return tmpVal; } #endif template<> etk::String etk::toString(const float& _val) { char tmpVal[256]; sprintf(tmpVal, "%f", _val); return tmpVal; } template<> etk::String etk::toString(const double& _val) { char tmpVal[256]; sprintf(tmpVal, "%f", _val); return tmpVal; } template<> etk::String etk::toString(const long double& _val) { char tmpVal[256]; sprintf(tmpVal, "%Lf", _val); return tmpVal; } template<> etk::String etk::toString(const etk::UString& _input) { etk::String out; for (size_t iii=0; iii<_input.size(); ++iii) { char output[10]; u32char::convertUtf8(_input[iii], output); out += output; } return out; } template<> etk::String etk::toString(const char32_t& _input) { etk::String out; char output[10]; u32char::convertUtf8(_input, output); out += output; return out; } size_t etk::String::find(char _value, size_t _pos) const { for (size_t iii=_pos; iii= m_data.size()) { return etk::String::npos; } if (_value[jjj] != m_data[iii+jjj]) { check = false; break; } } if (check == true) { return iii; } } return etk::String::npos; } size_t etk::String::rfind(char _value, size_t _pos) const { if (_pos >= m_data.size()) { _pos = m_data.size()-1; } for (int64_t iii=_pos; iii>=0; --iii) { if (_value == m_data[iii]) { return iii; } } return etk::String::npos; } size_t etk::String::rfind(const etk::String& _value, size_t _pos) const { if (_pos >= m_data.size()) { _pos = m_data.size()-1; } for (int64_t iii=_pos; iii>=0; --iii) { bool check = true; for (size_t jjj=0; jjj<_value.size(); ++jjj) { if (iii+jjj >= m_data.size()) { check = false; break; } if (_value[jjj] != m_data[iii+jjj]) { check = false; break; } } if (check == true) { return iii; } } return etk::String::npos; } etk::String& etk::String::replace(size_t _pos, size_t _len, char _replace) { erase(_pos, _len); insert(_pos, _replace); return *this; } etk::String& etk::String::replace(size_t _pos, size_t _len, const etk::String& _replace) { erase(_pos, _len); insert(_pos, _replace); return *this; } etk::String& etk::String::replace(char _val, char _replace) { size_t pos = 0; while ((pos = find(_val, pos)) != etk::String::npos) { replace(pos, 1, _replace); pos += 1; } return *this; } etk::String& etk::String::replace(const etk::String& _val, const etk::String& _replace) { size_t pos = 0; while ((pos = find(_val, pos)) != etk::String::npos) { replace(pos, _val.size(), _replace); pos += _replace.size(); } return *this; } etk::String etk::String::getLine(int32_t _pos) const { // search back : '\n' size_t startPos = rfind('\n', _pos); if ((int64_t)startPos == (int64_t)_pos) { startPos = 0; } else { startPos++; } // search forward : '\n' size_t stopPos = _pos; if (m_data[_pos] != '\n') { stopPos = find('\n', _pos); if ((int64_t)stopPos == _pos) { stopPos = size(); } } if (startPos == etk::String::npos) { startPos = 0; } else if (startPos >= size() ) { return ""; } if (stopPos == etk::String::npos) { return ""; } else if (stopPos >= size() ) { stopPos = size(); } return etk::String(*this, startPos, stopPos - startPos); } bool etk::String::compare(const etk::String& _val, bool _caseSensitive) const { if (_val.size() != size()) { return false; } if (_caseSensitive == true) { for(size_t iii=0; iii<_val.size(); ++iii) { if (_val[iii] != m_data[iii]) { return false; } } return true; } for(size_t iii=0; iii<_val.size(); ++iii) { if (etk::toLower(_val[iii]) != etk::toLower(m_data[iii])) { return false; } } return true; } etk::Vector etk::String::split(char _val) const { etk::Vector list; size_t lastStartPos = 0; for(size_t iii=0; iii etk::String::split(etk::String _val) const { etk::Vector list; size_t lastStartPos = 0; for(size_t iii=0; iii(); } double string_to_double(const etk::String& _obj) { return _obj.to(); } float string_to_float(const etk::String& _obj) { return _obj.to(); } int8_t string_to_int8_t(const etk::String& _obj) { return _obj.to(); } int16_t string_to_int16_t(const etk::String& _obj) { return _obj.to(); } int32_t string_to_int32_t(const etk::String& _obj) { return _obj.to(); } int64_t string_to_int64_t(const etk::String& _obj) { return _obj.to(); } uint8_t string_to_uint8_t(const etk::String& _obj) { return _obj.to(); } uint16_t string_to_uint16_t(const etk::String& _obj) { return _obj.to(); } uint32_t string_to_uint32_t(const etk::String& _obj) { return _obj.to(); } uint64_t string_to_uint64_t(const etk::String& _obj) { return _obj.to(); } uint64_t hexaString_to_uint64_t(const etk::String& _obj) { size_t iii = 0; uint64_t out = 0; bool invert = false; etk::String tmp = _obj.toLower(); if (tmp.startWith("0x") == true) { iii = 2; } else if (tmp.startWith("-0x") == true) { iii = 3; invert = true; } else if (tmp.startWith("+0x") == true) { iii = 3; } for (; iii= '0' && tmp[iii] <= '9') { out += uint64_t(tmp[iii]) - uint64_t('0'); continue; } if ( tmp[iii] >= 'a' && tmp[iii] <= 'f') { out += uint64_t(tmp[iii]) - uint64_t('a') + 10; continue; } ETK_THROW_EXCEPTION(etk::exception::InvalidArgument(" not an hexadecimal value: '" + _obj + "'")); } if (invert == true) { int64_t tmp = *((int64_t*)&out); tmp *= -1; out = *((uint64_t*)&tmp); } return out; } uint64_t bitString_to_uint64_t(const etk::String& _obj) { size_t iii = 0; uint64_t out = 0; bool invert = false; etk::String tmp = _obj.toLower(); if (tmp.startWith("0b") == true) { iii = 2; } else if (tmp.startWith("-0b") == true) { iii = 3; invert = true; } else if (tmp.startWith("+0b") == true) { iii = 3; } for (; iii= '0' && tmp[iii] <= '7') { out += uint64_t(tmp[iii]) - uint64_t('0'); continue; } ETK_THROW_EXCEPTION(etk::exception::InvalidArgument(" not an octal value: '" + _obj + "'")); } if (invert == true) { int64_t tmp = *((int64_t*)&out); tmp *= -1; out = *((uint64_t*)&tmp); } return out; } bool string_to_bool(const etk::String& _obj) { return _obj.to(); } etk::String toLower(etk::String _obj) { return _obj.toLower(); } etk::String toUpper(etk::String _obj) { return _obj.toUpper(); } bool compare_no_case(const etk::String& _obj, const etk::String& _val) { return _obj.compare(_val, false); } bool end_with(const etk::String& _obj, const etk::String& _val, bool _caseSensitive) { return _obj.endWith(_val, _caseSensitive); } bool start_with(const etk::String& _obj, const etk::String& _val, bool _caseSensitive) { return _obj.startWith(_val, _caseSensitive); } etk::String replace(const etk::String& _obj, char _val, char _replace) { etk::String tmp = _obj; tmp.replace(_val, _replace); return tmp; } etk::String extract_line(const etk::String& _obj, int32_t _pos) { return _obj.getLine(_pos); } etk::Vector split(const etk::String& _obj, char _val) { return _obj.split(_val); } } bool etk::operator> (const etk::String& _left, const etk::String& _right) { for (size_t iii=0; iii<_left.size() && iii<_right.size(); ++iii) { if (_left[iii] > _right[iii]) { return true; } if (_left[iii] < _right[iii]) { return false; } } if (_left.size() > _right.size()) { return true; } return false; } bool etk::operator>= (const etk::String& _left, const etk::String& _right) { for (size_t iii=0; iii<_left.size() && iii<_right.size(); ++iii) { if (_left[iii] > _right[iii]) { return true; } if (_left[iii] < _right[iii]) { return false; } } if (_left.size() >= _right.size()) { return true; } return false; } bool etk::operator< (const etk::String& _left, const etk::String& _right) { for (size_t iii=0; iii<_left.size() && iii<_right.size(); ++iii) { if (_left[iii] < _right[iii]) { return true; } if (_left[iii] > _right[iii]) { return false; } } if (_left.size() < _right.size()) { return true; } return false; } bool etk::operator<= (const etk::String& _left, const etk::String& _right) { for (size_t iii=0; iii<_left.size() && iii<_right.size(); ++iii) { if (_left[iii] < _right[iii]) { return true; } if (_left[iii] > _right[iii]) { return false; } } if (_left.size() <= _right.size()) { return true; } return false; } etk::String etk::operator+ (const etk::String& _left, const etk::String& _right) { etk::String tmp = _left; tmp += _right; return tmp; } etk::String etk::operator+ (const etk::String& _left, const char* _right) { etk::String tmp = _left; tmp += _right; return tmp; } etk::String etk::operator+ (const char* _left, const etk::String& _right) { etk::String tmp = _left; tmp += _right; return tmp; } etk::String etk::operator+ (const etk::String& _left, char _right) { etk::String tmp = _left; tmp.pushBack(_right); return tmp; } etk::String etk::operator+ (char _left, const etk::String& _right) { etk::String tmp = _left; tmp += _right; return tmp; } namespace etk { template<> etk::String toString(const etk::String& _val) { return _val; } template<> bool from_string(etk::String& _variableRet, const etk::UString& _value) { _variableRet = u32char::convertToUtf8(_value); return true; } } char etk::toHexChar(uint8_t _value) { char out; if (_value < 10) { return _value + '0'; } return _value - 10 + 'A'; } etk::String etk::toHex(uint64_t _value, uint32_t _size) { etk::String out; for (int32_t iii = 15; iii >=0; --iii) { if ( _size >= uint64_t(iii) || _value >= uint64_t(1)<>(iii*4)) & 0x0F); } } return out; } etk::String etk::toBin(uint64_t _value, uint32_t _size) { etk::String out; for (int32_t iii = 63; iii >=0; --iii) { if ( _size >= uint64_t(iii) || _value >= uint64_t(1)<>(iii)) & 0x01); } } return out; }