| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- //-------------------------------------------------------------------------------------------------------
- // 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
- {
- class LiteralStringWithPropertyStringPtr : public LiteralString
- {
- private:
- Field(PropertyString*) propertyString;
- Field(const Js::PropertyRecord*) propertyRecord;
- public:
- virtual Js::PropertyRecord const * GetPropertyRecord(bool dontLookupFromDictionary = false) override;
- PropertyString * GetPropertyString() const;
- PropertyString * GetOrAddPropertyString(); // Get if it's there, otherwise bring it in.
- void SetPropertyString(PropertyString * propStr);
- template <typename StringType> static LiteralStringWithPropertyStringPtr * ConvertString(StringType * originalString);
- static uint GetOffsetOfPropertyString() { return offsetof(LiteralStringWithPropertyStringPtr, propertyString); }
- static bool Is(Var var);
- static bool Is(RecyclableObject* var);
- template <typename T> static LiteralStringWithPropertyStringPtr* TryFromVar(T var);
- static JavascriptString *
- NewFromCString(const char * cString, const CharCount charCount, JavascriptLibrary *const library);
- static JavascriptString *
- NewFromWideString(const char16 * wString, const CharCount charCount, JavascriptLibrary *const library);
- static JavascriptString * CreateEmptyString(JavascriptLibrary *const library);
- protected:
- LiteralStringWithPropertyStringPtr(StaticType* stringTypeStatic);
- LiteralStringWithPropertyStringPtr(const char16 * wString, const CharCount stringLength, JavascriptLibrary *const library);
- DEFINE_VTABLE_CTOR(LiteralStringWithPropertyStringPtr, LiteralString);
- public:
- virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
- {
- return VTableValue::VtableLiteralStringWithPropertyStringPtr;
- }
- };
- // Templated so that the Is call dispatchs to different function depending
- // on if argument is already a RecyclableObject* or only known to be a Var
- //
- // In case it is known to be a RecyclableObject*, the Is call skips that check
- template <typename T>
- inline LiteralStringWithPropertyStringPtr * LiteralStringWithPropertyStringPtr::TryFromVar(T var)
- {
- return LiteralStringWithPropertyStringPtr::Is(var)
- ? reinterpret_cast<LiteralStringWithPropertyStringPtr*>(var)
- : nullptr;
- }
- // Base class for concat strings.
- // Concat string is a virtual string, or a non-leaf node in concat string tree.
- // It does not hold characters by itself but has one or more child nodes.
- // Only leaf nodes (which are not concat strings) hold the actual characters.
- // The flattening happens on demand (call GetString() or GetSz()),
- // until then we don't create actual big char16* buffer, just keep concat tree as a tree.
- // The result of flattening the concat string tree is concat of all leaf nodes from left to right.
- // Usage pattern:
- // // Create concat tree using one of non-abstract derived classes.
- // JavascriptString* result = concatTree->GetString(); // At this time we flatten the tree into 1 actual wchat_t* string.
- class ConcatStringBase _ABSTRACT : public LiteralString // vtable will be switched to LiteralString's vtable after flattening
- {
- friend JavascriptString;
- protected:
- ConcatStringBase(StaticType* stringTypeStatic);
- DEFINE_VTABLE_CTOR_ABSTRACT(ConcatStringBase, LiteralString);
- virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer,
- StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) = 0;
- void CopyImpl(_Out_writes_(m_charLength) char16 *const buffer,
- int itemCount, _In_reads_(itemCount) JavascriptString * const * items,
- StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth);
- // Subclass can call this to implement GetSz and use the actual type to avoid virtual call to Copy.
- template <typename ConcatStringType> const char16 * GetSzImpl();
- public:
- virtual const char16* GetSz() = 0; // Force subclass to call GetSzImpl with the real type to avoid virtual calls
- using JavascriptString::Copy;
- virtual bool IsTree() const override sealed;
- };
- // Concat string with N (or less) child nodes.
- // Use it when you know the number of children at compile time.
- // There could be less nodes than N. When we find 1st NULL node going incrementing the index,
- // we see this as indication that the rest on the right are empty and stop iterating.
- // Usage pattern:
- // ConcatStringN<3>* tree = ConcatStringN<3>::New(scriptContext);
- // tree->SetItem(0, javascriptString1);
- // tree->SetItem(1, javascriptString2);
- // tree->SetItem(2, javascriptString3);
- template <int N>
- class ConcatStringN : public ConcatStringBase
- {
- friend JavascriptString;
- protected:
- ConcatStringN(StaticType* stringTypeStatic, bool doZeroSlotsAndLength = true);
- DEFINE_VTABLE_CTOR(ConcatStringN<N>, ConcatStringBase);
- virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override
- {
- __super::CopyImpl(buffer, N, AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
- }
- virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const
- {
- items = AddressOf(m_slots[0]);
- return N;
- }
- public:
- static ConcatStringN<N>* New(ScriptContext* scriptContext);
- const char16 * GetSz() override sealed;
- void SetItem(_In_range_(0, N - 1) int index, JavascriptString* value);
- protected:
- Field(JavascriptString*) m_slots[N]; // These contain the child nodes. 1 slot is per 1 item (JavascriptString*).
- };
- // Concat string that uses binary tree, each node has 2 children.
- // Usage pattern:
- // ConcatString* str = ConcatString::New(javascriptString1, javascriptString2);
- // Note: it's preferred you would use the following for concats, that would figure out whether concat string is optimal or create a new string is better.
- // JavascriptString::Concat(javascriptString1, javascriptString2);
- class ConcatString sealed : public ConcatStringN<2>
- {
- ConcatString(JavascriptString* a, JavascriptString* b);
- protected:
- DEFINE_VTABLE_CTOR(ConcatString, ConcatStringN<2>);
- public:
- static ConcatString* New(JavascriptString* a, JavascriptString* b);
- static const int MaxDepth = 1000;
- JavascriptString *LeftString() const { Assert(!IsFinalized()); return m_slots[0]; }
- JavascriptString *RightString() const { Assert(!IsFinalized()); return m_slots[1]; }
- };
- // Concat string with any number of child nodes, can grow dynamically.
- // Usage pattern:
- // ConcatStringBuilder* tree = ConcatStringBuider::New(scriptContext, 5);
- // tree->Append(javascriptString1);
- // tree->Append(javascriptString2);
- // ...
- // Implementation details:
- // - uses chunks, max chunk size is specified by c_maxChunkSlotCount, until we fit into that, we realloc, otherwise create new chunk.
- // - We use chunks in order to avoid big allocations, we don't expect lots of reallocs, that why chunk size is relatively big.
- // - the chunks are linked using m_prevChunk field. flattening happens from left to right, i.e. first we need to get
- // head chunk -- the one that has m_prevChunk == NULL.
- class ConcatStringBuilder sealed : public ConcatStringBase
- {
- friend JavascriptString;
- ConcatStringBuilder(ScriptContext* scriptContext, int initialSlotCount);
- ConcatStringBuilder(const ConcatStringBuilder& other);
- void AllocateSlots(int requestedSlotCount);
- ConcatStringBuilder* GetHead() const;
- protected:
- DEFINE_VTABLE_CTOR(ConcatStringBuilder, ConcatStringBase);
- virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override sealed;
- public:
- static ConcatStringBuilder* New(ScriptContext* scriptContext, int initialSlotCount);
- const char16 * GetSz() override sealed;
- void Append(JavascriptString* str);
- private:
- // MAX number of slots in one chunk. Until we fit into this, we realloc, otherwise create new chunk.
- static const int c_maxChunkSlotCount = 1024;
- int GetItemCount() const;
- Field(Field(JavascriptString*)*) m_slots; // Array of child nodes.
- Field(int) m_slotCount; // Number of allocated slots (1 slot holds 1 item) in this chunk.
- Field(int) m_count; // Actual number of items in this chunk.
- Field(ConcatStringBuilder*) m_prevChunk;
- };
- // Concat string that wraps another string.
- // Use it when you need to wrap something with e.g. { and }.
- // Usage pattern:
- // result = ConcatStringWrapping<_u('{'), _u('}')>::New(result);
- template <char16 L, char16 R>
- class ConcatStringWrapping sealed : public ConcatStringBase
- {
- friend JavascriptString;
- ConcatStringWrapping(JavascriptString* inner);
- JavascriptString* GetFirstItem() const;
- JavascriptString* GetLastItem() const;
- protected:
- DEFINE_VTABLE_CTOR(ConcatStringWrapping, ConcatStringBase);
- virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override sealed
- {
- const_cast<ConcatStringWrapping *>(this)->EnsureAllSlots();
- __super::CopyImpl(buffer, _countof(m_slots), AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
- }
- virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const override sealed
- {
- const_cast<ConcatStringWrapping *>(this)->EnsureAllSlots();
- items = AddressOf(m_slots[0]);
- return _countof(m_slots);
- }
- public:
- static ConcatStringWrapping<L, R>* New(JavascriptString* inner);
- const char16 * GetSz() override sealed;
- private:
- void EnsureAllSlots()
- {
- m_slots[0] = this->GetFirstItem();
- m_slots[1] = m_inner;
- m_slots[2] = this->GetLastItem();
- }
- Field(JavascriptString *) m_inner;
- // Use the padding space for the concat
- Field(JavascriptString *) m_slots[3];
- };
- // Make sure the padding doesn't add tot he size of ConcatStringWrapping
- #if defined(TARGET_64)
- CompileAssert(sizeof(ConcatStringWrapping<_u('"'), _u('"')>) == 64);
- #else
- CompileAssert(sizeof(ConcatStringWrapping<_u('"'), _u('"')>) == 32);
- #endif
- // Concat string with N child nodes. Use it when you don't know the number of children at compile time.
- // Usage pattern:
- // ConcatStringMulti* tree = ConcatStringMulti::New(3, scriptContext);
- // tree->SetItem(0, javascriptString1);
- // tree->SetItem(1, javascriptString2);
- // tree->SetItem(2, javascriptString3);
- class ConcatStringMulti sealed : public ConcatStringBase
- {
- friend JavascriptString;
- protected:
- ConcatStringMulti(uint slotCount, JavascriptString * a1, JavascriptString * a2, StaticType* stringTypeStatic);
- DEFINE_VTABLE_CTOR(ConcatStringMulti, ConcatStringBase);
- virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override
- {
- Assert(IsFilled());
- __super::CopyImpl(buffer, slotCount, AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
- }
- virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const
- {
- Assert(IsFilled());
- items = AddressOf(m_slots[0]);
- return slotCount;
- }
- public:
- static ConcatStringMulti * New(uint slotCount, JavascriptString * a1, JavascriptString * a2, ScriptContext* scriptContext);
- const char16 * GetSz() override sealed;
- static bool Is(Var var);
- static ConcatStringMulti * FromVar(Var value);
- static ConcatStringMulti * UnsafeFromVar(Var value);
- static size_t GetAllocSize(uint slotCount);
- void SetItem(_In_range_(0, slotCount - 1) uint index, JavascriptString* value);
- static uint32 GetOffsetOfSlotCount() { return offsetof(ConcatStringMulti, slotCount); }
- static uint32 GetOffsetOfSlots() { return offsetof(ConcatStringMulti, m_slots); }
- protected:
- Field(uint) slotCount;
- Field(uint) __alignment;
- Field(size_t) __alignmentPTR;
- Field(JavascriptString*) m_slots[]; // These contain the child nodes.
- #if DBG
- bool IsFilled() const;
- #endif
- public:
- virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
- {
- return VTableValue::VtableConcatStringMulti;
- }
- };
- }
|