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