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: 32837 $ 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) - 1; 50 TChar m_Buffer[Length + 1]; 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; 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, sizeof(Char) * (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 173 // for Test CheckState()174 bool CheckState() const 175 { 176 if (!IsValid()) 177 { 178 return true; 179 } 180 return 181 m_Buffer <= m_Data 182 && 0 <= m_Length && m_Length <= MaxLength 183 && m_Data + m_Length <= m_Buffer + Base::Length 184 && m_Data[m_Length] == 0 185 && MaxLength <= Base::Length 186 ; 187 } 188 FixedLengthString()189 FixedLengthString() 190 { 191 SetHead(); 192 SetLength(0); 193 } 194 195 template <class T> FixedLengthString(const T * s)196 FixedLengthString(const T* s) 197 { 198 if (s) 199 { 200 SetHead(); 201 SetLength(0); 202 CopyFrom(s); 203 } 204 else 205 { 206 SetInvalid(); 207 } 208 } 209 FixedLengthString(const FixedLengthString & s)210 FixedLengthString(const FixedLengthString& s) 211 { 212 SetHead(); 213 SetLength(0); 214 AppendTail(s); 215 } 216 217 template <size_t Length, size_t Size> FixedLengthString(const FixedLengthString<TChar,Length,Size> & s1)218 FixedLengthString(const FixedLengthString<TChar, Length, Size>& s1) 219 { 220 SetHead(); 221 SetLength(0); 222 AppendTail(s1); 223 } 224 GetLength()225 s32 GetLength() const 226 { 227 CheckValid(); 228 return m_Length; 229 } 230 Clear()231 FixedLengthString& Clear() 232 { 233 SetHead(); 234 SetLength(0); 235 return *this; 236 } 237 GetString()238 const Char* GetString() const 239 { 240 CheckValid(); 241 return m_Data; 242 } 243 244 operator const Char*() const { return GetString(); } 245 246 const Char& operator[](s32 i) const 247 { 248 CheckValid(); 249 CheckIndex(i); 250 return m_Data[i]; 251 } 252 GetChar(s32 i)253 Char GetChar(s32 i) const { return (*this)[i]; } 254 255 template <size_t Length, size_t Size> AppendHead(const FixedLengthString<Char,Length,Size> & str)256 FixedLengthString& AppendHead(const FixedLengthString<Char, Length, Size>& str) 257 { 258 if (!this->IsValid() || !str.IsValid()) 259 { 260 this->SetInvalid(); 261 return *this; 262 } 263 const Char* s = str.GetString(); 264 s32 length = str.GetLength(); 265 size_t totalSize = this->GetLength() + length; 266 if (totalSize > MaxLength) 267 { 268 SetInvalid(); 269 return *this; 270 } 271 if (this->GetHeadIndex() < length) 272 { 273 s32 originalLength = this->GetLength(); 274 std::memmove(m_Buffer + MaxLength - this->GetLength(), m_Data, sizeof(Char) * originalLength); 275 std::memcpy(m_Buffer + MaxLength - totalSize, s, sizeof(Char) * length); 276 SetHead(MaxLength - totalSize); 277 SetLength(totalSize); 278 NN_TASSERT_(m_Data[m_Length] == 0); 279 } 280 else 281 { 282 SetHead(GetHeadIndex() - length); 283 SetLength(this->GetLength() + length); 284 if (IsValid()) 285 { 286 std::memcpy(m_Data, s, length * sizeof(Char)); 287 } 288 } 289 return *this; 290 } 291 AppendHead(const Char * s)292 FixedLengthString& AppendHead(const Char* s) 293 { 294 if (!this->IsValid()) 295 { 296 return *this; 297 } 298 s32 length = CalculateLength(s, MaxLength - this->GetLength()); 299 if (s[length]) 300 { 301 SetInvalid(); 302 return *this; 303 } 304 if (this->GetHeadIndex() < length) 305 { 306 s32 originalLength = this->GetLength(); 307 size_t totalSize = this->GetLength() + length; 308 std::memmove(m_Buffer + MaxLength - this->GetLength(), m_Data, sizeof(Char) * originalLength); 309 std::memcpy(m_Buffer + MaxLength - totalSize, s, sizeof(Char) * length); 310 SetHead(MaxLength - totalSize); 311 SetLength(totalSize); 312 NN_TASSERT_(m_Data[m_Length] == 0); 313 } 314 else 315 { 316 SetHead(GetHeadIndex() - length); 317 SetLength(this->GetLength() + length); 318 if (IsValid()) 319 { 320 std::memcpy(m_Data, s, length * sizeof(Char)); 321 } 322 } 323 return *this; 324 } 325 326 template <size_t Length, size_t Size> AppendTail(const FixedLengthString<Char,Length,Size> & s)327 FixedLengthString& AppendTail(const FixedLengthString<Char, Length, Size>& s) 328 { 329 if (!this->IsValid() || !s.IsValid()) 330 { 331 this->SetInvalid(); 332 return *this; 333 } 334 if (GetHeadIndex() > Base::Length - MaxLength) 335 { 336 MoveData(); 337 } 338 Char* p = m_Data + this->GetLength(); 339 SetLength(this->GetLength() + s.GetLength()); 340 if (IsValid()) 341 { 342 std::memcpy(p, s.GetString(), sizeof(Char) * s.GetLength()); 343 NN_TASSERT_(m_Data[m_Length] == 0); 344 } 345 return *this; 346 } 347 AppendTail(const Char * s)348 FixedLengthString& AppendTail(const Char* s) 349 { 350 if (!this->IsValid()) 351 { 352 return *this; 353 } 354 if (GetHeadIndex() > Base::Length - MaxLength) 355 { 356 MoveData(); 357 } 358 CopyFrom(s, this->GetLength()); 359 return *this; 360 } 361 AppendHeadAsHex(bit32 x)362 FixedLengthString& AppendHeadAsHex(bit32 x) 363 { 364 Char hex[9]; 365 for (s32 i = 0; i < 8; ++i) 366 { 367 bit32 n = (x >> ((7 - i) * 4)) & 0xf; 368 NN_TASSERT_(0 <= n && n < 16); 369 hex[i] = static_cast<Char>(n < 10 ? '0' + n : 'a' + (n - 10)); 370 } 371 hex[8] = 0; 372 return AppendHead(hex); 373 } 374 AppendTailAsHex(bit32 x)375 FixedLengthString& AppendTailAsHex(bit32 x) 376 { 377 if (!this->IsValid()) 378 { 379 return *this; 380 } 381 if (GetHeadIndex() > Base::Length - MaxLength) 382 { 383 MoveData(); 384 } 385 Char* p = m_Data + this->GetLength(); 386 SetLength(this->GetLength() + 8); 387 if (IsValid()) 388 { 389 for (s32 i = 0; i < 8; ++i) 390 { 391 bit32 n = (x >> ((7 - i) * 4)) & 0xf; 392 NN_TASSERT_(0 <= n && n < 16); 393 p[i] = static_cast<Char>(n < 10 ? '0' + n : 'a' + (n - 10)); 394 } 395 NN_TASSERT_(m_Data[m_Length] == 0); 396 } 397 return *this; 398 } 399 400 template <class Char2> AppendTail(const Char2 * s,size_t size)401 FixedLengthString& AppendTail(const Char2* s, size_t size) 402 { 403 if (!this->IsValid()) 404 { 405 return *this; 406 } 407 if (GetHeadIndex() > Base::Length - MaxLength) 408 { 409 MoveData(); 410 } 411 Char* p = m_Data + this->GetLength(); 412 SetLength(this->GetLength() + size); 413 if (IsValid()) 414 { 415 for (s32 i = 0; i < size; ++i) 416 { 417 p[i] = s[i]; 418 } 419 NN_TASSERT_(m_Data[m_Length] == 0); 420 } 421 return *this; 422 } 423 424 template <class Char2, size_t Size> AppendTail(const Char2 s[Size])425 FixedLengthString& AppendTail(const Char2 s[Size]) 426 { 427 return AppendTail(s, Size); 428 } 429 EraseTail(size_t length)430 FixedLengthString& EraseTail(size_t length) 431 { 432 if (!this->IsValid()) 433 { 434 return *this; 435 } 436 this->SetLength(this->GetLength() - length); 437 return *this; 438 } 439 EraseHead(size_t length)440 FixedLengthString& EraseHead(size_t length) 441 { 442 if (!this->IsValid()) 443 { 444 return *this; 445 } 446 this->SetHead(this->GetHeadIndex() + length); 447 this->SetLength(this->GetLength() - length); 448 return *this; 449 } 450 451 template <size_t Length, size_t Size> 452 FixedLengthString& operator+=(const FixedLengthString<Char, Length, Size>& rhs) 453 { 454 this->AppendTail(rhs); 455 return *this; 456 } 457 458 template <class Char2, size_t Size> 459 FixedLengthString& operator+=(const Char2 s[Size]) { return AppendTail(s); } 460 461 FixedLengthString& operator+=(const Char* rhs) 462 { 463 this->AppendTail(rhs); 464 return *this; 465 } 466 467 template <size_t Length2, size_t Size2> 468 friend bool operator==(const FixedLengthString& lhs, const FixedLengthString<Char, Length2, Size2>& rhs) 469 { 470 return lhs.GetLength() == rhs.GetLength() && std::memcmp(lhs.GetString(), rhs.GetString(), sizeof(Char) * lhs.GetLength()) == 0; 471 } 472 473 friend bool operator==(const FixedLengthString& lhs, const Char* rhs) 474 { 475 return std::memcmp(lhs.m_Data, rhs, sizeof(Char) * lhs.GetLength()) == 0 && rhs[lhs.GetLength()] == 0; 476 } 477 478 friend bool operator==(const Char* lhs, const FixedLengthString& rhs) 479 { 480 return rhs == lhs; 481 } 482 483 template <size_t Length2, size_t Size2> 484 friend bool operator!=(const FixedLengthString& lhs, const FixedLengthString<Char, Length2, Size2>& rhs) 485 { 486 return !(lhs == rhs); 487 } 488 489 friend bool operator!=(const FixedLengthString& lhs, const Char* rhs) 490 { 491 return !(lhs == rhs); 492 } 493 494 friend bool operator!=(const Char* lhs, const FixedLengthString& rhs) 495 { 496 return !(lhs == rhs); 497 } 498 499 template <size_t Length, size_t Size> 500 friend bool operator<(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 501 { 502 int n = std::memcmp(lhs.GetString(), rhs.GetString(), sizeof(Char) * std::min(lhs.GetLength(), rhs.GetLength())); 503 return n < 0 || (n == 0 && lhs.GetLength() < rhs.GetLength()); 504 } 505 506 template <size_t Length, size_t Size> 507 friend bool operator>(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 508 { 509 return rhs < lhs; 510 } 511 512 template <size_t Length, size_t Size> 513 friend bool operator<=(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 514 { 515 return !(lhs > rhs); 516 } 517 518 template <size_t Length, size_t Size> 519 friend bool operator>=(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 520 { 521 return rhs <= lhs; 522 } 523 524 }; 525 526 // 固定長文字列 527 // 必ずしも NULL 終端ではない 528 // const な 値クラス 529 template <class TChar, size_t TMaxLength> 530 class LightFixedLengthString 531 { 532 public: 533 534 typedef TChar Char; 535 static const size_t MaxLength = TMaxLength; 536 537 private: 538 539 Char m_Buffer[MaxLength]; 540 CopyFrom(const Char * s)541 void CopyFrom(const Char* s) 542 { 543 for (size_t i = 0; i < MaxLength; ++i) 544 { 545 this->m_Buffer[i] = *s; 546 if (!*s++) 547 { 548 return; 549 } 550 } 551 NN_TWARNING_(*s, "too long string."); 552 if (*s) 553 { 554 // 長すぎるので無効 555 this->m_Buffer[0] = 0; 556 } 557 } 558 559 public: 560 LightFixedLengthString()561 LightFixedLengthString() 562 { 563 this->m_Buffer[0] = 0; 564 } 565 LightFixedLengthString(const Char * s)566 LightFixedLengthString(const Char* s) 567 { 568 CopyFrom(s); 569 } 570 LightFixedLengthString(const Char * s,size_t size)571 LightFixedLengthString(const Char* s, size_t size) 572 { 573 if (size > MaxLength) 574 { 575 size = MaxLength; 576 } 577 NN_TASSERT_(size <= MaxLength); 578 std::memcpy(this->m_Buffer, s, size); 579 if (size < MaxLength) 580 { 581 this->m_Buffer[size] = 0; 582 } 583 } 584 GetLength()585 size_t GetLength() const 586 { 587 size_t i = 0; 588 for (; i < MaxLength; ++i) 589 { 590 if (!m_Buffer[i]) 591 { 592 break; 593 } 594 } 595 return i; 596 } 597 598 Char operator[](size_t i) const 599 { 600 NN_TASSERT_(i < MaxLength); 601 return m_Buffer[i]; 602 } 603 604 LightFixedLengthString& operator=(const Char* s) 605 { 606 CopyFrom(s); 607 return *this; 608 } 609 610 }; 611 612 #pragma pop 613 614 }} 615 616 #endif 617