1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fnd_FixedLengthString.h
4 
5   Copyright (C)2009-2012 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: 46347 $
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 
56 
57 
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 // Fixed-length string
527 // Not always terminated by NULL
528 // const value classes
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             // Invalid because it's too long
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