Path: blob/master/thirdparty/icu4c/common/charstr.cpp
9903 views
// © 2016 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html2/*3*******************************************************************************4* Copyright (C) 2010-2015, International Business Machines5* Corporation and others. All Rights Reserved.6*******************************************************************************7* file name: charstr.cpp8* encoding: UTF-89* tab size: 8 (not used)10* indentation:411*12* created on: 2010may1913* created by: Markus W. Scherer14*/1516#include <cstdlib>1718#include "unicode/utypes.h"19#include "unicode/putil.h"20#include "charstr.h"21#include "cmemory.h"22#include "cstring.h"23#include "uinvchar.h"24#include "ustr_imp.h"2526U_NAMESPACE_BEGIN2728CharString::CharString(CharString&& src) noexcept29: buffer(std::move(src.buffer)), len(src.len) {30src.len = 0; // not strictly necessary because we make no guarantees on the source string31}3233CharString& CharString::operator=(CharString&& src) noexcept {34buffer = std::move(src.buffer);35len = src.len;36src.len = 0; // not strictly necessary because we make no guarantees on the source string37return *this;38}3940char *CharString::cloneData(UErrorCode &errorCode) const {41if (U_FAILURE(errorCode)) { return nullptr; }42char *p = static_cast<char *>(uprv_malloc(len + 1));43if (p == nullptr) {44errorCode = U_MEMORY_ALLOCATION_ERROR;45return nullptr;46}47uprv_memcpy(p, buffer.getAlias(), len + 1);48return p;49}5051int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {52if (U_FAILURE(errorCode)) { return len; }53if (capacity < 0 || (capacity > 0 && dest == nullptr)) {54errorCode = U_ILLEGAL_ARGUMENT_ERROR;55return len;56}57const char *src = buffer.getAlias();58if (0 < len && len <= capacity && src != dest) {59uprv_memcpy(dest, src, len);60}61return u_terminateChars(dest, capacity, len, &errorCode);62}6364CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {65if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {66len=s.len;67uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);68}69return *this;70}7172CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {73if (U_FAILURE(errorCode)) {74return *this;75}76len = 0;77append(s, errorCode);78return *this;79}8081int32_t CharString::lastIndexOf(char c) const {82for(int32_t i=len; i>0;) {83if(buffer[--i]==c) {84return i;85}86}87return -1;88}8990bool CharString::contains(StringPiece s) const {91if (s.empty()) { return false; }92const char *p = buffer.getAlias();93int32_t lastStart = len - s.length();94for (int32_t i = 0; i <= lastStart; ++i) {95if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {96return true;97}98}99return false;100}101102CharString &CharString::truncate(int32_t newLength) {103if(newLength<0) {104newLength=0;105}106if(newLength<len) {107buffer[len=newLength]=0;108}109return *this;110}111112CharString &CharString::append(char c, UErrorCode &errorCode) {113if(ensureCapacity(len+2, 0, errorCode)) {114buffer[len++]=c;115buffer[len]=0;116}117return *this;118}119120CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {121if(U_FAILURE(errorCode)) {122return *this;123}124if(sLength<-1 || (s==nullptr && sLength!=0)) {125errorCode=U_ILLEGAL_ARGUMENT_ERROR;126return *this;127}128if(sLength<0) {129sLength= static_cast<int32_t>(uprv_strlen(s));130}131if(sLength>0) {132if(s==(buffer.getAlias()+len)) {133// The caller wrote into the getAppendBuffer().134if(sLength>=(buffer.getCapacity()-len)) {135// The caller wrote too much.136errorCode=U_INTERNAL_PROGRAM_ERROR;137} else {138buffer[len+=sLength]=0;139}140} else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&141sLength>=(buffer.getCapacity()-len)142) {143// (Part of) this string is appended to itself which requires reallocation,144// so we have to make a copy of the substring and append that.145return append(CharString(s, sLength, errorCode), errorCode);146} else if(ensureCapacity(len+sLength+1, 0, errorCode)) {147uprv_memcpy(buffer.getAlias()+len, s, sLength);148buffer[len+=sLength]=0;149}150}151return *this;152}153154CharString &CharString::appendNumber(int64_t number, UErrorCode &status) {155if (number < 0) {156this->append('-', status);157if (U_FAILURE(status)) {158return *this;159}160}161162if (number == 0) {163this->append('0', status);164return *this;165}166167int32_t numLen = 0;168while (number != 0) {169int32_t residue = number % 10;170number /= 10;171this->append(std::abs(residue) + '0', status);172numLen++;173if (U_FAILURE(status)) {174return *this;175}176}177178int32_t start = this->length() - numLen, end = this->length() - 1;179while(start < end) {180std::swap(this->data()[start++], this->data()[end--]);181}182183return *this;184}185186char *CharString::getAppendBuffer(int32_t minCapacity,187int32_t desiredCapacityHint,188int32_t &resultCapacity,189UErrorCode &errorCode) {190if(U_FAILURE(errorCode)) {191resultCapacity=0;192return nullptr;193}194int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL195if(appendCapacity>=minCapacity) {196resultCapacity=appendCapacity;197return buffer.getAlias()+len;198}199if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {200resultCapacity=buffer.getCapacity()-len-1;201return buffer.getAlias()+len;202}203resultCapacity=0;204return nullptr;205}206207CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {208return appendInvariantChars(s.getBuffer(), s.length(), errorCode);209}210211CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) {212if(U_FAILURE(errorCode)) {213return *this;214}215if (!uprv_isInvariantUString(uchars, ucharsLen)) {216errorCode = U_INVARIANT_CONVERSION_ERROR;217return *this;218}219if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {220u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);221len += ucharsLen;222buffer[len] = 0;223}224return *this;225}226227UBool CharString::ensureCapacity(int32_t capacity,228int32_t desiredCapacityHint,229UErrorCode &errorCode) {230if(U_FAILURE(errorCode)) {231return false;232}233if(capacity>buffer.getCapacity()) {234if(desiredCapacityHint==0) {235desiredCapacityHint=capacity+buffer.getCapacity();236}237if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&238buffer.resize(capacity, len+1)==nullptr239) {240errorCode=U_MEMORY_ALLOCATION_ERROR;241return false;242}243}244return true;245}246247CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {248if(U_FAILURE(errorCode)) {249return *this;250}251if(s.length()==0) {252return *this;253}254char c;255if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {256append(getDirSepChar(), errorCode);257}258append(s, errorCode);259return *this;260}261262CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {263char c;264if(U_SUCCESS(errorCode) && len>0 &&265(c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {266append(getDirSepChar(), errorCode);267}268return *this;269}270271char CharString::getDirSepChar() const {272char dirSepChar = U_FILE_SEP_CHAR;273#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)274// We may need to return a different directory separator when building for Cygwin or MSYS2.275if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))276dirSepChar = U_FILE_ALT_SEP_CHAR;277#endif278return dirSepChar;279}280281U_NAMESPACE_END282283284