1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: fnd_FixedLengthString.h 4 5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 25571 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NN_FND_FIXEDLENGTHSTRING_H_ 17 #define NN_FND_FIXEDLENGTHSTRING_H_ 18 19 #include <cstring> 20 #include <algorithm> 21 #include <nn/util/util_TypeTraits.h> 22 #include <nn/util/util_StaticAssert.h> 23 24 namespace nn { namespace fnd { 25 26 #pragma push 27 #pragma diag_suppress 1301 28 #pragma diag_suppress 2530 29 30 namespace detail 31 { 32 template <class TChar> 33 class FixedLengthStringHeader 34 { 35 protected: 36 TChar* m_Data; 37 s32 m_Length; 38 }; 39 40 template <class TChar, size_t TMaxLength> 41 struct FixedLengthStringSize 42 { 43 static const size_t value = sizeof(FixedLengthStringHeader<TChar>) + (TMaxLength + 1) * sizeof(TChar); 44 }; 45 46 template <class TChar, size_t TObjectSize> 47 struct FixedLengthStringBuffer : public FixedLengthStringHeader<TChar> 48 { 49 static const size_t Length = (TObjectSize - sizeof(FixedLengthStringHeader<TChar>)) / sizeof(TChar); 50 TChar m_Buffer[Length]; 51 }; 52 } 53 54 /* 55 @brief 固定長の NULL 終端文字列 56 57 演算結果などが TMaxLength を超えた場合、IsValid が false を返す。 58 */ 59 template < 60 class TChar, 61 size_t TMaxLength, 62 size_t TObjectSize = detail::FixedLengthStringSize<TChar, TMaxLength>::value, 63 class = typename nn::util::enable_if<( 64 TObjectSize >= detail::FixedLengthStringSize<TChar, TMaxLength>::value 65 )>::type 66 > 67 class FixedLengthString : private detail::FixedLengthStringBuffer<TChar, TObjectSize> 68 { 69 typedef detail::FixedLengthStringBuffer<TChar, TObjectSize> Base; 70 public: 71 72 typedef TChar Char; 73 static const size_t MaxLength = TMaxLength; 74 static const size_t ObjectSize = TObjectSize; 75 static const size_t DefaultHead = (Base::Length - MaxLength) / 2; 76 77 private: 78 79 using Base::m_Buffer; 80 using Base::m_Length; 81 using Base::m_Data; 82 GetHeadIndex()83 size_t GetHeadIndex() const 84 { 85 return m_Data - m_Buffer; 86 } 87 SetInvalid()88 void SetInvalid() 89 { 90 this->m_Length = -1; 91 this->m_Data[0] = 0; 92 this->m_Data = 0; 93 } 94 CheckValid()95 void CheckValid() const 96 { 97 NN_TASSERT_(IsValid()); 98 } 99 CheckIndex(s32 i)100 void CheckIndex(s32 i) const 101 { 102 NN_UNUSED_VAR(i); 103 NN_TASSERT_(0 <= i && i <= m_Length); 104 } 105 CheckLength(s32 length)106 void CheckLength(s32 length) const 107 { 108 NN_UNUSED_VAR(length); 109 NN_TASSERT_(0 <= length && length <= MaxLength); 110 } 111 CalculateLength(const Char * s,s32 maxLength)112 static s32 CalculateLength(const Char* s, s32 maxLength) 113 { 114 for (s32 i = 0; i < maxLength + 1; ++i) 115 { 116 if (!s[i]) 117 { 118 return i; 119 } 120 } 121 return maxLength + 1; 122 } 123 124 template <class T> 125 void CopyFrom(const T* s, s32 i = 0) 126 { 127 for (; i < MaxLength + 1; ++i) 128 { 129 if (!*s) 130 { 131 SetLength(i); 132 return; 133 } 134 this->m_Data[i] = *s++; 135 } 136 NN_TWARNING_(true, "too long string."); 137 SetInvalid(); 138 } 139 140 void MoveData(size_t index = DefaultHead) 141 { 142 NN_TASSERT_(GetLength() + index <= Base::Length); 143 std::memmove(m_Buffer + index, m_Data, GetLength() + 1); 144 SetHead(index); 145 } 146 147 void SetHead(size_t index = DefaultHead) 148 { 149 this->m_Data = m_Buffer + index; 150 } 151 SetLength(s32 length)152 void SetLength(s32 length) 153 { 154 if (0 <= length && length <= MaxLength) 155 { 156 this->m_Length = length; 157 this->m_Data[length] = 0; 158 } 159 else 160 { 161 NN_TWARNING_(true, "too long string."); 162 SetInvalid(); 163 } 164 } 165 166 public: 167 IsValid()168 bool IsValid() const 169 { 170 return m_Data != 0; 171 } 172 FixedLengthString()173 FixedLengthString() 174 { 175 SetHead(); 176 SetLength(0); 177 } 178 179 template <class T> FixedLengthString(const T * s)180 FixedLengthString(const T* s) 181 { 182 if (s) 183 { 184 SetHead(); 185 SetLength(0); 186 CopyFrom(s); 187 } 188 else 189 { 190 SetInvalid(); 191 } 192 } 193 194 template <size_t Length, size_t Size> FixedLengthString(const FixedLengthString<TChar,Length,Size> & s1)195 FixedLengthString(const FixedLengthString<TChar, Length, Size>& s1) 196 { 197 SetHead(); 198 SetLength(0); 199 AppendTail(s1); 200 } 201 GetLength()202 s32 GetLength() const 203 { 204 CheckValid(); 205 return m_Length; 206 } 207 Clear()208 FixedLengthString& Clear() 209 { 210 SetHead(); 211 SetLength(0); 212 return *this; 213 } 214 GetString()215 const Char* GetString() const 216 { 217 CheckValid(); 218 return m_Data; 219 } 220 221 operator const Char*() const { return GetString(); } 222 223 const Char& operator[](s32 i) const 224 { 225 CheckValid(); 226 CheckIndex(i); 227 return m_Data[i]; 228 } 229 GetChar(s32 i)230 Char GetChar(s32 i) const { return (*this)[i]; } 231 232 template <size_t Length, size_t Size> AppendHead(const FixedLengthString<Char,Length,Size> & s)233 FixedLengthString& AppendHead(const FixedLengthString<Char, Length, Size>& s) 234 { 235 if (!this->IsValid() || !s.IsValid()) 236 { 237 this->SetInvalid(); 238 return *this; 239 } 240 if (this->GetHeadIndex() < s.GetLength()) 241 { 242 s32 originalLength = this->GetLength(); 243 SetLength(this->GetLength() + s.GetLength()); 244 if (IsValid()) 245 { 246 std::memmove(m_Data + s.GetLength(), m_Data, sizeof(Char) * originalLength); 247 std::memcpy(m_Data, s.GetString(), sizeof(Char) * s.GetLength()); 248 NN_TASSERT_(m_Data[m_Length] == 0); 249 } 250 } 251 else 252 { 253 SetHead(GetHeadIndex() - s.GetLength()); 254 SetLength(this->GetLength() + s.GetLength()); 255 if (IsValid()) 256 { 257 std::memcpy(m_Data, s.GetString(), s.GetLength() * sizeof(Char)); 258 } 259 } 260 return *this; 261 } 262 AppendHead(const Char * s)263 FixedLengthString& AppendHead(const Char* s) 264 { 265 if (!this->IsValid()) 266 { 267 return *this; 268 } 269 s32 length = CalculateLength(s, MaxLength - this->GetLength()); 270 if (this->GetHeadIndex() < length) 271 { 272 s32 originalLength = this->GetLength(); 273 SetLength(this->GetLength() + length); 274 if (IsValid()) 275 { 276 std::memmove(m_Data + length, m_Data, sizeof(Char) * originalLength); 277 std::memcpy(m_Data, s, sizeof(Char) * length); 278 NN_TASSERT_(m_Data[m_Length] == 0); 279 } 280 } 281 else 282 { 283 SetHead(GetHeadIndex() - length); 284 SetLength(this->GetLength() + length); 285 if (IsValid()) 286 { 287 std::memcpy(m_Data, s, length * sizeof(Char)); 288 } 289 } 290 return *this; 291 } 292 293 template <size_t Length, size_t Size> AppendTail(const FixedLengthString<Char,Length,Size> & s)294 FixedLengthString& AppendTail(const FixedLengthString<Char, Length, Size>& s) 295 { 296 if (!this->IsValid() || !s.IsValid()) 297 { 298 this->SetInvalid(); 299 return *this; 300 } 301 if (GetHeadIndex() > Base::Length - MaxLength) 302 { 303 MoveData(); 304 } 305 Char* p = m_Data + this->GetLength(); 306 SetLength(this->GetLength() + s.GetLength()); 307 if (IsValid()) 308 { 309 std::memcpy(p, s.GetString(), sizeof(Char) * s.GetLength()); 310 NN_TASSERT_(m_Data[m_Length] == 0); 311 } 312 return *this; 313 } 314 AppendTail(const Char * s)315 FixedLengthString& AppendTail(const Char* s) 316 { 317 if (!this->IsValid()) 318 { 319 return *this; 320 } 321 if (GetHeadIndex() > Base::Length - MaxLength) 322 { 323 MoveData(); 324 } 325 CopyFrom(s, this->GetLength()); 326 return *this; 327 } 328 AppendTailAsHex(bit32 x)329 FixedLengthString& AppendTailAsHex(bit32 x) 330 { 331 if (!this->IsValid()) 332 { 333 return *this; 334 } 335 if (GetHeadIndex() > Base::Length - MaxLength) 336 { 337 MoveData(); 338 } 339 Char* p = m_Data + this->GetLength(); 340 SetLength(this->GetLength() + 8); 341 if (IsValid()) 342 { 343 for (s32 i = 0; i < 8; ++i) 344 { 345 bit32 n = (x >> ((7 - i) * 4)) & 0xf; 346 NN_TASSERT_(0 <= n && n < 16); 347 p[i] = static_cast<Char>(n < 10 ? '0' + n : 'a' + (n - 10)); 348 } 349 NN_TASSERT_(m_Data[m_Length] == 0); 350 } 351 return *this; 352 } 353 354 template <class Char2> AppendTail(const Char2 * s,size_t size)355 FixedLengthString& AppendTail(const Char2* s, size_t size) 356 { 357 if (!this->IsValid()) 358 { 359 return *this; 360 } 361 if (GetHeadIndex() > Base::Length - MaxLength) 362 { 363 MoveData(); 364 } 365 Char* p = m_Data + this->GetLength(); 366 SetLength(this->GetLength() + size); 367 if (IsValid()) 368 { 369 for (s32 i = 0; i < size; ++i) 370 { 371 p[i] = s[i]; 372 } 373 NN_TASSERT_(m_Data[m_Length] == 0); 374 } 375 return *this; 376 } 377 378 template <class Char2, size_t Size> AppendTail(const Char2 s[Size])379 FixedLengthString& AppendTail(const Char2 s[Size]) 380 { 381 return AppendTail(s, Size); 382 } 383 EraseTail(size_t length)384 FixedLengthString& EraseTail(size_t length) 385 { 386 if (!this->IsValid()) 387 { 388 return *this; 389 } 390 this->SetLength(this->GetLength() - length); 391 return *this; 392 } 393 EraseHead(size_t length)394 FixedLengthString& EraseHead(size_t length) 395 { 396 if (!this->IsValid()) 397 { 398 return *this; 399 } 400 this->SetHead(this->GetHeadIndex() + length); 401 this->SetLength(this->GetLength() - length); 402 return *this; 403 } 404 405 template <size_t Length, size_t Size> 406 FixedLengthString& operator+=(const FixedLengthString<Char, Length, Size>& rhs) 407 { 408 this->AppendTail(rhs); 409 return *this; 410 } 411 412 template <class Char2, size_t Size> 413 FixedLengthString& operator+=(const Char2 s[Size]) { return AppendTail(s); } 414 415 FixedLengthString& operator+=(const Char* rhs) 416 { 417 this->AppendTail(rhs); 418 return *this; 419 } 420 421 template <size_t Length2, size_t Size2> 422 friend bool operator==(const FixedLengthString& lhs, const FixedLengthString<Char, Length2, Size2>& rhs) 423 { 424 return lhs.GetLength() == rhs.GetLength() && std::memcmp(lhs.GetString(), rhs.GetString(), sizeof(Char) * lhs.GetLength()) == 0; 425 } 426 427 friend bool operator==(const FixedLengthString& lhs, const Char* rhs) 428 { 429 return std::memcmp(lhs.m_Data, rhs, sizeof(Char) * lhs.GetLength()) == 0 && rhs[lhs.GetLength()] == 0; 430 } 431 432 friend bool operator==(const Char* lhs, const FixedLengthString& rhs) 433 { 434 return rhs == lhs; 435 } 436 437 template <size_t Length2, size_t Size2> 438 friend bool operator!=(const FixedLengthString& lhs, const FixedLengthString<Char, Length2, Size2>& rhs) 439 { 440 return !(lhs == rhs); 441 } 442 443 friend bool operator!=(const FixedLengthString& lhs, const Char* rhs) 444 { 445 return !(lhs == rhs); 446 } 447 448 friend bool operator!=(const Char* lhs, const FixedLengthString& rhs) 449 { 450 return !(lhs == rhs); 451 } 452 453 template <size_t Length, size_t Size> 454 friend bool operator<(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 455 { 456 int n = std::memcmp(lhs.GetString(), rhs.GetString(), sizeof(Char) * std::min(lhs.GetLength(), rhs.GetLength())); 457 return n < 0 || (n == 0 && lhs.GetLength() < rhs.GetLength()); 458 } 459 460 template <size_t Length, size_t Size> 461 friend bool operator>(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 462 { 463 return rhs < lhs; 464 } 465 466 template <size_t Length, size_t Size> 467 friend bool operator<=(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 468 { 469 return !(lhs > rhs); 470 } 471 472 template <size_t Length, size_t Size> 473 friend bool operator>=(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 474 { 475 return rhs <= lhs; 476 } 477 478 }; 479 480 // 固定長文字列 481 // 必ずしも NULL 終端ではない 482 // const な 値クラス 483 template <class TChar, size_t TMaxLength> 484 class LightFixedLengthString 485 { 486 public: 487 488 typedef TChar Char; 489 static const size_t MaxLength = TMaxLength; 490 491 private: 492 493 Char m_Buffer[MaxLength]; 494 CopyFrom(const Char * s)495 void CopyFrom(const Char* s) 496 { 497 for (size_t i = 0; i < MaxLength; ++i) 498 { 499 this->m_Buffer[i] = *s; 500 if (!*s++) 501 { 502 return; 503 } 504 } 505 NN_TWARNING_(*s, "too long string."); 506 if (*s) 507 { 508 // 長すぎるので無効 509 this->m_Buffer[0] = 0; 510 } 511 } 512 513 public: 514 LightFixedLengthString()515 LightFixedLengthString() 516 { 517 this->m_Buffer[0] = 0; 518 } 519 LightFixedLengthString(const Char * s)520 LightFixedLengthString(const Char* s) 521 { 522 CopyFrom(s); 523 } 524 LightFixedLengthString(const Char * s,size_t size)525 LightFixedLengthString(const Char* s, size_t size) 526 { 527 if (size > MaxLength) 528 { 529 size = MaxLength; 530 } 531 NN_TASSERT_(size <= MaxLength); 532 std::memcpy(this->m_Buffer, s, size); 533 if (size < MaxLength) 534 { 535 this->m_Buffer[size] = 0; 536 } 537 } 538 GetLength()539 size_t GetLength() const 540 { 541 size_t i = 0; 542 for (; i < MaxLength; ++i) 543 { 544 if (!m_Buffer[i]) 545 { 546 break; 547 } 548 } 549 return i; 550 } 551 552 Char operator[](size_t i) const 553 { 554 NN_TASSERT_(i < MaxLength); 555 return m_Buffer[i]; 556 } 557 558 LightFixedLengthString& operator=(const Char* s) 559 { 560 CopyFrom(s); 561 return *this; 562 } 563 564 }; 565 566 #pragma pop 567 568 }} 569 570 #endif 571