1// Copyright 2014 The Android Open Source Project 2// 3// This software is licensed under the terms of the GNU General Public 4// License version 2, as published by the Free Software Foundation, and 5// may be copied, distributed, and modified under those terms. 6// 7// This program is distributed in the hope that it will be useful, 8// but WITHOUT ANY WARRANTY; without even the implied warranty of 9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10// GNU General Public License for more details. 11 12#include "android/base/String.h" 13 14#include "android/base/Limits.h" 15#include "android/base/Log.h" 16#include "android/base/memory/MallocUsableSize.h" 17#include "android/base/StringView.h" 18 19#include <limits.h> 20#include <stdlib.h> 21#include <string.h> 22 23namespace android { 24namespace base { 25 26String::String() : mStr(mStorage), mSize(0) { 27 mStorage[0] = '\0'; 28} 29 30 31String::String(const char* str) : mStr(mStorage), mSize(0) { 32 assign(str, ::strlen(str)); 33} 34 35 36String::String(const char* str, size_t len) : mStr(mStorage), mSize(0) { 37 assign(str, len); 38} 39 40 41String::String(const String& other) : mStr(mStorage), mSize(0) { 42 assign(other); 43} 44 45 46String::String(const StringView& other) : mStr(mStorage), mSize(0) { 47 assign(other); 48} 49 50 51String::String(size_t count, char fill) : mStr(mStorage), mSize(0) { 52 this->assign(count, fill); 53} 54 55 56String::~String() { 57 reserve(0U); 58 // Prevent misuse from dangling pointers. 59 mStr = NULL; 60 mSize = 0; 61 mCapacity = 0; 62} 63 64String& String::assign(const char* str) { 65 return this->assign(str, ::strlen(str)); 66} 67 68 69String& String::assign(const char* str, size_t len) { 70 this->resize(len); 71 ::memmove(mStr, str, len); 72 return *this; 73} 74 75 76String& String::assign(const String& other) { 77 return this->assign(other.c_str(), other.size()); 78} 79 80 81String& String::assign(const StringView& other) { 82 return this->assign(other.str(), other.size()); 83} 84 85 86String& String::assign(char ch) { 87 return this->assign(&ch, 1U); 88} 89 90 91String& String::assign(size_t count, char fill) { 92 this->resize(count); 93 ::memset(mStr, fill, count); 94 return *this; 95} 96 97 98String& String::append(const char* str, size_t len) { 99 size_t oldSize = mSize; 100 this->resize(mSize + len); 101 ::memmove(mStr + oldSize, str, len); 102 return *this; 103} 104 105 106String& String::append(const char* str) { 107 return this->append(str, ::strlen(str)); 108} 109 110 111String& String::append(const String& other) { 112 return this->append(other.c_str(), other.size()); 113} 114 115 116String& String::append(const StringView& other) { 117 return this->append(other.str(), other.size()); 118} 119 120 121String& String::append(char ch) { 122 return this->append(&ch, 1U); 123} 124 125 126int String::compare(const char* str, size_t len) const { 127 if (mSize == 0) 128 return (len == 0) ? 0 : -1; 129 130 if (len == 0) 131 return +1; 132 133 int ret = ::strncmp(mStr, str, len); 134 if (ret < 0) 135 return -1; 136 if (ret > 0) 137 return +1; 138 139 if (mSize < len) 140 return -1; 141 if (mSize > len) 142 return +1; 143 return 0; 144} 145 146 147int String::compare(const char* str) const { 148 return compare(str, ::strlen(str)); 149} 150 151 152int String::compare(const String& other) const { 153 return compare(other.c_str(), other.size()); 154} 155 156 157int String::compare(const StringView& other) const { 158 return compare(other.str(), other.size()); 159} 160 161 162int String::compare(char ch) const { 163 return compare(&ch, 1U); 164} 165 166 167bool String::equals(const char* str, size_t len) const { 168 if (mSize == 0) 169 return (len == 0); 170 171 if (len != mSize) 172 return false; 173 174 return !::memcmp(mStr, str, len); 175} 176 177 178bool String::equals(const char* str) const { 179 return equals(str, ::strlen(str)); 180} 181 182 183bool String::equals(const String& other) const { 184 return equals(other.c_str(), other.size()); 185} 186 187 188bool String::equals(const StringView& other) const { 189 return equals(other.str(), other.size()); 190} 191 192 193bool String::equals(char ch) const { 194 return equals(&ch, 1U); 195} 196 197 198void String::resize(size_t newSize) { 199 if (!mStr) 200 mStr = mStorage; 201 202 size_t oldCapacity = capacity(); 203 if (newSize < oldCapacity) { 204 if (oldCapacity >= 256U && newSize < oldCapacity / 2) { 205 reserve(newSize); 206 } 207 } else if (newSize > oldCapacity) { 208 const size_t kMaxCapacity = SIZE_MAX - 1U; 209 CHECK(newSize < kMaxCapacity); 210 211 size_t newCapacity = oldCapacity; 212 while (newCapacity < newSize) { 213 size_t newCapacity2 = newCapacity + (newCapacity >> 2) + 8; 214 newCapacity = (newCapacity2 < newCapacity) 215 ? kMaxCapacity : newCapacity2; 216 } 217 reserve(newCapacity); 218 } 219 DCHECK(newSize <= capacity()); 220 mSize = newSize; 221 mStr[newSize] = '\0'; 222} 223 224 225void String::reserve(size_t newSize) { 226 size_t minSize = (newSize < kMinCapacity) ? kMinCapacity : newSize; 227 228 if (!mStr) 229 mStr = mStorage; 230 231 if (minSize == kMinCapacity) { 232 if (mStr != mStorage) { 233 // Copy the first bytes to mStorage, then free the heap 234 // allocated buffer. 235 ::memcpy(mStorage, mStr, newSize); 236 ::free(mStr); 237 mStr = mStorage; 238 } 239 } else /* newSize > kMinCapacity */ { 240 char* oldStorage = (mStr == mStorage) ? NULL : mStr; 241 size_t newStorageSize = newSize + 1U; 242 mStr = static_cast<char*>(::realloc(oldStorage, newStorageSize)); 243#if xxxUSE_MALLOC_USABLE_SIZE 244 size_t usableSize = malloc_usable_size(mStr); 245 if (usableSize > newStorageSize) 246 newStorageSize = usableSize; 247#endif 248 if (!oldStorage) { 249 ::memcpy(mStr, mStorage, mSize); 250 } 251 if (newSize > mSize) { 252 ::memset(mStr + mSize, 0, newSize - mSize); 253 } 254 mCapacity = newStorageSize - 1U; 255 } 256 mStr[newSize] = '\0'; 257} 258 259void String::swap(String* other) { 260 if (this == other) 261 return; 262 263 char* myStr = mStr; 264 size_t mySize = mSize; 265 size_t myCapacity = capacity(); 266 267 char* theirStr = other->mStr; 268 size_t theirSize = other->mSize; 269 size_t theirCapacity = other->capacity(); 270 271 if (myStr == mStorage) { 272 if (theirStr == other->mStorage) { 273 // Two small strings, swap buffer contents, no need to swap 274 // pointers or capacities. 275 for (size_t n = 0; n < kMinCapacity + 1U; ++n) { 276 char tmp = myStr[n]; 277 myStr[n] = theirStr[n]; 278 theirStr[n] = tmp; 279 } 280 } else { 281 // |this| is a small string, |other| is a long one. 282 ::memcpy(other->mStorage, mStorage, mySize + 1U); 283 other->mStr = other->mStorage; 284 mStr = theirStr; 285 mCapacity = theirCapacity; 286 } 287 } else if (theirStr == other->mStorage) { 288 // |this| is a long string, |other| is a short string. 289 ::memcpy(mStorage, other->mStorage, theirSize + 1U); 290 other->mStr = myStr; 291 other->mCapacity = myCapacity; 292 mStr = mStorage; 293 } else { 294 // Both |this| and |other| are long strings. 295 mStr = theirStr; 296 mCapacity = theirCapacity; 297 other->mStr = myStr; 298 other->mCapacity = myCapacity; 299 } 300 // Always swap the sizes. 301 mSize = theirSize; 302 other->mSize = mySize; 303} 304 305// static 306void String::adjustMovedSlice(String* fromStrings, 307 String* toStrings, 308 size_t count) { 309 for (size_t n = 0; n < count; ++n) { 310 if (toStrings[n].mStr == fromStrings[n].mStorage) { 311 toStrings[n].mStr = toStrings[n].mStorage; 312 } 313 } 314} 315 316// static 317void String::moveSlice(String* strings, 318 size_t from, 319 size_t to, 320 size_t count) { 321 // First, move all slice items with ::memmove(). 322 ::memmove(strings + to, strings + from, count * sizeof(String)); 323 // Second, adjust mStorage pointers. 324 adjustMovedSlice(strings + from, strings + to, count); 325} 326 327void String::finalizeSlice(String* strings, size_t count) { 328 for (size_t n = count; n > 0; --n) { 329 strings[n - 1U].reserve(0U); 330 } 331} 332 333} // namespace base 334} // namespace android 335