diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-08-10 11:37:26 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-10 11:37:26 -0400 |
| commit | fcdb4629c4c3dd2931eaa88b96b668d914c4519c (patch) | |
| tree | c54c0b9c6411f9be55b9a2816e528b91d6032703 | |
| parent | 1378fffd9da094beb41b2db89b96f556c23ab6cb (diff) | |
Yet more refactoring around Artifact (#2352)
* #include an absolute path didn't work - because paths were taken to always be relative.
* WIP with hierarchical enums.
* Some small fixes and improvements around artifact desc related types.
* Improvements around hierarchical enum.
* Fixes to get Artifact types refactor to be able to execute tests.
* Attempt to better categorize PTX.
* Work around for potentially unused function warning.
* Typo fix.
* Simplify Artifact header.
* Small improvements around Artifact kind/payload/style.
* Added IDestroyable/ICastable
* Add IArtifactList.
* First impl of IArtifactUtil.
* Use the ICastable interface for IArtifactRepresentation.
* Added IArtifactRepresentation & IArtifactAssociated.
* Add SLANG_OVERRIDE to avoid gcc/clang warning.
* Fix calling convention issue on win32.
* Fix missing SLANG_OVERRIDE.
* First attempt at file abstraction around Artifact.
* Added creation of lock file.
* Move functionality for determining file paths to the IArtifactUtil.
Add casting to ICastable.
* Added some casting/finding mechanisms.
* Simplify IArtifact interface, and use Items for file reps.
* Fix problem with libraries on DXIL.
* Split out ArtifactRepresentation.
* Move ArtifactDesc functionality to ArtifactDescUtil. ArtifactInfoUtil becomes ArtifactDescUtil.
* Split implementations from the interfaces for Artifact.
* Use TypeTextUtil for target name outputting.
* Add artifact impls.
* Add ICastableList
* Added UnknownCastableAdapter
* Make ISlangSharedLibrary derive from ICastable, and remain backwards compatible with slang-llvm.
* Refactor Representation on Artifact.
* Make our ISlangBlobs also derive from ICastable.
Make ISlangBlob atomic ref counted.
* Split out CastableList and related types, and placed in core.
* Small fixes around IArtifact.
Improve IArtifact docs.
First impl of getChildren for IArtifact.
* Documentation improvements for Artifact related types.
* Fix typo.
* Special case adding a ICastableList to a LazyCastableList.
* Small simplification of LazyCastableList, by adding State member.
* Removed the ILockFile interface because IFileArtifactRepresentation can be used.
19 files changed, 712 insertions, 644 deletions
diff --git a/build/visual-studio/core/core.vcxproj b/build/visual-studio/core/core.vcxproj index c4a28f94b..13e933326 100644 --- a/build/visual-studio/core/core.vcxproj +++ b/build/visual-studio/core/core.vcxproj @@ -281,6 +281,8 @@ <ClInclude Include="..\..\..\source\core\slang-basic.h" /> <ClInclude Include="..\..\..\source\core\slang-blob.h" /> <ClInclude Include="..\..\..\source\core\slang-byte-encode-util.h" /> + <ClInclude Include="..\..\..\source\core\slang-castable-list-impl.h" /> + <ClInclude Include="..\..\..\source\core\slang-castable-list.h" /> <ClInclude Include="..\..\..\source\core\slang-char-encode.h" /> <ClInclude Include="..\..\..\source\core\slang-char-util.h" /> <ClInclude Include="..\..\..\source\core\slang-chunked-list.h" /> @@ -299,6 +301,7 @@ <ClInclude Include="..\..\..\source\core\slang-hex-dump-util.h" /> <ClInclude Include="..\..\..\source\core\slang-http.h" /> <ClInclude Include="..\..\..\source\core\slang-io.h" /> + <ClInclude Include="..\..\..\source\core\slang-lazy-castable-list.h" /> <ClInclude Include="..\..\..\source\core\slang-linked-list.h" /> <ClInclude Include="..\..\..\source\core\slang-list.h" /> <ClInclude Include="..\..\..\source\core\slang-lz4-compression-system.h" /> @@ -342,6 +345,7 @@ <ClCompile Include="..\..\..\source\core\slang-archive-file-system.cpp" /> <ClCompile Include="..\..\..\source\core\slang-blob.cpp" /> <ClCompile Include="..\..\..\source\core\slang-byte-encode-util.cpp" /> + <ClCompile Include="..\..\..\source\core\slang-castable-list-impl.cpp" /> <ClCompile Include="..\..\..\source\core\slang-char-encode.cpp" /> <ClCompile Include="..\..\..\source\core\slang-char-util.cpp" /> <ClCompile Include="..\..\..\source\core\slang-command-line.cpp" /> @@ -351,6 +355,7 @@ <ClCompile Include="..\..\..\source\core\slang-hex-dump-util.cpp" /> <ClCompile Include="..\..\..\source\core\slang-http.cpp" /> <ClCompile Include="..\..\..\source\core\slang-io.cpp" /> + <ClCompile Include="..\..\..\source\core\slang-lazy-castable-list.cpp" /> <ClCompile Include="..\..\..\source\core\slang-lz4-compression-system.cpp" /> <ClCompile Include="..\..\..\source\core\slang-memory-arena.cpp" /> <ClCompile Include="..\..\..\source\core\slang-offset-container.cpp" /> diff --git a/build/visual-studio/core/core.vcxproj.filters b/build/visual-studio/core/core.vcxproj.filters index 91a852b8e..3d394caa8 100644 --- a/build/visual-studio/core/core.vcxproj.filters +++ b/build/visual-studio/core/core.vcxproj.filters @@ -30,6 +30,12 @@ <ClInclude Include="..\..\..\source\core\slang-byte-encode-util.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-castable-list-impl.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-castable-list.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\source\core\slang-char-encode.h"> <Filter>Header Files</Filter> </ClInclude> @@ -84,6 +90,9 @@ <ClInclude Include="..\..\..\source\core\slang-io.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-lazy-castable-list.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\source\core\slang-linked-list.h"> <Filter>Header Files</Filter> </ClInclude> @@ -209,6 +218,9 @@ <ClCompile Include="..\..\..\source\core\slang-byte-encode-util.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\core\slang-castable-list-impl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\source\core\slang-char-encode.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -236,6 +248,9 @@ <ClCompile Include="..\..\..\source\core\slang-io.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\core\slang-lazy-castable-list.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\source\core\slang-lz4-compression-system.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/build/visual-studio/slang-rt/slang-rt.vcxproj b/build/visual-studio/slang-rt/slang-rt.vcxproj index 723f5360e..1c1190be2 100644 --- a/build/visual-studio/slang-rt/slang-rt.vcxproj +++ b/build/visual-studio/slang-rt/slang-rt.vcxproj @@ -281,6 +281,8 @@ <ClInclude Include="..\..\..\source\core\slang-basic.h" /> <ClInclude Include="..\..\..\source\core\slang-blob.h" /> <ClInclude Include="..\..\..\source\core\slang-byte-encode-util.h" /> + <ClInclude Include="..\..\..\source\core\slang-castable-list-impl.h" /> + <ClInclude Include="..\..\..\source\core\slang-castable-list.h" /> <ClInclude Include="..\..\..\source\core\slang-char-encode.h" /> <ClInclude Include="..\..\..\source\core\slang-char-util.h" /> <ClInclude Include="..\..\..\source\core\slang-chunked-list.h" /> @@ -299,6 +301,7 @@ <ClInclude Include="..\..\..\source\core\slang-hex-dump-util.h" /> <ClInclude Include="..\..\..\source\core\slang-http.h" /> <ClInclude Include="..\..\..\source\core\slang-io.h" /> + <ClInclude Include="..\..\..\source\core\slang-lazy-castable-list.h" /> <ClInclude Include="..\..\..\source\core\slang-linked-list.h" /> <ClInclude Include="..\..\..\source\core\slang-list.h" /> <ClInclude Include="..\..\..\source\core\slang-lz4-compression-system.h" /> @@ -343,6 +346,7 @@ <ClCompile Include="..\..\..\source\core\slang-archive-file-system.cpp" /> <ClCompile Include="..\..\..\source\core\slang-blob.cpp" /> <ClCompile Include="..\..\..\source\core\slang-byte-encode-util.cpp" /> + <ClCompile Include="..\..\..\source\core\slang-castable-list-impl.cpp" /> <ClCompile Include="..\..\..\source\core\slang-char-encode.cpp" /> <ClCompile Include="..\..\..\source\core\slang-char-util.cpp" /> <ClCompile Include="..\..\..\source\core\slang-command-line.cpp" /> @@ -352,6 +356,7 @@ <ClCompile Include="..\..\..\source\core\slang-hex-dump-util.cpp" /> <ClCompile Include="..\..\..\source\core\slang-http.cpp" /> <ClCompile Include="..\..\..\source\core\slang-io.cpp" /> + <ClCompile Include="..\..\..\source\core\slang-lazy-castable-list.cpp" /> <ClCompile Include="..\..\..\source\core\slang-lz4-compression-system.cpp" /> <ClCompile Include="..\..\..\source\core\slang-memory-arena.cpp" /> <ClCompile Include="..\..\..\source\core\slang-offset-container.cpp" /> diff --git a/build/visual-studio/slang-rt/slang-rt.vcxproj.filters b/build/visual-studio/slang-rt/slang-rt.vcxproj.filters index 68fc24316..65952c3e7 100644 --- a/build/visual-studio/slang-rt/slang-rt.vcxproj.filters +++ b/build/visual-studio/slang-rt/slang-rt.vcxproj.filters @@ -30,6 +30,12 @@ <ClInclude Include="..\..\..\source\core\slang-byte-encode-util.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-castable-list-impl.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-castable-list.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\source\core\slang-char-encode.h"> <Filter>Header Files</Filter> </ClInclude> @@ -84,6 +90,9 @@ <ClInclude Include="..\..\..\source\core\slang-io.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-lazy-castable-list.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\source\core\slang-linked-list.h"> <Filter>Header Files</Filter> </ClInclude> @@ -212,6 +221,9 @@ <ClCompile Include="..\..\..\source\core\slang-byte-encode-util.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\core\slang-castable-list-impl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\source\core\slang-char-encode.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -239,6 +251,9 @@ <ClCompile Include="..\..\..\source\core\slang-io.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\core\slang-lazy-castable-list.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\source\core\slang-lz4-compression-system.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index 413858c32..69a9b66f1 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -651,9 +651,9 @@ UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& des Index pos = Path::findLastSeparatorIndex(basePath); if (pos >= 0) { - outPath.append(basePath.head(pos)); - outPath.append(Path::kPathDelimiter); - + // Keep the stem including the delimiter + outPath.append(basePath.head(pos + 1)); + // Get the baseName baseName = basePath.tail(pos + 1); } diff --git a/source/compiler-core/slang-artifact-impl.cpp b/source/compiler-core/slang-artifact-impl.cpp index d57edd2c8..73927db96 100644 --- a/source/compiler-core/slang-artifact-impl.cpp +++ b/source/compiler-core/slang-artifact-impl.cpp @@ -5,368 +5,9 @@ #include "slang-artifact-util.h" -namespace Slang { - -/* -If we use LazyCastableList for Items, it means we'll have to use the -UnknownCastableAdapter for ISharedLibrary, IBlob etc. - -That means when we look for an item in the list, we will always do a query interface on those types, -although it will always fail (so no atomic ref count). - -That doesn't seem wholey unreasonable. - -Note that we *can* derive from ICastable for *our* implementations of ISlangBlob, ISharedLibrary. So the -kludge is only needed for types that really do require adaption. For Blob we'll require multiple interface inheritance. -*/ - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LazyCastableList !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void LazyCastableList::removeAt(Index index) -{ - SLANG_ASSERT(index >= 0 && index < getCount()); - - if (auto list = as<ICastableList>(m_castable)) - { - list->removeAt(index); - } - else - { - SLANG_ASSERT(index == 0); - m_castable.setNull(); - } -} - -void LazyCastableList::clear() -{ - if (m_castable) - { - if (auto list = as<ICastableList>(m_castable)) - { - list->clear(); - } - else - { - m_castable.setNull(); - } - } -} - -void LazyCastableList::clearAndDeallocate() -{ - m_castable.setNull(); -} +#include "../core/slang-castable-list-impl.h" -Count LazyCastableList::getCount() const -{ - if (m_castable) - { - if (auto list = as<ICastableList>(m_castable)) - { - return list->getCount(); - } - return 1; - } - return 0; -} - -void LazyCastableList::add(ICastable* castable) -{ - SLANG_ASSERT(castable); - SLANG_ASSERT(castable != m_castable); - - if (m_castable) - { - if (auto list = as<ICastableList>(m_castable)) - { - // Shouldn't be in the list - SLANG_ASSERT(list->indexOf(castable) < 0); - list->add(castable); - } - else - { - list = new CastableList; - list->add(m_castable); - m_castable = list; - list->add(castable); - } - } - else - { - m_castable = castable; - } -} - -ICastableList* LazyCastableList::requireList() -{ - if (m_castable) - { - if (auto list = as<ICastableList>(m_castable)) - { - return list; - } - else - { - // Promote to a list with the element in it - list = new CastableList; - list->add(m_castable); - m_castable = list; - return list; - } - } - else - { - // Create an empty list - ICastableList* list = new CastableList; - m_castable = list; - return list; - } -} - -ICastableList* LazyCastableList::getList() -{ - return (m_castable == nullptr) ? nullptr : requireList(); -} - -void* LazyCastableList::find(const Guid& guid) -{ - if (!m_castable) - { - return nullptr; - } - if (auto list = as<ICastableList>(m_castable)) - { - return list->find(guid); - } - else - { - return m_castable->castAs(guid); - } -} - -ConstArrayView<ICastable*> LazyCastableList::getView() const -{ - if (!m_castable) - { - // Empty - return ConstArrayView<ICastable*>(); - } - - if (auto list = as<ICastableList>(m_castable)) - { - const auto count = list->getCount(); - const auto buffer = list->getBuffer(); - - return ConstArrayView<ICastable*>(buffer, count); - } - else - { - return ConstArrayView<ICastable*>((ICastable*const*)&m_castable, 1); - } -} - -Index LazyCastableList::indexOf(ICastable* castable) const -{ - return getView().indexOf(castable); -} - -Index LazyCastableList::indexOfUnknown(ISlangUnknown* unk) const -{ - { - ComPtr<ICastable> castable; - if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) - { - return indexOf(castable); - } - } - - // It's not derived from ICastable, so can only be in list via an adapter - const auto view = getView(); - - const Count count = view.getCount(); - for (Index i = 0; i < count; ++i) - { - auto adapter = as<IUnknownCastableAdapter>(view[i]); - if (adapter && adapter->getContained() == unk) - { - return i; - } - } - - return -1; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnknownCastableAdapter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* UnknownCastableAdapter::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - if (auto obj = getObject(guid)) - { - return obj; - } - - if (m_found && guid == m_foundGuid) - { - return m_found; - } - - ComPtr<ISlangUnknown> cast; - if (SLANG_SUCCEEDED(m_contained->queryInterface(guid, (void**)cast.writeRef())) && cast) - { - // Save the interface in the cache - m_found = cast; - m_foundGuid = guid; - - return cast; - } - return nullptr; -} - -void* UnknownCastableAdapter::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid()) - { - return static_cast<ICastable*>(this); - } - return nullptr; -} - -void* UnknownCastableAdapter::getObject(const Guid& guid) -{ - SLANG_UNUSED(guid); - return nullptr; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CastableList !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -CastableList::~CastableList() -{ - for (auto castable : m_list) - { - castable->release(); - } -} - -void* CastableList::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - return getObject(guid); -} - -void* CastableList::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == ICastableList::getTypeGuid()) - { - return static_cast<ICastableList*>(this); - } - return nullptr; -} - -void* CastableList::getObject(const Guid& guid) -{ - SLANG_UNUSED(guid); - return nullptr; -} - -void* CastableList::find(const Guid& guid) -{ - for (ICastable* castable : m_list) - { - if (auto ptr = castable->castAs(guid)) - { - return ptr; - } - } - return nullptr; -} - -Index CastableList::indexOf(ICastable* castable) -{ - const Count count = m_list.getCount(); - for (Index i = 0; i < count; ++i) - { - ICastable* cur = m_list[i]; - if (cur == castable) - { - return i; - } - } - return -1; -} - -void CastableList::add(ICastable* castable) -{ - SLANG_ASSERT(castable); - castable->addRef(); - m_list.add(castable); -} - -void CastableList::removeAt(Index i) -{ - auto castable = m_list[i]; - m_list.removeAt(i); - castable->release(); -} - -void CastableList::clear() -{ - for (auto castable : m_list) - { - castable->release(); - } - m_list.clear(); -} - -void CastableList::addUnknown(ISlangUnknown* unk) -{ - // If it has ICastable interface we can just add as that - { - ComPtr<ICastable> castable; - if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) - { - return add(castable); - } - } - - // Wrap it in an adapter - IUnknownCastableAdapter* adapter = new UnknownCastableAdapter(unk); - add(adapter); -} - -Index CastableList::indexOfUnknown(ISlangUnknown* unk) -{ - SLANG_ASSERT(unk); - // If it has a castable interface we can just look for that - { - ComPtr<ICastable> castable; - if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) - { - return indexOf(castable); - } - } - - // It's not derived from ICastable, so can only be in list via an adapter - const Count count = m_list.getCount(); - for (Index i = 0; i < count; ++i) - { - auto adapter = as<IUnknownCastableAdapter>(m_list[i]); - if (adapter && adapter->getContained() == unk) - { - return i; - } - } - return -1; -} +namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactList !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -535,15 +176,15 @@ ICastableList* Artifact::getAssociated() return m_associated.requireList(); } -void Artifact::addRepresentation(IArtifactRepresentation* rep) +void Artifact::addRepresentation(ICastable* castable) { - SLANG_ASSERT(rep); - if (m_representations.indexOf(rep) >= 0) + SLANG_ASSERT(castable); + if (m_representations.indexOf(castable) >= 0) { SLANG_ASSERT_FAILURE("Already have this representation"); return; } - m_representations.add(rep); + m_representations.add(castable); } void Artifact::addRepresentationUnknown(ISlangUnknown* unk) @@ -582,4 +223,19 @@ ICastableList* Artifact::getRepresentations() return m_representations.requireList(); } +IArtifactList* Artifact::getChildren() +{ + // If it has already evaluated, return it. + if (m_children) + { + return m_children; + } + + auto util = ArtifactUtilImpl::getSingleton(); + util->getChildrenDefaultImpl(this, m_children.writeRef()); + + return m_children; +} + + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-impl.h b/source/compiler-core/slang-artifact-impl.h index 79aad3b64..e4db46222 100644 --- a/source/compiler-core/slang-artifact-impl.h +++ b/source/compiler-core/slang-artifact-impl.h @@ -4,6 +4,8 @@ #include "slang-artifact.h" +#include "../core/slang-lazy-castable-list.h" + #include "../../slang-com-helper.h" #include "../../slang-com-ptr.h" @@ -12,89 +14,6 @@ namespace Slang { -/* An adapter such that types which aren't derived from ICastable, can be used as such. - -With the following caveats. -* the interfaces/objects of the adapter are checked *first*, so IUnknown will always be for the adapter -* assumes when doing a queryInterface on the contained item -*/ -class UnknownCastableAdapter : public ComBaseObject, public IUnknownCastableAdapter -{ -public: - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // IUnknownCastableAdapter - virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() SLANG_OVERRIDE { return m_contained; } - - UnknownCastableAdapter(ISlangUnknown* unk): - m_contained(unk) - { - SLANG_ASSERT(unk); - } - -protected: - void* getInterface(const Guid& guid); - void* getObject(const Guid& guid); - - ComPtr<ISlangUnknown> m_contained; - - // We hold a cache for a single lookup to make things a little faster - void* m_found = nullptr; - Guid m_foundGuid; -}; - -class CastableList : public ComBaseObject, public ICastableList -{ -public: - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // ICastableList - virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_list.getCount(); } - virtual ICastable* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE { return m_list[i]; } - virtual void SLANG_MCALL add(ICastable* castable) SLANG_OVERRIDE; - virtual void SLANG_MCALL addUnknown(ISlangUnknown* unk) SLANG_OVERRIDE; - virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE; - virtual void SLANG_MCALL clear() SLANG_OVERRIDE; - virtual Index SLANG_MCALL indexOf(ICastable* castable) SLANG_OVERRIDE; - virtual Index SLANG_MCALL indexOfUnknown(ISlangUnknown* unk) SLANG_OVERRIDE; - virtual void* SLANG_MCALL find(const Guid& guid) SLANG_OVERRIDE; - virtual ICastable* const* SLANG_MCALL getBuffer() SLANG_OVERRIDE { return m_list.getBuffer(); } - - virtual ~CastableList(); - -protected: - void* getInterface(const Guid& guid); - void* getObject(const Guid& guid); - - List<ICastable*> m_list; -}; - -class LazyCastableList -{ -public: - void add(ICastable* castable); - Count getCount() const; - void removeAt(Index index); - void clear(); - void clearAndDeallocate(); - void* find(const Guid& guid); - ConstArrayView<ICastable*> getView() const; - Index indexOf(ICastable* castable) const; - Index indexOfUnknown(ISlangUnknown* unk) const; - - ICastableList* requireList(); - ICastableList* getList(); - -protected: - ComPtr<ICastable> m_castable; -}; - class ArtifactList : public ComBaseObject, public IArtifactList { public: @@ -134,15 +53,6 @@ protected: /* Discussion: -It could make sense to remove the explicit variables of a ISlangBlob, and the file backing from this interface, as they could -all be implemented as element types presumably deriving from IArtifactInstance. Doing so would mean how a 'file' is turned into -a blob is abstracted. - -It may be helpful to be able to add temporary files to the artifact (such that they will be deleted when the artifact goes out of -scope). Using an implementation of the File backed IArtifactInstance, with a suitable desc would sort of work, but it breaks the idea -that any IArtifactInstance *represents* the contents of Artifact that contains it. Of course there could be types *not* deriving -from IArtifactInstance that handle temporary file existance. This is probably the simplest answer to the problem. - Another issue occurs around wanting to hold multiple kernels within a container. The problem here is that although through the desc we can identify what target a kernel is for, there is no way of telling what stage it is for. @@ -174,11 +84,13 @@ public: virtual void* SLANG_MCALL SLANG_MCALL findAssociated(const Guid& unk) SLANG_OVERRIDE; virtual ICastableList* SLANG_MCALL getAssociated() SLANG_OVERRIDE; - virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation(IArtifactRepresentation* rep) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation(ICastable* castable) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL addRepresentationUnknown(ISlangUnknown* rep) SLANG_OVERRIDE; virtual void* SLANG_MCALL SLANG_MCALL findRepresentation(const Guid& guid) SLANG_OVERRIDE; virtual ICastableList* SLANG_MCALL getRepresentations() SLANG_OVERRIDE; + virtual IArtifactList* SLANG_MCALL getChildren() SLANG_OVERRIDE; + /// Ctor Artifact(const Desc& desc, const String& name) : m_desc(desc), diff --git a/source/compiler-core/slang-artifact-representation-impl.cpp b/source/compiler-core/slang-artifact-representation-impl.cpp index 20480ae07..d1de75c79 100644 --- a/source/compiler-core/slang-artifact-representation-impl.cpp +++ b/source/compiler-core/slang-artifact-representation-impl.cpp @@ -77,71 +77,21 @@ bool FileArtifactRepresentation::exists() return SLANG_SUCCEEDED(res) && pathType == SLANG_PATH_TYPE_FILE; } -FileArtifactRepresentation::~FileArtifactRepresentation() -{ - if (m_kind == Kind::Owned) - { - auto fileSystem = _getFileSystem(); - fileSystem->remove(m_path.getBuffer()); - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LockFile !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* LockFile::getInterface(const Guid& guid) +void FileArtifactRepresentation::disown() { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == ILockFile::getTypeGuid()) + if (_isOwned()) { - return static_cast<ILockFile*>(this); + m_kind = Kind::Reference; } - return nullptr; -} - -void* LockFile::getObject(const Guid& guid) -{ - SLANG_UNUSED(guid); - return nullptr; } -ISlangMutableFileSystem* LockFile::_getFileSystem() -{ - return m_fileSystem ? m_fileSystem : OSFileSystem::getMutableSingleton(); -} - -void* LockFile::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - return getObject(guid); -} - -const char* LockFile::getPath() -{ - return (m_path.getLength() > 0) ? m_path.getBuffer() : nullptr; -} - -ISlangMutableFileSystem* LockFile::getFileSystem() -{ - return m_fileSystem; -} - -LockFile::~LockFile() +FileArtifactRepresentation::~FileArtifactRepresentation() { - if (m_path.getLength() > 0) + if (_isOwned()) { auto fileSystem = _getFileSystem(); fileSystem->remove(m_path.getBuffer()); } } -void LockFile::disown() -{ - m_path = String(); - m_fileSystem.setNull(); -} - } // namespace Slang diff --git a/source/compiler-core/slang-artifact-representation-impl.h b/source/compiler-core/slang-artifact-representation-impl.h index 9c2066e55..a40adf0e9 100644 --- a/source/compiler-core/slang-artifact-representation-impl.h +++ b/source/compiler-core/slang-artifact-representation-impl.h @@ -12,41 +12,7 @@ namespace Slang { -/* An implementation of ILockFile */ -class LockFile : public ComBaseObject, public ILockFile -{ -public: - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // ILockFile - SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE; - SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() SLANG_OVERRIDE; - SLANG_NO_THROW void SLANG_MCALL disown() SLANG_OVERRIDE; - - /// Ctor - LockFile(String path, ISlangMutableFileSystem* fileSystem) : - m_path(path), - m_fileSystem(fileSystem) - { - } - - ~LockFile(); - -protected: - void* getInterface(const Guid& uuid); - void* getObject(const Guid& uuid); - - ISlangMutableFileSystem* _getFileSystem(); - - String m_path; - ComPtr<ISlangMutableFileSystem> m_fileSystem; -}; - -/* -A representation of an artifact that is held in a file */ +/* A representation of an artifact that is held in a file */ class FileArtifactRepresentation : public ComBaseObject, public IFileArtifactRepresentation { public: @@ -64,10 +30,11 @@ public: // IFileArtifactRepresentation virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() SLANG_OVERRIDE { return m_kind; } virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE { return m_path.getBuffer(); } - virtual SLANG_NO_THROW ILockFile* SLANG_MCALL getLockFile() SLANG_OVERRIDE { return m_lockFile; } virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() SLANG_OVERRIDE { return m_fileSystem; } + virtual SLANG_NO_THROW void SLANG_MCALL disown() SLANG_OVERRIDE; + virtual SLANG_NO_THROW IFileArtifactRepresentation* SLANG_MCALL getLockFile() SLANG_OVERRIDE { return m_lockFile; } - FileArtifactRepresentation(Kind kind, String path, ILockFile* lockFile, ISlangMutableFileSystem* fileSystem): + FileArtifactRepresentation(Kind kind, String path, IFileArtifactRepresentation* lockFile, ISlangMutableFileSystem* fileSystem): m_kind(kind), m_path(path), m_lockFile(lockFile), @@ -81,11 +48,14 @@ protected: void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); + /// True if the file is owned + bool _isOwned() const { return Index(m_kind) >= Index(Kind::Owned); } + ISlangMutableFileSystem* _getFileSystem(); Kind m_kind; String m_path; - ComPtr<ILockFile> m_lockFile; + ComPtr<IFileArtifactRepresentation> m_lockFile; ComPtr<ISlangMutableFileSystem> m_fileSystem; }; diff --git a/source/compiler-core/slang-artifact-representation.h b/source/compiler-core/slang-artifact-representation.h index 00a5c9e5b..230283ce4 100644 --- a/source/compiler-core/slang-artifact-representation.h +++ b/source/compiler-core/slang-artifact-representation.h @@ -7,20 +7,6 @@ namespace Slang { -/* A lock file */ -class ILockFile : public ICastable -{ - SLANG_COM_INTERFACE(0x9177ea36, 0xa608, 0x4490, { 0x87, 0xf0, 0xf3, 0x93, 0x9, 0x7d, 0x36, 0xce }) - - /// The path to a lock file. - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; - /// Optional, the file system it's on. If nullptr its on 'regular' OS file system. - virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() = 0; - - /// Makes the lock file no longer owned. Doing so will make the path nullptr, and getFileSystem nullptr. - virtual SLANG_NO_THROW void SLANG_MCALL disown() = 0; -}; - /* A representation as a file. If it is a temporary file, it will likely disappear. A file representation does not have to be a representation of a file on the file system. @@ -30,21 +16,26 @@ to be usable. */ class IFileArtifactRepresentation : public IArtifactRepresentation { public: + // NOTE! enum class Kind { Reference, ///< References a file on the file system - Owned, ///< File is *owned* by this instance and will be deleted when goes out of scope NameOnly, ///< Typically used for items that can be found by the 'system'. The path is just a name, and cannot typically be loaded as a blob. + Owned, ///< File is *owned* by this instance and will be deleted when goes out of scope + Lock, ///< An owned type, indicates potentially in part may only exist to 'lock' a path for a temporary file + CountOf, }; - + /// The the kind of file. virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() = 0; /// The path (on the file system) virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; - /// Get the lock file. Return nullptr if there is no lock file. - virtual SLANG_NO_THROW ILockFile* SLANG_MCALL getLockFile() = 0; /// Optional, the file system it's on. If nullptr its on 'regular' OS file system. virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() = 0; + /// Makes the file no longer owned. Only applicable for Owned/Lock and they will become 'Reference' + virtual SLANG_NO_THROW void SLANG_MCALL disown() = 0; + /// Gets the 'lock file' if any associated with this file. Returns nullptr if there isn't one. + virtual SLANG_NO_THROW IFileArtifactRepresentation* SLANG_MCALL getLockFile() = 0; }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-util.cpp b/source/compiler-core/slang-artifact-util.cpp index 7f69a0464..909c9b3d2 100644 --- a/source/compiler-core/slang-artifact-util.cpp +++ b/source/compiler-core/slang-artifact-util.cpp @@ -67,7 +67,7 @@ ArtifactStyle ArtifactUtilImpl::getStyleParent(ArtifactStyle style) { return get UnownedStringSlice ArtifactUtilImpl::getStyleName(ArtifactStyle style) { return getName(style); } bool ArtifactUtilImpl::isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) { return isDerivedFrom(style, base); } -SlangResult ArtifactUtilImpl::createLockFile(const char* inNameBase, ISlangMutableFileSystem* fileSystem, ILockFile** outLockFile) +SlangResult ArtifactUtilImpl::createLockFile(const char* inNameBase, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outLockFile) { if (fileSystem) { @@ -84,7 +84,7 @@ SlangResult ArtifactUtilImpl::createLockFile(const char* inNameBase, ISlangMutab String lockPath; SLANG_RETURN_ON_FAIL(File::generateTemporary(nameBase, lockPath)); - ComPtr<ILockFile> lockFile(new LockFile(lockPath, fileSystem)); + ComPtr<IFileArtifactRepresentation> lockFile(new FileArtifactRepresentation(IFileArtifactRepresentation::Kind::Lock, lockPath, nullptr, fileSystem)); *outLockFile = lockFile.detach(); return SLANG_OK; @@ -114,7 +114,7 @@ SlangResult ArtifactUtilImpl::requireFileDefaultImpl(IArtifact* artifact, Artifa SLANG_RETURN_ON_FAIL(artifact->loadBlob(keep, blob.writeRef())); // Okay we need to store as a temporary. Get a lock file. - ComPtr<ILockFile> lockFile; + ComPtr<IFileArtifactRepresentation> lockFile; SLANG_RETURN_ON_FAIL(createLockFile(artifact->getName(), nullptr, lockFile.writeRef())); // Now we need the appropriate name for this item @@ -126,25 +126,32 @@ SlangResult ArtifactUtilImpl::requireFileDefaultImpl(IArtifact* artifact, Artifa // Write the contents SLANG_RETURN_ON_FAIL(File::writeAllBytes(path, blob->getBufferPointer(), blob->getBufferSize())); - // If the paths are identical we don't need a lock file + ComPtr<IFileArtifactRepresentation> fileRep; + + // TODO(JS): This path comparison is perhaps not perfect, in that it assumes the path is not changed + // in any way. For example an impl of calcArtifactPath that changed slashes or used a canonical path + // might mean the lock file and the rep have the same path. + // As it stands calcArtifactPath impl doesn't do that, but that is perhaps somewhatfragile + + // If the paths are identical, we can just use the lock file for the rep if (UnownedStringSlice(lockFile->getPath()) == path.getUnownedSlice()) { - // Make the lockFile no longer own the file - lockFile->disown(); - // We no longer need the lock file - lockFile.setNull(); + fileRep.swap(lockFile); + } + else + { + // Create a new rep that references the lock file + fileRep = new FileArtifactRepresentation(IFileArtifactRepresentation::Kind::Owned, path, lockFile, nullptr); } - + // Create the rep - IFileArtifactRepresentation* fileRep = new FileArtifactRepresentation(IFileArtifactRepresentation::Kind::Owned, path, lockFile, nullptr); if (canKeep(keep)) { artifact->addRepresentation(fileRep); } - // Return it - fileRep->addRef(); - *outFile = fileRep; + // Return the file + *outFile = fileRep.detach(); return SLANG_OK; } @@ -153,4 +160,19 @@ ArtifactDesc ArtifactUtilImpl::makeDescFromCompileTarget(SlangCompileTarget targ return ArtifactDescUtil::makeDescFromCompileTarget(target); } +SlangResult ArtifactUtilImpl::getChildrenDefaultImpl(IArtifact* artifact, IArtifactList** outList) +{ + auto desc = artifact->getDesc(); + + // If it's a container type for now, just create empty list of children + if (isDerivedFrom(desc.kind, ArtifactKind::Container)) + { + *outList = ComPtr<IArtifactList>(new ArtifactList(artifact)).detach(); + return SLANG_OK; + } + + return SLANG_E_NOT_AVAILABLE; +} + + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-util.h b/source/compiler-core/slang-artifact-util.h index f9070a76e..c391a5056 100644 --- a/source/compiler-core/slang-artifact-util.h +++ b/source/compiler-core/slang-artifact-util.h @@ -28,7 +28,7 @@ class IArtifactUtil : public ISlangUnknown virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) = 0; virtual SLANG_NO_THROW bool SLANG_MCALL isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) = 0; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, ILockFile** outLockFile) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outLockFile) = 0; /// Given a desc and a basePath returns a suitable name virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) = 0; @@ -37,6 +37,8 @@ class IArtifactUtil : public ISlangUnknown virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFileDefaultImpl(IArtifact* artifact, ArtifactKeep keep, IFileArtifactRepresentation** outFileRep) = 0; virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescFromCompileTarget(SlangCompileTarget target) = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getChildrenDefaultImpl(IArtifact* artifact, IArtifactList** outList) = 0; }; class ArtifactUtilImpl : public IArtifactUtil @@ -64,7 +66,7 @@ public: virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, ILockFile** outLockFile) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outLockFile) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; @@ -72,6 +74,8 @@ public: virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescFromCompileTarget(SlangCompileTarget target) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getChildrenDefaultImpl(IArtifact* artifact, IArtifactList** outList) SLANG_OVERRIDE; + static IArtifactUtil* getSingleton() { return &g_singleton; } protected: diff --git a/source/compiler-core/slang-artifact.h b/source/compiler-core/slang-artifact.h index 3c991b7b6..55b3ff89f 100644 --- a/source/compiler-core/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -4,9 +4,10 @@ #include "../core/slang-basic.h" -#include "../../slang-com-helper.h" +//#include "../../slang-com-helper.h" +//#include "../core/slang-destroyable.h" -#include "../core/slang-destroyable.h" +#include "../core/slang-castable-list.h" namespace Slang { @@ -202,6 +203,7 @@ inline /* static */ArtifactDesc ArtifactDesc::make(Packed inPacked) // Forward declare class IFileArtifactRepresentation; class IArtifactRepresentation; +class IArtifactList; // Controls what items can be kept. enum class ArtifactKeep @@ -218,40 +220,6 @@ SLANG_INLINE bool canKeep(ArtifactKeep keep) { return Index(keep) >= Index(Artif /// Returns the keep type for an intermediate SLANG_INLINE ArtifactKeep getIntermediateKeep(ArtifactKeep keep) { return (keep == ArtifactKeep::All) ? ArtifactKeep::All : ArtifactKeep::No; } -/* A useful interface for handling lists of castable interfaces. Cannot hold nullptr */ -class ICastableList : public ICastable -{ - SLANG_COM_INTERFACE(0x335f3d40, 0x934c, 0x40dc, { 0xb5, 0xe1, 0xf7, 0x6e, 0x40, 0x3, 0x62, 0x5 }) - - /// Get the count of all interfaces held in the list - virtual Count SLANG_MCALL getCount() = 0; - /// Get the interface at the specified index - virtual ICastable* SLANG_MCALL getAt(Index i) = 0; - /// Add an item to the list - virtual void SLANG_MCALL add(ICastable* unk) = 0; - /// Add IUnknown, will cast to ICastable and if that's not possible will wrap - virtual void SLANG_MCALL addUnknown(ISlangUnknown* unk) = 0; - /// Remove item at index, remaining items stay in the same order - virtual void SLANG_MCALL removeAt(Index i) = 0; - /// Clear the list - virtual void SLANG_MCALL clear() = 0; - /// Find the first index of castable, or -1 if not found - virtual Index SLANG_MCALL indexOf(ICastable* castable) = 0; - /// Find the index interface (handling wrapping if necessary) - virtual Index SLANG_MCALL indexOfUnknown(ISlangUnknown* unk) = 0; - /// Find the first item that casts to non null - virtual void* SLANG_MCALL find(const Guid& guid) = 0; - /// Access the internal buffer (any mutation can invalidate this value) - virtual ICastable*const* SLANG_MCALL getBuffer() = 0; -}; - -// Simply finding things in a ICastableList -template <typename T> -SLANG_FORCE_INLINE T* find(ICastableList* list) -{ - return reinterpret_cast<T*>(list->find(T::getTypeGuid())); -} - /* The IArtifact interface is designed to represent some Artifact of compilation. It could be input to or output from a compilation. An abstraction is desirable here, because depending on the compiler the artifact/s could be @@ -277,12 +245,23 @@ files could be a Container containing artifacts for * Files that contain known types * Callable interface (an ISlangSharedLibrary) -Each one of these additions is an 'Element'. An Element is an interface pointer and a Desc that describes what the -inteface represents. Having the associated desc provides more detail about what the interface pointer actually is -without having to make the interface know what it is being used for. This allows an interface to be used in multiple -ways - for example the ISlangBlob interface could be used to represent some text, or a compiled kernel. +There are several types of ways to associate data with an artifact: + +* A representation +* Associated data +* A child artifact + +A `representation` has to wholly represent the artifact. That representation could be a blob, a file on the file system, +an in memory representation. There are two classes of `Representation` - ones that can be turned into blobs (and therefore +derive from IArtifactRepresentation) and ones that are in of themselves a representation (such as a blob or or ISlangSharedLibrary). + +`Associated data` is information that is associated with the artifact, but isn't a (whole) representation. It could be part +of the representation, or useful for the implementation of a representation. Could also be considered as a kind of side channel +to associate arbitrary temporary data with an artifact. + +A `child artifact` belongs to the artifact, within the hierarchy of artifacts. Child artifacts are held in an IArtifactList. -A more long term goals would be to +More long term goals would be to * Make Diagnostics into an interface (such it can be added to a Artifact result) * Use Artifact and related types for downstream compiler @@ -329,16 +308,27 @@ public: /// Get the list of associated items virtual ICastableList* SLANG_MCALL getAssociated() = 0; - /// Add a representation that derives from IArtifactRepresentation - virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation(IArtifactRepresentation* rep) = 0; + /// Add a representation + virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation(ICastable* castable) = 0; /// Add a representation that doesn't derive from IArtifactRepresentation virtual SLANG_NO_THROW void SLANG_MCALL addRepresentationUnknown(ISlangUnknown* rep) = 0; /// Find representation virtual void* SLANG_MCALL SLANG_MCALL findRepresentation(const Guid& guid) = 0; /// Get the list of all representations virtual ICastableList* SLANG_MCALL getRepresentations() = 0; + + /// Get the children. This may be evaluated lazily. + /// Only artifacts with a ArtifactKind that derives from Container generally produce childen. + /// If an artifact doesn't support children, it can return nullptr. + virtual IArtifactList* SLANG_MCALL getChildren() = 0; }; +template <typename T> +SLANG_FORCE_INLINE T* findRepresentation(IArtifact* artifact) +{ + return reinterpret_cast<T*>(artifact->findRepresentation(T::getTypeGuid())); +} + /* A list of artifacts. */ class IArtifactList : public ICastable { @@ -380,11 +370,6 @@ class IArtifactRepresentation : public ICastable virtual SLANG_NO_THROW bool SLANG_MCALL exists() = 0; }; -template <typename T> -SLANG_FORCE_INLINE T* findRepresentation(IArtifact* artifact) -{ - return reinterpret_cast<T*>(artifact->findRepresentation(T::getTypeGuid())); -} } // namespace Slang diff --git a/source/core/slang-castable-list-impl.cpp b/source/core/slang-castable-list-impl.cpp new file mode 100644 index 000000000..ee10ea995 --- /dev/null +++ b/source/core/slang-castable-list-impl.cpp @@ -0,0 +1,178 @@ +// slang-castable-list-impl.cpp +#include "slang-castable-list-impl.h" + +namespace Slang { + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnknownCastableAdapter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* UnknownCastableAdapter::castAs(const Guid& guid) +{ + if (auto intf = getInterface(guid)) + { + return intf; + } + if (auto obj = getObject(guid)) + { + return obj; + } + + if (m_found && guid == m_foundGuid) + { + return m_found; + } + + ComPtr<ISlangUnknown> cast; + if (SLANG_SUCCEEDED(m_contained->queryInterface(guid, (void**)cast.writeRef())) && cast) + { + // Save the interface in the cache + m_found = cast; + m_foundGuid = guid; + + return cast; + } + return nullptr; +} + +void* UnknownCastableAdapter::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid()) + { + return static_cast<ICastable*>(this); + } + return nullptr; +} + +void* UnknownCastableAdapter::getObject(const Guid& guid) +{ + SLANG_UNUSED(guid); + return nullptr; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CastableList !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +CastableList::~CastableList() +{ + for (auto castable : m_list) + { + castable->release(); + } +} + +void* CastableList::castAs(const Guid& guid) +{ + if (auto intf = getInterface(guid)) + { + return intf; + } + return getObject(guid); +} + +void* CastableList::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == ICastableList::getTypeGuid()) + { + return static_cast<ICastableList*>(this); + } + return nullptr; +} + +void* CastableList::getObject(const Guid& guid) +{ + SLANG_UNUSED(guid); + return nullptr; +} + +void* CastableList::find(const Guid& guid) +{ + for (ICastable* castable : m_list) + { + if (auto ptr = castable->castAs(guid)) + { + return ptr; + } + } + return nullptr; +} + +Index CastableList::indexOf(ICastable* castable) +{ + const Count count = m_list.getCount(); + for (Index i = 0; i < count; ++i) + { + ICastable* cur = m_list[i]; + if (cur == castable) + { + return i; + } + } + return -1; +} + +void CastableList::add(ICastable* castable) +{ + SLANG_ASSERT(castable); + castable->addRef(); + m_list.add(castable); +} + +void CastableList::removeAt(Index i) +{ + auto castable = m_list[i]; + m_list.removeAt(i); + castable->release(); +} + +void CastableList::clear() +{ + for (auto castable : m_list) + { + castable->release(); + } + m_list.clear(); +} + +void CastableList::addUnknown(ISlangUnknown* unk) +{ + // If it has ICastable interface we can just add as that + { + ComPtr<ICastable> castable; + if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) + { + return add(castable); + } + } + + // Wrap it in an adapter + IUnknownCastableAdapter* adapter = new UnknownCastableAdapter(unk); + add(adapter); +} + +Index CastableList::indexOfUnknown(ISlangUnknown* unk) +{ + SLANG_ASSERT(unk); + // If it has a castable interface we can just look for that + { + ComPtr<ICastable> castable; + if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) + { + return indexOf(castable); + } + } + + // It's not derived from ICastable, so can only be in list via an adapter + const Count count = m_list.getCount(); + for (Index i = 0; i < count; ++i) + { + auto adapter = as<IUnknownCastableAdapter>(m_list[i]); + if (adapter && adapter->getContained() == unk) + { + return i; + } + } + return -1; +} + +} // namespace Slang diff --git a/source/core/slang-castable-list-impl.h b/source/core/slang-castable-list-impl.h new file mode 100644 index 000000000..6c03855f2 --- /dev/null +++ b/source/core/slang-castable-list-impl.h @@ -0,0 +1,83 @@ +// slang-castable-list.h +#ifndef SLANG_CASTABLE_LIST_IMPL_H +#define SLANG_CASTABLE_LIST_IMPL_H + +#include "slang-castable-list.h" + +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + +#include "../core/slang-com-object.h" + +namespace Slang +{ + +/* An adapter such that types which aren't derived from ICastable, can be used as such. + +With the following caveats. +* the interfaces/objects of the adapter are checked *first*, so IUnknown will always be for the adapter +* assumes when doing a queryInterface on the contained item, it will remain in scope when released (this is *not* strict COM) +*/ +class UnknownCastableAdapter : public ComBaseObject, public IUnknownCastableAdapter +{ +public: + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + + // IUnknownCastableAdapter + virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() SLANG_OVERRIDE { return m_contained; } + + UnknownCastableAdapter(ISlangUnknown* unk): + m_contained(unk) + { + SLANG_ASSERT(unk); + } + +protected: + void* getInterface(const Guid& guid); + void* getObject(const Guid& guid); + + ComPtr<ISlangUnknown> m_contained; + + // We hold a cache for a single lookup to make things a little faster + void* m_found = nullptr; + Guid m_foundGuid; +}; + +/* Implementation of the ICastableList interface. +Is atomic reference counted*/ +class CastableList : public ComBaseObject, public ICastableList +{ +public: + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + + // ICastableList + virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_list.getCount(); } + virtual ICastable* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE { return m_list[i]; } + virtual void SLANG_MCALL add(ICastable* castable) SLANG_OVERRIDE; + virtual void SLANG_MCALL addUnknown(ISlangUnknown* unk) SLANG_OVERRIDE; + virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE; + virtual void SLANG_MCALL clear() SLANG_OVERRIDE; + virtual Index SLANG_MCALL indexOf(ICastable* castable) SLANG_OVERRIDE; + virtual Index SLANG_MCALL indexOfUnknown(ISlangUnknown* unk) SLANG_OVERRIDE; + virtual void* SLANG_MCALL find(const Guid& guid) SLANG_OVERRIDE; + virtual ICastable*const* SLANG_MCALL getBuffer() SLANG_OVERRIDE { return m_list.getBuffer(); } + + /// Dtor + virtual ~CastableList(); + +protected: + void* getInterface(const Guid& guid); + void* getObject(const Guid& guid); + + List<ICastable*> m_list; +}; + +} // namespace Slang + +#endif diff --git a/source/core/slang-castable-list.h b/source/core/slang-castable-list.h new file mode 100644 index 000000000..942f53376 --- /dev/null +++ b/source/core/slang-castable-list.h @@ -0,0 +1,57 @@ +// slang-castable-list.h +#ifndef SLANG_CASTABLE_LIST_H +#define SLANG_CASTABLE_LIST_H + +#include "../core/slang-basic.h" + +#include "../core/slang-destroyable.h" + +namespace Slang +{ + +/* A useful interface for handling lists of castable interfaces. Cannot hold nullptr */ +class ICastableList : public ICastable +{ + SLANG_COM_INTERFACE(0x335f3d40, 0x934c, 0x40dc, { 0xb5, 0xe1, 0xf7, 0x6e, 0x40, 0x3, 0x62, 0x5 }) + + /// Get the count of all interfaces held in the list + virtual Count SLANG_MCALL getCount() = 0; + /// Get the interface at the specified index + virtual ICastable* SLANG_MCALL getAt(Index i) = 0; + /// Add an item to the list + virtual void SLANG_MCALL add(ICastable* unk) = 0; + /// Add IUnknown, will cast to ICastable and if that's not possible will wrap + virtual void SLANG_MCALL addUnknown(ISlangUnknown* unk) = 0; + /// Remove item at index, remaining items stay in the same order + virtual void SLANG_MCALL removeAt(Index i) = 0; + /// Clear the list + virtual void SLANG_MCALL clear() = 0; + /// Find the first index of castable, or -1 if not found + virtual Index SLANG_MCALL indexOf(ICastable* castable) = 0; + /// Find the index interface (handling wrapping if necessary) + virtual Index SLANG_MCALL indexOfUnknown(ISlangUnknown* unk) = 0; + /// Find the first item that casts to non null + virtual void* SLANG_MCALL find(const Guid& guid) = 0; + /// Access the internal buffer (any mutation can invalidate this value) + virtual ICastable*const* SLANG_MCALL getBuffer() = 0; +}; + +// Simply finding things in a ICastableList +template <typename T> +SLANG_FORCE_INLINE T* find(ICastableList* list) +{ + return reinterpret_cast<T*>(list->find(T::getTypeGuid())); +} + +/* Adapter interface to make a non castable types work as ICastable */ +class IUnknownCastableAdapter : public ICastable +{ + SLANG_COM_INTERFACE(0x8b4aad81, 0x4934, 0x4a67, { 0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54 }); + + /// When using the adapter, this provides a way to directly get the internal no ICastable type + virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() = 0; +}; + +} // namespace Slang + +#endif diff --git a/source/core/slang-destroyable.h b/source/core/slang-destroyable.h index bf373ba33..390b16e7c 100644 --- a/source/core/slang-destroyable.h +++ b/source/core/slang-destroyable.h @@ -9,15 +9,6 @@ namespace Slang { -/* Adapter interface to make a non castable type work as ICastable */ -class IUnknownCastableAdapter : public ICastable -{ - SLANG_COM_INTERFACE(0x8b4aad81, 0x4934, 0x4a67, { 0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54 } ); - - /// When using the adapter, this provides a way to directly get the internal no ICastable type - virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() = 0; -}; - /* An interface that allows for an object to implement 'destruction'. A destroyed interface/object should release any other contained references. Behavior of an interface that is IDestroyed should be defined on the interface. Typically diff --git a/source/core/slang-lazy-castable-list.cpp b/source/core/slang-lazy-castable-list.cpp new file mode 100644 index 000000000..d9f0090d5 --- /dev/null +++ b/source/core/slang-lazy-castable-list.cpp @@ -0,0 +1,163 @@ +// slang-lazy-castable-list.cpp +#include "slang-lazy-castable-list.h" + +#include "slang-castable-list-impl.h" + +namespace Slang { + +void LazyCastableList::removeAt(Index index) +{ + SLANG_ASSERT(index >= 0 && index < getCount()); + + switch (m_state) + { + case State::None: break; + case State::One: + { + m_state = State::None; + m_castable.setNull(); + break; + } + case State::List: + { + static_cast<ICastableList*>(m_castable.get())->removeAt(index); + break; + } + } +} + +void LazyCastableList::clear() +{ + if (m_state == State::List) + { + auto list = static_cast<ICastableList*>(m_castable.get()); + list->clear(); + } + else + { + m_state = State::None; + m_castable.setNull(); + } +} + +void LazyCastableList::clearAndDeallocate() +{ + m_state = State::None; + m_castable.setNull(); +} + +Count LazyCastableList::getCount() const +{ + switch (m_state) + { + case State::None: return 0; + case State::One: return 1; + default: + case State::List: return static_cast<ICastableList*>(m_castable.get())->getCount(); + } +} + +void LazyCastableList::add(ICastable* castable) +{ + SLANG_ASSERT(castable); + if (m_state == State::None) + { + m_castable = castable; + m_state = State::One; + } + else + { + requireList()->add(castable); + } +} + +ICastableList* LazyCastableList::requireList() +{ + switch (m_state) + { + case State::None: + { + m_castable = new CastableList; + m_state = State::List; + break; + } + case State::One: + { + // Turn into a list + auto list = new CastableList; + list->add(m_castable); + m_castable = list; + m_state = State::List; + break; + } + default: break; + } + SLANG_ASSERT(m_state == State::List); + return static_cast<ICastableList*>(m_castable.get()); +} + +ICastableList* LazyCastableList::getList() +{ + return (m_state == State::None) ? nullptr : requireList(); +} + +void* LazyCastableList::find(const Guid& guid) +{ + for (auto castable : getView()) + { + if (auto ptr = castable->castAs(guid)) + { + return ptr; + } + } + return nullptr; +} + +ConstArrayView<ICastable*> LazyCastableList::getView() const +{ + switch (m_state) + { + case State::None: return ConstArrayView<ICastable*>(); + case State::One: return ConstArrayView<ICastable*>((ICastable*const*)&m_castable, 1); + default: + case State::List: + { + auto list = static_cast<ICastableList*>(m_castable.get()); + return ConstArrayView<ICastable*>(list->getBuffer(), list->getCount()); + } + } +} + +Index LazyCastableList::indexOf(ICastable* castable) const +{ + return getView().indexOf(castable); +} + +Index LazyCastableList::indexOfUnknown(ISlangUnknown* unk) const +{ + // Try as a ICastable first + { + ComPtr<ICastable> castable; + if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) + { + return indexOf(castable); + } + } + + // It's not derived from ICastable, so can only be in list via an adapter + const auto view = getView(); + + const Count count = view.getCount(); + for (Index i = 0; i < count; ++i) + { + auto adapter = as<IUnknownCastableAdapter>(view[i]); + if (adapter && adapter->getContained() == unk) + { + return i; + } + } + + return -1; +} + +} // namespace Slang diff --git a/source/core/slang-lazy-castable-list.h b/source/core/slang-lazy-castable-list.h new file mode 100644 index 000000000..4f73ce9ca --- /dev/null +++ b/source/core/slang-lazy-castable-list.h @@ -0,0 +1,66 @@ +// slang-lazy-castable-list.h +#ifndef SLANG_LAZY_CASTABLE_LIST_H +#define SLANG_LAZY_CASTABLE_LIST_H + +#include "slang-castable-list.h" + +#include "../../slang-com-ptr.h" + +namespace Slang +{ + +/* Sometimes the overhead around having a potential list of items that might often be +empty or only contain a single element is considerable. + +The `LazyCastableList` provides functionality around ICastableList to minimize allocation, or the +need to allocate an ICastableList. It does this by tracking state in m_state, and varying the +meaning of m_castable. + +* State::None - there is no list +* State::One - there is a single entry, that is held in m_castable +* State::List - m_castable is actually ICastableList, and holds the contents +*/ +class LazyCastableList +{ +public: + /// Add a castable to the lsit + void add(ICastable* castable); + /// Return the amount of items in the list + Count getCount() const; + /// Remove the item at the specified index + void removeAt(Index index); + /// Clear the list + void clear(); + /// Clear and deallocate the list + void clearAndDeallocate(); + /// Find the first item that castAs(guid) produces a result + void* find(const Guid& guid); + /// Get the contents of the list as a view + ConstArrayView<ICastable*> getView() const; + /// Get the index of castable in the list. Returns -1 if not found + Index indexOf(ICastable* castable) const; + /// Get the index of unk. Handles if the wrapping has been used. + Index indexOfUnknown(ISlangUnknown* unk) const; + + /// Will always return a valid ICastableList + ICastableList* requireList(); + /// Will return nullptr if the list is empty, else it returns a ICastableList holding the elements + ICastableList* getList(); + +protected: + enum class State + { + None, + One, + List, + }; + // A state is not *strictly* necessary, because we can always determine what m_castable is + // with a castAs. But doing so is not exactly fast, and using the state makes some code simpler + // additionally. + State m_state = State::None; + ComPtr<ICastable> m_castable; +}; + +} // namespace Slang + +#endif |
