• R/O
  • SSH
  • HTTPS

eirrepo: Commit


Commit MetaInfo

Revision130 (tree)
Time2018-09-17 04:47:43
Authorquiret

Log Message

- added eir::MultiString type that will be the basis for filePath in FileSystem
- fixed various bugs in eir::MultiString
- added unit tests for eir::MultiString, will be expanding on that

Change Summary

Incremental Difference

--- common/sdk/ABIHelpers.h (revision 129)
+++ common/sdk/ABIHelpers.h (revision 130)
@@ -85,7 +85,8 @@
8585 allocateContainer( str, strLen );
8686 }
8787
88- inline abiVirtualString( const std::basic_string <charType>& right ) : abiVirtualString( right.c_str(), right.size() )
88+ template <typename allocatorType>
89+ inline abiVirtualString( const eir::String <charType, allocatorType>& right ) : abiVirtualString( right.GetConstString(), right.GetLength() )
8990 {
9091 return;
9192 }
@@ -166,7 +167,8 @@
166167 return std::basic_string <charType> ( this->c_str(), this->length() );
167168 }
168169
169- inline operator eir::String <charType> ( void ) const
170+ template <typename allocatorType>
171+ inline operator eir::String <charType, allocatorType> ( void ) const
170172 {
171173 return eir::String <charType> ( this->c_str(), this->length() );
172174 }
--- common/sdk/Map.h (revision 129)
+++ common/sdk/Map.h (revision 130)
@@ -29,12 +29,6 @@
2929 namespace eir
3030 {
3131
32-// A very special pass-in just for creation with the allocator initialization.
33-enum constr_with_alloc
34-{
35- CONSTR_WITH_ALLOC
36-};
37-
3832 // Default comparator for objects inside the Map.
3933 struct MapDefaultComparator
4034 {
--- common/sdk/MultiString.h (nonexistent)
+++ common/sdk/MultiString.h (revision 130)
@@ -0,0 +1,1608 @@
1+/*****************************************************************************
2+*
3+* PROJECT: Eir SDK
4+* LICENSE: See LICENSE in the top level directory
5+* FILE: eirrepo/sdk/MultiString.h
6+* PURPOSE: Character string that can deal with multiple encodings.
7+*
8+* Find the Eir SDK at: https://osdn.net/projects/eirrepo/
9+* Multi Theft Auto is available from http://www.multitheftauto.com/
10+*
11+*****************************************************************************/
12+
13+// We had this filePath definition in the global headers of FileSystem for pretty long.
14+// Across many filesystem implementations there are a multitude of encodings internally used,
15+// so it makes much sense to involve an encoding-transparent type for it.
16+// But since that type has become so complicated and powerful, it is a really good idea
17+// to put it here. Besides, not just FileSystem could require such a type!
18+
19+#ifndef _EIR_MULTISTRING_HEADER_
20+#define _EIR_MULTISTRING_HEADER_
21+
22+#include <cwchar>
23+#include <type_traits>
24+#include <assert.h>
25+
26+#include "MemoryRaw.h"
27+#include "UniChar.h"
28+
29+#include "eirutils.h"
30+#include "ABIHelpers.h"
31+#include "MacroUtils.h"
32+#include "MetaHelpers.h"
33+#include "rwlist.hpp"
34+
35+#include "String.h"
36+
37+namespace eir
38+{
39+
40+// String container that is encoding-transparent.
41+// Supports both unicode and ANSI, can run case-sensitive or opposite.
42+#define MSTR_TEMPLARGS \
43+ template <typename allocatorType>
44+#define MSTR_TEMPLUSE \
45+ <allocatorType>
46+
47+MSTR_TEMPLARGS
48+struct MultiString
49+{
50+private:
51+ // We need some virtual string types for ABI compatibility.
52+ typedef abiVirtualString <char8_t> abiUTF8String;
53+
54+ struct stringProvider abstract
55+ {
56+ virtual ~stringProvider( void ) {}
57+
58+ // Friendly reminder: only clone to MultiStrings that have a compatible allocatorType.
59+ virtual stringProvider* Clone( MultiString *refPtr ) const = 0;
60+ virtual stringProvider* InheritConstruct( MultiString *refPtr ) const = 0;
61+
62+ virtual void UpdateRefPtr( MultiString *newRefPtr ) noexcept = 0;
63+
64+ virtual void Clear( void ) noexcept = 0;
65+ virtual void SetSize( size_t strSize ) = 0;
66+
67+ virtual size_t GetLength( void ) const = 0;
68+ virtual size_t GetDecodedLength( void ) const = 0;
69+
70+ virtual void InsertChars( size_t offset, const char *src, size_t srcLen ) = 0;
71+ virtual void InsertChars( size_t offset, const wchar_t *src, size_t srcLen ) = 0;
72+ virtual void InsertChars( size_t offset, const char16_t *src, size_t srcLen ) = 0;
73+ virtual void InsertChars( size_t offset, const char32_t *src, size_t srcLen ) = 0;
74+ virtual void InsertChars( size_t offset, const char8_t *src, size_t srcLen ) = 0;
75+ virtual void Insert( size_t offset, const stringProvider *right, size_t srcLen ) = 0;
76+
77+ virtual void AppendChars( const char *right, size_t rightLen ) = 0;
78+ virtual void AppendChars( const wchar_t *right, size_t rightLen ) = 0;
79+ virtual void AppendChars( const char16_t *right, size_t rightLen ) = 0;
80+ virtual void AppendChars( const char32_t *right, size_t rightLen ) = 0;
81+ virtual void AppendChars( const char8_t *right, size_t rightLen ) = 0;
82+ virtual void Append( const stringProvider *right ) = 0;
83+
84+ virtual bool CompareToChars( const char *right, size_t rightLen, bool caseSensitive ) const = 0;
85+ virtual bool CompareToChars( const wchar_t *right, size_t rightLen, bool caseSensitive ) const = 0;
86+ virtual bool CompareToChars( const char16_t *right, size_t rightLen, bool caseSensitive ) const = 0;
87+ virtual bool CompareToChars( const char32_t *right, size_t rightLen, bool caseSensitive ) const = 0;
88+ virtual bool CompareToChars( const char8_t *right, size_t rightLen, bool caseSensitive ) const = 0;
89+ virtual bool CompareTo( const stringProvider *right, bool caseSensitive ) const = 0;
90+
91+ virtual char GetCharacterANSI( size_t pos ) const = 0;
92+ virtual wchar_t GetCharacterUnicode( size_t pos ) const = 0;
93+ virtual char16_t GetCharacterUTF16( size_t pos ) const = 0;
94+ virtual char32_t GetCharacter( size_t pos ) const = 0;
95+ virtual char8_t GetCharacterUTF8( size_t pos ) const = 0;
96+
97+ virtual bool CompareCharacterAt( char refChar, size_t pos, bool caseSensitive ) const = 0;
98+ virtual bool CompareCharacterAt( wchar_t refChar, size_t pos, bool caseSensitive ) const = 0;
99+ virtual bool CompareCharacterAt( char16_t refChar, size_t pos, bool caseSensitive ) const = 0;
100+ virtual bool CompareCharacterAt( char32_t refChar, size_t pos, bool caseSensitive ) const = 0;
101+ virtual bool CompareCharacterAt( char8_t refChar, size_t pos, bool caseSensitive ) const = 0;
102+
103+ virtual abiString ToANSI( void ) const = 0;
104+ virtual abiWideString ToUnicode( void ) const = 0;
105+ virtual abiUTF8String ToUTF8( void ) const = 0;
106+
107+ virtual const char* GetConstANSIString( void ) const noexcept { return nullptr; }
108+ virtual const wchar_t* GetConstUnicodeString( void ) const noexcept { return nullptr; }
109+ virtual const char16_t* GetConstUTF16String( void ) const noexcept { return nullptr; }
110+ virtual const char8_t* GetConstUTF8String( void ) const noexcept { return nullptr; }
111+ virtual const char32_t* GetConstUTF32String( void ) const noexcept { return nullptr; }
112+
113+ virtual bool IsUnicode( void ) const noexcept = 0;
114+ virtual bool IsSameCharType( const stringProvider *other ) const noexcept = 0;
115+
116+ // Helper.
117+ template <typename callbackType, typename... Args>
118+ static AINLINE void StringProviderCharPipe( const stringProvider *right, Args... theArgs )
119+ {
120+ if ( const char *str = right->GetConstANSIString() )
121+ {
122+ callbackType::ProcChars( str, std::forward <Args> ( theArgs )... );
123+ }
124+ else if ( const wchar_t *str = right->GetConstUnicodeString() )
125+ {
126+ callbackType::ProcChars( str, std::forward <Args> ( theArgs )... );
127+ }
128+ else if ( const char16_t *str = right->GetConstUTF16String() )
129+ {
130+ callbackType::ProcChars( str, std::forward <Args> ( theArgs )... );
131+ }
132+ else if ( const char8_t *str = right->GetConstUTF8String() )
133+ {
134+ callbackType::ProcChars( str, std::forward <Args> ( theArgs )... );
135+ }
136+ else if ( const char32_t *str = right->GetConstUTF32String() )
137+ {
138+ callbackType::ProcChars( str, std::forward <Args> ( theArgs )... );
139+ }
140+ else
141+ {
142+ throw codepoint_exception( "invalid character type in codepoint operation" );
143+ }
144+ }
145+ };
146+
147+ template <typename charType>
148+ inline static const charType* GetConstCharStringProvider( const stringProvider *prov )
149+ {
150+ if constexpr ( std::is_same <charType, char>::value )
151+ {
152+ return prov->GetConstANSIString();
153+ }
154+ if constexpr ( std::is_same <charType, wchar_t>::value )
155+ {
156+ return prov->GetConstUnicodeString();
157+ }
158+ if constexpr ( std::is_same <charType, char16_t>::value )
159+ {
160+ return prov->GetConstUTF16String();
161+ }
162+ if constexpr ( std::is_same <charType, char8_t>::value )
163+ {
164+ return prov->GetConstUTF8String();
165+ }
166+ if constexpr ( std::is_same <charType, char32_t>::value )
167+ {
168+ return prov->GetConstUTF32String();
169+ }
170+
171+ return nullptr;
172+ }
173+
174+ // Helper to check which character type a stringProvider does store.
175+ template <typename charType>
176+ static AINLINE bool is_string_prov_char( const stringProvider *prov )
177+ {
178+ return ( GetConstCharStringProvider <charType> ( prov ) != nullptr );
179+ }
180+
181+ // We need to host the allocator directly inside the MultiString.
182+ INSTANCE_SUBSTRUCTCHECK( is_object );
183+
184+ static constexpr bool hasObjectAllocator = PERFORM_SUBSTRUCTCHECK( allocatorType, is_object );
185+
186+ // Allocator redirect from any sub-string directly to allocator of MultiString.
187+ struct directMSAllocator
188+ {
189+ inline directMSAllocator( MultiString *refPtr )
190+ {
191+ this->refPtr = refPtr;
192+ }
193+
194+ inline void* Allocate( void *_, size_t memSize, size_t alignment )
195+ {
196+ MultiString *refPtr = this->refPtr;
197+ return refPtr->data.allocData.Allocate( refPtr, memSize, alignment );
198+ }
199+
200+ inline bool Resize( void *_, void *memPtr, size_t reqSize )
201+ {
202+ MultiString *refPtr = this->refPtr;
203+ return refPtr->data.allocData.Resize( refPtr, memPtr, reqSize );
204+ }
205+
206+ inline void Free( void *_, void *memPtr )
207+ {
208+ MultiString *refPtr = this->refPtr;
209+ refPtr->data.allocData.Free( refPtr, memPtr );
210+ }
211+
212+ MultiString *refPtr;
213+
214+ struct is_object {};
215+ };
216+
217+#define CSP_TEMPLARGS \
218+ template <typename charType>
219+#define CSP_TEMPLUSE \
220+ <charType>
221+
222+ CSP_TEMPLARGS
223+ struct charStringProvider : public stringProvider
224+ {
225+ typedef character_env <charType> char_env;
226+ typedef charenv_charprov_tocplen <charType> char_prov_t;
227+ typedef character_env_iterator <charType, char_prov_t> char_iterator;
228+
229+ // Redirect allocator calls from the character provider.
230+ DEFINE_HEAP_REDIR_ALLOC( cspRedirAlloc );
231+
232+ MultiString *refPtr;
233+ eir::String <charType, cspRedirAlloc> strData;
234+
235+ inline charStringProvider( MultiString *refPtr ) : refPtr( refPtr )
236+ {
237+ return;
238+ }
239+ inline charStringProvider( const charStringProvider& right ) = default;
240+ inline charStringProvider( const charStringProvider& right, MultiString *refPtr ) : refPtr( refPtr ), strData( right.strData )
241+ {
242+ return;
243+ }
244+
245+ void UpdateRefPtr( MultiString *newRefPtr ) noexcept override final
246+ {
247+ this->refPtr = newRefPtr;
248+ }
249+
250+ void Clear( void ) noexcept override final { strData.Clear(); }
251+ void SetSize( size_t strSize ) override final { strData.Resize( strSize ); }
252+ size_t GetLength( void ) const override final { return strData.GetLength(); }
253+ size_t GetDecodedLength( void ) const override final
254+ {
255+ size_t len = 0;
256+
257+ const charType *str = strData.GetConstString();
258+
259+ char_prov_t char_prov( str, strData.GetLength() );
260+
261+ for ( char_iterator iter( str, std::move( char_prov ) ); !iter.IsEnd(); iter.Increment() )
262+ {
263+ len++;
264+ }
265+
266+ return len;
267+ }
268+
269+ private:
270+ AINLINE static size_t get_encoding_strpos( const charType *data, size_t dataLen, size_t charPos )
271+ {
272+ // For ANSI this function is supposed to optimize down to a return of charPos.
273+ // Needs verification.
274+
275+ const charType *str = data;
276+
277+ char_prov_t char_prov( str, dataLen );
278+
279+ char_iterator iter( str, std::move( char_prov ) );
280+
281+ size_t cur_i = 0;
282+
283+ for ( ; !iter.IsEnd(), cur_i < charPos; iter.Increment(), cur_i++ );
284+
285+ return ( iter.GetPointer() - data );
286+ }
287+
288+ void InsertCharsNative( size_t offset, const charType *src, size_t srcLen )
289+ {
290+ size_t real_pos = get_encoding_strpos( strData.GetConstString(), strData.GetLength(), offset );
291+
292+ strData.Insert( real_pos, src, srcLen );
293+ }
294+
295+ template <typename transCharType>
296+ AINLINE void InsertCharsTrans( size_t offset, const transCharType *src, size_t srcLen )
297+ {
298+ eir::String <charType, directMSAllocator> nativeOut = CharacterUtil::ConvertStringsLength <transCharType, charType, directMSAllocator> ( src, srcLen, this->refPtr );
299+
300+ InsertCharsNative( offset, nativeOut.GetConstString(), nativeOut.GetLength() );
301+ }
302+
303+ public:
304+ void InsertChars( size_t offset, const char *src, size_t srcLen ) override final
305+ {
306+ if constexpr ( std::is_same <charType, char>::value == false )
307+ {
308+ InsertCharsTrans( offset, src, srcLen );
309+ }
310+ else
311+ {
312+ InsertCharsNative( offset, src, srcLen );
313+ }
314+ }
315+ void InsertChars( size_t offset, const wchar_t *src, size_t srcLen ) override final
316+ {
317+ if constexpr ( std::is_same <charType, wchar_t>::value == false )
318+ {
319+ InsertCharsTrans( offset, src, srcLen );
320+ }
321+ else
322+ {
323+ InsertCharsNative( offset, src, srcLen );
324+ }
325+ }
326+ void InsertChars( size_t offset, const char16_t *src, size_t srcLen ) override final
327+ {
328+ if constexpr ( std::is_same <charType, char16_t>::value == false )
329+ {
330+ InsertCharsTrans( offset, src, srcLen );
331+ }
332+ else
333+ {
334+ InsertCharsNative( offset, src, srcLen );
335+ }
336+ }
337+ void InsertChars( size_t offset, const char32_t *src, size_t srcLen ) override final
338+ {
339+ if constexpr ( std::is_same <charType, char32_t>::value == false )
340+ {
341+ InsertCharsTrans( offset, src, srcLen );
342+ }
343+ else
344+ {
345+ InsertCharsNative( offset, src, srcLen );
346+ }
347+ }
348+ void InsertChars( size_t offset, const char8_t *src, size_t srcLen ) override final
349+ {
350+ if constexpr ( std::is_same <charType, char8_t>::value == false )
351+ {
352+ InsertCharsTrans( offset, src, srcLen );
353+ }
354+ else
355+ {
356+ InsertCharsNative( offset, src, srcLen );
357+ }
358+ }
359+
360+ private:
361+ void AppendCharsNative( const charType *right, size_t rightLen )
362+ {
363+ strData.Append( right, rightLen );
364+ }
365+
366+ template <typename transCharType>
367+ AINLINE void AppendCharsTrans( const transCharType *right, size_t rightLen )
368+ {
369+ eir::String <charType, directMSAllocator> nativeOut = CharacterUtil::ConvertStringsLength <transCharType, charType, directMSAllocator> ( right, rightLen, this->refPtr );
370+
371+ AppendChars( nativeOut.GetConstString(), nativeOut.GetLength() );
372+ }
373+
374+ public:
375+ void AppendChars( const char *right, size_t rightLen ) override final
376+ {
377+ if constexpr ( std::is_same <charType, char>::value == false )
378+ {
379+ AppendCharsTrans( right, rightLen );
380+ }
381+ else
382+ {
383+ AppendCharsNative( right, rightLen );
384+ }
385+ }
386+ void AppendChars( const wchar_t *right, size_t rightLen ) override final
387+ {
388+ if constexpr ( std::is_same <charType, wchar_t>::value == false )
389+ {
390+ AppendCharsTrans( right, rightLen );
391+ }
392+ else
393+ {
394+ AppendCharsNative( right, rightLen );
395+ }
396+ }
397+ void AppendChars( const char16_t *right, size_t rightLen ) override final
398+ {
399+ if constexpr ( std::is_same <charType, char16_t>::value == false )
400+ {
401+ AppendCharsTrans( right, rightLen );
402+ }
403+ else
404+ {
405+ AppendCharsNative( right, rightLen );
406+ }
407+ }
408+ void AppendChars( const char32_t *right, size_t rightLen ) override final
409+ {
410+ if constexpr ( std::is_same <charType, char32_t>::value == false )
411+ {
412+ AppendCharsTrans( right, rightLen );
413+ }
414+ else
415+ {
416+ AppendCharsNative( right, rightLen );
417+ }
418+ }
419+ void AppendChars( const char8_t *right, size_t rightLen ) override final
420+ {
421+ if constexpr ( std::is_same <charType, char8_t>::value == false )
422+ {
423+ AppendCharsTrans( right, rightLen );
424+ }
425+ else
426+ {
427+ AppendCharsNative( right, rightLen );
428+ }
429+ }
430+
431+ private:
432+ template <typename transCharType>
433+ AINLINE bool CompareToCharsNative( const transCharType *transStr, size_t strLen, bool caseSensitive ) const
434+ {
435+ return UniversalCompareStrings( this->strData.GetConstString(), this->strData.GetLength(), transStr, strLen, caseSensitive );
436+ }
437+
438+ public:
439+ bool CompareToChars( const char *right, size_t rightLen, bool caseSensitive ) const override final
440+ {
441+ return CompareToCharsNative( right, rightLen, caseSensitive );
442+ }
443+ bool CompareToChars( const wchar_t *right, size_t rightLen, bool caseSensitive ) const override final
444+ {
445+ return CompareToCharsNative( right, rightLen, caseSensitive );
446+ }
447+ bool CompareToChars( const char16_t *right, size_t rightLen, bool caseSensitive ) const override final
448+ {
449+ return CompareToCharsNative( right, rightLen, caseSensitive );
450+ }
451+ bool CompareToChars( const char32_t *right, size_t rightLen, bool caseSensitive ) const override final
452+ {
453+ return CompareToCharsNative( right, rightLen, caseSensitive );
454+ }
455+ bool CompareToChars( const char8_t *right, size_t rightLen, bool caseSensitive ) const override final
456+ {
457+ return CompareToCharsNative( right, rightLen, caseSensitive );
458+ }
459+
460+ bool CompareTo( const stringProvider *right, bool caseSensitive ) const override final
461+ {
462+ bool isEqual = false;
463+
464+ if ( const char *ansiStr = right->GetConstANSIString() )
465+ {
466+ isEqual = CompareToChars( ansiStr, right->GetLength(), caseSensitive );
467+ }
468+ else if ( const wchar_t *wideStr = right->GetConstUnicodeString() )
469+ {
470+ isEqual = CompareToChars( wideStr, right->GetLength(), caseSensitive );
471+ }
472+ else if ( const char16_t *wideStr = right->GetConstUTF16String() )
473+ {
474+ isEqual = CompareToChars( wideStr, right->GetLength(), caseSensitive );
475+ }
476+ else if ( const char8_t *utf8Str = right->GetConstUTF8String() )
477+ {
478+ isEqual = CompareToChars( utf8Str, right->GetLength(), caseSensitive );
479+ }
480+ else if ( const char32_t *utf32Str = right->GetConstUTF32String() )
481+ {
482+ isEqual = CompareToChars( utf32Str, right->GetLength(), caseSensitive );
483+ }
484+ else if ( this->strData.IsEmpty() )
485+ {
486+ isEqual = true;
487+ }
488+
489+ return isEqual;
490+ }
491+
492+ private:
493+ template <typename transCharType>
494+ AINLINE transCharType GetCharacterFromNative( size_t strPos ) const
495+ {
496+ transCharType resVal = (transCharType)0xCC;
497+
498+ const charType *ourStr = this->strData.GetConstString();
499+ size_t cplen = this->strData.GetLength();
500+
501+ size_t realPos = get_encoding_strpos( ourStr, cplen, strPos );
502+
503+ if ( realPos < cplen )
504+ {
505+ size_t leftLen = ( cplen - realPos );
506+
507+ const charType *reqPos = ( ourStr + realPos );
508+
509+ char_prov_t char_prov( reqPos, leftLen );
510+
511+ typename char_env::ucp_t ourNativeChar = char_iterator( ourStr + realPos, std::move( char_prov ) ).Resolve();
512+
513+ // Transform our character into a character of the destination environment.
514+ typedef character_env <transCharType> trans_env;
515+
516+ typename trans_env::ucp_t trans_ucp;
517+
518+ if ( AcquireDirectUCP <char_env, trans_env> ( ourNativeChar, trans_ucp ) )
519+ {
520+ typename trans_env::enc_result encRes;
521+ trans_env::EncodeUCP( trans_ucp, encRes );
522+
523+ if ( encRes.numData > 0 )
524+ {
525+ // We simply return the first character.
526+ // Actually should consider returning all of the characters.
527+ resVal = encRes.data[0];
528+ }
529+ }
530+ }
531+
532+ return resVal;
533+ }
534+
535+ public:
536+ char GetCharacterANSI( size_t strPos ) const override final
537+ {
538+ // For ANSI, this function should optimize down to a return of value.
539+
540+ return GetCharacterFromNative <char> ( strPos );
541+ }
542+ wchar_t GetCharacterUnicode( size_t strPos ) const override final
543+ {
544+ return GetCharacterFromNative <wchar_t> ( strPos );
545+ }
546+ char16_t GetCharacterUTF16( size_t strPos ) const override final
547+ {
548+ return GetCharacterFromNative <wchar_t> ( strPos );
549+ }
550+ char32_t GetCharacter( size_t strPos ) const override final
551+ {
552+ return GetCharacterFromNative <char32_t> ( strPos );
553+ }
554+ char8_t GetCharacterUTF8( size_t strPos ) const override final
555+ {
556+ return GetCharacterFromNative <char8_t> ( strPos );
557+ }
558+
559+ private:
560+ template <typename transCharType>
561+ AINLINE bool CompareCharacterAtWithNative( transCharType refChar, size_t strPos, bool caseSensitive ) const
562+ {
563+ const charType *ourStr = this->strData.GetConstString();
564+ size_t cplen = this->strData.GetLength();
565+
566+ size_t realPos = get_encoding_strpos( ourStr, cplen, strPos );
567+
568+ bool isEqual = false;
569+
570+ if ( realPos < cplen )
571+ {
572+ size_t leftLen = ( cplen - realPos );
573+
574+ const charType *reqPos = ( ourStr + realPos );
575+
576+ char_prov_t char_prov( reqPos, leftLen );
577+
578+ typename char_env::ucp_t ourVal = char_iterator( ourStr + realPos, std::move( char_prov ) ).Resolve();
579+
580+ isEqual = IsCharacterEqual( ourVal, refChar, caseSensitive );
581+ }
582+
583+ return isEqual;
584+ }
585+
586+ public:
587+ bool CompareCharacterAt( char refChar, size_t strPos, bool caseSensitive ) const override final
588+ {
589+ // Should optimize down very well in case of ANSI-ANSI comparison.
590+
591+ return CompareCharacterAtWithNative( refChar, strPos, caseSensitive );
592+ }
593+ bool CompareCharacterAt( wchar_t refChar, size_t strPos, bool caseSensitive ) const override final
594+ {
595+ return CompareCharacterAtWithNative( refChar, strPos, caseSensitive );
596+ }
597+ bool CompareCharacterAt( char16_t refChar, size_t strPos, bool caseSensitive ) const override final
598+ {
599+ return CompareCharacterAtWithNative( refChar, strPos, caseSensitive );
600+ }
601+ bool CompareCharacterAt( char32_t refChar, size_t strPos, bool caseSensitive ) const override final
602+ {
603+ return CompareCharacterAtWithNative( refChar, strPos, caseSensitive );
604+ }
605+ bool CompareCharacterAt( char8_t refChar, size_t strPos, bool caseSensitive ) const override final
606+ {
607+ // Subtle differences to ANSI comparison.
608+
609+ return CompareCharacterAtWithNative( refChar, strPos, caseSensitive );
610+ }
611+
612+ private:
613+ struct InsertCharsFunctor
614+ {
615+ template <typename subCharType>
616+ static AINLINE void ProcChars( const subCharType *str, stringProvider *thisProv, size_t offset, size_t srcLen )
617+ {
618+ thisProv->InsertChars( offset, str, srcLen );
619+ }
620+ };
621+
622+ public:
623+ void Insert( size_t offset, const stringProvider *right, size_t srcLen ) override final
624+ {
625+ StringProviderCharPipe <InsertCharsFunctor> ( right, this, offset, srcLen );
626+ }
627+
628+ private:
629+ struct AppendCharsFunctor
630+ {
631+ template <typename subCharType>
632+ static AINLINE void ProcChars( const subCharType *str, stringProvider *thisProv, size_t strLen )
633+ {
634+ thisProv->AppendChars( str, strLen );
635+ }
636+ };
637+
638+ public:
639+ void Append( const stringProvider *right ) override final
640+ {
641+ StringProviderCharPipe <AppendCharsFunctor> ( right, this, right->GetLength() );
642+ }
643+
644+ bool IsUnicode( void ) const noexcept override final
645+ {
646+ return ( std::is_same <charType, char>::value == false );
647+ }
648+
649+ bool IsSameCharType( const stringProvider *other ) const noexcept override final
650+ {
651+ return ( is_string_prov_char <charType> ( other ) );
652+ }
653+
654+ abiString ToANSI( void ) const override final
655+ {
656+ if constexpr ( std::is_same <charType, char>::value == false )
657+ {
658+ return CharacterUtil::ConvertStringsLength <charType, char, directMSAllocator> ( this->strData.GetConstString(), this->strData.GetLength(), this->refPtr );
659+ }
660+ else
661+ {
662+ return abiString( this->strData.GetConstString(), this->strData.GetLength() );
663+ }
664+ }
665+
666+ abiWideString ToUnicode( void ) const override final
667+ {
668+ if constexpr ( std::is_same <charType, wchar_t>::value == false )
669+ {
670+ return CharacterUtil::ConvertStringsLength <charType, wchar_t, directMSAllocator> ( this->strData.GetConstString(), this->strData.GetLength(), this->refPtr );
671+ }
672+ else
673+ {
674+ return abiWideString( this->strData.GetConstString(), this->strData.GetLength() );
675+ }
676+ }
677+
678+ abiUTF8String ToUTF8( void ) const override final
679+ {
680+ if constexpr ( std::is_same <charType, char8_t>::value == false )
681+ {
682+ return CharacterUtil::ConvertStringsLength <charType, char8_t, directMSAllocator> ( this->strData.GetConstString(), this->strData.GetLength(), this->refPtr );
683+ }
684+ else
685+ {
686+ return abiUTF8String( this->strData.GetConstString(), this->strData.GetLength() );
687+ }
688+ }
689+ };
690+
691+ // Construct a type helper.
692+ template <typename structType, typename... Args>
693+ static AINLINE structType* make_struct( MultiString *refPtr, Args... constrArgs )
694+ {
695+ void *memPtr = refPtr->data.allocData.Allocate( refPtr, sizeof(structType), alignof(structType) );
696+
697+ if ( !memPtr )
698+ {
699+ throw eir_exception();
700+ }
701+
702+ try
703+ {
704+ return new (memPtr) structType( std::forward <Args> ( constrArgs )... );
705+ }
706+ catch( ... )
707+ {
708+ refPtr->data.allocData.Free( refPtr, memPtr );
709+ throw;
710+ }
711+ }
712+
713+ struct ansiStringProvider final : public charStringProvider <char>
714+ {
715+ using charStringProvider::charStringProvider;
716+
717+ stringProvider* Clone( MultiString *refPtr ) const override final
718+ {
719+ return make_struct <ansiStringProvider> ( refPtr, *this, refPtr );
720+ }
721+
722+ stringProvider* InheritConstruct( MultiString *refPtr ) const override final
723+ {
724+ return make_struct <ansiStringProvider> ( refPtr, refPtr );
725+ }
726+
727+ // Dangerous function!
728+ const char* GetConstANSIString( void ) const noexcept override final
729+ {
730+ return strData.GetConstString();
731+ }
732+ };
733+
734+ struct wideStringProvider final : public charStringProvider <wchar_t>
735+ {
736+ using charStringProvider::charStringProvider;
737+
738+ stringProvider* Clone( MultiString *refPtr ) const override final
739+ {
740+ return make_struct <wideStringProvider> ( refPtr, *this, refPtr );
741+ }
742+
743+ stringProvider* InheritConstruct( MultiString *refPtr ) const override final
744+ {
745+ return make_struct <wideStringProvider> ( refPtr, refPtr );
746+ }
747+
748+ // Dangerous function!
749+ const wchar_t* GetConstUnicodeString( void ) const noexcept final
750+ {
751+ return strData.GetConstString();
752+ }
753+ };
754+
755+ struct char16StringProvider final : public charStringProvider <char16_t>
756+ {
757+ using charStringProvider::charStringProvider;
758+
759+ stringProvider* Clone( MultiString *refPtr ) const override final
760+ {
761+ return make_struct <char16StringProvider> ( refPtr, *this, refPtr );
762+ }
763+
764+ stringProvider* InheritConstruct( MultiString *refPtr ) const override final
765+ {
766+ return make_struct <char16StringProvider> ( refPtr, refPtr );
767+ }
768+
769+ // Dangerous function!
770+ const char16_t* GetConstUTF16String( void ) const noexcept final
771+ {
772+ return strData.GetConstString();
773+ }
774+ };
775+
776+ struct utf8StringProvider final : public charStringProvider <char8_t>
777+ {
778+ using charStringProvider::charStringProvider;
779+
780+ stringProvider* Clone( MultiString *refPtr ) const override final
781+ {
782+ return make_struct <utf8StringProvider> ( refPtr, *this, refPtr );
783+ }
784+
785+ stringProvider* InheritConstruct( MultiString *refPtr ) const override final
786+ {
787+ return make_struct <utf8StringProvider> ( refPtr, refPtr );
788+ }
789+
790+ // Dangerous function!
791+ const char8_t* GetConstUTF8String( void ) const noexcept final
792+ {
793+ return strData.GetConstString();
794+ }
795+ };
796+
797+ struct utf32StringProvider final : public charStringProvider <char32_t>
798+ {
799+ using charStringProvider::charStringProvider;
800+
801+ stringProvider* Clone( MultiString *refPtr ) const override final
802+ {
803+ return make_struct <utf32StringProvider> ( refPtr, *this, refPtr );
804+ }
805+
806+ stringProvider* InheritConstruct( MultiString *refPtr ) const override final
807+ {
808+ return make_struct <utf32StringProvider> ( refPtr, refPtr );
809+ }
810+
811+ // Dangerous function!
812+ const char32_t* GetConstUTF32String( void ) const noexcept final
813+ {
814+ return strData.GetConstString();
815+ }
816+ };
817+
818+ template <typename charType>
819+ inline stringProvider* CreateStringProvider( void )
820+ {
821+ if constexpr ( std::is_same <charType, char>::value )
822+ {
823+ return make_struct <ansiStringProvider> ( this, this );
824+ }
825+ if constexpr ( std::is_same <charType, wchar_t>::value )
826+ {
827+ return make_struct <wideStringProvider> ( this, this );
828+ }
829+ if constexpr ( std::is_same <charType, char16_t>::value )
830+ {
831+ return make_struct <char16StringProvider> ( this, this );
832+ }
833+ if constexpr ( std::is_same <charType, char8_t>::value )
834+ {
835+ return make_struct <utf8StringProvider> ( this, this );
836+ }
837+ if constexpr ( std::is_same <charType, char32_t>::value )
838+ {
839+ return make_struct <utf32StringProvider> ( this, this );
840+ }
841+
842+ // Cannot construct for this character type.
843+ throw eir_exception();
844+ }
845+
846+ inline void DestroyStringProvider( stringProvider *prov )
847+ {
848+ // First just destroy the type.
849+ prov->~stringProvider();
850+
851+ // Free the associated memory.
852+ this->data.allocData.Free( this, prov );
853+ }
854+
855+ template <typename charType>
856+ inline static void AppendStringProvider( stringProvider *prov, const charType *str, size_t len )
857+ {
858+ if constexpr ( std::is_same <charType, char>::value )
859+ {
860+ prov->AppendChars( str, len );
861+ }
862+ else if constexpr ( std::is_same <charType, wchar_t>::value )
863+ {
864+ prov->AppendChars( str, len );
865+ }
866+ else if constexpr ( std::is_same <charType, char8_t>::value )
867+ {
868+ prov->AppendChars( str, len );
869+ }
870+ else
871+ {
872+ // Only available to MSVC because it is a smarter compiler.
873+#ifdef _MSC_VER
874+ static_assert( false, "invalid character type for string provider append" );
875+#endif //_MSC_VER
876+ }
877+ }
878+
879+ // Compatibility upgrade function for input characters.
880+ template <typename otherCharType>
881+ AINLINE void compat_upgrade( void )
882+ {
883+ stringProvider *curProv = this->data.strData;
884+
885+ // If we have no string provider, we just create one that is the same as the required character type.
886+ if ( !curProv )
887+ {
888+ this->data.strData = CreateStringProvider <otherCharType> ();
889+
890+ return;
891+ }
892+
893+ // Otherwise we check if the target character type (otherCharType) can fit into the current provider.
894+ // If not then we upgrade to the target.
895+ if ( curProv->IsUnicode() )
896+ {
897+ // Anything can fit.
898+ return;
899+ }
900+
901+ // If we just want to input ANSI things, then we are fine.
902+ if constexpr ( std::is_same <otherCharType, char>::value )
903+ {
904+ return;
905+ }
906+
907+ // Upgrade to the target.
908+ //TODO: maybe limit us to certain types, such as char or wchar_t.
909+ charStringProvider <otherCharType> *newProv = CreateStringProvider <otherCharType> ();
910+
911+ try
912+ {
913+ // Take over the old characters.
914+ newProv->Append( curProv );
915+
916+ // Delete old character stuff.
917+ DestroyStringProvider( curProv );
918+
919+ this->data.strData = newProv;
920+ }
921+ catch( ... )
922+ {
923+ DestroyStringProvider( newProv );
924+ throw;
925+ }
926+ }
927+
928+ // Upgrading compatibility based on a source string provider.
929+ AINLINE void compat_strprov_upgrade( const stringProvider *other )
930+ {
931+ stringProvider *curProv = this->data.strData;
932+
933+ // If we had no provider, then we just create one that matches the target.
934+ if ( !curProv )
935+ {
936+ this->data.strData = other->InhericConstruct();
937+
938+ return;
939+ }
940+
941+ // If our current string provider is already unicode then we are ok.
942+ if ( curProv->IsUnicode() )
943+ {
944+ return;
945+ }
946+
947+ // Otherwise if the other is not unicode too, then we are ok too.
948+ if ( other->IsUnicode() == false )
949+ {
950+ return;
951+ }
952+
953+ stringProvider *newProv = other->InheritConstruct();
954+
955+ try
956+ {
957+ // Take over the old characters.
958+ newProv->Append( curProv );
959+
960+ // Delete old character stuff.
961+ DestroyStringProvider( curProv );
962+
963+ this->data.strData = newProv;
964+ }
965+ catch( ... )
966+ {
967+ DestroyStringProvider( newProv );
968+ throw;
969+ }
970+ }
971+
972+public:
973+ inline MultiString( void ) noexcept
974+ {
975+ this->data.strData = nullptr;
976+ }
977+
978+ template <typename charType>
979+ inline MultiString( const charType *right, size_t cplen )
980+ {
981+ this->data.strData = CreateStringProvider <charType> ();
982+
983+ this->data.strData->AppendChars( right, cplen );
984+ }
985+
986+ template <typename charType>
987+ inline MultiString( const charType *right )
988+ {
989+ this->data.strData = CreateStringProvider <charType> ();
990+
991+ this->data.strData->AppendChars( right, cplen_tozero( right ) );
992+ }
993+
994+ template <typename charType, typename strAllocatorType>
995+ inline explicit MultiString( const eir::String <charType, strAllocatorType>& right )
996+ {
997+ this->data.strData = CreateStringProvider <charType> ();
998+
999+ this->data.strData->AppendChars( right.GetConstString(), right.GetLength() );
1000+ }
1001+
1002+ // Special constructor for taking-over the allocation data.
1003+ // We do not copy the string data though, so do not get confused!
1004+ inline MultiString( constr_with_alloc _, const MultiString& right ) : data( right.data )
1005+ {
1006+ // But we do not start with string data.
1007+ this->data.strData = nullptr;
1008+ }
1009+
1010+ template <typename charType>
1011+ AINLINE static MultiString Make( const charType *str, size_t len )
1012+ {
1013+ MultiString path;
1014+
1015+ path.compat_upgrade <charType> ();
1016+
1017+ AppendStringProvider <charType> ( path.data.strData, str, len );
1018+
1019+ return path;
1020+ }
1021+
1022+ inline MultiString( const MultiString& right ) : data( right.data )
1023+ {
1024+ this->data.strData = nullptr;
1025+
1026+ if ( right.data.strData )
1027+ {
1028+ this->data.strData = right.data.strData->Clone();
1029+ }
1030+ }
1031+
1032+ // WARNING: only move if you know that allocators are the same.
1033+ inline MultiString( MultiString&& right ) noexcept : data( right.data )
1034+ {
1035+ this->data.strData = right.data.strData;
1036+
1037+ right.data.strData = nullptr;
1038+ }
1039+
1040+ inline ~MultiString( void )
1041+ {
1042+ if ( stringProvider *provider = this->data.strData )
1043+ {
1044+ DestroyStringProvider( provider );
1045+ }
1046+ }
1047+
1048+ inline size_t size( void ) const
1049+ {
1050+ size_t outSize = 0;
1051+
1052+ if ( stringProvider *provider = this->data.strData )
1053+ {
1054+ outSize = provider->GetLength();
1055+ }
1056+
1057+ return outSize;
1058+ }
1059+
1060+ inline size_t charlen( void ) const
1061+ {
1062+ size_t outLen = 0;
1063+
1064+ if ( stringProvider *provider = this->data.strData )
1065+ {
1066+ outLen = provider->GetDecodedLength();
1067+ }
1068+
1069+ return outLen;
1070+ }
1071+
1072+ inline void resize( size_t strSize )
1073+ {
1074+ if ( this->data.strData == nullptr )
1075+ {
1076+ this->data.strData = CreateStringProvider <char> ();
1077+ }
1078+
1079+ this->data.strData->SetSize( strSize );
1080+ }
1081+
1082+ inline bool empty( void ) const
1083+ {
1084+ bool isEmpty = true;
1085+
1086+ if ( stringProvider *provider = this->data.strData )
1087+ {
1088+ isEmpty = ( provider->GetLength() == 0 );
1089+ }
1090+
1091+ return isEmpty;
1092+ }
1093+
1094+ inline void clear( void ) noexcept
1095+ {
1096+ if ( stringProvider *provider = this->data.strData )
1097+ {
1098+ provider->Clear();
1099+ }
1100+ }
1101+
1102+ inline char at( size_t strPos ) const
1103+ {
1104+ if ( strPos >= size() || !this->data.strData )
1105+ {
1106+ throw std::out_of_range( "strPos too big!" );
1107+ }
1108+
1109+ return this->data.strData->GetCharacterANSI( strPos );
1110+ }
1111+
1112+ inline wchar_t at_w( size_t strPos ) const
1113+ {
1114+ if ( strPos >= size() || !this->data.strData )
1115+ {
1116+ throw std::out_of_range( "strPos too big!" );
1117+ }
1118+
1119+ return this->data.strData->GetCharacterUnicode( strPos );
1120+ }
1121+
1122+ inline char32_t charat_u32( size_t charPos ) const
1123+ {
1124+ if ( charPos >= charlen() || !this->data.strData )
1125+ {
1126+ throw std::out_of_range( "charPos too big!" );
1127+ }
1128+
1129+ return this->data.strData->GetCharacter( charPos );
1130+ }
1131+
1132+ template <typename charType>
1133+ inline bool compareCharAt( charType refChar, size_t strPos, bool caseSensitive = true ) const
1134+ {
1135+ bool isEqual = false;
1136+
1137+ if ( stringProvider *provider = this->data.strData )
1138+ {
1139+ isEqual = provider->CompareCharacterAt( refChar, strPos, caseSensitive );
1140+ }
1141+
1142+ return isEqual;
1143+ }
1144+
1145+ inline int compare( const MultiString& right ) const
1146+ {
1147+ const stringProvider *leftStrProv = this->data.strData;
1148+ const stringProvider *rightStrProv = right.data.strData;
1149+
1150+ if ( !leftStrProv && !rightStrProv )
1151+ return 0;
1152+
1153+ if ( !leftStrProv )
1154+ return -1;
1155+
1156+ if ( !rightStrProv )
1157+ return 1;
1158+
1159+ size_t leftStrLen = leftStrProv->GetLength();
1160+ size_t rightStrLen = rightStrProv->GetLength();
1161+
1162+ if ( leftStrLen != rightStrLen )
1163+ {
1164+ return (int)( leftStrLen - rightStrLen );
1165+ }
1166+
1167+ size_t strpos = 0;
1168+
1169+ while ( true )
1170+ {
1171+ // Check what strings have ended.
1172+ bool hasEnded = ( strpos > leftStrLen );
1173+
1174+ if ( hasEnded )
1175+ {
1176+ // We are done without conflicts.
1177+ break;
1178+ }
1179+ // a premature end is impossible due to above check for equal length.
1180+
1181+ // Compare by character.
1182+ char32_t univLeftChar = leftStrProv->GetCharacter( strpos );
1183+ char32_t univRightChar = rightStrProv->GetCharacter( strpos );
1184+
1185+ if ( univLeftChar != univRightChar )
1186+ {
1187+ return (int)( univLeftChar - univRightChar );
1188+ }
1189+
1190+ strpos++;
1191+ }
1192+
1193+ // Done without conflicts.
1194+ return 0;
1195+ }
1196+
1197+ inline bool operator < ( const MultiString& right ) const
1198+ {
1199+ return ( this->compare( right ) < 0 );
1200+ }
1201+
1202+ template <typename otherCharType>
1203+ inline void insert( size_t offset, const otherCharType *src, size_t srcCount )
1204+ {
1205+ this->compat_upgrade <otherCharType> ();
1206+
1207+ this->data.strData->InsertChars( offset, src, srcCount );
1208+ }
1209+
1210+ inline void insert( size_t offset, const MultiString& src, size_t srcLen )
1211+ {
1212+ const stringProvider *rightProv = src.data.strData;
1213+
1214+ if ( !rightProv )
1215+ return;
1216+
1217+ this->compat_strprov_upgrade( rightProv );
1218+
1219+ this->data.strData->Insert( offset, rightProv, srcLen );
1220+ }
1221+
1222+ inline MultiString substr( size_t pos, size_t len = std::numeric_limits <size_t>::max() ) const
1223+ {
1224+ MultiString subresult( CONSTR_WITH_ALLOC, *this );
1225+
1226+ if ( stringProvider *prov = this->data.strData )
1227+ {
1228+ size_t cur_pos = pos;
1229+
1230+ size_t num_iter = 0;
1231+
1232+ size_t char_count = prov->GetDecodedLength();
1233+
1234+ while ( true )
1235+ {
1236+ size_t cur_iter = num_iter++;
1237+
1238+ if ( cur_iter >= len )
1239+ break;
1240+
1241+ size_t n = cur_pos++;
1242+
1243+ if ( n >= len )
1244+ break;
1245+
1246+ if ( n >= char_count )
1247+ break;
1248+
1249+ subresult += prov->GetCharacter( n );
1250+ }
1251+ }
1252+
1253+ return subresult;
1254+ }
1255+
1256+ // NOTE: this copy operator uses the fact that both MultiString have the same allocatorType.
1257+ inline MultiString& operator = ( const MultiString& right )
1258+ {
1259+ if ( this->data.strData )
1260+ {
1261+ DestroyStringProvider( this->data.strData );
1262+
1263+ this->data.strData = nullptr;
1264+ }
1265+
1266+ if ( right.data.strData )
1267+ {
1268+ this->data.strData = right.data.strData->Clone( this );
1269+ }
1270+
1271+ return *this;
1272+ }
1273+
1274+ inline MultiString& operator = ( MultiString&& right ) noexcept
1275+ {
1276+ if ( this->data.strData )
1277+ {
1278+ DestroyStringProvider( this->data.strData );
1279+
1280+ this->data.strData = nullptr;
1281+ }
1282+
1283+ this->data.strData = right.data.strData;
1284+
1285+ right.data.strData = nullptr;
1286+
1287+ return *this;
1288+ }
1289+
1290+ template <typename charType>
1291+ inline bool equals( const charType *right, bool caseSensitive = true ) const
1292+ {
1293+ bool isEqual = false;
1294+
1295+ if ( this->data.strData )
1296+ {
1297+ isEqual = this->data.strData->CompareToChars( right, cplen_tozero( right ), caseSensitive );
1298+ }
1299+ else if ( *right == (charType)0 )
1300+ {
1301+ isEqual = true;
1302+ }
1303+
1304+ return isEqual;
1305+ }
1306+
1307+ inline bool equals( const MultiString& right, bool caseSensitive = true ) const
1308+ {
1309+ bool isEqual = false;
1310+
1311+ if ( this->data.strData && right.data.strData )
1312+ {
1313+ isEqual = this->strData->CompareTo( right.data.strData, caseSensitive );
1314+ }
1315+ else if ( this->data.strData == nullptr && right.data.strData == nullptr )
1316+ {
1317+ isEqual = true;
1318+ }
1319+
1320+ return isEqual;
1321+ }
1322+
1323+ inline bool operator == ( const MultiString& right ) const
1324+ {
1325+ return equals( right, true );
1326+ }
1327+
1328+ inline bool operator != ( const MultiString& right ) const
1329+ {
1330+ return !( this->operator == ( right ) );
1331+ }
1332+
1333+ template <typename otherCharType>
1334+ inline bool operator == ( const otherCharType *right ) const
1335+ {
1336+ return equals( right, true );
1337+ }
1338+
1339+ template <typename otherCharType>
1340+ inline bool operator != ( const otherCharType *right ) const
1341+ {
1342+ return !( this->operator == ( right ) );
1343+ }
1344+
1345+ inline MultiString operator + ( const MultiString& right ) const
1346+ {
1347+ MultiString newPath( *this );
1348+
1349+ if ( stringProvider *rightProv = right.data.strData )
1350+ {
1351+ newPath.compat_strprov_upgrade( rightProv );
1352+
1353+ newPath.data.strData->Append( rightProv );
1354+ }
1355+
1356+ return newPath;
1357+ }
1358+
1359+ template <typename charType>
1360+ inline MultiString operator + ( const charType *right ) const
1361+ {
1362+ MultiString newPath( *this );
1363+
1364+ newPath.compat_upgrade <charType> ();
1365+
1366+ newPath.data.strData->AppendChars( right, cplen_tozero( right ) );
1367+
1368+ return newPath;
1369+ }
1370+
1371+ inline MultiString& operator += ( const MultiString& right )
1372+ {
1373+ if ( stringProvider *rightProv = right.data.strData )
1374+ {
1375+ this->compat_strprov_upgrade( rightProv );
1376+
1377+ this->data.strData->Append( rightProv );
1378+ }
1379+
1380+ return *this;
1381+ }
1382+
1383+ template <typename otherCharType, typename otherAllocatorType>
1384+ inline MultiString& operator += ( const eir::String <otherCharType, otherAllocatorType>& right )
1385+ {
1386+ this->compat_upgrade <otherCharType> ();
1387+
1388+ this->data.strData->AppendChars( right.GetConstString(), right.GetLength() );
1389+
1390+ return *this;
1391+ }
1392+
1393+ template <typename otherCharType>
1394+ inline MultiString& operator += ( const otherCharType *right )
1395+ {
1396+ this->compat_upgrade <otherCharType> ();
1397+
1398+ this->data.strData->AppendChars( right, cplen_tozero( right ) );
1399+
1400+ return *this;
1401+ }
1402+
1403+ inline const char* c_str( void ) const noexcept
1404+ {
1405+ const char *outString = "";
1406+
1407+ if ( stringProvider *provider = this->data.strData )
1408+ {
1409+ outString = provider->GetConstANSIString();
1410+ }
1411+
1412+ return outString;
1413+ }
1414+
1415+ inline const wchar_t* w_str( void ) const noexcept
1416+ {
1417+ const wchar_t *outString = L"";
1418+
1419+ if ( stringProvider *provider = this->data.strData )
1420+ {
1421+ outString = provider->GetConstUnicodeString();
1422+ }
1423+
1424+ return outString;
1425+ }
1426+
1427+ inline const char16_t* u16_str( void ) const noexcept
1428+ {
1429+ const char16_t *outString = u"";
1430+
1431+ if ( stringProvider *provider = this->data.strData )
1432+ {
1433+ outString = provider->GetConstUTF16String();
1434+ }
1435+
1436+ return outString;
1437+ }
1438+
1439+ inline const char8_t* u8_str( void ) const noexcept
1440+ {
1441+ const char8_t *outString = (const char8_t*)"";
1442+
1443+ if ( stringProvider *provider = this->data.strData )
1444+ {
1445+ outString = provider->GetConstUTF8String();
1446+ }
1447+
1448+ return outString;
1449+ }
1450+
1451+ inline const char32_t* u32_str( void ) const noexcept
1452+ {
1453+ const char32_t *outString = U"";
1454+
1455+ if ( stringProvider *provider = this->data.strData )
1456+ {
1457+ outString = provider->GetConstUTF32String();
1458+ }
1459+
1460+ return outString;
1461+ }
1462+
1463+ // More advanced functions.
1464+ inline eir::String <char, directMSAllocator> convert_ansi( void ) const
1465+ {
1466+ eir::String <char, directMSAllocator> ansiOut( nullptr, 0, this );
1467+
1468+ if ( stringProvider *provider = this->data.strData )
1469+ {
1470+ ansiOut = provider->ToANSI();
1471+ }
1472+
1473+ return ansiOut;
1474+ }
1475+
1476+ inline eir::String <wchar_t, directMSAllocator> convert_unicode( void ) const
1477+ {
1478+ eir::String <wchar_t, directMSAllocator> unicodeOut( nullptr, 0, this );
1479+
1480+ if ( stringProvider *provider = this->data.strData )
1481+ {
1482+ unicodeOut = provider->ToUnicode();
1483+ }
1484+
1485+ return unicodeOut;
1486+ }
1487+
1488+ template <typename charType>
1489+ inline void transform_to( void )
1490+ {
1491+ stringProvider *origProv = this->data.strData;
1492+
1493+ if ( !origProv )
1494+ return;
1495+
1496+ // Check if origProv already is that transformation char type.
1497+ if ( GetConstCharStringProvider <charType> ( origProv ) != nullptr )
1498+ {
1499+ return;
1500+ }
1501+
1502+ // Need to turn things into our type.
1503+ stringProvider *newProv = CreateStringProvider <charType> ();
1504+
1505+ try
1506+ {
1507+ newProv->Append( origProv );
1508+ }
1509+ catch( ... )
1510+ {
1511+ DestroyStringProvider( newProv );
1512+ throw;
1513+ }
1514+
1515+ DestroyStringProvider( origProv );
1516+
1517+ this->data.strData = newProv;
1518+ }
1519+
1520+private:
1521+ template <typename callbackType>
1522+ struct staticToRuntimeDispatch
1523+ {
1524+ template <typename charType>
1525+ static AINLINE void ProcChars( const charType *str, const callbackType& cb )
1526+ {
1527+ cb( str );
1528+ }
1529+ };
1530+
1531+public:
1532+ template <typename callbackType>
1533+ AINLINE void char_dispatch( const callbackType& cb ) const
1534+ {
1535+ stringProvider *prov = this->data.strData;
1536+
1537+ if ( !prov )
1538+ return;
1539+
1540+ prov->StringProviderCharPipe <staticToRuntimeDispatch <callbackType>> ( prov, cb );
1541+ }
1542+
1543+ // Functions to determine the underlying string type.
1544+ template <typename charType>
1545+ inline bool is_underlying_char( void ) const
1546+ {
1547+ stringProvider *prov = this->data.strData;
1548+
1549+ if ( prov == nullptr )
1550+ return false;
1551+
1552+ return is_string_prov_char <charType> ( prov );
1553+ }
1554+
1555+ inline stringProvider* string_prov( void ) const
1556+ {
1557+ return this->data.strData;
1558+ }
1559+
1560+ static inline bool is_system_case_sensitive( void )
1561+ {
1562+#if defined(_WIN32)
1563+ return false;
1564+#elif defined(__linux__)
1565+ return true;
1566+#else
1567+#error Unknown platform
1568+#endif
1569+ }
1570+
1571+private:
1572+ struct fields
1573+ {
1574+ stringProvider *strData;
1575+ };
1576+
1577+ size_opt <hasObjectAllocator, allocatorType, fields> data;
1578+};
1579+
1580+// Flesh out the allocator redirect from CSP to MultiString.
1581+MSTR_TEMPLARGS
1582+CSP_TEMPLARGS
1583+IMPL_HEAP_REDIR_DIRECT_ALLOC_METH_ALLOCATE_RETURN MultiString MSTR_TEMPLUSE::template charStringProvider CSP_TEMPLUSE::cspRedirAlloc::Allocate IMPL_HEAP_REDIR_DIRECT_ALLOC_METH_ALLOCATE_ARGS
1584+{
1585+ charStringProvider *hostStruct = LIST_GETITEM( charStringProvider, refMem, strData );
1586+ MultiString *refStruct = hostStruct->refPtr;
1587+ return refStruct->data.allocData.Allocate( refStruct, memSize, alignment );
1588+}
1589+MSTR_TEMPLARGS
1590+CSP_TEMPLARGS
1591+IMPL_HEAP_REDIR_DIRECT_ALLOC_METH_RESIZE_RETURN MultiString MSTR_TEMPLUSE::template charStringProvider CSP_TEMPLUSE::cspRedirAlloc::Resize IMPL_HEAP_REDIR_DIRECT_ALLOC_METH_RESIZE_ARGS
1592+{
1593+ charStringProvider *hostStruct = LIST_GETITEM( charStringProvider, refMem, strData );
1594+ MultiString *refStruct = hostStruct->refPtr;
1595+ return refStruct->data.allocData.Resize( refStruct, objMem, reqNewSize );
1596+}
1597+MSTR_TEMPLARGS
1598+CSP_TEMPLARGS
1599+IMPL_HEAP_REDIR_DIRECT_ALLOC_METH_FREE_RETURN MultiString MSTR_TEMPLUSE::template charStringProvider CSP_TEMPLUSE::cspRedirAlloc::Free IMPL_HEAP_REDIR_DIRECT_ALLOC_METH_FREE_ARGS
1600+{
1601+ charStringProvider *hostStruct = LIST_GETITEM( charStringProvider, refMem, strData );
1602+ MultiString *refStruct = hostStruct->refPtr;
1603+ refStruct->data.allocData.Free( refStruct, memPtr );
1604+}
1605+
1606+}
1607+
1608+#endif //_EIR_MULTISTRING_HEADER_
\ No newline at end of file
--- common/sdk/OSUtils.memheap.h (revision 129)
+++ common/sdk/OSUtils.memheap.h (revision 130)
@@ -939,6 +939,10 @@
939939 {
940940 usageStats stats;
941941
942+ // Have to take the header bytes of each island as meta-bytes into account.
943+ // Just saying that having too many islands is not the best idea.
944+ stats.usedMetaBytes += sizeof( VMemIsland );
945+
942946 LIST_FOREACH_BEGIN( VMemFreeBlock, this->sortedByAddrFreeBlocks.root, sortedByAddrNode )
943947
944948 // If we have an allocation associated with this free block, add up the data bytes.
--- common/sdk/String.h (revision 129)
+++ common/sdk/String.h (revision 130)
@@ -56,7 +56,7 @@
5656 this->data.char_data = empty_string;
5757 this->data.num_chars = 0;
5858 }
59-
59+
6060 public:
6161 inline String( void )
6262 {
@@ -163,21 +163,34 @@
163163 {
164164 size_t newRequiredCharsSize = sizeof(charType) * ( newCharCount + 1 );
165165
166- charType *useBuf = nullptr;
167- bool isBufNew;
166+ bool hasBuf = false;
167+ charType *useBuf = nullptr; // initializing this just to stop compiler warnings.
168+ bool isBufNew = false;
168169
169170 if ( oldCharBuf && oldCharCount > 0 )
170171 {
171- bool couldResize = refMem->data.allocData.Resize( refMem, oldCharBuf, newRequiredCharsSize );
172+ if ( newCharCount == 0 )
173+ {
174+ refMem->data.allocData.Free( refMem, oldCharBuf );
172175
173- if ( couldResize )
176+ hasBuf = true;
177+ useBuf = nullptr;
178+ isBufNew = true;
179+ }
180+ else
174181 {
175- useBuf = oldCharBuf;
176- isBufNew = false;
182+ bool couldResize = refMem->data.allocData.Resize( refMem, oldCharBuf, newRequiredCharsSize );
183+
184+ if ( couldResize )
185+ {
186+ hasBuf = true;
187+ useBuf = oldCharBuf;
188+ isBufNew = false;
189+ }
177190 }
178191 }
179192
180- if ( useBuf == nullptr )
193+ if ( hasBuf == false )
181194 {
182195 useBuf = (charType*)refMem->data.allocData.Allocate( refMem, newRequiredCharsSize, alignof(charType) );
183196
@@ -187,12 +200,15 @@
187200 }
188201
189202 // Guarranteed to throw no exception due to the trivial charType.
190- if ( oldCharCopyCount > 0 )
203+ size_t charCopyCount = std::min( oldCharCopyCount, newCharCount );
204+
205+ if ( charCopyCount > 0 )
191206 {
192207 // Copy over the characters.
193- FSDataUtil::copy_impl( oldCharBuf, oldCharBuf + oldCharCopyCount, useBuf );
208+ FSDataUtil::copy_impl( oldCharBuf, oldCharBuf + charCopyCount, useBuf );
194209 }
195210
211+ hasBuf = true;
196212 isBufNew = true;
197213 }
198214
@@ -366,7 +382,41 @@
366382 this->data.num_chars = newCharCount;
367383 }
368384 }
385+
386+ // Empties out the string by freeing the associated buffer.
387+ inline void Clear( void )
388+ {
389+ free_old_buffer( this, this->data.char_data, this->data.num_chars, true );
369390
391+ this->reset_to_empty();
392+ }
393+
394+ // Sets the amount of code points that this string is consisting of.
395+ // If the string grows then it is padded with zeroes.
396+ inline void Resize( size_t numCodePoints )
397+ {
398+ charType *oldCharBuf = this->data.char_data;
399+ size_t oldCharCount = this->data.num_chars;
400+
401+ charType *useBuf;
402+ bool isBufNew;
403+
404+ expand_buffer( this, oldCharBuf, oldCharCount, numCodePoints, numCodePoints, useBuf, isBufNew );
405+
406+ // Fill up the zeroes.
407+ for ( size_t idx = oldCharCount; idx < numCodePoints; idx++ )
408+ {
409+ useBuf[ idx ] = (charType)0;
410+ }
411+
412+ // Destroy any previous buffer.
413+ free_old_buffer( this, oldCharBuf, oldCharCount, isBufNew );
414+
415+ // Remember the new thing.
416+ this->data.char_data = useBuf;
417+ this->data.num_chars = numCodePoints;
418+ }
419+
370420 // Returns true if the codepoints of compareWith match this string.
371421 // This check if of course case-sensitive.
372422 // Use other algorithms if you need an case-insensitive comparison because it is complicated (UniChar.h).
@@ -400,6 +450,11 @@
400450 return equals( compareWith, cplen_tozero( compareWith ) );
401451 }
402452
453+ inline bool IsEmpty( void ) const
454+ {
455+ return ( this->data.num_chars == 0 );
456+ }
457+
403458 inline size_t GetLength( void ) const
404459 {
405460 return this->data.num_chars;
--- common/sdk/UniChar.casesense.h (revision 129)
+++ common/sdk/UniChar.casesense.h (revision 130)
@@ -50,6 +50,11 @@
5050 {
5151 using dyna_toupper_lookup::dyna_toupper_lookup;
5252 };
53+template <>
54+struct toupper_lookup <char16_t> : dyna_toupper_lookup <char16_t>
55+{
56+ using dyna_toupper_lookup::dyna_toupper_lookup;
57+};
5358
5459 struct utf32_wchar_toupper_lookup
5560 {
--- common/sdk/UniChar.h (revision 129)
+++ common/sdk/UniChar.h (revision 130)
@@ -1087,7 +1087,7 @@
10871087 }
10881088
10891089 template <typename inputCharType, typename outputCharType, typename allocatorType, bool optimizeEqual = true, typename... Args>
1090- inline std::basic_string <outputCharType> ConvertStringsLength( const inputCharType *inputChars, size_t inputLen, Args... allocArgs )
1090+ inline eir::String <outputCharType, allocatorType> ConvertStringsLength( const inputCharType *inputChars, size_t inputLen, Args... allocArgs )
10911091 {
10921092 if constexpr ( optimizeEqual && std::is_same <inputCharType, outputCharType>::value )
10931093 {
--- common/sdk/Vector.h (revision 129)
+++ common/sdk/Vector.h (revision 130)
@@ -347,6 +347,30 @@
347347 });
348348 }
349349
350+private:
351+ AINLINE void shrink_backed_memory( structType *use_data, size_t newCount )
352+ {
353+ if ( newCount == 0 )
354+ {
355+ this->data.allocData.Free( this, use_data );
356+
357+ // Gotta do this.
358+ this->data.data_entries = nullptr;
359+ }
360+ else
361+ {
362+ bool resizeSuccess = this->data.allocData.Resize( this, use_data, sizeof(structType) * newCount );
363+
364+ // Since the CRT allocator is valid too and it does not support resizing, we actually ignore a failed resize.
365+ // It does not matter actually, we would just waste some space.
366+ //assert( resizeSuccess == true );
367+ (void)resizeSuccess;
368+ }
369+
370+ this->data.data_count = newCount;
371+ }
372+
373+public:
350374 inline void RemoveByIndex( size_t removeIdx )
351375 {
352376 size_t oldCount = this->data.data_count;
@@ -371,21 +395,7 @@
371395 }
372396 }
373397
374- if ( newCount == 0 )
375- {
376- this->data.allocData.Free( this, use_data );
377-
378- // Gotta do this.
379- this->data.data_entries = nullptr;
380- }
381- else
382- {
383- bool resizeSuccess = this->data.allocData.Resize( this, use_data, sizeof(structType) * newCount );
384-
385- assert( resizeSuccess == true );
386- }
387-
388- this->data.data_count = newCount;
398+ this->shrink_backed_memory( use_data, newCount );
389399 }
390400
391401 inline void RemoveFromBack( void )
@@ -402,21 +412,7 @@
402412
403413 use_data[ newCount ].~structType();
404414
405- if ( newCount == 0 )
406- {
407- this->data.allocData.Free( this, use_data );
408-
409- // Gotta do this.
410- this->data.data_entries = nullptr;
411- }
412- else
413- {
414- bool resizeSuccess = this->data.allocData.Resize( this, use_data, sizeof(structType) * newCount );
415-
416- assert( resizeSuccess == true );
417- }
418-
419- this->data.data_count = newCount;
415+ this->shrink_backed_memory( use_data, newCount );
420416 }
421417
422418 // Removes all items from this array by release the back-end memory.
--- common/sdk/eirutils.h (revision 129)
+++ common/sdk/eirutils.h (revision 130)
@@ -17,6 +17,17 @@
1717
1818 #include "MacroUtils.h"
1919
20+namespace eir
21+{
22+
23+// A very special pass-in just for creation with the allocator initialization.
24+enum constr_with_alloc
25+{
26+ CONSTR_WITH_ALLOC
27+};
28+
29+}
30+
2031 // TODO: flesh out this exception stuff.
2132 struct eir_exception
2233 {
--- unittests/src/alloc_helper.hxx (revision 129)
+++ unittests/src/alloc_helper.hxx (revision 130)
@@ -2,6 +2,7 @@
22 #ifndef _ALLOC_HELPERS_
33 #define _ALLOC_HELPERS_
44
5+#include <stdlib.h>
56 #include <sdk/OSUtils.memheap.h>
67
78 extern NativeHeapAllocator globalHeapAlloc;
@@ -56,4 +57,23 @@
5657 struct is_object {};
5758 };
5859
60+struct CRTHeapAllocator
61+{
62+ static inline void* Allocate( void *refMem, size_t memSize, size_t alignment )
63+ {
64+ return _aligned_malloc( memSize, alignment );
65+ }
66+
67+ static inline bool Resize( void *refMem, void *memPtr, size_t reqSize )
68+ {
69+ // The CRT cannot properly resize.
70+ return false;
71+ }
72+
73+ static inline void Free( void *refMem, void *memPtr )
74+ {
75+ _aligned_free( memPtr );
76+ }
77+};
78+
5979 #endif //_ALLOC_HELPERS_
\ No newline at end of file
--- unittests/src/avltree.cpp (revision 129)
+++ unittests/src/avltree.cpp (revision 130)
@@ -139,7 +139,7 @@
139139 {
140140 AVLTree <IntegerItem> tree;
141141
142- static constexpr size_t NUM_ITEMS_TO_INSERT = 1000000;
142+ static constexpr size_t NUM_ITEMS_TO_INSERT = 100000;
143143
144144 IntegerItem *items = new IntegerItem[ NUM_ITEMS_TO_INSERT ];
145145
--- unittests/src/impltests.cpp (revision 129)
+++ unittests/src/impltests.cpp (revision 130)
@@ -89,6 +89,37 @@
8989 cheapAllocator alloc;
9090 };
9191
92+template <typename oneType>
93+struct outer_template
94+{
95+ template <typename twoType>
96+ struct inner_template
97+ {
98+ struct theStruct
99+ {
100+ static void Test( void );
101+ };
102+
103+ static void Test2( void );
104+ };
105+
106+ static void Test3( void );
107+};
108+
109+template <typename oneType>
110+template <typename twoType>
111+void outer_template <oneType>::inner_template <twoType>::Test2( void )
112+{
113+ return;
114+}
115+
116+template <typename oneType>
117+template <typename twoType>
118+void outer_template <oneType>::inner_template <twoType>::theStruct::Test( void )
119+{
120+ return;
121+}
122+
92123 void IMPLEMENTATION_TESTS( void )
93124 {
94125 // TODO.
--- unittests/src/main.cpp (revision 129)
+++ unittests/src/main.cpp (revision 130)
@@ -18,6 +18,7 @@
1818 extern void VECTOR_TESTS( void );
1919 extern void MAP_TESTS( void );
2020 extern void STRING_TESTS( void );
21+extern void MULTISTRING_TESTS( void );
2122
2223 #ifdef _WIN32
2324 // Shell extension test.
@@ -36,6 +37,7 @@
3637 VECTOR_TESTS();
3738 MAP_TESTS();
3839 STRING_TESTS();
40+ MULTISTRING_TESTS();
3941
4042 // Done.
4143 return 0;
--- unittests/src/multistring.cpp (nonexistent)
+++ unittests/src/multistring.cpp (revision 130)
@@ -0,0 +1,63 @@
1+// Unit tests for the MultiString object.
2+#include <sdk/MultiString.h>
3+
4+#include "alloc_helper.hxx"
5+
6+void MULTISTRING_TESTS( void )
7+{
8+ printf( "testing multi-string constructor..." );
9+ {
10+ eir::MultiString <EirHeapAllocator> string;
11+
12+ assert( string.empty() == true );
13+ assert( string == "" );
14+ }
15+ printf( "ok.\n" );
16+
17+ printf( "testing multi-string char constructor..." );
18+ {
19+ eir::MultiString <EirHeapAllocator> charString( "hello world" );
20+
21+ assert( charString.empty() == false );
22+ assert( charString == "hello world" );
23+ }
24+ printf( "ok.\n" );
25+
26+ printf( "testing multi-string wchar_t constructor..." );
27+ {
28+ eir::MultiString <EirHeapAllocator> wcharString( L"hello world" );
29+
30+ assert( wcharString.empty() == false );
31+ assert( wcharString == "hello world" );
32+ }
33+ printf( "ok.\n" );
34+
35+ printf( "testing multi-string char16_t constructor..." );
36+ {
37+ eir::MultiString <EirHeapAllocator> char16String( u"hello world" );
38+
39+ assert( char16String.empty() == false );
40+ assert( char16String == "hello world" );
41+ }
42+ printf( "ok.\n" );
43+
44+ printf( "testing multi-string char8_t constructor..." );
45+ {
46+ eir::MultiString <EirHeapAllocator> char8String( (const char8_t*)"hello world" );
47+
48+ assert( char8String.empty() == false );
49+ assert( char8String == "hello world" );
50+ }
51+ printf( "ok.\n" );
52+
53+ printf( "testing multi-string char32_t constructor..." );
54+ {
55+ eir::MultiString <EirHeapAllocator> char32String( U"hello world" );
56+
57+ assert( char32String.empty() == false );
58+ assert( char32String == "hello world" );
59+ }
60+ printf( "ok.\n" );
61+
62+
63+}
\ No newline at end of file
--- unittests/src/string.cpp (revision 129)
+++ unittests/src/string.cpp (revision 130)
@@ -170,4 +170,24 @@
170170 static_assert( sizeof(stringHeap) == sizeof(void*) + sizeof(size_t) );
171171 }
172172 printf( "ok.\n" );
173+
174+ printf( "testing string with CRT memory..." );
175+ {
176+ eir::String <char, CRTHeapAllocator> crtString( "meow" );
177+
178+ assert( crtString == "meow" );
179+ assert( crtString.GetLength() == 4 );
180+
181+ for ( size_t n = 0; n < 1000; n++ )
182+ {
183+ crtString += "ow";
184+ }
185+
186+ assert( crtString.GetLength() == 2004 );
187+
188+ crtString.Clear();
189+
190+ assert( crtString.GetLength() == 0 );
191+ }
192+ printf( "ok.\n" );
173193 }
\ No newline at end of file
--- unittests/src/vector.cpp (revision 129)
+++ unittests/src/vector.cpp (revision 130)
@@ -213,4 +213,20 @@
213213 assert( customVec == customVec2 );
214214 }
215215 printf( "ok.\n" );
216+
217+ printf( "testing vector with CRT allocator..." );
218+ {
219+ eir::Vector <long long, CRTHeapAllocator> crtVector;
220+
221+ crtVector.AddToBack( 42 );
222+ crtVector.AddToBack( 101 );
223+
224+ assert( crtVector.GetCount() == 2 );
225+
226+ crtVector.RemoveFromBack();
227+ crtVector.RemoveFromBack();
228+
229+ assert( crtVector.GetCount() == 0 );
230+ }
231+ printf( "ok.\n" );
216232 }
\ No newline at end of file
Show on old repository browser