| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- namespace Js
- {
- // -------------------------------------------------------------------------------------------------------------------------
- // Storage
- // -------------------------------------------------------------------------------------------------------------------------
- //
- // CompoundString uses available buffer space to directly store characters or pointers, or to pack information such as a
- // substring's start index and length. It is optimized for concatenation. A compound string begins in direct character mode,
- // where it appends characters directly to the buffers. When a somewhat larger string is concatenated, the compound string
- // switches to pointer mode and records the direct character length. From that point onwards, only pointers or packed
- // information is stored in the buffers. Each piece of packed information is stored as a pointer with the lowest bit tagged.
- //
- // A compound string may have several chained Block objects, each with a buffer allocated inline with the block. The
- // compound string references only the last block in the chain (to save space), and each block references its previous block
- // in the chain. As a consequence, during flattening, blocks are iterated backwards and flattening is also done backwards.
- //
- // -------------------------------------------------------------------------------------------------------------------------
- // Using as a character-only string builder
- // -------------------------------------------------------------------------------------------------------------------------
- //
- // Using the AppendChars set of functions requires that the compound string is in direct character mode, and forces it to
- // remain in direct character mode by appending all characters directly to the buffer. Those functions can be used to build
- // a string like a typical character-only string builder. Flattening is much faster when in direct character mode, and the
- // AppendChars set of functions also get to omit the check to see if the compound string is in direct character mode, but it
- // is at the cost of having to append all characters even in the case of appending large strings, instead of just appending
- // a pointer.
- //
- // -------------------------------------------------------------------------------------------------------------------------
- // Appending
- // -------------------------------------------------------------------------------------------------------------------------
- //
- // The compound string and builder have simple Append and AppendChars functions that delegate to a set of AppendGeneric
- // functions that do the actual work. AppendGeneric functions are templatized and their implementation is shared between the
- // compound string and builder.
- //
- // After determining how to append, the AppendGeneric functions call a TryAppendGeneric function that will perform the
- // append if there is enough space in the last block's buffer. If there is no space, the AppendGeneric functions call a
- // AppendSlow function. In a compound string, the AppendSlow function grows the buffer or creates a new chained block, and
- // performs the append. In a builder, the AppendSlow function creates the compound string and delegates to it from that
- // point onwards.
- //
- // -------------------------------------------------------------------------------------------------------------------------
- // Buffer sharing and ownership
- // -------------------------------------------------------------------------------------------------------------------------
- //
- // Multiple compound string objects may reference and use the same buffers. Cloning a compound string creates a new object
- // that references the same buffer. However, only one compound string may own the last block at any given time, since the
- // last block's buffer is mutable through concatenation. Compound string objects that don't own the last block keep track of
- // the character length of the buffer in their last block info (BlockInfo object), since the block's length may be changed
- // by the block's owner.
- //
- // When a concatenation operation is performed on a compound string that does not own the last block, it will first need to
- // take ownership of that block. So, it is necessary to call PrepareForAppend() before the first append operation for a
- // compound string whose buffers may be shared. Taking ownership of a block is done by either resizing the block (and hence
- // copying the buffer up to the point to which it is used), or shallow-cloning the last block and chaining a new block to
- // it. Shallow cloning copies the block's metadata but does not copy the buffer. The character length of the clone is set to
- // the length of the portion of the buffer that is used by the compound string. The cloned block references the original
- // block that owns the buffer, for access to the buffer. Once a new block is chained to it, it then becomes the last block,
- // effectively making the clone immutable by the compound string.
- //
- // -------------------------------------------------------------------------------------------------------------------------
- // Last block info (BlockInfo object)
- // -------------------------------------------------------------------------------------------------------------------------
- //
- // Blocks are only created once chaining begins. Until then, the buffer is allocated directly and stored in the last block
- // info. The buffer is resized until it reaches a threshold, and upon the final resize before chaining begins, a block is
- // created. From that point onwards, blocks are no longer resized and only chained, although a new chained block may be
- // larger than the previous block.
- //
- // The last block info is also used to serve as a cache for information in the last block. Since the last block is where
- // concatenation occurs, it is significantly beneficial to prevent having to dereference the last block to get to its
- // information. So, the BlockInfo object representing the last block info caches the last block's information and only it is
- // used during append operations. Only when space runs out, is the actual last block updated with information from the last
- // block info. As a consequence of this and the fact that multiple compound strings may share blocks, the last block's
- // character length may not be up-to-date, or may not be relevant to the compound string querying it, so it should never be
- // queried except in specific cases where it is guaranteed to be correct.
- //
- // -------------------------------------------------------------------------------------------------------------------------
- // Builder
- // -------------------------------------------------------------------------------------------------------------------------
- //
- // The builder uses stack-allocated space for the initial buffer. It may perform better in some scenarios, but the tradeoff
- // is that it is at the cost of an additional check per append.
- //
- // It typically performs better in cases where the number of concatenations is highly unpredictable and may range from just
- // a few to a large number:
- // - For few concatenations, the final compound string's buffer will be the minimum size necessary, so it helps by
- // saving space, and as a result, performing a faster allocation
- // - For many concatenations, the use of stack space reduces the number of allocations that would otherwise be necessary
- // to grow the buffer
- class CompoundString sealed : public LiteralString // vtable will be switched to LiteralString's vtable after flattening
- {
- #pragma region CompoundString::Block
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- private:
- class Block
- {
- public:
- static const uint ChainSizeThreshold;
- private:
- static const uint MaxChainedBlockSize;
- private:
- Field(Block *const) bufferOwner;
- Field(CharCount) charLength;
- Field(CharCount) charCapacity;
- Field(const Block *const) previous;
- private:
- Block(const CharCount charCapacity, const Block *const previous);
- Block(const void *const buffer, const CharCount charLength, const CharCount charCapacity);
- Block(const Block &other, const CharCount usedCharLength);
- public:
- static Block *New(const uint size, const Block *const previous, Recycler *const recycler);
- static Block *New(const void *const buffer, const CharCount usedCharLength, const bool reserveMoreSpace, Recycler *const recycler);
- Block *Clone(const CharCount usedCharLength, Recycler *const recycler) const;
- private:
- static CharCount CharCapacityFromSize(const uint size);
- static uint SizeFromCharCapacity(const CharCount charCapacity);
- private:
- static CharCount PointerAlign(const CharCount charLength);
- public:
- static const char16 *Chars(const void *const buffer);
- static char16 *Chars(void *const buffer);
- static const Field(void*) *Pointers(const void *const buffer);
- static Field(void*) *Pointers(void *const buffer);
- static CharCount PointerCapacityFromCharCapacity(const CharCount charCapacity);
- static CharCount CharCapacityFromPointerCapacity(const CharCount pointerCapacity);
- static CharCount PointerLengthFromCharLength(const CharCount charLength);
- static CharCount CharLengthFromPointerLength(const CharCount pointerLength);
- static uint SizeFromUsedCharLength(const CharCount usedCharLength);
- public:
- static bool ShouldAppendChars(const CharCount appendCharLength, const uint additionalSizeForPointerAppend = 0);
- public:
- const void *Buffer() const;
- void *Buffer();
- const Block *Previous() const;
- public:
- const char16 *Chars() const;
- char16 *Chars();
- CharCount CharLength() const;
- void SetCharLength(const CharCount charLength);
- CharCount CharCapacity() const;
- public:
- const Field(void*) *Pointers() const;
- Field(void*) *Pointers();
- CharCount PointerLength() const;
- CharCount PointerCapacity() const;
- private:
- static uint GrowSize(const uint size);
- static uint GrowSizeForChaining(const uint size);
- public:
- Block *Chain(Recycler *const recycler);
- private:
- PREVENT_COPY(Block);
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma endregion
- #pragma region CompoundString::BlockInfo
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- private:
- class BlockInfo
- {
- private:
- Field(void *) buffer;
- Field(CharCount) charLength;
- Field(CharCount) charCapacity;
- public:
- BlockInfo();
- BlockInfo(Block *const block);
- public:
- char16 *Chars() const;
- CharCount CharLength() const;
- void SetCharLength(const CharCount charLength);
- CharCount CharCapacity() const;
- public:
- Field(void*) *Pointers() const;
- CharCount PointerLength() const;
- void SetPointerLength(const CharCount pointerLength);
- CharCount PointerCapacity() const;
- public:
- static CharCount AlignCharCapacityForAllocation(const CharCount charCapacity);
- static CharCount GrowCharCapacity(const CharCount charCapacity);
- static bool ShouldAllocateBuffer(const CharCount charCapacity);
- void AllocateBuffer(const CharCount charCapacity, Recycler *const recycler);
- Block *CopyBuffer(const void *const buffer, const CharCount usedCharLength, const bool reserveMoreSpace, Recycler *const recycler);
- Block *Resize(Recycler *const recycler);
- static size_t GetOffsetOfCharLength() { return offsetof(BlockInfo, charLength); }
- static size_t GetOffsetOfCharCapacity() { return offsetof(BlockInfo, charCapacity); }
- static size_t GetOffsetOfBuffer() { return offsetof(BlockInfo, buffer); }
- public:
- void CopyFrom(Block *const block);
- void CopyTo(Block *const block);
- void Unreference();
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma endregion
- #pragma region CompoundString::Builder
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public:
- template<CharCount MinimumCharCapacity>
- class Builder
- {
- private:
- // Array size needs to be a constant expression. This expression is equivalent to
- // Block::PointerLengthFromCharLength(MinimumCharCapacity), and generates a pointer capacity that equates to a char
- // capacity that is >= MinimumCharCapacity.
- void *buffer[
- (
- (MinimumCharCapacity + sizeof(void *) / sizeof(char16) - 1) &
- ~(sizeof(void *) / sizeof(char16) - 1)
- ) / (sizeof(void *) / sizeof(char16))];
- CharCount stringLength;
- CharCount charLength;
- CharCount directCharLength;
- CompoundString *compoundString;
- ScriptContext *const scriptContext;
- #if DBG
- bool isFinalized;
- #endif
- public:
- Builder(ScriptContext *const scriptContext);
- private:
- bool IsFinalized() const;
- bool HasOnlyDirectChars() const;
- void SwitchToPointerMode();
- bool OwnsLastBlock() const;
- const char16 *GetAppendStringBuffer(JavascriptString *const s) const;
- ScriptContext *GetScriptContext() const;
- JavascriptLibrary *GetLibrary() const;
- private:
- char16 *LastBlockChars();
- CharCount LastBlockCharLength() const;
- void SetLastBlockCharLength(const CharCount charLength);
- CharCount LastBlockCharCapacity() const;
- private:
- Field(void*) *LastBlockPointers();
- CharCount LastBlockPointerLength() const;
- void SetLastBlockPointerLength(const CharCount pointerLength);
- CharCount LastBlockPointerCapacity() const;
- private:
- CharCount GetLength() const;
- void SetLength(const CharCount stringLength);
- private:
- void AppendSlow(const char16 c);
- void AppendSlow(JavascriptString *const s);
- void AppendSlow(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength);
- void AppendSlow(JavascriptString *const s, void *const packedSubstringInfo, void *const packedSubstringInfo2, const CharCount appendCharLength);
- public:
- void Append(const char16 c);
- void AppendChars(const char16 c);
- void Append(JavascriptString *const s);
- void AppendChars(JavascriptString *const s);
- void Append(JavascriptString *const s, const CharCount startIndex, const CharCount appendCharLength);
- void AppendChars(JavascriptString *const s, const CharCount startIndex, const CharCount appendCharLength);
- template<CharCount AppendCharLengthPlusOne> void Append(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral = true);
- template<CharCount AppendCharLengthPlusOne> void AppendChars(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral = true);
- void Append(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength);
- void AppendChars(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength);
- template<class TValue, class FConvertToString> void Append(const TValue &value, const CharCount maximumAppendCharLength, const FConvertToString ConvertToString);
- template<class TValue, class FConvertToString> void AppendChars(const TValue &value, const CharCount maximumAppendCharLength, const FConvertToString ConvertToString);
- private:
- CompoundString *CreateCompoundString(const bool reserveMoreSpace) const;
- public:
- JavascriptString *ToString();
- friend CompoundString;
- PREVENT_COPY(Builder);
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma endregion
- #pragma region CompoundString
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- private:
- Field(BlockInfo) lastBlockInfo;
- Field(CharCount) directCharLength;
- Field(bool) ownsLastBlock;
- Field(Block *) lastBlock;
- private:
- CompoundString(const CharCount initialCharCapacity, JavascriptLibrary *const library);
- CompoundString(const CharCount initialBlockSize, const bool allocateBlock, JavascriptLibrary *const library);
- CompoundString(const CharCount stringLength, const CharCount directCharLength, const void *const buffer, const CharCount usedCharLength, const bool reserveMoreSpace, JavascriptLibrary *const library);
- CompoundString(CompoundString &other, const bool forAppending);
- public:
- static CompoundString *NewWithCharCapacity(const CharCount initialCharCapacity, JavascriptLibrary *const library);
- static CompoundString *NewWithPointerCapacity(const CharCount initialPointerCapacity, JavascriptLibrary *const library);
- private:
- static CompoundString *NewWithBufferCharCapacity(const CharCount initialCharCapacity, JavascriptLibrary *const library);
- static CompoundString *NewWithBlockSize(const CharCount initialBlockSize, JavascriptLibrary *const library);
- static CompoundString *New(const CharCount stringLength, const CharCount directCharLength, const void *const buffer, const CharCount usedCharLength, const bool reserveMoreSpace, JavascriptLibrary *const library);
- public:
- CompoundString *Clone(const bool forAppending);
- static CompoundString * JitClone(CompoundString * cs);
- static CompoundString * JitCloneForAppending(CompoundString * cs);
- public:
- static size_t GetOffsetOfOwnsLastBlock() { return offsetof(CompoundString, ownsLastBlock); }
- static size_t GetOffsetOfDirectCharLength() { return offsetof(CompoundString, directCharLength); }
- static size_t GetOffsetOfLastBlockInfo() { return offsetof(CompoundString, lastBlockInfo); }
- static size_t GetOffsetOfLastBlockInfoCharLength() { return CompoundString::BlockInfo::GetOffsetOfCharLength(); }
- static size_t GetOffsetOfLastBlockInfoCharCapacity() { return CompoundString::BlockInfo::GetOffsetOfCharCapacity(); }
- static size_t GetOffsetOfLastBlockInfoBuffer() { return CompoundString::BlockInfo::GetOffsetOfBuffer(); }
- public:
- static JavascriptString *GetImmutableOrScriptUnreferencedString(JavascriptString *const s);
- static bool ShouldAppendChars(const CharCount appendCharLength);
- private:
- bool HasOnlyDirectChars() const;
- void SwitchToPointerMode();
- bool OwnsLastBlock() const;
- const char16 *GetAppendStringBuffer(JavascriptString *const s) const;
- private:
- char16 *LastBlockChars() const;
- CharCount LastBlockCharLength() const;
- void SetLastBlockCharLength(const CharCount charLength);
- CharCount LastBlockCharCapacity() const;
- private:
- Field(void*) *LastBlockPointers() const;
- CharCount LastBlockPointerLength() const;
- void SetLastBlockPointerLength(const CharCount pointerLength);
- CharCount LastBlockPointerCapacity() const;
- private:
- static void PackSubstringInfo(const CharCount startIndex, const CharCount length, void * *const packedSubstringInfoRef, void * *const packedSubstringInfo2Ref);
- public:
- static bool IsPackedInfo(void *const pointer);
- static void UnpackSubstringInfo(void *const pointer, void *const pointer2, CharCount *const startIndexRef, CharCount *const lengthRef);
- private:
- template<class String> static bool TryAppendGeneric(const char16 c, String *const toString);
- template<class String> static bool TryAppendGeneric(JavascriptString *const s, const CharCount appendCharLength, String *const toString);
- template<class String> static bool TryAppendFewCharsGeneric(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength, String *const toString);
- template<class String> static bool TryAppendGeneric(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength, String *const toString);
- template<class String> static bool TryAppendGeneric(JavascriptString *const s, void *const packedSubstringInfo, void *const packedSubstringInfo2, const CharCount appendCharLength, String *const toString);
- private:
- template<class String> static void AppendGeneric(const char16 c, String *const toString, const bool appendChars);
- template<class String> static void AppendGeneric(JavascriptString *const s, String *const toString, const bool appendChars);
- template<class String> static void AppendGeneric(JavascriptString *const s, const CharCount startIndex, const CharCount appendCharLength, String *const toString, const bool appendChars);
- template<CharCount AppendCharLengthPlusOne, class String> static void AppendGeneric(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral, String *const toString, const bool appendChars);
- template<class String> static void AppendGeneric(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength, String *const toString, const bool appendChars);
- template<class TValue, class FConvertToString, class String> static void AppendGeneric(const TValue &value, CharCount maximumAppendCharLength, const FConvertToString ConvertToString, String *const toString, const bool appendChars);
- private:
- void AppendSlow(const char16 c);
- void AppendSlow(JavascriptString *const s);
- void AppendSlow(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength);
- void AppendSlow(JavascriptString *const s, void *const packedSubstringInfo, void *const packedSubstringInfo2, const CharCount appendCharLength);
- public:
- void PrepareForAppend();
- void Append(const char16 c);
- void AppendChars(const char16 c);
- void Append(JavascriptString *const s);
- void AppendChars(JavascriptString *const s);
- void Append(JavascriptString *const s, const CharCount startIndex, const CharCount appendCharLength);
- void AppendChars(JavascriptString *const s, const CharCount startIndex, const CharCount appendCharLength);
- template<CharCount AppendCharLengthPlusOne> void Append(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral = true);
- template<CharCount AppendCharLengthPlusOne> void AppendChars(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral = true);
- void Append(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength);
- void AppendChars(__in_xcount(appendCharLength) const char16 *const s, const CharCount appendCharLength);
- void AppendCharsSz(__in_z const char16 *const s);
- template<class TValue, class FConvertToString> void Append(const TValue &value, const CharCount maximumAppendCharLength, const FConvertToString ConvertToString);
- template<class TValue, class FConvertToString> void AppendChars(const TValue &value, const CharCount maximumAppendCharLength, const FConvertToString ConvertToString);
- private:
- void Grow();
- void TakeOwnershipOfLastBlock();
- private:
- void Unreference();
- public:
- virtual const char16 *GetSz() override sealed;
- using JavascriptString::Copy;
- virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override sealed;
- virtual bool IsTree() const override sealed;
- protected:
- DEFINE_VTABLE_CTOR(CompoundString, LiteralString);
- private:
- PREVENT_COPY(CompoundString);
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma endregion
- public:
- virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
- {
- return VTableValue::VtableCompoundString;
- }
- };
- template <> bool VarIsImpl<CompoundString>(RecyclableObject * object);
- #pragma region CompoundString::Builder definition
- #ifndef CompoundStringJsDiag
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- template<CharCount MinimumCharCapacity>
- CompoundString::Builder<MinimumCharCapacity>::Builder(ScriptContext *const scriptContext)
- : stringLength(0),
- charLength(0),
- directCharLength(static_cast<CharCount>(-1)),
- compoundString(nullptr),
- scriptContext(scriptContext)
- #if DBG
- , isFinalized(false)
- #endif
- {
- CompileAssert(MinimumCharCapacity != 0);
- Assert(LastBlockCharCapacity() >= MinimumCharCapacity);
- }
- template<CharCount MinimumCharCapacity>
- bool CompoundString::Builder<MinimumCharCapacity>::IsFinalized() const
- {
- #if DBG
- return isFinalized;
- #else
- return false;
- #endif
- }
- template<CharCount MinimumCharCapacity>
- bool CompoundString::Builder<MinimumCharCapacity>::HasOnlyDirectChars() const
- {
- return directCharLength == static_cast<CharCount>(-1);
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::SwitchToPointerMode()
- {
- Assert(HasOnlyDirectChars());
- directCharLength = charLength;
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(_u("CompoundString::SwitchToPointerMode() - directCharLength = %u\n"), directCharLength);
- Output::Flush();
- }
- }
- template<CharCount MinimumCharCapacity>
- bool CompoundString::Builder<MinimumCharCapacity>::OwnsLastBlock() const
- {
- return true;
- }
- template<CharCount MinimumCharCapacity>
- inline const char16 *CompoundString::Builder<MinimumCharCapacity>::GetAppendStringBuffer(
- JavascriptString *const s) const
- {
- Assert(s);
- return s->GetString();
- }
- template<CharCount MinimumCharCapacity>
- ScriptContext *CompoundString::Builder<MinimumCharCapacity>::GetScriptContext() const
- {
- return scriptContext;
- }
- template<CharCount MinimumCharCapacity>
- JavascriptLibrary *CompoundString::Builder<MinimumCharCapacity>::GetLibrary() const
- {
- return scriptContext->GetLibrary();
- }
- template<CharCount MinimumCharCapacity>
- char16 *CompoundString::Builder<MinimumCharCapacity>::LastBlockChars()
- {
- return Block::Chars(buffer);
- }
- template<CharCount MinimumCharCapacity>
- CharCount CompoundString::Builder<MinimumCharCapacity>::LastBlockCharLength() const
- {
- return charLength;
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::SetLastBlockCharLength(const CharCount charLength)
- {
- this->charLength = charLength;
- }
- template<CharCount MinimumCharCapacity>
- CharCount CompoundString::Builder<MinimumCharCapacity>::LastBlockCharCapacity() const
- {
- return Block::CharCapacityFromPointerCapacity(LastBlockPointerCapacity());
- }
- template<CharCount MinimumCharCapacity>
- Field(void*) *CompoundString::Builder<MinimumCharCapacity>::LastBlockPointers()
- {
- return Block::Pointers(buffer);
- }
- template<CharCount MinimumCharCapacity>
- CharCount CompoundString::Builder<MinimumCharCapacity>::LastBlockPointerLength() const
- {
- return Block::PointerLengthFromCharLength(charLength);
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::SetLastBlockPointerLength(const CharCount pointerLength)
- {
- charLength = Block::CharLengthFromPointerLength(pointerLength);
- }
- template<CharCount MinimumCharCapacity>
- CharCount CompoundString::Builder<MinimumCharCapacity>::LastBlockPointerCapacity() const
- {
- return _countof(buffer);
- }
- template<CharCount MinimumCharCapacity>
- CharCount CompoundString::Builder<MinimumCharCapacity>::GetLength() const
- {
- return stringLength;
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::SetLength(const CharCount stringLength)
- {
- if(!IsValidCharCount(stringLength))
- Throw::OutOfMemory();
- this->stringLength = stringLength;
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::AppendSlow(const char16 c)
- {
- Assert(!this->compoundString);
- CompoundString *const compoundString = CreateCompoundString(true);
- this->compoundString = compoundString;
- const bool appended =
- HasOnlyDirectChars()
- ? TryAppendGeneric(c, compoundString)
- : TryAppendGeneric(GetLibrary()->GetCharStringCache().GetStringForChar(c), 1, compoundString);
- Assert(appended);
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::AppendSlow(JavascriptString *const s)
- {
- Assert(!this->compoundString);
- CompoundString *const compoundString = CreateCompoundString(true);
- this->compoundString = compoundString;
- const bool appended = TryAppendGeneric(s, s->GetLength(), compoundString);
- Assert(appended);
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::AppendSlow(
- __in_xcount(appendCharLength) const char16 *const s,
- const CharCount appendCharLength)
- {
- // Even though CreateCompoundString() will create a compound string with some additional space reserved for appending,
- // the amount of space available may still not be enough, so need to check and fall back to the slow path as well
- Assert(!this->compoundString);
- CompoundString *const compoundString = CreateCompoundString(true);
- this->compoundString = compoundString;
- if(TryAppendGeneric(s, appendCharLength, compoundString))
- return;
- compoundString->AppendSlow(s, appendCharLength);
- }
- template<CharCount MinimumCharCapacity>
- void CompoundString::Builder<MinimumCharCapacity>::AppendSlow(
- JavascriptString *const s,
- void *const packedSubstringInfo,
- void *const packedSubstringInfo2,
- const CharCount appendCharLength)
- {
- Assert(!this->compoundString);
- CompoundString *const compoundString = CreateCompoundString(true);
- this->compoundString = compoundString;
- const bool appended = TryAppendGeneric(s, packedSubstringInfo, packedSubstringInfo2, appendCharLength, compoundString);
- Assert(appended);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::Append(const char16 c)
- {
- if(!compoundString)
- {
- AppendGeneric(c, this, false);
- return;
- }
- compoundString->Append(c);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::AppendChars(const char16 c)
- {
- if(!compoundString)
- {
- AppendGeneric(c, this, true);
- return;
- }
- compoundString->AppendChars(c);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::Append(JavascriptString *const s)
- {
- if(!compoundString)
- {
- AppendGeneric(s, this, false);
- return;
- }
- compoundString->Append(s);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::AppendChars(JavascriptString *const s)
- {
- if(!compoundString)
- {
- AppendGeneric(s, this, true);
- return;
- }
- compoundString->AppendChars(s);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::Append(
- JavascriptString *const s,
- const CharCount startIndex,
- const CharCount appendCharLength)
- {
- if(!compoundString)
- {
- AppendGeneric(s, startIndex, appendCharLength, this, false);
- return;
- }
- compoundString->Append(s, startIndex, appendCharLength);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::AppendChars(
- JavascriptString *const s,
- const CharCount startIndex,
- const CharCount appendCharLength)
- {
- if(!compoundString)
- {
- AppendGeneric(s, startIndex, appendCharLength, this, true);
- return;
- }
- compoundString->AppendChars(s, startIndex, appendCharLength);
- }
- template<CharCount MinimumCharCapacity>
- template<CharCount AppendCharLengthPlusOne>
- inline void CompoundString::Builder<MinimumCharCapacity>::Append(
- const char16 (&s)[AppendCharLengthPlusOne],
- const bool isCppLiteral)
- {
- if(!compoundString)
- {
- AppendGeneric(s, isCppLiteral, this, false);
- return;
- }
- compoundString->Append(s, isCppLiteral);
- }
- template<CharCount MinimumCharCapacity>
- template<CharCount AppendCharLengthPlusOne>
- inline void CompoundString::Builder<MinimumCharCapacity>::AppendChars(
- const char16 (&s)[AppendCharLengthPlusOne],
- const bool isCppLiteral)
- {
- if(!compoundString)
- {
- AppendGeneric(s, isCppLiteral, this, true);
- return;
- }
- compoundString->AppendChars(s, isCppLiteral);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::Append(
- __in_xcount(appendCharLength) const char16 *const s,
- const CharCount appendCharLength)
- {
- if(!compoundString)
- {
- AppendGeneric(s, appendCharLength, this, false);
- return;
- }
- compoundString->Append(s, appendCharLength);
- }
- template<CharCount MinimumCharCapacity>
- inline void CompoundString::Builder<MinimumCharCapacity>::AppendChars(
- __in_xcount(appendCharLength) const char16 *const s,
- const CharCount appendCharLength)
- {
- if(!compoundString)
- {
- AppendGeneric(s, appendCharLength, this, true);
- return;
- }
- compoundString->AppendChars(s, appendCharLength);
- }
- template<CharCount MinimumCharCapacity>
- template<class TValue, class FConvertToString>
- inline void CompoundString::Builder<MinimumCharCapacity>::Append(
- const TValue &value,
- const CharCount maximumAppendCharLength,
- const FConvertToString ConvertToString)
- {
- if(!compoundString)
- {
- AppendGeneric(value, maximumAppendCharLength, ConvertToString, this, false);
- return;
- }
- compoundString->Append(value, maximumAppendCharLength, ConvertToString);
- }
- template<CharCount MinimumCharCapacity>
- template<class TValue, class FConvertToString>
- inline void CompoundString::Builder<MinimumCharCapacity>::AppendChars(
- const TValue &value,
- const CharCount maximumAppendCharLength,
- const FConvertToString ConvertToString)
- {
- if(!compoundString)
- {
- AppendGeneric(value, maximumAppendCharLength, ConvertToString, this, true);
- return;
- }
- compoundString->AppendChars(value, maximumAppendCharLength, ConvertToString);
- }
- template<CharCount MinimumCharCapacity>
- CompoundString *CompoundString::Builder<MinimumCharCapacity>::CreateCompoundString(const bool reserveMoreSpace) const
- {
- return
- CompoundString::New(
- stringLength,
- directCharLength,
- buffer,
- charLength,
- reserveMoreSpace,
- this->GetLibrary());
- }
- template<CharCount MinimumCharCapacity>
- inline JavascriptString *CompoundString::Builder<MinimumCharCapacity>::ToString()
- {
- #if DBG
- // Should not append to the builder after this function is called
- isFinalized = true;
- #endif
- CompoundString *const compoundString = this->compoundString;
- if(compoundString)
- return compoundString;
- switch(stringLength)
- {
- default:
- return CreateCompoundString(false);
- case 0:
- return this->GetLibrary()->GetEmptyString();
- case 1:
- Assert(HasOnlyDirectChars());
- Assert(LastBlockCharLength() == 1);
- return this->GetLibrary()->GetCharStringCache().GetStringForChar(LastBlockChars()[0]);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #endif
- #pragma endregion
- #pragma region CompoundString template member definitions
- #ifndef CompoundStringJsDiag
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- template<class String>
- inline bool CompoundString::TryAppendGeneric(const char16 c, String *const toString)
- {
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(toString->HasOnlyDirectChars());
- const CharCount blockCharLength = toString->LastBlockCharLength();
- if(blockCharLength < toString->LastBlockCharCapacity())
- {
- toString->LastBlockChars()[blockCharLength] = c;
- toString->SetLength(toString->GetLength() + 1);
- toString->SetLastBlockCharLength(blockCharLength + 1);
- return true;
- }
- return false;
- }
- template<class String>
- inline bool CompoundString::TryAppendGeneric(
- JavascriptString *const s,
- const CharCount appendCharLength,
- String *const toString)
- {
- Assert(s);
- Assert(appendCharLength == s->GetLength());
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!toString->HasOnlyDirectChars());
- const CharCount blockPointerLength = toString->LastBlockPointerLength();
- if(blockPointerLength < toString->LastBlockPointerCapacity())
- {
- toString->LastBlockPointers()[blockPointerLength] = GetImmutableOrScriptUnreferencedString(s);
- toString->SetLength(toString->GetLength() + appendCharLength);
- toString->SetLastBlockPointerLength(blockPointerLength + 1);
- return true;
- }
- return false;
- }
- template<class String>
- inline bool CompoundString::TryAppendFewCharsGeneric(
- __in_xcount(appendCharLength) const char16 *const s,
- const CharCount appendCharLength,
- String *const toString)
- {
- Assert(s);
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(toString->HasOnlyDirectChars());
- const CharCount blockCharLength = toString->LastBlockCharLength();
- if(appendCharLength <= toString->LastBlockCharCapacity() - blockCharLength)
- {
- const char16 *appendCharBuffer = s;
- char16 *charBuffer = &toString->LastBlockChars()[blockCharLength];
- const char16 *const charBufferEnd = charBuffer + appendCharLength;
- for(; charBuffer != charBufferEnd; ++appendCharBuffer, ++charBuffer)
- *charBuffer = *appendCharBuffer;
- toString->SetLength(toString->GetLength() + appendCharLength);
- toString->SetLastBlockCharLength(blockCharLength + appendCharLength);
- return true;
- }
- return false;
- }
- template<class String>
- inline bool CompoundString::TryAppendGeneric(
- __in_xcount(appendCharLength) const char16 *const s,
- const CharCount appendCharLength,
- String *const toString)
- {
- Assert(s);
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(toString->HasOnlyDirectChars());
- const CharCount blockCharLength = toString->LastBlockCharLength();
- if(appendCharLength <= toString->LastBlockCharCapacity() - blockCharLength)
- {
- CopyHelper(&toString->LastBlockChars()[blockCharLength], s, appendCharLength);
- toString->SetLength(toString->GetLength() + appendCharLength);
- toString->SetLastBlockCharLength(blockCharLength + appendCharLength);
- return true;
- }
- return false;
- }
- template<class String>
- inline bool CompoundString::TryAppendGeneric(
- JavascriptString *const s,
- void *const packedSubstringInfo,
- void *const packedSubstringInfo2,
- const CharCount appendCharLength,
- String *const toString)
- {
- Assert(s);
- Assert(packedSubstringInfo);
- Assert(appendCharLength <= s->GetLength());
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!toString->HasOnlyDirectChars());
- const CharCount blockPointerLength = toString->LastBlockPointerLength();
- const CharCount appendPointerLength = 2 + !!packedSubstringInfo2;
- if(blockPointerLength < toString->LastBlockPointerCapacity() - (appendPointerLength - 1))
- {
- Field(void*)* pointers = toString->LastBlockPointers();
- pointers[blockPointerLength] = GetImmutableOrScriptUnreferencedString(s);
- if(packedSubstringInfo2)
- pointers[blockPointerLength + 1] = packedSubstringInfo2;
- pointers[blockPointerLength + (appendPointerLength - 1)] = packedSubstringInfo;
- toString->SetLength(toString->GetLength() + appendCharLength);
- toString->SetLastBlockPointerLength(blockPointerLength + appendPointerLength);
- return true;
- }
- return false;
- }
- template<class String>
- inline void CompoundString::AppendGeneric(const char16 c, String *const toString, const bool appendChars)
- {
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!(appendChars && !toString->HasOnlyDirectChars()));
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(_u("CompoundString::AppendGeneric('%c', appendChars = %s)\n"), c, appendChars ? _u("true") : _u("false"));
- Output::Flush();
- }
- if(appendChars || toString->HasOnlyDirectChars()
- ? TryAppendGeneric(c, toString)
- : TryAppendGeneric(toString->GetLibrary()->GetCharStringCache().GetStringForChar(c), 1, toString))
- {
- return;
- }
- toString->AppendSlow(c);
- }
- template<class String>
- inline void CompoundString::AppendGeneric(
- JavascriptString *const s,
- String *const toString,
- const bool appendChars)
- {
- Assert(s);
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!(appendChars && !toString->HasOnlyDirectChars()));
- const CharCount appendCharLength = s->GetLength();
- if(appendCharLength == 0)
- return;
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(
- _u("CompoundString::AppendGeneric(JavascriptString *s = \"%.8s%s\", appendCharLength = %u, appendChars = %s)\n"),
- s->IsFinalized() ? s->GetString() : _u(""),
- !s->IsFinalized() || appendCharLength > 8 ? _u("...") : _u(""),
- appendCharLength,
- appendChars ? _u("true") : _u("false"));
- Output::Flush();
- }
- if(appendChars || toString->HasOnlyDirectChars())
- {
- if(appendCharLength == 1)
- {
- const char16 c = toString->GetAppendStringBuffer(s)[0];
- if(TryAppendGeneric(c, toString))
- return;
- toString->AppendSlow(c);
- return;
- }
- if(appendChars || Block::ShouldAppendChars(appendCharLength))
- {
- const char16 *const appendBuffer = toString->GetAppendStringBuffer(s);
- if(appendChars
- ? TryAppendGeneric(appendBuffer, appendCharLength, toString)
- : TryAppendFewCharsGeneric(appendBuffer, appendCharLength, toString))
- {
- return;
- }
- toString->AppendSlow(appendBuffer, appendCharLength);
- return;
- }
- toString->SwitchToPointerMode();
- }
- if(TryAppendGeneric(s, appendCharLength, toString))
- return;
- toString->AppendSlow(s);
- }
- template<class String>
- inline void CompoundString::AppendGeneric(
- JavascriptString *const s,
- const CharCount startIndex,
- const CharCount appendCharLength,
- String *const toString,
- const bool appendChars)
- {
- Assert(s);
- Assert(startIndex <= s->GetLength());
- Assert(appendCharLength <= s->GetLength() - startIndex);
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!(appendChars && !toString->HasOnlyDirectChars()));
- if(appendCharLength == 0)
- return;
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(
- _u("CompoundString::AppendGeneric(JavascriptString *s = \"%.*s%s\", startIndex = %u, appendCharLength = %u, appendChars = %s)\n"),
- min(static_cast<CharCount>(8), appendCharLength),
- s->IsFinalized() ? &s->GetString()[startIndex] : _u(""),
- !s->IsFinalized() || appendCharLength > 8 ? _u("...") : _u(""),
- startIndex,
- appendCharLength,
- appendChars ? _u("true") : _u("false"));
- Output::Flush();
- }
- if(appendChars || toString->HasOnlyDirectChars())
- {
- if(appendCharLength == 1)
- {
- const char16 c = toString->GetAppendStringBuffer(s)[startIndex];
- if(TryAppendGeneric(c, toString))
- return;
- toString->AppendSlow(c);
- return;
- }
- if(appendChars || Block::ShouldAppendChars(appendCharLength, sizeof(void *)))
- {
- const char16 *const appendBuffer = &toString->GetAppendStringBuffer(s)[startIndex];
- if(appendChars
- ? TryAppendGeneric(appendBuffer, appendCharLength, toString)
- : TryAppendFewCharsGeneric(appendBuffer, appendCharLength, toString))
- {
- return;
- }
- toString->AppendSlow(appendBuffer, appendCharLength);
- return;
- }
- toString->SwitchToPointerMode();
- }
- if(appendCharLength == 1)
- {
- JavascriptString *const js =
- toString->GetLibrary()->GetCharStringCache().GetStringForChar(toString->GetAppendStringBuffer(s)[startIndex]);
- if(TryAppendGeneric(js, 1, toString))
- return;
- toString->AppendSlow(js);
- return;
- }
- void *packedSubstringInfo, *packedSubstringInfo2;
- PackSubstringInfo(startIndex, appendCharLength, &packedSubstringInfo, &packedSubstringInfo2);
- if(TryAppendGeneric(s, packedSubstringInfo, packedSubstringInfo2, appendCharLength, toString))
- return;
- toString->AppendSlow(s, packedSubstringInfo, packedSubstringInfo2, appendCharLength);
- }
- template<CharCount AppendCharLengthPlusOne, class String>
- inline void CompoundString::AppendGeneric(
- const char16 (&s)[AppendCharLengthPlusOne],
- const bool isCppLiteral,
- String *const toString,
- const bool appendChars)
- {
- CompileAssert(AppendCharLengthPlusOne != 0);
- Assert(s);
- Assert(s[AppendCharLengthPlusOne - 1] == _u('\0'));
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!(appendChars && !toString->HasOnlyDirectChars()));
- if(AppendCharLengthPlusOne == 1)
- return;
- if(AppendCharLengthPlusOne == 2)
- {
- AppendGeneric(s[0], toString, appendChars);
- return;
- }
- const CharCount appendCharLength = AppendCharLengthPlusOne - 1;
- if(!isCppLiteral)
- {
- AppendGeneric(s, appendCharLength, toString, appendChars);
- return;
- }
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(
- _u("CompoundString::AppendGeneric(C++ literal \"%.8s%s\", appendCharLength = %u, appendChars = %s)\n"),
- s,
- appendCharLength > 8 ? _u("...") : _u(""),
- appendCharLength,
- appendChars ? _u("true") : _u("false"));
- Output::Flush();
- }
- if(appendChars || toString->HasOnlyDirectChars())
- {
- if(appendChars || Block::ShouldAppendChars(appendCharLength, sizeof(LiteralString)))
- {
- if(appendChars
- ? TryAppendGeneric(s, appendCharLength, toString)
- : TryAppendFewCharsGeneric(s, appendCharLength, toString))
- {
- return;
- }
- toString->AppendSlow(s, appendCharLength);
- return;
- }
- toString->SwitchToPointerMode();
- }
- JavascriptString *const js = toString->GetLibrary()->CreateStringFromCppLiteral(s);
- if(TryAppendGeneric(js, appendCharLength, toString))
- return;
- toString->AppendSlow(js);
- }
- template<class String>
- inline void CompoundString::AppendGeneric(
- __in_xcount(appendCharLength) const char16 *const s,
- const CharCount appendCharLength,
- String *const toString,
- const bool appendChars)
- {
- Assert(s);
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!(appendChars && !toString->HasOnlyDirectChars()));
- if(appendCharLength == 0)
- return;
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(
- _u("CompoundString::AppendGeneric(char16 *s = \"%.8s%s\", appendCharLength = %u, appendChars = %s)\n"),
- s,
- appendCharLength > 8 ? _u("...") : _u(""),
- appendCharLength,
- appendChars ? _u("true") : _u("false"));
- Output::Flush();
- }
- if(appendChars || toString->HasOnlyDirectChars())
- {
- if(appendCharLength == 1)
- {
- const char16 c = s[0];
- if(TryAppendGeneric(c, toString))
- return;
- toString->AppendSlow(c);
- return;
- }
- // Skip the check for Block::ShouldAppendChars because the string buffer has to be copied anyway
- if(TryAppendGeneric(s, appendCharLength, toString))
- return;
- toString->AppendSlow(s, appendCharLength);
- return;
- }
- JavascriptString *const js = JavascriptString::NewCopyBuffer(s, appendCharLength, toString->GetScriptContext());
- if(TryAppendGeneric(js, appendCharLength, toString))
- return;
- toString->AppendSlow(js);
- }
- template<class TValue, class FConvertToString, class String>
- inline void CompoundString::AppendGeneric(
- const TValue &value,
- CharCount maximumAppendCharLength,
- const FConvertToString ConvertToString,
- String *const toString,
- const bool appendChars)
- {
- const CharCount AbsoluteMaximumAppendCharLength = 20; // maximum length of uint64 converted to base-10 string
- Assert(maximumAppendCharLength != 0);
- Assert(maximumAppendCharLength <= AbsoluteMaximumAppendCharLength);
- Assert(toString);
- Assert(!toString->IsFinalized());
- Assert(toString->OwnsLastBlock());
- Assert(!(appendChars && !toString->HasOnlyDirectChars()));
- ++maximumAppendCharLength; // + 1 for null terminator
- const CharCount blockCharLength = toString->LastBlockCharLength();
- const bool convertInPlace =
- (appendChars || toString->HasOnlyDirectChars()) &&
- maximumAppendCharLength <= toString->LastBlockCharCapacity() - blockCharLength;
- char16 localConvertBuffer[AbsoluteMaximumAppendCharLength + 1]; // + 1 for null terminator
- char16 *const convertBuffer = convertInPlace ? &toString->LastBlockChars()[blockCharLength] : localConvertBuffer;
- ConvertToString(value, convertBuffer, maximumAppendCharLength);
- const CharCount appendCharLength = static_cast<CharCount>(wcslen(convertBuffer));
- if(PHASE_TRACE_StringConcat)
- {
- Output::Print(
- _u("CompoundString::AppendGeneric(TValue &, appendChars = %s) - converted = \"%.8s%s\", appendCharLength = %u\n"),
- appendChars ? _u("true") : _u("false"),
- convertBuffer,
- appendCharLength > 8 ? _u("...") : _u(""),
- appendCharLength);
- Output::Flush();
- }
- if(convertInPlace)
- {
- toString->SetLength(toString->GetLength() + appendCharLength);
- toString->SetLastBlockCharLength(blockCharLength + appendCharLength);
- return;
- }
- AnalysisAssert(convertBuffer == localConvertBuffer);
- AppendGeneric(static_cast<const char16* const>(localConvertBuffer), appendCharLength, toString, appendChars);
- }
- template<CharCount AppendCharLengthPlusOne>
- inline void CompoundString::Append(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral)
- {
- AppendGeneric(s, isCppLiteral, this, false);
- }
- template<CharCount AppendCharLengthPlusOne>
- inline void CompoundString::AppendChars(const char16 (&s)[AppendCharLengthPlusOne], const bool isCppLiteral)
- {
- AppendGeneric(s, isCppLiteral, this, true);
- }
- template<class TValue, class FConvertToString>
- inline void CompoundString::Append(
- const TValue &value,
- const CharCount maximumAppendCharLength,
- const FConvertToString ConvertToString)
- {
- AppendGeneric(value, maximumAppendCharLength, ConvertToString, this, false);
- }
- template<class TValue, class FConvertToString>
- inline void CompoundString::AppendChars(
- const TValue &value,
- const CharCount maximumAppendCharLength,
- const FConvertToString ConvertToString)
- {
- AppendGeneric(value, maximumAppendCharLength, ConvertToString, this, true);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #endif
- #pragma endregion
- }
|