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: 31045 $ 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 AppendHeadAsHex(bit32 x)329 FixedLengthString& AppendHeadAsHex(bit32 x) 330 { 331 Char hex[9]; 332 for (s32 i = 0; i < 8; ++i) 333 { 334 bit32 n = (x >> ((7 - i) * 4)) & 0xf; 335 NN_TASSERT_(0 <= n && n < 16); 336 hex[i] = static_cast<Char>(n < 10 ? '0' + n : 'a' + (n - 10)); 337 } 338 hex[8] = 0; 339 return AppendHead(hex); 340 } 341 AppendTailAsHex(bit32 x)342 FixedLengthString& AppendTailAsHex(bit32 x) 343 { 344 if (!this->IsValid()) 345 { 346 return *this; 347 } 348 if (GetHeadIndex() > Base::Length - MaxLength) 349 { 350 MoveData(); 351 } 352 Char* p = m_Data + this->GetLength(); 353 SetLength(this->GetLength() + 8); 354 if (IsValid()) 355 { 356 for (s32 i = 0; i < 8; ++i) 357 { 358 bit32 n = (x >> ((7 - i) * 4)) & 0xf; 359 NN_TASSERT_(0 <= n && n < 16); 360 p[i] = static_cast<Char>(n < 10 ? '0' + n : 'a' + (n - 10)); 361 } 362 NN_TASSERT_(m_Data[m_Length] == 0); 363 } 364 return *this; 365 } 366 367 template <class Char2> AppendTail(const Char2 * s,size_t size)368 FixedLengthString& AppendTail(const Char2* s, size_t size) 369 { 370 if (!this->IsValid()) 371 { 372 return *this; 373 } 374 if (GetHeadIndex() > Base::Length - MaxLength) 375 { 376 MoveData(); 377 } 378 Char* p = m_Data + this->GetLength(); 379 SetLength(this->GetLength() + size); 380 if (IsValid()) 381 { 382 for (s32 i = 0; i < size; ++i) 383 { 384 p[i] = s[i]; 385 } 386 NN_TASSERT_(m_Data[m_Length] == 0); 387 } 388 return *this; 389 } 390 391 template <class Char2, size_t Size> AppendTail(const Char2 s[Size])392 FixedLengthString& AppendTail(const Char2 s[Size]) 393 { 394 return AppendTail(s, Size); 395 } 396 EraseTail(size_t length)397 FixedLengthString& EraseTail(size_t length) 398 { 399 if (!this->IsValid()) 400 { 401 return *this; 402 } 403 this->SetLength(this->GetLength() - length); 404 return *this; 405 } 406 EraseHead(size_t length)407 FixedLengthString& EraseHead(size_t length) 408 { 409 if (!this->IsValid()) 410 { 411 return *this; 412 } 413 this->SetHead(this->GetHeadIndex() + length); 414 this->SetLength(this->GetLength() - length); 415 return *this; 416 } 417 418 template <size_t Length, size_t Size> 419 FixedLengthString& operator+=(const FixedLengthString<Char, Length, Size>& rhs) 420 { 421 this->AppendTail(rhs); 422 return *this; 423 } 424 425 template <class Char2, size_t Size> 426 FixedLengthString& operator+=(const Char2 s[Size]) { return AppendTail(s); } 427 428 FixedLengthString& operator+=(const Char* rhs) 429 { 430 this->AppendTail(rhs); 431 return *this; 432 } 433 434 template <size_t Length2, size_t Size2> 435 friend bool operator==(const FixedLengthString& lhs, const FixedLengthString<Char, Length2, Size2>& rhs) 436 { 437 return lhs.GetLength() == rhs.GetLength() && std::memcmp(lhs.GetString(), rhs.GetString(), sizeof(Char) * lhs.GetLength()) == 0; 438 } 439 440 friend bool operator==(const FixedLengthString& lhs, const Char* rhs) 441 { 442 return std::memcmp(lhs.m_Data, rhs, sizeof(Char) * lhs.GetLength()) == 0 && rhs[lhs.GetLength()] == 0; 443 } 444 445 friend bool operator==(const Char* lhs, const FixedLengthString& rhs) 446 { 447 return rhs == lhs; 448 } 449 450 template <size_t Length2, size_t Size2> 451 friend bool operator!=(const FixedLengthString& lhs, const FixedLengthString<Char, Length2, Size2>& rhs) 452 { 453 return !(lhs == rhs); 454 } 455 456 friend bool operator!=(const FixedLengthString& lhs, const Char* rhs) 457 { 458 return !(lhs == rhs); 459 } 460 461 friend bool operator!=(const Char* lhs, const FixedLengthString& rhs) 462 { 463 return !(lhs == rhs); 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 int n = std::memcmp(lhs.GetString(), rhs.GetString(), sizeof(Char) * std::min(lhs.GetLength(), rhs.GetLength())); 470 return n < 0 || (n == 0 && lhs.GetLength() < rhs.GetLength()); 471 } 472 473 template <size_t Length, size_t Size> 474 friend bool operator>(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 475 { 476 return rhs < lhs; 477 } 478 479 template <size_t Length, size_t Size> 480 friend bool operator<=(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 481 { 482 return !(lhs > rhs); 483 } 484 485 template <size_t Length, size_t Size> 486 friend bool operator>=(const FixedLengthString& lhs, const FixedLengthString<TChar, Length, Size>& rhs) 487 { 488 return rhs <= lhs; 489 } 490 491 }; 492 493 // 固定長文字列 494 // 必ずしも NULL 終端ではない 495 // const な 値クラス 496 template <class TChar, size_t TMaxLength> 497 class LightFixedLengthString 498 { 499 public: 500 501 typedef TChar Char; 502 static const size_t MaxLength = TMaxLength; 503 504 private: 505 506 Char m_Buffer[MaxLength]; 507 CopyFrom(const Char * s)508 void CopyFrom(const Char* s) 509 { 510 for (size_t i = 0; i < MaxLength; ++i) 511 { 512 this->m_Buffer[i] = *s; 513 if (!*s++) 514 { 515 return; 516 } 517 } 518 NN_TWARNING_(*s, "too long string."); 519 if (*s) 520 { 521 // 長すぎるので無効 522 this->m_Buffer[0] = 0; 523 } 524 } 525 526 public: 527 LightFixedLengthString()528 LightFixedLengthString() 529 { 530 this->m_Buffer[0] = 0; 531 } 532 LightFixedLengthString(const Char * s)533 LightFixedLengthString(const Char* s) 534 { 535 CopyFrom(s); 536 } 537 LightFixedLengthString(const Char * s,size_t size)538 LightFixedLengthString(const Char* s, size_t size) 539 { 540 if (size > MaxLength) 541 { 542 size = MaxLength; 543 } 544 NN_TASSERT_(size <= MaxLength); 545 std::memcpy(this->m_Buffer, s, size); 546 if (size < MaxLength) 547 { 548 this->m_Buffer[size] = 0; 549 } 550 } 551 GetLength()552 size_t GetLength() const 553 { 554 size_t i = 0; 555 for (; i < MaxLength; ++i) 556 { 557 if (!m_Buffer[i]) 558 { 559 break; 560 } 561 } 562 return i; 563 } 564 565 Char operator[](size_t i) const 566 { 567 NN_TASSERT_(i < MaxLength); 568 return m_Buffer[i]; 569 } 570 571 LightFixedLengthString& operator=(const Char* s) 572 { 573 CopyFrom(s); 574 return *this; 575 } 576 577 }; 578 579 #pragma pop 580 581 }} 582 583 #endif 584