diff options
Diffstat (limited to 'source/core')
125 files changed, 13096 insertions, 11127 deletions
diff --git a/source/core/slang-allocator.h b/source/core/slang-allocator.h index 8942f993b..03cfabe40 100644 --- a/source/core/slang-allocator.h +++ b/source/core/slang-allocator.h @@ -5,89 +5,77 @@ #include <stdlib.h> #ifdef _MSC_VER -# include <malloc.h> +#include <malloc.h> #endif #include <type_traits> namespace Slang { - inline void* alignedAllocate(size_t size, size_t alignment) - { +inline void* alignedAllocate(size_t size, size_t alignment) +{ #ifdef _MSC_VER - return _aligned_malloc(size, alignment); + return _aligned_malloc(size, alignment); #elif defined(__CYGWIN__) - return aligned_alloc(alignment, size); + return aligned_alloc(alignment, size); #else - void* rs = nullptr; - int succ = posix_memalign(&rs, alignment, size); - return (succ == 0) ? rs : nullptr; + void* rs = nullptr; + int succ = posix_memalign(&rs, alignment, size); + return (succ == 0) ? rs : nullptr; #endif - } +} - inline void alignedDeallocate(void* ptr) - { +inline void alignedDeallocate(void* ptr) +{ #ifdef _MSC_VER - _aligned_free(ptr); + _aligned_free(ptr); #else - free(ptr); + free(ptr); #endif - } +} - class StandardAllocator - { - public: - // not really called - void* allocate(size_t size) - { - return ::malloc(size); - } - void deallocate(void * ptr) - { - return ::free(ptr); - } - }; +class StandardAllocator +{ +public: + // not really called + void* allocate(size_t size) { return ::malloc(size); } + void deallocate(void* ptr) { return ::free(ptr); } +}; - template<int ALIGNMENT> - class AlignedAllocator - { - public: - void* allocate(size_t size) - { - return alignedAllocate(size, ALIGNMENT); - } - void deallocate(void * ptr) - { - return alignedDeallocate(ptr); - } - }; +template<int ALIGNMENT> +class AlignedAllocator +{ +public: + void* allocate(size_t size) { return alignedAllocate(size, ALIGNMENT); } + void deallocate(void* ptr) { return alignedDeallocate(ptr); } +}; - template<typename T, typename TAllocator> - class AllocateMethod +template<typename T, typename TAllocator> +class AllocateMethod +{ +public: + static inline T* allocateArray(Index count) { - public: - static inline T* allocateArray(Index count) + TAllocator allocator; + T* rs = (T*)allocator.allocate(count * sizeof(T)); + if (!std::is_trivially_constructible<T>::value) { - TAllocator allocator; - T* rs = (T*)allocator.allocate(count * sizeof(T)); - if (!std::is_trivially_constructible<T>::value) - { - for (Index i = 0; i < count; i++) - new (rs + i) T(); - } - return rs; + for (Index i = 0; i < count; i++) + new (rs + i) T(); } - static inline void deallocateArray(T* ptr, Index count) + return rs; + } + static inline void deallocateArray(T* ptr, Index count) + { + TAllocator allocator; + if (!std::is_trivially_destructible<T>::value) { - TAllocator allocator; - if (!std::is_trivially_destructible<T>::value) - { - for (Index i = 0; i < count; i++) - ptr[i].~T(); - } - allocator.deallocate(ptr); + for (Index i = 0; i < count; i++) + ptr[i].~T(); } - }; + allocator.deallocate(ptr); + } +}; #if 0 template<typename T> @@ -104,6 +92,6 @@ namespace Slang } }; #endif -} +} // namespace Slang #endif diff --git a/source/core/slang-archive-file-system.cpp b/source/core/slang-archive-file-system.cpp index e219fcbb5..9513e6372 100644 --- a/source/core/slang-archive-file-system.cpp +++ b/source/core/slang-archive-file-system.cpp @@ -1,29 +1,28 @@ #include "slang-archive-file-system.h" +#include "../core/slang-castable.h" +#include "slang-blob.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" - -#include "../core/slang-castable.h" - #include "slang-io.h" -#include "slang-string-util.h" -#include "slang-blob.h" - #include "slang-riff-file-system.h" +#include "slang-string-util.h" // Compression systems #include "slang-deflate-compression-system.h" #include "slang-lz4-compression-system.h" // Zip file system -#include "slang-zip-file-system.h" - #include "slang-riff.h" +#include "slang-zip-file-system.h" namespace Slang { -SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComPtr<ISlangFileSystemExt>& outFileSystem) +SlangResult loadArchiveFileSystem( + const void* data, + size_t dataSizeInBytes, + ComPtr<ISlangFileSystemExt>& outFileSystem) { ComPtr<ISlangMutableFileSystem> fileSystem; if (ZipFileSystem::isArchive(data, dataSizeInBytes)) @@ -34,7 +33,7 @@ SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComP else if (RiffFileSystem::isArchive(data, dataSizeInBytes)) { // It's riff contained (Slang specific) - fileSystem = new RiffFileSystem(nullptr); + fileSystem = new RiffFileSystem(nullptr); } else { @@ -52,26 +51,28 @@ SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComP outFileSystem = fileSystem; return SLANG_OK; } - -SlangResult createArchiveFileSystem(SlangArchiveType type, ComPtr<ISlangMutableFileSystem>& outFileSystem) + +SlangResult createArchiveFileSystem( + SlangArchiveType type, + ComPtr<ISlangMutableFileSystem>& outFileSystem) { switch (type) { - case SLANG_ARCHIVE_TYPE_ZIP: + case SLANG_ARCHIVE_TYPE_ZIP: { return ZipFileSystem::create(outFileSystem); } - case SLANG_ARCHIVE_TYPE_RIFF: + case SLANG_ARCHIVE_TYPE_RIFF: { outFileSystem = new RiffFileSystem(nullptr); return SLANG_OK; } - case SLANG_ARCHIVE_TYPE_RIFF_DEFLATE: + case SLANG_ARCHIVE_TYPE_RIFF_DEFLATE: { outFileSystem = new RiffFileSystem(DeflateCompressionSystem::getSingleton()); return SLANG_OK; } - case SLANG_ARCHIVE_TYPE_RIFF_LZ4: + case SLANG_ARCHIVE_TYPE_RIFF_LZ4: { outFileSystem = new RiffFileSystem(LZ4CompressionSystem::getSingleton()); return SLANG_OK; diff --git a/source/core/slang-archive-file-system.h b/source/core/slang-archive-file-system.h index 13b226019..25bac0812 100644 --- a/source/core/slang-archive-file-system.h +++ b/source/core/slang-archive-file-system.h @@ -2,9 +2,7 @@ #define SLANG_CORE_ARCHIVE_FILE_SYSTEM_H #include "slang-basic.h" - #include "slang-com-ptr.h" - #include "slang-compression-system.h" namespace Slang @@ -12,20 +10,32 @@ namespace Slang class IArchiveFileSystem : public ISlangCastable { - SLANG_COM_INTERFACE(0x5c565aac, 0xe834, 0x41fc, { 0x8b, 0xb, 0x7d, 0x4c, 0xf3, 0x8b, 0x89, 0x50 }); - - /// Loads an archive. - SLANG_NO_THROW virtual SlangResult SLANG_MCALL loadArchive(const void* archive, size_t archiveSizeInBytes) = 0; - /// Get as an archive (that can be saved to disk) - /// NOTE! If the blob is not owned, it's contents can be invalidated by any call to a method of the file system or loss of scope - SLANG_NO_THROW virtual SlangResult SLANG_MCALL storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) = 0; - /// Set the compression - used for any subsequent items added + SLANG_COM_INTERFACE( + 0x5c565aac, + 0xe834, + 0x41fc, + {0x8b, 0xb, 0x7d, 0x4c, 0xf3, 0x8b, 0x89, 0x50}); + + /// Loads an archive. + SLANG_NO_THROW virtual SlangResult SLANG_MCALL + loadArchive(const void* archive, size_t archiveSizeInBytes) = 0; + /// Get as an archive (that can be saved to disk) + /// NOTE! If the blob is not owned, it's contents can be invalidated by any call to a method of + /// the file system or loss of scope + SLANG_NO_THROW virtual SlangResult SLANG_MCALL + storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) = 0; + /// Set the compression - used for any subsequent items added SLANG_NO_THROW virtual void SLANG_MCALL setCompressionStyle(const CompressionStyle& style) = 0; }; -SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComPtr<ISlangFileSystemExt>& outFileSystem); -SlangResult createArchiveFileSystem(SlangArchiveType type, ComPtr<ISlangMutableFileSystem>& outFileSystem); +SlangResult loadArchiveFileSystem( + const void* data, + size_t dataSizeInBytes, + ComPtr<ISlangFileSystemExt>& outFileSystem); +SlangResult createArchiveFileSystem( + SlangArchiveType type, + ComPtr<ISlangMutableFileSystem>& outFileSystem); -} +} // namespace Slang #endif diff --git a/source/core/slang-array-view.h b/source/core/slang-array-view.h index 50270e0a0..21b6ce113 100644 --- a/source/core/slang-array-view.h +++ b/source/core/slang-array-view.h @@ -6,222 +6,225 @@ namespace Slang { - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ConstArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ConstArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!! - template<typename T> - class ConstArrayView - { - public: - typedef ConstArrayView ThisType; +template<typename T> +class ConstArrayView +{ +public: + typedef ConstArrayView ThisType; - SLANG_FORCE_INLINE const T* begin() const { return m_buffer; } - - SLANG_FORCE_INLINE const T* end() const { return m_buffer + m_count; } - - SLANG_FORCE_INLINE Count getCount() const { return m_count; } + SLANG_FORCE_INLINE const T* begin() const { return m_buffer; } - SLANG_FORCE_INLINE const T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - - SLANG_FORCE_INLINE const T* getBuffer() const { return m_buffer; } - - template<typename T2> - Index indexOf(const T2& val) const - { - for (Index i = 0; i < m_count; i++) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } + SLANG_FORCE_INLINE const T* end() const { return m_buffer + m_count; } - template<typename T2> - Index lastIndexOf(const T2& val) const - { - for (Index i = m_count - 1; i >= 0; i--) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } + SLANG_FORCE_INLINE Count getCount() const { return m_count; } - template<typename Func> - Index findFirstIndex(const Func& predicate) const - { - for (Index i = 0; i < m_count; i++) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; - } + SLANG_FORCE_INLINE const T& operator[](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } - template<typename Func> - Index findLastIndex(const Func& predicate) const - { - for (Index i = m_count - 1; i >= 0; i--) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; - } + SLANG_FORCE_INLINE const T* getBuffer() const { return m_buffer; } - bool containsMemory(const ThisType& rhs) const + template<typename T2> + Index indexOf(const T2& val) const + { + for (Index i = 0; i < m_count; i++) { - return rhs.getBuffer() >= getBuffer() && rhs.end() <= end(); + if (m_buffer[i] == val) + return i; } + return -1; + } - bool operator==(const ThisType& rhs) const + template<typename T2> + Index lastIndexOf(const T2& val) const + { + for (Index i = m_count - 1; i >= 0; i--) { - if (&rhs == this) - { - return true; - } - const Count count = getCount(); - if (count != rhs.getCount()) - { - return false; - } - const T* thisEle = getBuffer(); - const T* rhsEle = rhs.getBuffer(); - for (Index i = 0; i < count; ++i) - { - if (thisEle[i] != rhsEle[i]) - { - return false; - } - } - return true; + if (m_buffer[i] == val) + return i; } - SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + return -1; + } - ThisType head(Index index) const + template<typename Func> + Index findFirstIndex(const Func& predicate) const + { + for (Index i = 0; i < m_count; i++) { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer, index); + if (predicate(m_buffer[i])) + return i; } - ThisType tail(Index index) const + return -1; + } + + template<typename Func> + Index findLastIndex(const Func& predicate) const + { + for (Index i = m_count - 1; i >= 0; i--) { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer + index, m_count - index); + if (predicate(m_buffer[i])) + return i; } + return -1; + } - ConstArrayView() : - m_buffer(nullptr), - m_count(0) + bool containsMemory(const ThisType& rhs) const + { + return rhs.getBuffer() >= getBuffer() && rhs.end() <= end(); + } + + bool operator==(const ThisType& rhs) const + { + if (&rhs == this) { + return true; } - - ConstArrayView(const T* buffer, Count count) : - m_buffer(const_cast<T*>(buffer)), - m_count(count) + const Count count = getCount(); + if (count != rhs.getCount()) { + return false; } - - protected: - ConstArrayView(T* buffer, Count count) : - m_buffer(buffer), - m_count(count) + const T* thisEle = getBuffer(); + const T* rhsEle = rhs.getBuffer(); + for (Index i = 0; i < count; ++i) { + if (thisEle[i] != rhsEle[i]) + { + return false; + } } + return true; + } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - T* m_buffer; ///< Note that this isn't const, as is used for derived class ArrayView also - Count m_count; - }; + ThisType head(Index index) const + { + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer, index); + } + ThisType tail(Index index) const + { + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer + index, m_count - index); + } - template<typename T> - ConstArrayView<T> makeConstArrayViewSingle(const T& obj) + ConstArrayView() + : m_buffer(nullptr), m_count(0) { - return ConstArrayView<T>(&obj, 1); - } + } - template<typename T> - ConstArrayView<T> makeConstArrayView(const T* buffer, Count count) + ConstArrayView(const T* buffer, Count count) + : m_buffer(const_cast<T*>(buffer)), m_count(count) { - return ConstArrayView<T>(buffer, count); } - template<typename T, size_t N> - ConstArrayView<T> makeConstArrayView(const T (&arr)[N]) +protected: + ConstArrayView(T* buffer, Count count) + : m_buffer(buffer), m_count(count) { - return ConstArrayView<T>(arr, Index(N)); } + T* m_buffer; ///< Note that this isn't const, as is used for derived class ArrayView also + Count m_count; +}; - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +template<typename T> +ConstArrayView<T> makeConstArrayViewSingle(const T& obj) +{ + return ConstArrayView<T>(&obj, 1); +} - template<typename T> - class ArrayView: public ConstArrayView<T> - { - public: - typedef ArrayView ThisType; +template<typename T> +ConstArrayView<T> makeConstArrayView(const T* buffer, Count count) +{ + return ConstArrayView<T>(buffer, count); +} - typedef ConstArrayView<T> Super; - - using Super::m_buffer; - using Super::m_count; +template<typename T, size_t N> +ConstArrayView<T> makeConstArrayView(const T (&arr)[N]) +{ + return ConstArrayView<T>(arr, Index(N)); +} - using Super::begin; - T* begin() { return m_buffer; } - using Super::end; - T* end() { return m_buffer + m_count; } - - using Super::head; - using Super::tail; +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - using Super::operator[]; - inline T& operator [](Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } +template<typename T> +class ArrayView : public ConstArrayView<T> +{ +public: + typedef ArrayView ThisType; - using Super::getBuffer; - inline T* getBuffer() { return m_buffer; } + typedef ConstArrayView<T> Super; - ThisType head(Index index) - { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer, index); - } - ThisType tail(Index index) - { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer + index, m_count - index); - } + using Super::m_buffer; + using Super::m_count; + + using Super::begin; + T* begin() { return m_buffer; } - T& getLast() { return m_buffer[m_count - 1]; } + using Super::end; + T* end() { return m_buffer + m_count; } - ArrayView() : Super() {} - ArrayView(T* buffer, Index size) :Super(buffer, size) {} - }; + using Super::head; + using Super::tail; - template<typename T> - ArrayView<T> makeArrayViewSingle(T& obj) + using Super::operator[]; + inline T& operator[](Index idx) { - return ArrayView<T>(&obj, 1); - } - - template<typename T> - ArrayView<T> makeArrayView(T* buffer, Count count) + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + + using Super::getBuffer; + inline T* getBuffer() { return m_buffer; } + + ThisType head(Index index) { - return ArrayView<T>(buffer, count); + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer, index); } + ThisType tail(Index index) + { + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer + index, m_count - index); + } + + T& getLast() { return m_buffer[m_count - 1]; } - template<typename T, size_t N> - ArrayView<T> makeArrayView(T (&arr)[N]) + ArrayView() + : Super() { - return ArrayView<T>(arr, Count(N)); } + ArrayView(T* buffer, Index size) + : Super(buffer, size) + { + } +}; + +template<typename T> +ArrayView<T> makeArrayViewSingle(T& obj) +{ + return ArrayView<T>(&obj, 1); +} +template<typename T> +ArrayView<T> makeArrayView(T* buffer, Count count) +{ + return ArrayView<T>(buffer, count); +} +template<typename T, size_t N> +ArrayView<T> makeArrayView(T (&arr)[N]) +{ + return ArrayView<T>(arr, Count(N)); } + +} // namespace Slang + #endif diff --git a/source/core/slang-array.h b/source/core/slang-array.h index d24ff0970..5c2fefc26 100644 --- a/source/core/slang-array.h +++ b/source/core/slang-array.h @@ -1,197 +1,220 @@ #ifndef SLANG_CORE_ARRAY_H #define SLANG_CORE_ARRAY_H -#include "slang-exception.h" #include "slang-array-view.h" +#include "slang-exception.h" namespace Slang { - /* An array container with fixed maximum size defined by COUNT. */ - template<typename T, Index COUNT> - class Array - { - public: - T* begin() { return m_buffer; } - const T* begin() const { return m_buffer; } - - const T* end() const { return m_buffer + m_count; } - T* end() { return m_buffer + m_count; } - - inline Index getCapacity() const { return COUNT; } - inline Index getCount() const { return m_count; } - inline const T& getFirst() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - inline T& getFirst() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - inline const T& getLast() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } - inline T& getLast() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } - inline void setCount(Index newCount) - { - SLANG_ASSERT(newCount >= 0 && newCount <= COUNT); - m_count = newCount; - } - inline void add(const T& item) - { - SLANG_ASSERT(m_count < COUNT); - m_buffer[m_count++] = item; - } - inline void add(T&& item) - { - SLANG_ASSERT(m_count < COUNT); - m_buffer[m_count++] = _Move(item); - } - - inline const T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - inline T& operator [](Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - - inline const T* getBuffer() const { return m_buffer; } - inline T* getBuffer() { return m_buffer; } - - inline void clear() { m_count = 0; } - - template<typename T2> - Index indexOf(const T2& val) const { return getView().indexOf(val); } - template<typename T2> - Index lastIndexOf(const T2& val) const { return getView().lastIndexOf(val); } - template<typename Func> - Index findFirstIndex(const Func& predicate) const { return getView().findFirstIndex(predicate); } - template<typename Func> - Index findLastIndex(const Func& predicate) const { return getView().findLastIndex(predicate); } - - inline ConstArrayView<T> getView() const { return ConstArrayView<T>(m_buffer, m_count); } - inline ConstArrayView<T> getView(Index start, Index count) const - { - SLANG_ASSERT(start >= 0 && count >= 0); - SLANG_ASSERT(start <= m_count && start + count < m_count); - return ConstArrayView<T>(m_buffer + start, count); - } - - inline ArrayView<T> getView() { return ArrayView<T>(m_buffer, m_count); } - inline ArrayView<T> getView(Index start, Index count) - { - SLANG_ASSERT(start >= 0 && count >= 0); - SLANG_ASSERT(start <= m_count && start + count < m_count); - return ArrayView<T>(m_buffer + start, count); - } - - private: - T m_buffer[COUNT]; - Index m_count = 0; - }; - - template<typename T> - class Array<T, 0> - { - public: - T* begin() { return nullptr; } - const T* begin() const { return nullptr; } - - const T* end() const { return nullptr; } - T* end() { return nullptr; } - - inline Index getCapacity() const { return 0; } - inline Index getCount() const { return 0; } - inline void setCount(Index newCount) - { - SLANG_ASSERT(newCount == 0); - } - inline const T* getBuffer() const { return nullptr; } - inline T* getBuffer() { return nullptr; } - inline void clear() {} - - template<typename T2> - Index indexOf(const T2& val) const { return getView().indexOf(val); } - template<typename T2> - Index lastIndexOf(const T2& val) const { return getView().lastIndexOf(val); } - template<typename Func> - Index findFirstIndex(const Func& predicate) const { return getView().findFirstIndex(predicate); } - template<typename Func> - Index findLastIndex(const Func& predicate) const { return getView().findLastIndex(predicate); } - - inline ConstArrayView<T> getView() const { return ConstArrayView<T>(nullptr, 0); } - inline ConstArrayView<T> getView(Index start, Index count) const - { - SLANG_ASSERT(start == 0 && count == 0); - return ConstArrayView<T>(nullptr, 0); - } - - inline ArrayView<T> getView() { return ArrayView<T>(nullptr, 0); } - inline ArrayView<T> getView(Index start, Index count) - { - SLANG_ASSERT(start == 0 && count == 0); - return ArrayView<T>(nullptr, 0); - } - }; - - template<typename T, typename ...TArgs> - struct FirstType - { - typedef T Type; - }; - - - template<typename T, Index SIZE> - void insertArray(Array<T, SIZE>&) {} - - template<typename T, typename ...TArgs, Index SIZE> - void insertArray(Array<T, SIZE>& arr, const T& val, TArgs... args) - { - arr.add(val); - insertArray<T>(arr, args...); - } - - template<typename ...TArgs> - auto makeArray(TArgs ...args) -> Array<typename FirstType<TArgs...>::Type, sizeof...(args)> - { - Array<typename FirstType<TArgs...>::Type, Index(sizeof...(args))> rs; - insertArray<typename FirstType<TArgs...>::Type>(rs, args...); - return rs; - } - - template<typename T> - auto makeArray() -> Array<T, 0> - { - return Array<T, 0>(); - } - - - template<typename TList> - void addToList(TList&) - { - } - template<typename TList, typename T> - void addToList(TList& list, T node) - { - list.add(node); - } - template<typename TList, typename T, typename ... TArgs> - void addToList(TList& list, T node, TArgs ... args) - { - list.add(node); - addToList(list, args...); +/* An array container with fixed maximum size defined by COUNT. */ +template<typename T, Index COUNT> +class Array +{ +public: + T* begin() { return m_buffer; } + const T* begin() const { return m_buffer; } + + const T* end() const { return m_buffer + m_count; } + T* end() { return m_buffer + m_count; } + + inline Index getCapacity() const { return COUNT; } + inline Index getCount() const { return m_count; } + inline const T& getFirst() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } + inline T& getFirst() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } + inline const T& getLast() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } + inline T& getLast() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } + inline void setCount(Index newCount) + { + SLANG_ASSERT(newCount >= 0 && newCount <= COUNT); + m_count = newCount; + } + inline void add(const T& item) + { + SLANG_ASSERT(m_count < COUNT); + m_buffer[m_count++] = item; + } + inline void add(T&& item) + { + SLANG_ASSERT(m_count < COUNT); + m_buffer[m_count++] = _Move(item); + } + + inline const T& operator[](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + inline T& operator[](Index idx) + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + + inline const T* getBuffer() const { return m_buffer; } + inline T* getBuffer() { return m_buffer; } + + inline void clear() { m_count = 0; } + + template<typename T2> + Index indexOf(const T2& val) const + { + return getView().indexOf(val); + } + template<typename T2> + Index lastIndexOf(const T2& val) const + { + return getView().lastIndexOf(val); + } + template<typename Func> + Index findFirstIndex(const Func& predicate) const + { + return getView().findFirstIndex(predicate); + } + template<typename Func> + Index findLastIndex(const Func& predicate) const + { + return getView().findLastIndex(predicate); + } + + inline ConstArrayView<T> getView() const { return ConstArrayView<T>(m_buffer, m_count); } + inline ConstArrayView<T> getView(Index start, Index count) const + { + SLANG_ASSERT(start >= 0 && count >= 0); + SLANG_ASSERT(start <= m_count && start + count < m_count); + return ConstArrayView<T>(m_buffer + start, count); + } + + inline ArrayView<T> getView() { return ArrayView<T>(m_buffer, m_count); } + inline ArrayView<T> getView(Index start, Index count) + { + SLANG_ASSERT(start >= 0 && count >= 0); + SLANG_ASSERT(start <= m_count && start + count < m_count); + return ArrayView<T>(m_buffer + start, count); } + +private: + T m_buffer[COUNT]; + Index m_count = 0; +}; + +template<typename T> +class Array<T, 0> +{ +public: + T* begin() { return nullptr; } + const T* begin() const { return nullptr; } + + const T* end() const { return nullptr; } + T* end() { return nullptr; } + + inline Index getCapacity() const { return 0; } + inline Index getCount() const { return 0; } + inline void setCount(Index newCount) { SLANG_ASSERT(newCount == 0); } + inline const T* getBuffer() const { return nullptr; } + inline T* getBuffer() { return nullptr; } + inline void clear() {} + + template<typename T2> + Index indexOf(const T2& val) const + { + return getView().indexOf(val); + } + template<typename T2> + Index lastIndexOf(const T2& val) const + { + return getView().lastIndexOf(val); + } + template<typename Func> + Index findFirstIndex(const Func& predicate) const + { + return getView().findFirstIndex(predicate); + } + template<typename Func> + Index findLastIndex(const Func& predicate) const + { + return getView().findLastIndex(predicate); + } + + inline ConstArrayView<T> getView() const { return ConstArrayView<T>(nullptr, 0); } + inline ConstArrayView<T> getView(Index start, Index count) const + { + SLANG_ASSERT(start == 0 && count == 0); + return ConstArrayView<T>(nullptr, 0); + } + + inline ArrayView<T> getView() { return ArrayView<T>(nullptr, 0); } + inline ArrayView<T> getView(Index start, Index count) + { + SLANG_ASSERT(start == 0 && count == 0); + return ArrayView<T>(nullptr, 0); + } +}; + +template<typename T, typename... TArgs> +struct FirstType +{ + typedef T Type; +}; + + +template<typename T, Index SIZE> +void insertArray(Array<T, SIZE>&) +{ +} + +template<typename T, typename... TArgs, Index SIZE> +void insertArray(Array<T, SIZE>& arr, const T& val, TArgs... args) +{ + arr.add(val); + insertArray<T>(arr, args...); +} + +template<typename... TArgs> +auto makeArray(TArgs... args) -> Array<typename FirstType<TArgs...>::Type, sizeof...(args)> +{ + Array<typename FirstType<TArgs...>::Type, Index(sizeof...(args))> rs; + insertArray<typename FirstType<TArgs...>::Type>(rs, args...); + return rs; +} + +template<typename T> +auto makeArray() -> Array<T, 0> +{ + return Array<T, 0>(); +} + + +template<typename TList> +void addToList(TList&) +{ +} +template<typename TList, typename T> +void addToList(TList& list, T node) +{ + list.add(node); +} +template<typename TList, typename T, typename... TArgs> +void addToList(TList& list, T node, TArgs... args) +{ + list.add(node); + addToList(list, args...); } +} // namespace Slang #endif diff --git a/source/core/slang-basic.h b/source/core/slang-basic.h index 5387af4aa..d37782160 100644 --- a/source/core/slang-basic.h +++ b/source/core/slang-basic.h @@ -1,14 +1,14 @@ #ifndef SLANG_CORE_BASIC_H #define SLANG_CORE_BASIC_H -#include "slang-common.h" -#include "slang-math.h" -#include "slang-string.h" #include "slang-array.h" +#include "slang-common.h" +#include "slang-dictionary.h" +#include "slang-exception.h" #include "slang-list.h" +#include "slang-math.h" #include "slang-short-list.h" #include "slang-smart-pointer.h" -#include "slang-exception.h" -#include "slang-dictionary.h" +#include "slang-string.h" #endif diff --git a/source/core/slang-blob.cpp b/source/core/slang-blob.cpp index 19a4281bd..ea4f4b6c0 100644 --- a/source/core/slang-blob.cpp +++ b/source/core/slang-blob.cpp @@ -1,13 +1,13 @@ #include "slang-blob.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BlobBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ISlangUnknown* BlobBase::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ISlangBlob::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangBlob::getTypeGuid()) { return static_cast<ISlangBlob*>(this); } @@ -41,12 +41,11 @@ void StringBlob::_setUniqueRep(StringRepresentation* uniqueRep) m_uniqueRep = uniqueRep; - m_slice = uniqueRep ? - UnownedTerminatedStringSlice(uniqueRep->getData(), uniqueRep->getLength()) : - UnownedTerminatedStringSlice(); + m_slice = uniqueRep ? UnownedTerminatedStringSlice(uniqueRep->getData(), uniqueRep->getLength()) + : UnownedTerminatedStringSlice(); } -/* static */StringRepresentation* StringBlob::_createUniqueCopy(StringRepresentation* rep) +/* static */ StringRepresentation* StringBlob::_createUniqueCopy(StringRepresentation* rep) { if (rep) { @@ -75,7 +74,7 @@ void StringBlob::_setWithMove(StringRepresentation* rep) if (rep && !rep->isUniquelyReferenced()) { _setUniqueRep(_createUniqueCopy(rep)); - // We need to release a ref as rep is passed in with the 'current' ref count + // We need to release a ref as rep is passed in with the 'current' ref count rep->releaseReference(); } else @@ -84,7 +83,7 @@ void StringBlob::_setWithMove(StringRepresentation* rep) } } -/* static */ComPtr<ISlangBlob> StringBlob::create(const UnownedStringSlice& slice) +/* static */ ComPtr<ISlangBlob> StringBlob::create(const UnownedStringSlice& slice) { StringRepresentation* rep = nullptr; if (slice.getLength()) @@ -93,27 +92,27 @@ void StringBlob::_setWithMove(StringRepresentation* rep) } auto blob = new StringBlob; - + // rep must be unique at this point blob->_setUniqueRep(rep); return ComPtr<ISlangBlob>(blob); } -/* static */ComPtr<ISlangBlob> StringBlob::create(const String& in) +/* static */ ComPtr<ISlangBlob> StringBlob::create(const String& in) { auto blob = new StringBlob; blob->_setWithCopy(in.getStringRepresentation()); return ComPtr<ISlangBlob>(blob); } -/* static */ComPtr<ISlangBlob> StringBlob::moveCreate(String& in) +/* static */ ComPtr<ISlangBlob> StringBlob::moveCreate(String& in) { auto blob = new StringBlob; blob->_setWithMove(in.detachStringRepresentation()); return ComPtr<ISlangBlob>(blob); } -/* static */ComPtr<ISlangBlob> StringBlob::moveCreate(String&& in) +/* static */ ComPtr<ISlangBlob> StringBlob::moveCreate(String&& in) { auto blob = new StringBlob; blob->_setWithMove(in.detachStringRepresentation()); @@ -167,7 +166,7 @@ void* RawBlob::getObject(const Guid& guid) // If the data has 0 termination, we can return the pointer if (guid == SlangTerminatedChars::getTypeGuid() && m_data.isTerminated()) { - return (char*)m_data.getData(); + return (char*)m_data.getData(); } return nullptr; } @@ -185,7 +184,7 @@ void* ScopeBlob::castAs(const SlangUUID& guid) return obj; } - // If the contained thing is castable, ask it + // If the contained thing is castable, ask it if (m_castable) { return m_castable->castAs(guid); @@ -225,7 +224,7 @@ void* ListBlob::getObject(const Guid& guid) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StaticBlob !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -SlangResult StaticBlob::queryInterface(SlangUUID const& guid, void** outObject) +SlangResult StaticBlob::queryInterface(SlangUUID const& guid, void** outObject) { if (auto intf = getInterface(guid)) { @@ -246,8 +245,7 @@ void* StaticBlob::castAs(const SlangUUID& guid) ISlangUnknown* StaticBlob::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ISlangBlob::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangBlob::getTypeGuid()) { return static_cast<ISlangBlob*>(this); } diff --git a/source/core/slang-blob.h b/source/core/slang-blob.h index 4df8f0db6..af3206fb5 100644 --- a/source/core/slang-blob.h +++ b/source/core/slang-blob.h @@ -1,22 +1,20 @@ #ifndef SLANG_CORE_BLOB_H #define SLANG_CORE_BLOB_H -#include "slang.h" - -#include "slang-string.h" -#include "slang-list.h" - -#include <stdarg.h> - +#include "../core/slang-com-object.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" +#include "slang-list.h" +#include "slang-string.h" +#include "slang.h" -#include "../core/slang-com-object.h" +#include <stdarg.h> -namespace Slang { +namespace Slang +{ /** Base class for simple blobs. -*/ + */ class BlobBase : public ISlangBlob, public ICastable, public ComBaseObject { public: @@ -33,53 +31,57 @@ protected: /** A blob that uses a `StringRepresentation` for its storage. -By design the StringBlob owns a unique reference to the StringRepresentation. +By design the StringBlob owns a unique reference to the StringRepresentation. This is because StringBlob, implements an interface which should work across threads. */ class StringBlob : public BlobBase { public: - SLANG_CLASS_GUID(0xf7e0e93c, 0xde70, 0x4531, { 0x9c, 0x9f, 0xdd, 0xa3, 0xf6, 0xc6, 0xc0, 0xdd }); + SLANG_CLASS_GUID(0xf7e0e93c, 0xde70, 0x4531, {0x9c, 0x9f, 0xdd, 0xa3, 0xf6, 0xc6, 0xc0, 0xdd}); // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_slice.begin(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_slice.begin(); + } SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_slice.getLength(); } - /// Since in is not being moved will *always* create a new representation, unless the in is empty + /// Since in is not being moved will *always* create a new representation, unless the in is + /// empty static ComPtr<ISlangBlob> create(const String& in); - /// Create from a slice + /// Create from a slice static ComPtr<ISlangBlob> create(const UnownedStringSlice& slice); - /// Moves from in into the created blob. - /// NOTE! That will only use the representation from in, if it is *unique* - /// otherwise it will make a new copy. + /// Moves from in into the created blob. + /// NOTE! That will only use the representation from in, if it is *unique* + /// otherwise it will make a new copy. static ComPtr<ISlangBlob> moveCreate(String& in); static ComPtr<ISlangBlob> moveCreate(String&& in); - /// Dtor + /// Dtor ~StringBlob(); protected: - - /// Init with a rep when can't be owned. + /// Init with a rep when can't be owned. void _setWithCopy(StringRepresentation* rep); - /// Init with a representation that has been moved. + /// Init with a representation that has been moved. void _setWithMove(StringRepresentation* rep); - /// Create a unique copy of rep. - /// If nullptr will work (if rep is empty, will return that) + /// Create a unique copy of rep. + /// If nullptr will work (if rep is empty, will return that) static StringRepresentation* _createUniqueCopy(StringRepresentation* rep); - /// Rep can only be nullptr or have a single ref + /// Rep can only be nullptr or have a single ref void _setUniqueRep(StringRepresentation* rep); void* getObject(const Guid& guid); - UnownedTerminatedStringSlice m_slice; ///< The contents - StringRepresentation* m_uniqueRep = nullptr; ///< Holds actual bytes. Can be nullptr if it's an empty string. + UnownedTerminatedStringSlice m_slice; ///< The contents + StringRepresentation* m_uniqueRep = + nullptr; ///< Holds actual bytes. Can be nullptr if it's an empty string. }; class ListBlob : public BlobBase @@ -91,17 +93,32 @@ public: // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data.getBuffer(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_data.getBuffer(); + } SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_data.getCount(); } - static ComPtr<ISlangBlob> create(const List<uint8_t>& data) { return ComPtr<ISlangBlob>(new ListBlob(data)); } - - static ComPtr<ISlangBlob> moveCreate(List<uint8_t>& data) { return ComPtr<ISlangBlob>(new ListBlob(_Move(data))); } + static ComPtr<ISlangBlob> create(const List<uint8_t>& data) + { + return ComPtr<ISlangBlob>(new ListBlob(data)); + } + + static ComPtr<ISlangBlob> moveCreate(List<uint8_t>& data) + { + return ComPtr<ISlangBlob>(new ListBlob(_Move(data))); + } protected: - explicit ListBlob(const List<uint8_t>& data) : m_data(data) {} - // Move ctor - explicit ListBlob(List<uint8_t>&& data) : m_data(data) {} + explicit ListBlob(const List<uint8_t>& data) + : m_data(data) + { + } + // Move ctor + explicit ListBlob(List<uint8_t>&& data) + : m_data(data) + { + } void* getObject(const Guid& guid); @@ -126,7 +143,7 @@ public: m_capacityInBytes = size; return m_data; } - /// Allocate size including a 0 byte at `size`. + /// Allocate size including a 0 byte at `size`. void* allocateTerminated(size_t size) { SLANG_ASSUME(size != std::numeric_limits<size_t>::max()); @@ -146,7 +163,8 @@ public: m_sizeInBytes = 0; m_capacityInBytes = 0; } - // Reallocate so the buffer is the specified capacity/size. Contents of buffer up to size remain intact. + // Reallocate so the buffer is the specified capacity/size. Contents of buffer up to size remain + // intact. void reallocate(size_t capacity) { if (capacity != m_capacityInBytes) @@ -156,7 +174,8 @@ public: m_capacityInBytes = capacity; } } - /// Makes this no longer own the allocation. Returns the allocated data (or nullptr if no allocation) + /// Makes this no longer own the allocation. Returns the allocated data (or nullptr if no + /// allocation) void* detach() { void* data = m_data; @@ -185,14 +204,14 @@ public: return dst; } - /// Get the allocated data. Returns nullptr if there is no allocated data + /// Get the allocated data. Returns nullptr if there is no allocated data void* getData() const { return m_data; } - /// Get the size of the allocated data. + /// Get the size of the allocated data. size_t getSizeInBytes() const { return m_sizeInBytes; } - /// Get the capacity in bytes + /// Get the capacity in bytes size_t getCapacityInBytes() const { return m_capacityInBytes; } - void setSizeInBytes(size_t size) + void setSizeInBytes(size_t size) { SLANG_ASSERT(size <= m_capacityInBytes); m_sizeInBytes = size; @@ -205,13 +224,14 @@ public: Swap(m_capacityInBytes, rhs.m_capacityInBytes); } - /// True if has zero termination, at the byte at m_sizeInBytes - bool isTerminated() const { return m_capacityInBytes > m_sizeInBytes && ((const char*)m_data)[m_sizeInBytes] == 0; } + /// True if has zero termination, at the byte at m_sizeInBytes + bool isTerminated() const + { + return m_capacityInBytes > m_sizeInBytes && ((const char*)m_data)[m_sizeInBytes] == 0; + } - ScopedAllocation() : - m_data(nullptr), - m_sizeInBytes(0), - m_capacityInBytes(0) + ScopedAllocation() + : m_data(nullptr), m_sizeInBytes(0), m_capacityInBytes(0) { } @@ -228,15 +248,21 @@ private: }; /** A blob that manages some raw data that it owns. -*/ + */ class RawBlob : public BlobBase { public: // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data.getData(); } - SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_data.getSizeInBytes(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_data.getData(); + } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE + { + return m_data.getSizeInBytes(); + } static ComPtr<ISlangBlob> moveCreate(ScopedAllocation& alloc) { @@ -245,7 +271,7 @@ public: return ComPtr<ISlangBlob>(blob); } - /// Create a blob that will retain (a copy of) raw data. + /// Create a blob that will retain (a copy of) raw data. static inline ComPtr<ISlangBlob> create(void const* inData, size_t size) { return ComPtr<ISlangBlob>(new RawBlob(inData, size)); @@ -254,10 +280,7 @@ public: protected: // Ctor // NOTE! Takes a copy of the input data - RawBlob(const void* data, size_t size) - { - memcpy(m_data.allocateTerminated(size), data, size); - } + RawBlob(const void* data, size_t size) { memcpy(m_data.allocateTerminated(size), data, size); } void* getObject(const Guid& guid); @@ -281,9 +304,8 @@ public: protected: // Ctor - UnownedRawBlob(const void* data, size_t size) : - m_data(data), - m_dataSizeInBytes(size) + UnownedRawBlob(const void* data, size_t size) + : m_data(data), m_dataSizeInBytes(size) { } @@ -300,9 +322,9 @@ This is useful when a Blob is useful to represent some global immutable chunk of class StaticBlob : public ISlangBlob, public ICastable { public: - // ISlangUnknown - SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) + SLANG_OVERRIDE; SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } @@ -313,9 +335,8 @@ public: SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data; } SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_dataCount; } - StaticBlob(const void* data, size_t dataCount): - m_data(data), - m_dataCount(dataCount) + StaticBlob(const void* data, size_t dataCount) + : m_data(data), m_dataCount(dataCount) { } @@ -334,8 +355,14 @@ public: virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_blob->getBufferPointer(); } - SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_blob->getBufferSize(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_blob->getBufferPointer(); + } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE + { + return m_blob->getBufferSize(); + } static inline ComPtr<ISlangBlob> create(ISlangBlob* blob, ISlangUnknown* scope) { @@ -343,11 +370,9 @@ public: } protected: - // Ctor - ScopeBlob(ISlangBlob* blob, ISlangUnknown* scope) : - m_blob(blob), - m_scope(scope) + ScopeBlob(ISlangBlob* blob, ISlangUnknown* scope) + : m_blob(blob), m_scope(scope) { // Cache the ICastable interface if there is one. blob->queryInterface(SLANG_IID_PPV_ARGS(m_castable.writeRef())); @@ -355,7 +380,8 @@ protected: ComPtr<ISlangUnknown> m_scope; ComPtr<ISlangBlob> m_blob; - ComPtr<ICastable> m_castable; ///< Set if the blob has this interface. Set to nullptr if does not. + ComPtr<ICastable> + m_castable; ///< Set if the blob has this interface. Set to nullptr if does not. }; } // namespace Slang diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index c7022397f..acafdf2b4 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -1,17 +1,18 @@ #include "slang-byte-encode-util.h" -namespace Slang { +namespace Slang +{ // Descriptions of algorithms here... // https://github.com/stoklund/varint #if SLANG_LITTLE_ENDIAN && SLANG_UNALIGNED_ACCESS // Testing on i7, unaligned access is around 40% faster -# define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 1 +#define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 1 #endif #ifndef SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS -# define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 0 +#define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 0 #endif #define SLANG_REPEAT_2(n) n, n @@ -22,23 +23,22 @@ namespace Slang { #define SLANG_REPEAT_64(n) SLANG_REPEAT_32(n), SLANG_REPEAT_32(n) #define SLANG_REPEAT_128(n) SLANG_REPEAT_64(n), SLANG_REPEAT_64(n) -/* static */const int8_t ByteEncodeUtil::s_msb8[256] = -{ - - 1, - 0, - SLANG_REPEAT_2(1), - SLANG_REPEAT_4(2), - SLANG_REPEAT_8(3), - SLANG_REPEAT_16(4), +/* static */ const int8_t ByteEncodeUtil::s_msb8[256] = { + -1, + 0, + SLANG_REPEAT_2(1), + SLANG_REPEAT_4(2), + SLANG_REPEAT_8(3), + SLANG_REPEAT_16(4), SLANG_REPEAT_32(5), SLANG_REPEAT_64(6), SLANG_REPEAT_128(7), }; -/* static */size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num) +/* static */ size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num) { size_t totalNumEncodeBytes = 0; - + for (size_t i = 0; i < num; i++) { const uint32_t v = in[i]; @@ -59,7 +59,10 @@ namespace Slang { return totalNumEncodeBytes; } -/* static */size_t ByteEncodeUtil::encodeLiteUInt32(const uint32_t* in, size_t num, uint8_t* encodeOut) +/* static */ size_t ByteEncodeUtil::encodeLiteUInt32( + const uint32_t* in, + size_t num, + uint8_t* encodeOut) { uint8_t* encodeStart = encodeOut; @@ -67,7 +70,7 @@ namespace Slang { { uint32_t v = in[i]; - if(v < kLiteCut1) + if (v < kLiteCut1) { *encodeOut++ = uint8_t(v); } @@ -95,7 +98,10 @@ namespace Slang { return size_t(encodeOut - encodeStart); } -/* static */void ByteEncodeUtil::encodeLiteUInt32(const uint32_t* in, size_t num, List<uint8_t>& encodeArrayOut) +/* static */ void ByteEncodeUtil::encodeLiteUInt32( + const uint32_t* in, + size_t num, + List<uint8_t>& encodeArrayOut) { // Make sure there is at least enough space for all bytes encodeArrayOut.setCount(num); @@ -111,7 +117,7 @@ namespace Slang { const size_t offset = size_t(encodeOut - encodeArrayOut.begin()); const UInt oldCapacity = encodeArrayOut.getCapacity(); - + // Make some more space encodeArrayOut.reserve(oldCapacity + (oldCapacity >> 1) + kMaxLiteEncodeUInt32); // Make the size the capacity @@ -154,7 +160,7 @@ namespace Slang { encodeArrayOut.compress(); } -/* static */int ByteEncodeUtil::encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]) +/* static */ int ByteEncodeUtil::encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]) { // 0-184 1 byte value = B0 // 185 - 248 2 bytes value = 185 + 256 * (B0 - 185) + B1 @@ -187,8 +193,7 @@ namespace Slang { } } -static const uint32_t s_unalignedUInt32Mask[5] = -{ +static const uint32_t s_unalignedUInt32Mask[5] = { 0x00000000, 0x000000ff, 0x0000ffff, @@ -196,8 +201,8 @@ static const uint32_t s_unalignedUInt32Mask[5] = 0xffffffff, }; -// Decode the >= kLiteCut2. -// in is pointing past the first byte. +// Decode the >= kLiteCut2. +// in is pointing past the first byte. // Only valid numBytesRemaining is 2, 3, or 4 SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int numBytesRemaining) { @@ -205,26 +210,26 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int #if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS switch (numBytesRemaining) { - case 2: value = *(const uint16_t*)in; break; - case 3: value = (uint32_t(in[2]) << 16) | (uint32_t(in[1]) << 8) | uint32_t(in[0]); break; - case 4: value = *(const uint32_t*)in; break; - default: break; + case 2: value = *(const uint16_t*)in; break; + case 3: value = (uint32_t(in[2]) << 16) | (uint32_t(in[1]) << 8) | uint32_t(in[0]); break; + case 4: value = *(const uint32_t*)in; break; + default: break; } #else // This works on all cpus although slower value = in[0]; switch (numBytesRemaining) { - case 4: value |= uint32_t(in[3]) << 24; /* fall thru */ - case 3: value |= uint32_t(in[2]) << 16; /* fall thru */ - case 2: value |= uint32_t(in[1]) << 8; /* fall thru */ - case 1: break; + case 4: value |= uint32_t(in[3]) << 24; /* fall thru */ + case 3: value |= uint32_t(in[2]) << 16; /* fall thru */ + case 2: value |= uint32_t(in[1]) << 8; /* fall thru */ + case 1: break; } #endif return value; } -/* static */int ByteEncodeUtil::decodeLiteUInt32(const uint8_t* in, uint32_t* out) +/* static */ int ByteEncodeUtil::decodeLiteUInt32(const uint8_t* in, uint32_t* out) { uint8_t b0 = *in++; if (b0 < kLiteCut1) @@ -246,7 +251,10 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int } } -/* static */size_t ByteEncodeUtil::decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut) +/* static */ size_t ByteEncodeUtil::decodeLiteUInt32( + const uint8_t* encodeIn, + size_t numValues, + uint32_t* valuesOut) { const uint8_t* encodeStart = encodeIn; @@ -267,13 +275,13 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int const int numBytesRemaining = b0 - kLiteCut2 + 2 - 1; // For unaligned access, do not use unaligned access for the last two values, - // (3rd last is safe because this value will have at least 2 bytes, followed by at worst two 1-byte values) - // otherwise we can access outside the bounds of the encoded array + // (3rd last is safe because this value will have at least 2 bytes, followed by at worst + // two 1-byte values) otherwise we can access outside the bounds of the encoded array // This prevents memory validation tools from causing an exception here if (SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS && i < numValues - 2) { const uint32_t mask = s_unalignedUInt32Mask[numBytesRemaining]; - //const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); + // const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); valuesOut[i] = (*(const uint32_t*)encodeIn) & mask; } else diff --git a/source/core/slang-byte-encode-util.h b/source/core/slang-byte-encode-util.h index 728f9ac2f..81fc0ef98 100644 --- a/source/core/slang-byte-encode-util.h +++ b/source/core/slang-byte-encode-util.h @@ -3,88 +3,90 @@ #include "slang-list.h" -namespace Slang { +namespace Slang +{ struct ByteEncodeUtil { enum { kMaxLiteEncodeUInt16 = 3, /// One byte for prefix, the remaining 2 bytes hold the value - kMaxLiteEncodeUInt32 = 5, /// One byte for prefix, the remaining 4 bytes hold the value + kMaxLiteEncodeUInt32 = 5, /// One byte for prefix, the remaining 4 bytes hold the value // Cut values for 'Lite' encoding style kLiteCut1 = 185, kLiteCut2 = 249, }; - /** Find the most significant bit for 8 bits - @param v The value to find most significant bit on - @return The most significant bit, or -1 if no bits are set - */ + /** Find the most significant bit for 8 bits + @param v The value to find most significant bit on + @return The most significant bit, or -1 if no bits are set + */ SLANG_FORCE_INLINE static int calcMsb8(uint32_t v); - - /** Find the most significant bit for 32 bits - @param v The value to find most significant bit on - @return The most significant bit, or -1 if no bits are set - */ + + /** Find the most significant bit for 32 bits + @param v The value to find most significant bit on + @return The most significant bit, or -1 if no bits are set + */ SLANG_FORCE_INLINE static int calcMsb32(uint32_t v); - - /** Calculates the 'most significant' byte ie the highest bytes that is non zero. - Note return value is *undefined* if in is 0. - @param in Value - cannot be 0. - @return The byte index of the highest byte that is non zero. - */ + + /** Calculates the 'most significant' byte ie the highest bytes that is non zero. + Note return value is *undefined* if in is 0. + @param in Value - cannot be 0. + @return The byte index of the highest byte that is non zero. + */ SLANG_FORCE_INLINE static int calcNonZeroMsByte32(uint32_t in); - /** Calculates the 'most significant' byte ie the highest bytes that is non zero. - @param in Value - cannot be 0. - @return The byte index of the highest byte that is non zero. - */ + /** Calculates the 'most significant' byte ie the highest bytes that is non zero. + @param in Value - cannot be 0. + @return The byte index of the highest byte that is non zero. + */ SLANG_FORCE_INLINE static int calcMsByte32(uint32_t in); - /// Calculate the size of encoding bytes + /// Calculate the size of encoding bytes static size_t calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num); - /// Calculate the size of a single value + /// Calculate the size of a single value static size_t calcEncodeLiteSizeUInt32(uint32_t in); - - /** Encodes a uint32_t as an integer - @return the number of bytes needed to encode */ + + /** Encodes a uint32_t as an integer + @return the number of bytes needed to encode */ static int encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]); - /** Decode a lite encoding. - @param in The lite encoded bytes - @param out Value constructed - @return number of bytes on in consumed */ + /** Decode a lite encoding. + @param in The lite encoded bytes + @param out Value constructed + @return number of bytes on in consumed */ static int decodeLiteUInt32(const uint8_t* in, uint32_t* out); - /** Encode an array of uint32_t - @param in The values to encode - @param num The amount of values to encode - @param encodeOut The buffer to hold the encoded value. MUST be large enough to hold the encoding - @return The size of the encoding in bytes - */ + /** Encode an array of uint32_t + @param in The values to encode + @param num The amount of values to encode + @param encodeOut The buffer to hold the encoded value. MUST be large enough to hold the encoding + @return The size of the encoding in bytes + */ static size_t encodeLiteUInt32(const uint32_t* in, size_t num, uint8_t* encodeOut); - /** Encode an array of uint32_t - @param in The values to encode - @param num The amount of values to encode - @param encodeOut The buffer to hold the encoded value. - */ + /** Encode an array of uint32_t + @param in The values to encode + @param num The amount of values to encode + @param encodeOut The buffer to hold the encoded value. + */ static void encodeLiteUInt32(const uint32_t* in, size_t num, List<uint8_t>& encodeOut); - /** Encode an array of uint32_t - @param encodeIn The encoded values - @param numValues The amount of values to be decoded (NOTE! This is the number of valuesOut, not encodeIn) - @param valuesOut The buffer to hold the encoded value. MUST be large enough to hold the encoding - @return The amount of bytes decoded - */ - static size_t decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut); + /** Encode an array of uint32_t + @param encodeIn The encoded values + @param numValues The amount of values to be decoded (NOTE! This is the number of valuesOut, not + encodeIn) + @param valuesOut The buffer to hold the encoded value. MUST be large enough to hold the encoding + @return The amount of bytes decoded + */ + static size_t decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut); - /// Table that maps 8 bits to it's most significant bit. If 0 returns -1. + /// Table that maps 8 bits to it's most significant bit. If 0 returns -1. static const int8_t s_msb8[256]; }; -#if SLANG_VC +#if SLANG_VC // Works on ARM and x86/64 on visual studio compiler // --------------------------------------------------------------------------- @@ -102,7 +104,7 @@ SLANG_FORCE_INLINE int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in) SLANG_FORCE_INLINE int ByteEncodeUtil::calcMsByte32(uint32_t in) { if (in == 0) - { + { return -1; } // Can use intrinsic @@ -113,7 +115,7 @@ SLANG_FORCE_INLINE int ByteEncodeUtil::calcMsByte32(uint32_t in) } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb8(uint32_t v) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb8(uint32_t v) { SLANG_ASSERT((v & 0xffffff00) == 0); if (v == 0) @@ -126,7 +128,7 @@ SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb8(uint32_t v) } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb32(uint32_t v) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb32(uint32_t v) { if (v == 0) { @@ -140,41 +142,36 @@ SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb32(uint32_t v) #else // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in) { - return (in & 0xffff0000) ? - ((in & 0xff000000) ? 3 : 2) : - ((in & 0x0000ff00) ? 1 : 0); + return (in & 0xffff0000) ? ((in & 0xff000000) ? 3 : 2) : ((in & 0x0000ff00) ? 1 : 0); } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsByte32(uint32_t in) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsByte32(uint32_t in) { - return (in & 0xffff0000) ? - ((in & 0xff000000) ? 3 : 2) : - ((in & 0x0000ff00) ? 1 : - ((in == 0) ? -1 : 0)); + return (in & 0xffff0000) ? ((in & 0xff000000) ? 3 : 2) + : ((in & 0x0000ff00) ? 1 : ((in == 0) ? -1 : 0)); } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb8(uint32_t v) -{ - SLANG_ASSERT((v & 0xffffff00) == 0); - return s_msb8[v]; +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb8(uint32_t v) +{ + SLANG_ASSERT((v & 0xffffff00) == 0); + return s_msb8[v]; } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb32(uint32_t v) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb32(uint32_t v) { - return (v & 0xffff0000) ? - ((v & 0xff000000) ? s_msb8[v >> 24] + 24 : s_msb8[v >> 16] + 16) : - ((v & 0x0000ff00) ? s_msb8[v >> 8] + 8 : s_msb8[v]); + return (v & 0xffff0000) ? ((v & 0xff000000) ? s_msb8[v >> 24] + 24 : s_msb8[v >> 16] + 16) + : ((v & 0x0000ff00) ? s_msb8[v >> 8] + 8 : s_msb8[v]); } #endif // --------------------------------------------------------------------------- -inline /* static */size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(uint32_t v) +inline /* static */ size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(uint32_t v) { if (v < kLiteCut1) { diff --git a/source/core/slang-castable.cpp b/source/core/slang-castable.cpp index f3c6541dd..ece87fe2b 100644 --- a/source/core/slang-castable.cpp +++ b/source/core/slang-castable.cpp @@ -1,11 +1,12 @@ // slang-castable.cpp #include "slang-castable.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CastableUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */ComPtr<ICastable> CastableUtil::getCastable(ISlangUnknown* unk) +/* static */ ComPtr<ICastable> CastableUtil::getCastable(ISlangUnknown* unk) { SLANG_ASSERT(unk); ComPtr<ICastable> castable; @@ -52,8 +53,7 @@ void* UnknownCastableAdapter::castAs(const Guid& guid) void* UnknownCastableAdapter::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IUnknownCastableAdapter::getTypeGuid()) { return static_cast<IUnknownCastableAdapter*>(this); diff --git a/source/core/slang-castable.h b/source/core/slang-castable.h index e2b9c4a8e..50b41766a 100644 --- a/source/core/slang-castable.h +++ b/source/core/slang-castable.h @@ -3,16 +3,15 @@ #define SLANG_CASTABLE_H +#include "../core/slang-com-object.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" -#include "../core/slang-com-object.h" - namespace Slang { // Dynamic cast of ICastable derived types -template <typename T> +template<typename T> SLANG_FORCE_INLINE T* dynamicCast(ICastable* castable) { if (castable) @@ -24,7 +23,7 @@ SLANG_FORCE_INLINE T* dynamicCast(ICastable* castable) } // as style cast -template <typename T> +template<typename T> SLANG_FORCE_INLINE T* as(ICastable* castable) { if (castable) @@ -36,34 +35,38 @@ SLANG_FORCE_INLINE T* as(ICastable* castable) } /* An interface for boxing values */ -class IBoxValueBase: public ICastable +class IBoxValueBase : public ICastable { - SLANG_COM_INTERFACE(0x8b4aad81, 0x4934, 0x4a67, { 0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54 }); + SLANG_COM_INTERFACE( + 0x8b4aad81, + 0x4934, + 0x4a67, + {0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54}); - /// Get the contained object + /// Get the contained object virtual SLANG_NO_THROW void* SLANG_MCALL getValuePtr() = 0; - /// Get the guid that represents the contained ref object + /// Get the guid that represents the contained ref object virtual SLANG_NO_THROW SlangUUID SLANG_MCALL getValueTypeGuid() = 0; }; -template <typename T> +template<typename T> class IBoxValue : public IBoxValueBase { - public: - +public: SLANG_FORCE_INLINE T& get() { return *reinterpret_cast<T*>(getValuePtr()); } SLANG_FORCE_INLINE T* getPtr() { return reinterpret_cast<T*>(getValuePtr()); } }; // Cast into a boxed value type -template <typename T> +template<typename T> SLANG_FORCE_INLINE IBoxValue<T>* asBoxValue(ICastable* castable) { IBoxValueBase* base = as<IBoxValueBase>(castable); - return (base && base->getValueTypeGuid() == T::getTypeGuid()) ? static_cast<IBoxValue<T>*>(base) : nullptr; + return (base && base->getValueTypeGuid() == T::getTypeGuid()) ? static_cast<IBoxValue<T>*>(base) + : nullptr; } -template <typename T> +template<typename T> class BoxValue : public ComBaseObject, public IBoxValue<T> { public: @@ -78,24 +81,23 @@ public: BoxValue() {} - explicit BoxValue(const T& rhs): - m_value(rhs) + explicit BoxValue(const T& rhs) + : m_value(rhs) { } protected: - void* getInterface(const Guid& guid); + void* getInterface(const Guid& guid); void* getObject(const Guid& guid); - + T m_value; }; // ------------------------------------------------------------ -template <typename T> +template<typename T> void* BoxValue<T>::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IBoxValueBase::getTypeGuid()) { return static_cast<IBoxValueBase*>(this); @@ -104,7 +106,7 @@ void* BoxValue<T>::getInterface(const Guid& guid) } // ------------------------------------------------------------ -template <typename T> +template<typename T> void* BoxValue<T>::getObject(const Guid& guid) { if (guid == T::getTypeGuid()) @@ -115,7 +117,7 @@ void* BoxValue<T>::getObject(const Guid& guid) } // ------------------------------------------------------------ -template <typename T> +template<typename T> void* BoxValue<T>::castAs(const Guid& guid) { if (auto ptr = getObject(guid)) @@ -124,22 +126,28 @@ void* BoxValue<T>::castAs(const Guid& guid) } return getInterface(guid); } - + /* 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 }); + 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 adapter such that types which aren't derived from ICastable, can be used as such. +/* 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) +* 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 { @@ -150,10 +158,13 @@ public: 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; } + virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() SLANG_OVERRIDE + { + return m_contained; + } - UnknownCastableAdapter(ISlangUnknown* unk): - m_contained(unk) + UnknownCastableAdapter(ISlangUnknown* unk) + : m_contained(unk) { SLANG_ASSERT(unk); } @@ -171,15 +182,15 @@ protected: struct CastableUtil { - /// Given an ISlangUnkown return as a castable interface. - /// Can use UnknownCastableAdapter if can't queryInterface unk to ICastable + /// Given an ISlangUnkown return as a castable interface. + /// Can use UnknownCastableAdapter if can't queryInterface unk to ICastable static ComPtr<ICastable> getCastable(ISlangUnknown* unk); }; -// A way to clone an interface (that derives from IClonable) such that it returns an interface +// A way to clone an interface (that derives from IClonable) such that it returns an interface // of the same type. -template <typename T> +template<typename T> SLANG_FORCE_INLINE ComPtr<T> cloneInterface(T* in) { SLANG_ASSERT(in); diff --git a/source/core/slang-char-encode.cpp b/source/core/slang-char-encode.cpp index 526c6c923..a27e7ba82 100644 --- a/source/core/slang-char-encode.cpp +++ b/source/core/slang-char-encode.cpp @@ -3,20 +3,23 @@ namespace Slang { -class Utf8CharEncoding : public CharEncoding +class Utf8CharEncoding : public CharEncoding { public: typedef CharEncoding Super; - virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override - { + virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override + { ioBuffer.addRange((const Byte*)slice.begin(), slice.getLength()); - } - virtual void decode(const Byte* bytes, int length, List<char>& ioChars) override - { + } + virtual void decode(const Byte* bytes, int length, List<char>& ioChars) override + { ioChars.addRange((const char*)bytes, length); - } - Utf8CharEncoding() : Super(CharEncodeType::UTF8) {} + } + Utf8CharEncoding() + : Super(CharEncodeType::UTF8) + { + } }; class Utf32CharEncoding : public CharEncoding @@ -24,93 +27,98 @@ class Utf32CharEncoding : public CharEncoding public: typedef CharEncoding Super; - virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override - { - Index ptr = 0; - while (ptr < slice.getLength()) - { - const Char32 codePoint = getUnicodePointFromUTF8([&]() -> Byte - { - if (ptr < slice.getLength()) - return slice[ptr++]; - else - return '\0'; - }); + virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override + { + Index ptr = 0; + while (ptr < slice.getLength()) + { + const Char32 codePoint = getUnicodePointFromUTF8( + [&]() -> Byte + { + if (ptr < slice.getLength()) + return slice[ptr++]; + else + return '\0'; + }); // Note: Assumes byte order is same as arch byte order ioBuffer.addRange((const Byte*)&codePoint, 4); - } - } - virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override - { + } + } + virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override + { // Note: Assumes bytes is Char32 aligned SLANG_ASSERT((size_t(bytes) & 3) == 0); - const Char32* content = (const Char32*)bytes; - for (int i = 0; i < (length >> 2); i++) - { - char buf[5]; - int count = encodeUnicodePointToUTF8(content[i], buf); + const Char32* content = (const Char32*)bytes; + for (int i = 0; i < (length >> 2); i++) + { + char buf[5]; + int count = encodeUnicodePointToUTF8(content[i], buf); for (int j = 0; j < count; j++) ioBuffer.addRange(buf, count); - } - } + } + } - Utf32CharEncoding() : Super(CharEncodeType::UTF32) {} + Utf32CharEncoding() + : Super(CharEncodeType::UTF32) + { + } }; -class Utf16CharEncoding : public CharEncoding //UTF16 +class Utf16CharEncoding : public CharEncoding // UTF16 { public: typedef CharEncoding Super; - Utf16CharEncoding(bool reverseOrder): - Super(reverseOrder ? CharEncodeType::UTF16Reversed : CharEncodeType::UTF16), - m_reverseOrder(reverseOrder) - {} - virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override - { - Index index = 0; - while (index < slice.getLength()) - { - const Char32 codePoint = getUnicodePointFromUTF8([&]() -> Byte - { - if (index < slice.getLength()) - return slice[index++]; - else - return '\0'; - }); - - Char16 buffer[2]; - int count; - if (!m_reverseOrder) - count = encodeUnicodePointToUTF16(codePoint, buffer); - else - count = encodeUnicodePointToUTF16Reversed(codePoint, buffer); + Utf16CharEncoding(bool reverseOrder) + : Super(reverseOrder ? CharEncodeType::UTF16Reversed : CharEncodeType::UTF16) + , m_reverseOrder(reverseOrder) + { + } + virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override + { + Index index = 0; + while (index < slice.getLength()) + { + const Char32 codePoint = getUnicodePointFromUTF8( + [&]() -> Byte + { + if (index < slice.getLength()) + return slice[index++]; + else + return '\0'; + }); + + Char16 buffer[2]; + int count; + if (!m_reverseOrder) + count = encodeUnicodePointToUTF16(codePoint, buffer); + else + count = encodeUnicodePointToUTF16Reversed(codePoint, buffer); ioBuffer.addRange((const Byte*)buffer, count * 2); - } - } - virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override - { - Index index = 0; - while (index < length) - { - auto readByte = [&]() -> Byte - { - return (index < length) ? bytes[index++] : Byte(0); - }; - const Char32 codePoint = m_reverseOrder ? - getUnicodePointFromUTF16Reversed(readByte) : - getUnicodePointFromUTF16(readByte); - - char buf[5]; - int count = encodeUnicodePointToUTF8(codePoint, buf); - ioBuffer.addRange((const char*)buf, count); - } - } + } + } + virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override + { + Index index = 0; + while (index < length) + { + auto readByte = [&]() -> Byte { return (index < length) ? bytes[index++] : Byte(0); }; + const Char32 codePoint = m_reverseOrder ? getUnicodePointFromUTF16Reversed(readByte) + : getUnicodePointFromUTF16(readByte); + + char buf[5]; + int count = encodeUnicodePointToUTF8(codePoint, buf); + ioBuffer.addRange((const char*)buf, count); + } + } private: bool m_reverseOrder = false; }; -/* static */CharEncodeType CharEncoding::determineEncoding(const Byte* bytes, size_t bytesCount, size_t& outOffset) +/* static */ CharEncodeType CharEncoding::determineEncoding( + const Byte* bytes, + size_t bytesCount, + size_t& outOffset) { // TODO(JS): Assumes the bytes are suitably aligned @@ -137,7 +145,7 @@ private: // If we don't have a 'mark' byte then we are bit stumped. We'll look for // null (non-terminator) bytes and assume they mean we have a 16-bit encoding - for(size_t i = 0; i < (bytesCount-1); i += 2) + for (size_t i = 0; i < (bytesCount - 1); i += 2) { #if SLANG_LITTLE_ENDIAN const auto low = bytes[i]; @@ -164,41 +172,42 @@ static Utf16CharEncoding _utf16Encoding(false); static Utf16CharEncoding _utf16EncodingReversed(true); static Utf32CharEncoding _utf32Encoding; -/* static */CharEncoding* const CharEncoding::g_encoding[Index(CharEncodeType::CountOf)] -{ - &_utf8Encoding, // UTF8, - &_utf16Encoding, // UTF16, - &_utf16EncodingReversed, // UTF16Reversed, - &_utf32Encoding, // UTF32, +/* static */ CharEncoding* const CharEncoding::g_encoding[Index(CharEncodeType::CountOf)]{ + &_utf8Encoding, // UTF8, + &_utf16Encoding, // UTF16, + &_utf16EncodingReversed, // UTF16Reversed, + &_utf32Encoding, // UTF32, }; CharEncoding* CharEncoding::UTF8 = &_utf8Encoding; CharEncoding* CharEncoding::UTF16 = &_utf16Encoding; CharEncoding* CharEncoding::UTF16Reversed = &_utf16EncodingReversed; CharEncoding* CharEncoding::UTF32 = &_utf32Encoding; - + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UTF8Util !!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */Index UTF8Util::calcCodePointCount(const UnownedStringSlice& in) +/* static */ Index UTF8Util::calcCodePointCount(const UnownedStringSlice& in) { Index count = 0; // Analyse with bytes... const int8_t* cur = (const int8_t*)in.begin(); - const int8_t*const end = (const int8_t*)in.end(); + const int8_t* const end = (const int8_t*)in.end(); while (cur < end) { const auto c = *cur++; - + count++; // If c < 0 it means the top bit is set... which means we have multiple bytes if (c < 0) { // https://en.wikipedia.org/wiki/UTF-8 - // All continuation bytes contain exactly six bits from the code point.So the next six bits of the code point - /// are stored in the low order six bits of the next byte, and 10 is stored in the high order two bits to + // All continuation bytes contain exactly six bits from the code point.So the next six + // bits of the code point + /// are stored in the low order six bits of the next byte, and 10 is stored in the high + /// order two bits to // mark it as a continuation byte(so 10000010). while (cur < end && (*cur & 0xc0) == 0x80) @@ -217,7 +226,8 @@ Index UTF8Util::calcUTF16CharCount(const UnownedStringSlice& in) Index readPtr = 0; for (;;) { - int c = getUnicodePointFromUTF8([&]() -> Byte + int c = getUnicodePointFromUTF8( + [&]() -> Byte { if (readPtr < in.getLength()) return in[readPtr++]; diff --git a/source/core/slang-char-encode.h b/source/core/slang-char-encode.h index a7cd501ab..74968a6ab 100644 --- a/source/core/slang-char-encode.h +++ b/source/core/slang-char-encode.h @@ -1,13 +1,13 @@ #ifndef SLANG_CORE_CHAR_ENCODE_H #define SLANG_CORE_CHAR_ENCODE_H -#include "slang-secure-crt.h" #include "slang-basic.h" +#include "slang-secure-crt.h" namespace Slang { -// NOTE! Order must be kept the same to match up with +// NOTE! Order must be kept the same to match up with enum class CharEncodeType { UTF8, @@ -17,7 +17,7 @@ enum class CharEncodeType CountOf, }; -template <typename ReadByteFunc> +template<typename ReadByteFunc> Char32 getUnicodePointFromUTF8(const ReadByteFunc& readByte) { Char32 codePoint = 0; @@ -38,7 +38,7 @@ Char32 getUnicodePointFromUTF8(const ReadByteFunc& readByte) return codePoint; } -template <typename ReadByteFunc> +template<typename ReadByteFunc> Char32 getUnicodePointFromUTF16(const ReadByteFunc& readByte) { uint32_t byte0 = Byte(readByte()); @@ -55,7 +55,7 @@ Char32 getUnicodePointFromUTF16(const ReadByteFunc& readByte) return Char32(word0); } -template <typename ReadByteFunc> +template<typename ReadByteFunc> Char32 getUnicodePointFromUTF16Reversed(const ReadByteFunc& readByte) { uint32_t byte0 = Byte(readByte()); @@ -72,7 +72,7 @@ Char32 getUnicodePointFromUTF16Reversed(const ReadByteFunc& readByte) return Char32(word0); } -template <typename ReadByteFunc> +template<typename ReadByteFunc> Char32 getUnicodePointFromUTF32(const ReadByteFunc& readByte) { uint32_t byte0 = Byte(readByte()); @@ -163,52 +163,55 @@ static const Char16 kUTF16ReversedHeader = 0xFFFE; class CharEncoding { public: - static CharEncoding* UTF8,* UTF16,* UTF16Reversed,* UTF32; + static CharEncoding *UTF8, *UTF16, *UTF16Reversed, *UTF32; - /// Encode Utf8 held in slice append into ioBuffer + /// Encode Utf8 held in slice append into ioBuffer virtual void encode(const UnownedStringSlice& str, List<Byte>& ioBuffer) = 0; - /// Decode buffer into Utf8 held in ioBuffer + /// Decode buffer into Utf8 held in ioBuffer virtual void decode(const Byte* buffer, int length, List<char>& ioBuffer) = 0; - virtual ~CharEncoding() {} + virtual ~CharEncoding() {} - /// Get the encoding type + /// Get the encoding type CharEncodeType getEncodingType() const { return m_encodingType; } - /// Given some bytes determines a character encoding type, based on the initial bytes. - /// If can't be determined will assume UTF8. - /// Outputs the offset to the first non mark in outOffset - static CharEncodeType determineEncoding(const Byte* bytes, size_t bytesCount, size_t& outOffset); + /// Given some bytes determines a character encoding type, based on the initial bytes. + /// If can't be determined will assume UTF8. + /// Outputs the offset to the first non mark in outOffset + static CharEncodeType determineEncoding( + const Byte* bytes, + size_t bytesCount, + size_t& outOffset); - /// Get the + /// Get the static CharEncoding* getEncoding(CharEncodeType type) { return g_encoding[Index(type)]; } - CharEncoding(CharEncodeType encodingType) : - m_encodingType(encodingType) + CharEncoding(CharEncodeType encodingType) + : m_encodingType(encodingType) { } protected: - CharEncodeType m_encodingType; - static CharEncoding*const g_encoding[Index(CharEncodeType::CountOf)]; + static CharEncoding* const g_encoding[Index(CharEncodeType::CountOf)]; }; struct UTF8Util { - /// Given a slice calculate the number of code points (unicode chars) - /// - /// NOTE! This doesn't check the *validity* of code points/encoding. - /// Non valid utf8 input or ending starting in partial characters, will produce - /// undefined results without error. + /// Given a slice calculate the number of code points (unicode chars) + /// + /// NOTE! This doesn't check the *validity* of code points/encoding. + /// Non valid utf8 input or ending starting in partial characters, will produce + /// undefined results without error. static Index calcCodePointCount(const UnownedStringSlice& in); - /// Given a slice in UTF8, calculate the number of UTF16 characters needed to represent the string. + /// Given a slice in UTF8, calculate the number of UTF16 characters needed to represent the + /// string. static Index calcUTF16CharCount(const UnownedStringSlice& in); }; -} +} // namespace Slang #endif diff --git a/source/core/slang-char-util.cpp b/source/core/slang-char-util.cpp index ea9e6dbf2..f9c61ec03 100644 --- a/source/core/slang-char-util.cpp +++ b/source/core/slang-char-util.cpp @@ -1,8 +1,9 @@ #include "slang-char-util.h" -namespace Slang { +namespace Slang +{ -/* static */CharUtil::CharFlagMap CharUtil::makeCharFlagMap() +/* static */ CharUtil::CharFlagMap CharUtil::makeCharFlagMap() { CharUtil::CharFlagMap map; memset(&map, 0, sizeof(map)); @@ -46,11 +47,11 @@ namespace Slang { return map; } -/* static */int CharUtil::_ensureLink() +/* static */ int CharUtil::_ensureLink() { return makeCharFlagMap().flags[0]; } -/* static */const CharUtil::CharFlagMap CharUtil::g_charFlagMap = makeCharFlagMap(); +/* static */ const CharUtil::CharFlagMap CharUtil::g_charFlagMap = makeCharFlagMap(); } // namespace Slang diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h index 88af24426..896eb6956 100644 --- a/source/core/slang-char-util.h +++ b/source/core/slang-char-util.h @@ -3,7 +3,8 @@ #include "slang-string.h" -namespace Slang { +namespace Slang +{ struct CharUtil { @@ -12,12 +13,13 @@ struct CharUtil { enum Enum : Flags { - Upper = 0x01, ///< A-Z - Lower = 0x02, ///< a-z - Digit = 0x04, ///< 0-9 - HorizontalWhitespace = 0x08, ///< Whitespace that can appear horizontally (ie excluding CR/LF) - HexDigit = 0x10, ///< 0-9, a-f, A-F - VerticalWhitespace = 0x20, ///< \n \r + Upper = 0x01, ///< A-Z + Lower = 0x02, ///< a-z + Digit = 0x04, ///< 0-9 + HorizontalWhitespace = + 0x08, ///< Whitespace that can appear horizontally (ie excluding CR/LF) + HexDigit = 0x10, ///< 0-9, a-f, A-F + VerticalWhitespace = 0x20, ///< \n \r }; }; @@ -26,40 +28,62 @@ struct CharUtil SLANG_FORCE_INLINE static bool isUpper(char c) { return c >= 'A' && c <= 'Z'; } SLANG_FORCE_INLINE static bool isHorizontalWhitespace(char c) { return c == ' ' || c == '\t'; } SLANG_FORCE_INLINE static bool isVerticalWhitespace(char c) { return c == '\n' || c == '\r'; } - SLANG_FORCE_INLINE static bool isWhitespace(char c) { return (getFlags(c) & (Flag::HorizontalWhitespace | Flag::VerticalWhitespace)) != 0; } + SLANG_FORCE_INLINE static bool isWhitespace(char c) + { + return (getFlags(c) & (Flag::HorizontalWhitespace | Flag::VerticalWhitespace)) != 0; + } - /// True if it's alpha - SLANG_FORCE_INLINE static bool isAlpha(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower)) != 0; } - /// True if it's alpha or a digit - SLANG_FORCE_INLINE static bool isAlphaOrDigit(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower | Flag::Digit)) != 0; } + /// True if it's alpha + SLANG_FORCE_INLINE static bool isAlpha(char c) + { + return (getFlags(c) & (Flag::Upper | Flag::Lower)) != 0; + } + /// True if it's alpha or a digit + SLANG_FORCE_INLINE static bool isAlphaOrDigit(char c) + { + return (getFlags(c) & (Flag::Upper | Flag::Lower | Flag::Digit)) != 0; + } - /// True if the character is a valid hex character - SLANG_FORCE_INLINE static bool isHexDigit(char c) { return (getFlags(c) & Flag::HexDigit) != 0; } + /// True if the character is a valid hex character + SLANG_FORCE_INLINE static bool isHexDigit(char c) + { + return (getFlags(c) & Flag::HexDigit) != 0; + } - /// True if the character is an octal digit + /// True if the character is an octal digit SLANG_FORCE_INLINE static bool isOctalDigit(char c) { return c >= '0' && c <= '7'; } - /// For a given character get the associated flags + /// For a given character get the associated flags SLANG_FORCE_INLINE static Flags getFlags(char c) { return g_charFlagMap.flags[size_t(c)]; } - /// Given a character return the lower case equivalent - SLANG_FORCE_INLINE static char toLower(char c) { return (c >= 'A' && c <= 'Z') ? (c -'A' + 'a') : c; } - /// Given a character return the upper case equivalent - SLANG_FORCE_INLINE static char toUpper(char c) { return (c >= 'a' && c <= 'z') ? (c -'a' + 'A') : c; } + /// Given a character return the lower case equivalent + SLANG_FORCE_INLINE static char toLower(char c) + { + return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; + } + /// Given a character return the upper case equivalent + SLANG_FORCE_INLINE static char toUpper(char c) + { + return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c; + } - /// Given a value between 0-15 inclusive returns the hex digit. Uses lower case hex. - SLANG_FORCE_INLINE static char getHexChar(Index i) { SLANG_ASSERT((i & ~Index(0xf)) == 0); return char(i >= 10 ? (i - 10 + 'a') : (i + '0')); } + /// Given a value between 0-15 inclusive returns the hex digit. Uses lower case hex. + SLANG_FORCE_INLINE static char getHexChar(Index i) + { + SLANG_ASSERT((i & ~Index(0xf)) == 0); + return char(i >= 10 ? (i - 10 + 'a') : (i + '0')); + } - /// Returns the value if c interpretted as a decimal digit - /// If c is not a valid digit returns -1 + /// Returns the value if c interpretted as a decimal digit + /// If c is not a valid digit returns -1 inline static int getDecimalDigitValue(char c) { return isDigit(c) ? (c - '0') : -1; } - /// Returns the value if c interpretted as a hex digit - /// If c is not a valid hex returns -1 + /// Returns the value if c interpretted as a hex digit + /// If c is not a valid hex returns -1 inline static int getHexDigitValue(char c); - - /// Returns the value if c interpretted as a octal digit - /// If c is not a valid octal returns -1 + + /// Returns the value if c interpretted as a octal digit + /// If c is not a valid octal returns -1 inline static int getOctalDigitValue(char c) { return isOctalDigit(c) ? (c - '0') : -1; } struct CharFlagMap @@ -69,16 +93,17 @@ struct CharUtil static CharFlagMap makeCharFlagMap(); - // HACK! - // JS: Many of the inlined functions of CharUtil just access a global map. That referencing this global is *NOT* enough to - // link correctly with CharUtil on linux for a shared library. Caling this function can force linkage. + // HACK! + // JS: Many of the inlined functions of CharUtil just access a global map. That referencing this + // global is *NOT* enough to link correctly with CharUtil on linux for a shared library. Caling + // this function can force linkage. static int _ensureLink(); static const CharFlagMap g_charFlagMap; }; - + // ------------------------------------------------------------------------------------ -inline /* static */int CharUtil::getHexDigitValue(char c) +inline /* static */ int CharUtil::getHexDigitValue(char c) { if (c >= '0' && c <= '9') { diff --git a/source/core/slang-chunked-list.h b/source/core/slang-chunked-list.h index d414eaefb..95324f8c9 100644 --- a/source/core/slang-chunked-list.h +++ b/source/core/slang-chunked-list.h @@ -1,16 +1,15 @@ #ifndef SLANG_CORE_CHUNKED_LIST_H #define SLANG_CORE_CHUNKED_LIST_H -#include "slang.h" - #include "slang-allocator.h" #include "slang-array-view.h" #include "slang-math.h" +#include "slang.h" namespace Slang { // Items stored in a ChunkedList are guaranteed to have fixed address. -template <typename T, uint32_t defaultChunkSize = 16, typename TAllocator = StandardAllocator> +template<typename T, uint32_t defaultChunkSize = 16, typename TAllocator = StandardAllocator> class ChunkedList { private: @@ -21,10 +20,7 @@ private: uint32_t size = 0; uint32_t capacity = defaultChunkSize; Chunk* next = nullptr; - T* begin() - { - return reinterpret_cast<T*>(this + 1); - } + T* begin() { return reinterpret_cast<T*>(this + 1); } T* end() { return begin() + size; } }; @@ -60,24 +56,26 @@ private: public: typedef ChunkedList<T, defaultChunkSize, TAllocator> ThisType; ChunkedList() - : m_lastChunk(&m_firstChunk) - , m_count(0) - {} - template <typename... Args> ChunkedList(const T& val, Args... args) { _init(val, args...); } + : m_lastChunk(&m_firstChunk), m_count(0) + { + } + template<typename... Args> + ChunkedList(const T& val, Args... args) + { + _init(val, args...); + } ChunkedList(const ThisType& list) - : m_lastChunk(&m_firstChunk) - , m_count(0) + : m_lastChunk(&m_firstChunk), m_count(0) { this->operator=(list); } ChunkedList(ThisType&& list) - : m_lastChunk(&m_firstChunk) - , m_count(0) + : m_lastChunk(&m_firstChunk), m_count(0) { this->operator=(static_cast<ThisType&&>(list)); } ~ChunkedList() { _deallocateBuffer(); } - template <int _otherShortListSize, typename TOtherAllocator> + template<int _otherShortListSize, typename TOtherAllocator> ThisType& operator=(const ChunkedList<T, _otherShortListSize, TOtherAllocator>& list) { clearAndDeallocate(); @@ -213,7 +211,8 @@ public: return result; } - template <typename TContainer> T* addRange(const TContainer& list) + template<typename TContainer> + T* addRange(const TContainer& list) { Chunk* chunk = _maybeReserveForAdd((uint32_t)list.getCount()); auto result = chunk->begin() + chunk->size; @@ -235,7 +234,6 @@ public: } private: - Index m_count = 0; ///< The amount of elements FirstChunk m_firstChunk; Chunk* m_lastChunk = &m_firstChunk; @@ -262,7 +260,8 @@ private: return AllocateMethod<T, TAllocator>::deallocateArray(ptr, count); } - template <typename... Args> void _init(const T& val, Args... args) + template<typename... Args> + void _init(const T& val, Args... args) { add(val); _init(args...); diff --git a/source/core/slang-com-object.h b/source/core/slang-com-object.h index 617b7ccca..801af61a4 100644 --- a/source/core/slang-com-object.h +++ b/source/core/slang-com-object.h @@ -2,34 +2,35 @@ #define SLANG_COM_OBJECT_H #include "slang-basic.h" + #include <atomic> namespace Slang { -/// A base class for COM interfaces that require atomic ref counting +/// A base class for COM interfaces that require atomic ref counting /// and are *NOT* derived from RefObject class ComBaseObject { public: - - /// If assigned the the ref count is *NOT* copied + /// If assigned the the ref count is *NOT* copied ComBaseObject& operator=(const ComBaseObject&) { return *this; } - /// Copy Ctor, does not copy ref count - ComBaseObject(const ComBaseObject&) : - m_refCount(0) - {} + /// Copy Ctor, does not copy ref count + ComBaseObject(const ComBaseObject&) + : m_refCount(0) + { + } - /// Default Ctor sets with no refs + /// Default Ctor sets with no refs ComBaseObject() : m_refCount(0) - {} + { + } - /// Dtor needs to be virtual to avoid needing to - /// Implement release for all derived types. - virtual ~ComBaseObject() - {} + /// Dtor needs to be virtual to avoid needing to + /// Implement release for all derived types. + virtual ~ComBaseObject() {} protected: inline uint32_t _releaseImpl(); @@ -50,7 +51,7 @@ inline uint32_t ComBaseObject::_releaseImpl() return count; } -#define SLANG_COM_BASE_IUNKNOWN_QUERY_INTERFACE \ +#define SLANG_COM_BASE_IUNKNOWN_QUERY_INTERFACE \ SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) \ SLANG_OVERRIDE \ { \ @@ -63,10 +64,16 @@ inline uint32_t ComBaseObject::_releaseImpl() } \ return SLANG_E_NO_INTERFACE; \ } -#define SLANG_COM_BASE_IUNKNOWN_ADD_REF \ - SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return ++m_refCount; } -#define SLANG_COM_BASE_IUNKNOWN_RELEASE \ - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return _releaseImpl(); } +#define SLANG_COM_BASE_IUNKNOWN_ADD_REF \ + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE \ + { \ + return ++m_refCount; \ + } +#define SLANG_COM_BASE_IUNKNOWN_RELEASE \ + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE \ + { \ + return _releaseImpl(); \ + } #define SLANG_COM_BASE_IUNKNOWN_ALL \ SLANG_COM_BASE_IUNKNOWN_QUERY_INTERFACE \ SLANG_COM_BASE_IUNKNOWN_ADD_REF \ @@ -82,11 +89,12 @@ protected: public: ComObject() : comRefCount(0) - {} - ComObject(const ComObject& rhs) : - RefObject(rhs), - comRefCount(0) - {} + { + } + ComObject(const ComObject& rhs) + : RefObject(rhs), comRefCount(0) + { + } ComObject& operator=(const ComObject&) { return *this; } @@ -125,10 +133,16 @@ public: } \ return SLANG_E_NO_INTERFACE; \ } -#define SLANG_COM_OBJECT_IUNKNOWN_ADD_REF \ - SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return addRefImpl(); } -#define SLANG_COM_OBJECT_IUNKNOWN_RELEASE \ - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return releaseImpl(); } +#define SLANG_COM_OBJECT_IUNKNOWN_ADD_REF \ + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE \ + { \ + return addRefImpl(); \ + } +#define SLANG_COM_OBJECT_IUNKNOWN_RELEASE \ + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE \ + { \ + return releaseImpl(); \ + } #define SLANG_COM_OBJECT_IUNKNOWN_ALL \ SLANG_COM_OBJECT_IUNKNOWN_QUERY_INTERFACE \ SLANG_COM_OBJECT_IUNKNOWN_ADD_REF \ diff --git a/source/core/slang-command-line.cpp b/source/core/slang-command-line.cpp index bfd9ed11a..8269d37c5 100644 --- a/source/core/slang-command-line.cpp +++ b/source/core/slang-command-line.cpp @@ -1,17 +1,17 @@ // slang-command-line.cpp #include "slang-command-line.h" +#include "slang-com-helper.h" #include "slang-process.h" - -#include "slang-string.h" #include "slang-string-escape-util.h" #include "slang-string-util.h" +#include "slang-string.h" -#include "slang-com-helper.h" - -namespace Slang { +namespace Slang +{ -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExecutableLocation !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExecutableLocation !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ void ExecutableLocation::set(const String& dir, const String& name) { diff --git a/source/core/slang-command-line.h b/source/core/slang-command-line.h index 163daf710..804266ad1 100644 --- a/source/core/slang-command-line.h +++ b/source/core/slang-command-line.h @@ -2,10 +2,11 @@ #ifndef SLANG_COMMAND_LINE_H #define SLANG_COMMAND_LINE_H -#include "slang-string.h" #include "slang-list.h" +#include "slang-string.h" -namespace Slang { +namespace Slang +{ struct ExecutableLocation { @@ -13,43 +14,67 @@ struct ExecutableLocation enum Type { - Unknown, ///< Not specified - Path, ///< The executable is set as a path (ie won't be searched for) - Name, ///< The executable is passed as a name which will be searched for + Unknown, ///< Not specified + Path, ///< The executable is set as a path (ie won't be searched for) + Name, ///< The executable is passed as a name which will be searched for }; - /// Set the executable path. - /// NOTE! On some targets the executable path *must* include an extension to be able to start as a process - void setPath(const String& path) { m_type = Type::Path; m_pathOrName = path; } + /// Set the executable path. + /// NOTE! On some targets the executable path *must* include an extension to be able to start as + /// a process + void setPath(const String& path) + { + m_type = Type::Path; + m_pathOrName = path; + } - /// Set a filename (such that the path will be looked up) - void setName(const String& filename) { m_type = Type::Name; m_pathOrName = filename; } + /// Set a filename (such that the path will be looked up) + void setName(const String& filename) + { + m_type = Type::Name; + m_pathOrName = filename; + } - void set(Type type, const String& pathOrName) { m_type = type; m_pathOrName = pathOrName; } + void set(Type type, const String& pathOrName) + { + m_type = type; + m_pathOrName = pathOrName; + } - /// Set the executable path from a base directory and an executable name (no suffix such as '.exe' needed) + /// Set the executable path from a base directory and an executable name (no suffix such as + /// '.exe' needed) void set(const String& dir, const String& name); - /// Determines if it's a name or a path when it sets + /// Determines if it's a name or a path when it sets void set(const String& nameOrPath); - /// Append as text to out. + /// Append as text to out. void append(StringBuilder& out) const; - /// Reset state to be same as ctor - void reset() { m_type = Type::Unknown; m_pathOrName = String(); } + /// Reset state to be same as ctor + void reset() + { + m_type = Type::Unknown; + m_pathOrName = String(); + } - /// Equality means exactly the same definition. - /// *NOT* that exactly the same executable is specified - bool operator==(const ThisType& rhs) const { return m_type == rhs.m_type && m_pathOrName == rhs.m_pathOrName; } + /// Equality means exactly the same definition. + /// *NOT* that exactly the same executable is specified + bool operator==(const ThisType& rhs) const + { + return m_type == rhs.m_type && m_pathOrName == rhs.m_pathOrName; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } ExecutableLocation() {} - ExecutableLocation(const String& dir, const String& name) { set(dir, name); } - ExecutableLocation(Type type, const String& pathOrName) : m_type(type), m_pathOrName(pathOrName) {} + ExecutableLocation(const String& dir, const String& name) { set(dir, name); } + ExecutableLocation(Type type, const String& pathOrName) + : m_type(type), m_pathOrName(pathOrName) + { + } explicit ExecutableLocation(const String& nameOrPath) { set(nameOrPath); } - + Type m_type = Type::Unknown; String m_pathOrName; }; @@ -58,42 +83,52 @@ struct CommandLine { typedef CommandLine ThisType; - /// Add args - assumed unescaped + /// Add args - assumed unescaped void addArg(const String& in) { m_args.add(in); } - void addArgs(const String* args, Int argsCount) { for (Int i = 0; i < argsCount; ++i) addArg(args[i]); } + void addArgs(const String* args, Int argsCount) + { + for (Int i = 0; i < argsCount; ++i) + addArg(args[i]); + } void addArgIfNotFound(const String& in); - /// Find the index of an arg which is exact match for slice - SLANG_INLINE Index findArgIndex(const UnownedStringSlice& slice) const { return m_args.indexOf(slice); } + /// Find the index of an arg which is exact match for slice + SLANG_INLINE Index findArgIndex(const UnownedStringSlice& slice) const + { + return m_args.indexOf(slice); + } - /// For handling args where the switch is placed directly in front of the path - void addPrefixPathArg(const char* prefix, const String& path, const char* pathPostfix = nullptr); + /// For handling args where the switch is placed directly in front of the path + void addPrefixPathArg( + const char* prefix, + const String& path, + const char* pathPostfix = nullptr); - /// Get the total number of args + /// Get the total number of args SLANG_FORCE_INLINE Index getArgCount() const { return m_args.getCount(); } - /// Reset to the initial state - void reset() { *this = CommandLine(); } + /// Reset to the initial state + void reset() { *this = CommandLine(); } - /// Append the args + /// Append the args void appendArgs(StringBuilder& out) const; - /// Append the command line to out + /// Append the command line to out void append(StringBuilder& out) const; - /// convert into a string + /// convert into a string String toString() const; - /// Convert just the args to string + /// Convert just the args to string String toStringArgs() const; - /// Set an executable location + /// Set an executable location void setExecutableLocation(const ExecutableLocation& loc) { m_executableLocation = loc; } - ExecutableLocation m_executableLocation; ///< The executable location - List<String> m_args; ///< The arguments (Stored *unescaped*) + ExecutableLocation m_executableLocation; ///< The executable location + List<String> m_args; ///< The arguments (Stored *unescaped*) }; -} +} // namespace Slang #endif // SLANG_COMMAND_LINE_H diff --git a/source/core/slang-command-options-writer.cpp b/source/core/slang-command-options-writer.cpp index afa46db64..f46bcc56c 100644 --- a/source/core/slang-command-options-writer.cpp +++ b/source/core/slang-command-options-writer.cpp @@ -2,18 +2,26 @@ #include "slang-command-options-writer.h" -#include "slang-string-util.h" -#include "slang-char-util.h" #include "slang-byte-encode-util.h" +#include "slang-char-util.h" +#include "slang-string-util.h" + +namespace Slang +{ -namespace Slang { - -namespace { // anonymous +namespace +{ // anonymous typedef CommandOptionsWriter::Style Style; -} // anonymous +} // namespace -static bool _isMarkdown(Style style) { return style == Style::Markdown || style == Style::NoLinkMarkdown; } -static bool _hasLinks(Style style) { return style == Style::Markdown; } +static bool _isMarkdown(Style style) +{ + return style == Style::Markdown || style == Style::NoLinkMarkdown; +} +static bool _hasLinks(Style style) +{ + return style == Style::Markdown; +} /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MarkdownCommandOptionsWriter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -25,17 +33,17 @@ public: typedef uint32_t LinkFlags; struct LinkFlag { - enum Enum + enum Enum { Category = 0x1, - Option = 0x2, + Option = 0x2, All = Category | Option, }; }; - MarkdownCommandOptionsWriter(const Options& options): - Super(options) + MarkdownCommandOptionsWriter(const Options& options) + : Super(options) { } @@ -45,15 +53,17 @@ protected: virtual void appendDescriptionImpl() SLANG_OVERRIDE; void _appendParagraph(const UnownedStringSlice& text, LinkFlags flags = LinkFlag::All); - void _appendParagraph(const ConstArrayView<UnownedStringSlice>& words, LinkFlags flags = LinkFlag::All); + void _appendParagraph( + const ConstArrayView<UnownedStringSlice>& words, + LinkFlags flags = LinkFlag::All); - void _appendMaybeLink(const UnownedStringSlice& word, LinkFlags linkFlags); + void _appendMaybeLink(const UnownedStringSlice& word, LinkFlags linkFlags); void _appendText(const UnownedStringSlice& text); void _appendDescriptionForCategory(Index categoryIndex); UnownedStringSlice _getLinkName(CommandOptions::LookupKind kind, Index index); UnownedStringSlice _getLinkName(const NameKey& key, Index index); - + void _appendQuickLinks(); bool m_hasLinks = false; @@ -91,15 +101,15 @@ static bool _needsMarkdownEscape(const UnownedStringSlice& text) { switch (c) { - case '<': - case '>': - case '&': - case '[': - case ']': + case '<': + case '>': + case '&': + case '[': + case ']': { return true; } - default: break; + default: break; } } @@ -115,12 +125,12 @@ void _appendEscapedMarkdown(const UnownedStringSlice& text, StringBuilder& ioBuf { switch (c) { - case '<': ioBuf << "<"; break; - case '>': ioBuf << ">"; break; - case '&': ioBuf << "&"; break; - case '[': ioBuf << "\\["; break; - case ']': ioBuf << "\\]"; break; - default: ioBuf << c; + case '<': ioBuf << "<"; break; + case '>': ioBuf << ">"; break; + case '&': ioBuf << "&"; break; + case '[': ioBuf << "\\["; break; + case ']': ioBuf << "\\]"; break; + default: ioBuf << c; } } } @@ -149,7 +159,9 @@ void MarkdownCommandOptionsWriter::_appendQuickLinks() m_builder << "\n"; } -void MarkdownCommandOptionsWriter::_appendParagraph(const UnownedStringSlice& text, LinkFlags linkFlags) +void MarkdownCommandOptionsWriter::_appendParagraph( + const UnownedStringSlice& text, + LinkFlags linkFlags) { List<UnownedStringSlice> words; StringUtil::splitOnWhitespace(text, words); @@ -171,12 +183,16 @@ static UnownedStringSlice _trimPunctuation(const UnownedStringSlice& word) const char* start = word.begin(); const char* end = word.end(); - while (start < end && _isStartPunctionation(*start)) start++; - while (end > start && _isEndPunctionation(end[-1])) --end; + while (start < end && _isStartPunctionation(*start)) + start++; + while (end > start && _isEndPunctionation(end[-1])) + --end; return UnownedStringSlice(start, end); } -void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& inWord, LinkFlags linkFlags) +void MarkdownCommandOptionsWriter::_appendMaybeLink( + const UnownedStringSlice& inWord, + LinkFlags linkFlags) { if (linkFlags) { @@ -190,17 +206,27 @@ void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& in // Look for options if (trimmedWord[0] == '-' && (linkFlags & LinkFlag::Option)) { - index = m_commandOptions->findTargetIndexByName(LookupKind::Option, trimmedWord, &nameKey); + index = m_commandOptions->findTargetIndexByName( + LookupKind::Option, + trimmedWord, + &nameKey); } - else if (trimmedWord[0] == '<' && trimmedWord[trimmedWord.getLength() - 1] == '>' && (linkFlags & LinkFlag::Category)) + else if ( + trimmedWord[0] == '<' && trimmedWord[trimmedWord.getLength() - 1] == '>' && + (linkFlags & LinkFlag::Category)) { - index = m_commandOptions->findTargetIndexByName(LookupKind::Category, trimmedWord.subString(1, trimmedWord.getLength() - 2), &nameKey); + index = m_commandOptions->findTargetIndexByName( + LookupKind::Category, + trimmedWord.subString(1, trimmedWord.getLength() - 2), + &nameKey); } - + if (index > 0) { // Append before the link - _appendEscapedMarkdown(UnownedStringSlice(inWord.begin(), trimmedWord.begin()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(inWord.begin(), trimmedWord.begin()), + m_builder); // Make into a link m_builder << "["; @@ -208,7 +234,9 @@ void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& in m_builder << "](#" << _getLinkName(nameKey, index) << ")"; // Append after the link - _appendEscapedMarkdown(UnownedStringSlice(trimmedWord.end(), inWord.end()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(trimmedWord.end(), inWord.end()), + m_builder); return; } } @@ -217,7 +245,9 @@ void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& in _appendEscapedMarkdown(inWord, m_builder); } -void MarkdownCommandOptionsWriter::_appendParagraph(const ConstArrayView<UnownedStringSlice>& words, LinkFlags linkFlags) +void MarkdownCommandOptionsWriter::_appendParagraph( + const ConstArrayView<UnownedStringSlice>& words, + LinkFlags linkFlags) { if (m_hasLinks && linkFlags) { @@ -271,19 +301,21 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI if (m_hasLinks) { // Output anchor - m_builder << "<a id=\"" << _getLinkName(LookupKind::Category, categoryIndex) << "\"></a>\n"; + m_builder << "<a id=\"" << _getLinkName(LookupKind::Category, categoryIndex) + << "\"></a>\n"; } m_builder << "# " << category.name << "\n\n"; - + // If there is a description output, making \n split paragraphs if (category.description.getLength() > 0) { _appendText(category.description); - } + } } - for (Index optionIndex = category.optionStartIndex; optionIndex < category.optionEndIndex; ++optionIndex) + for (Index optionIndex = category.optionStartIndex; optionIndex < category.optionEndIndex; + ++optionIndex) { const auto& option = options.getOptionAt(optionIndex); @@ -294,7 +326,7 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI if (isValue) { m_builder << "* "; - // Output all the names + // Output all the names m_builder << "`"; StringUtil::join(names.getBuffer(), names.getCount(), toSlice("`, `"), m_builder); m_builder << "` "; @@ -303,7 +335,8 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI { if (m_hasLinks) { - m_builder << "<a id=\"" << _getLinkName(LookupKind::Option, optionIndex) << "\"></a>\n"; + m_builder << "<a id=\"" << _getLinkName(LookupKind::Option, optionIndex) + << "\"></a>\n"; } m_builder << "## "; @@ -322,17 +355,24 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI const char* cur = option.usage.begin(); for (auto usedCategory : usedCategories) { - _appendEscapedMarkdown(UnownedStringSlice(cur, usedCategory.begin()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(cur, usedCategory.begin()), + m_builder); // Now do the link - const Index usedCategoryIndex = options.findCategoryByName(usedCategory); + const Index usedCategoryIndex = + options.findCategoryByName(usedCategory); - m_builder << "[" << usedCategory << "](#" << _getLinkName(LookupKind::Category, usedCategoryIndex) << ")"; + m_builder << "[" << usedCategory << "](#" + << _getLinkName(LookupKind::Category, usedCategoryIndex) + << ")"; cur = usedCategory.end(); } - _appendEscapedMarkdown(UnownedStringSlice(cur, option.usage.end()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(cur, option.usage.end()), + m_builder); } else { @@ -370,9 +410,9 @@ UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName(const NameKey& key return m_pool.getSlice(*ptr); } - UnownedStringSlice prefix = (key.kind == CommandOptions::LookupKind::Category) ? - m_commandOptions->getFirstNameForCategory(index) : - m_commandOptions->getFirstNameForOption(index); + UnownedStringSlice prefix = (key.kind == CommandOptions::LookupKind::Category) + ? m_commandOptions->getFirstNameForCategory(index) + : m_commandOptions->getFirstNameForOption(index); prefix = prefix.trim('-'); if (prefix.getLength() == 0) @@ -406,17 +446,17 @@ UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName(const NameKey& key return m_pool.getSlice(handle); } -UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName(CommandOptions::LookupKind kind, Index index) +UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName( + CommandOptions::LookupKind kind, + Index index) { auto& options = *m_commandOptions; - // Set up the name key - const auto key = (kind == LookupKind::Category) ? - options.getNameKeyForCategory(index) : - options.getNameKeyForOption(index); - - return _getLinkName(key, index); + // Set up the name key + const auto key = (kind == LookupKind::Category) ? options.getNameKeyForCategory(index) + : options.getNameKeyForOption(index); + return _getLinkName(key, index); } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TextCommandOptionsWriter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -425,11 +465,12 @@ class TextCommandOptionsWriter : public CommandOptionsWriter { public: typedef CommandOptionsWriter Super; - - TextCommandOptionsWriter(const Options& options) : - Super(options) + + TextCommandOptionsWriter(const Options& options) + : Super(options) { } + protected: // CommandOptionsWriter virtual void appendDescriptionForCategoryImpl(Index categoryIndex) SLANG_OVERRIDE; @@ -580,26 +621,24 @@ void TextCommandOptionsWriter::_appendText(Count indentCount, const UnownedStrin typedef CommandOptionsWriter::Style Style; -static const NamesDescriptionValue s_styleInfos[] = -{ - { ValueInt(Style::Text), "text", "Text suitable for output to a terminal" }, - { ValueInt(Style::Markdown), "markdown", "Markdown" }, - { ValueInt(Style::NoLinkMarkdown), "no-link-markdown", "Markdown without links" }, +static const NamesDescriptionValue s_styleInfos[] = { + {ValueInt(Style::Text), "text", "Text suitable for output to a terminal"}, + {ValueInt(Style::Markdown), "markdown", "Markdown"}, + {ValueInt(Style::NoLinkMarkdown), "no-link-markdown", "Markdown without links"}, }; -/* static */ConstArrayView<NamesDescriptionValue> CommandOptionsWriter::getStyleInfos() +/* static */ ConstArrayView<NamesDescriptionValue> CommandOptionsWriter::getStyleInfos() { return makeConstArrayView(s_styleInfos); } -CommandOptionsWriter::CommandOptionsWriter(const Options& options) : - m_pool(StringSlicePool::Style::Default), - m_options(options) +CommandOptionsWriter::CommandOptionsWriter(const Options& options) + : m_pool(StringSlicePool::Style::Default), m_options(options) { m_options.indent = m_pool.addAndGetSlice(options.indent); } -/* static */RefPtr<CommandOptionsWriter> CommandOptionsWriter::create(const Options& options) +/* static */ RefPtr<CommandOptionsWriter> CommandOptionsWriter::create(const Options& options) { if (_isMarkdown(options.style)) { @@ -611,7 +650,9 @@ CommandOptionsWriter::CommandOptionsWriter(const Options& options) : } } -void CommandOptionsWriter::appendDescriptionForCategory(CommandOptions* options, Index categoryIndex) +void CommandOptionsWriter::appendDescriptionForCategory( + CommandOptions* options, + Index categoryIndex) { m_commandOptions = options; appendDescriptionForCategoryImpl(categoryIndex); @@ -667,7 +708,10 @@ void CommandOptionsWriter::_requireIndent(Count indentCount) } } -void CommandOptionsWriter::_appendWrappedIndented(Count indentCount, List<UnownedStringSlice>& slices, const UnownedStringSlice& delimit) +void CommandOptionsWriter::_appendWrappedIndented( + Count indentCount, + List<UnownedStringSlice>& slices, + const UnownedStringSlice& delimit) { Count lineLength = _getCurrentLineLength(); @@ -708,5 +752,3 @@ void CommandOptionsWriter::_appendWrappedIndented(Count indentCount, List<Unowne } } // namespace Slang - - diff --git a/source/core/slang-command-options-writer.h b/source/core/slang-command-options-writer.h index eb9a2795f..5452d7617 100644 --- a/source/core/slang-command-options-writer.h +++ b/source/core/slang-command-options-writer.h @@ -19,51 +19,54 @@ public: Markdown, ///< Markdown NoLinkMarkdown, ///< Markdown without links }; - + static ConstArrayView<NamesDescriptionValue> getStyleInfos(); struct Options { - Style style = Style::Text; ///< The style - Index lineLength = 120; ///< The maximum amount of characters on a line - UnownedStringSlice indent = toSlice(" ");; + Style style = Style::Text; ///< The style + Index lineLength = 120; ///< The maximum amount of characters on a line + UnownedStringSlice indent = toSlice(" "); + ; }; - /// Append descirption for a category + /// Append descirption for a category void appendDescriptionForCategory(CommandOptions* options, Index categoryIndex); - /// Appends a description of all of the options + /// Appends a description of all of the options void appendDescription(CommandOptions* options); - /// Get the builder that string is being written to + /// Get the builder that string is being written to StringBuilder& getBuilder() { return m_builder; } static RefPtr<CommandOptionsWriter> create(const Options& options); - -protected: - /// Append descirption for a category +protected: + /// Append descirption for a category virtual void appendDescriptionForCategoryImpl(Index categoryIndex) = 0; - /// Appends a description of all of the options + /// Appends a description of all of the options virtual void appendDescriptionImpl() = 0; // Ctor, use create to create a writer CommandOptionsWriter(const Options& options); - /// Get the length of the current line in ascii chars/bytes + /// Get the length of the current line in ascii chars/bytes Count _getCurrentLineLength(); - /// Indentation/wrapping + /// Indentation/wrapping void _requireIndent(Count indentCount); - void _appendWrappedIndented(Count indentCount, List<UnownedStringSlice>& slices, const UnownedStringSlice& delimit); - + void _appendWrappedIndented( + Count indentCount, + List<UnownedStringSlice>& slices, + const UnownedStringSlice& delimit); + CommandOptions* m_commandOptions = nullptr; - StringSlicePool m_pool; + StringSlicePool m_pool; StringBuilder m_builder; Options m_options; }; } // namespace Slang -#endif +#endif diff --git a/source/core/slang-command-options.cpp b/source/core/slang-command-options.cpp index 5bbe59a0d..a4bb8b552 100644 --- a/source/core/slang-command-options.cpp +++ b/source/core/slang-command-options.cpp @@ -2,11 +2,12 @@ #include "slang-command-options.h" -#include "slang-string-util.h" -#include "slang-char-util.h" #include "slang-byte-encode-util.h" +#include "slang-char-util.h" +#include "slang-string-util.h" -namespace Slang { +namespace Slang +{ UnownedStringSlice CommandOptions::getFirstNameForOption(Index optionIndex) { @@ -26,7 +27,8 @@ CommandOptions::NameKey CommandOptions::getNameKeyForOption(Index optionIndex) const auto& cat = m_categories[opt.categoryIndex]; NameKey key; key.nameIndex = m_pool.findIndex(getFirstNameForOption(optionIndex)); - key.kind = (cat.kind == CategoryKind::Option) ? LookupKind::Option : makeLookupKind(opt.categoryIndex); + key.kind = + (cat.kind == CategoryKind::Option) ? LookupKind::Option : makeLookupKind(opt.categoryIndex); return key; } @@ -38,7 +40,10 @@ CommandOptions::NameKey CommandOptions::getNameKeyForCategory(Index categoryInde return key; } -SlangResult CommandOptions::_addName(LookupKind kind, const UnownedStringSlice& name, Index targetIndex) +SlangResult CommandOptions::_addName( + LookupKind kind, + const UnownedStringSlice& name, + Index targetIndex) { NameKey nameKey; nameKey.kind = kind; @@ -52,7 +57,10 @@ SlangResult CommandOptions::_addName(LookupKind kind, const UnownedStringSlice& return SLANG_OK; } -SlangResult CommandOptions::_addOptionName(const UnownedStringSlice& name, Flags flags, Index targetIndex) +SlangResult CommandOptions::_addOptionName( + const UnownedStringSlice& name, + Flags flags, + Index targetIndex) { SLANG_RETURN_ON_FAIL(_addName(LookupKind::Option, name, targetIndex)); @@ -67,7 +75,10 @@ SlangResult CommandOptions::_addOptionName(const UnownedStringSlice& name, Flags return SLANG_OK; } -SlangResult CommandOptions::_addValueName(const UnownedStringSlice& name, Index categoryIndex, Index optionIndex) +SlangResult CommandOptions::_addValueName( + const UnownedStringSlice& name, + Index categoryIndex, + Index optionIndex) { return _addName(LookupKind(categoryIndex), name, optionIndex); } @@ -122,7 +133,10 @@ Index CommandOptions::_addOption(const UnownedStringSlice& name, const Option& i } } -Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCount, const Option& inOption) +Index CommandOptions::_addOption( + const UnownedStringSlice* names, + Count namesCount, + const Option& inOption) { SLANG_ASSERT(namesCount > 0); SLANG_ASSERT(inOption.categoryIndex >= 0); @@ -134,7 +148,8 @@ Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCou auto& cat = m_categories[inOption.categoryIndex]; - // If there are already options associated with this category, we have to be in the run of the last ones added + // If there are already options associated with this category, we have to be in the run of the + // last ones added if (cat.optionStartIndex != cat.optionEndIndex) { // If we aren't at the end then this is an error @@ -172,9 +187,10 @@ Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCou { for (Index i = 0; i < namesCount; ++i) { - _addValueName(names[i], inOption.categoryIndex, optionIndex); + _addValueName(names[i], inOption.categoryIndex, optionIndex); } - if (SLANG_FAILED(_addUserValue(LookupKind(inOption.categoryIndex), inOption.userValue, optionIndex))) + if (SLANG_FAILED( + _addUserValue(LookupKind(inOption.categoryIndex), inOption.userValue, optionIndex))) { return -1; } @@ -198,7 +214,7 @@ Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCou // Set the end index cat.optionEndIndex = optionIndex + 1; - + return optionIndex; } @@ -219,7 +235,11 @@ static void _handlePostFix(UnownedStringSlice& ioSlice, CommandOptions::Flags& i } } -void CommandOptions::add(const char* inName, const char* usage, const char* description, UserValue userValue) +void CommandOptions::add( + const char* inName, + const char* usage, + const char* description, + UserValue userValue) { UnownedStringSlice nameSlice(inName); @@ -250,7 +270,13 @@ void CommandOptions::add(const char* inName, const char* usage, const char* desc } } -void CommandOptions::add(const UnownedStringSlice* names, Count namesCount, const char* usage, const char* description, UserValue userValue, Flags flags) +void CommandOptions::add( + const UnownedStringSlice* names, + Count namesCount, + const char* usage, + const char* description, + UserValue userValue, + Flags flags) { Option option; option.categoryIndex = m_currentCategoryIndex; @@ -337,7 +363,10 @@ void CommandOptions::addValue(const UnownedStringSlice& name, UserValue userValu _addValue(name, option); } -void CommandOptions::addValue(const UnownedStringSlice& name, const UnownedStringSlice& description, UserValue userValue) +void CommandOptions::addValue( + const UnownedStringSlice& name, + const UnownedStringSlice& description, + UserValue userValue) { Option option; option.categoryIndex = m_currentCategoryIndex; @@ -346,7 +375,10 @@ void CommandOptions::addValue(const UnownedStringSlice& name, const UnownedStrin _addValue(name, option); } -void CommandOptions::addValue(const UnownedStringSlice* names, Count namesCount, UserValue userValue) +void CommandOptions::addValue( + const UnownedStringSlice* names, + Count namesCount, + UserValue userValue) { Option option; option.categoryIndex = m_currentCategoryIndex; @@ -377,7 +409,11 @@ void CommandOptions::addValue(const char* name, UserValue userValue) addValue(UnownedStringSlice(name), userValue); } -Index CommandOptions::addCategory(CategoryKind kind, const char* name, const char* description, UserValue userValue) +Index CommandOptions::addCategory( + CategoryKind kind, + const char* name, + const char* description, + UserValue userValue) { const UnownedStringSlice nameSlice(name); @@ -425,7 +461,10 @@ void CommandOptions::setCategory(const char* name) m_currentCategoryIndex = -1; } -Index CommandOptions::findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey) const +Index CommandOptions::findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey) const { // Look up directly { @@ -470,7 +509,10 @@ Index CommandOptions::findTargetIndexByName(LookupKind kind, const UnownedString return -1; } -Index CommandOptions::_findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey) const +Index CommandOptions::_findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey) const { const auto nameIndex = m_pool.findIndex(name); // If the name isn't in the pool then there isn't a category with this name @@ -524,7 +566,9 @@ Index CommandOptions::findCategoryByCaseInsensitiveName(const UnownedStringSlice return -1; } -Index CommandOptions::findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) const +Index CommandOptions::findOptionByCategoryUserValue( + UserValue categoryUserValue, + const UnownedStringSlice& name) const { Index categoryIndex = findTargetIndexByUserValue(LookupKind::Category, categoryUserValue); if (categoryIndex < 0) @@ -535,14 +579,19 @@ Index CommandOptions::findOptionByCategoryUserValue(UserValue categoryUserValue, return findValueByName(categoryIndex, name); } -ConstArrayView<CommandOptions::Option> CommandOptions::getOptionsForCategory(Index categoryIndex) const +ConstArrayView<CommandOptions::Option> CommandOptions::getOptionsForCategory( + Index categoryIndex) const { const auto& cat = m_categories[categoryIndex]; - return makeConstArrayView(m_options.getBuffer() + cat.optionStartIndex, cat.optionEndIndex - cat.optionStartIndex); + return makeConstArrayView( + m_options.getBuffer() + cat.optionStartIndex, + cat.optionEndIndex - cat.optionStartIndex); } -void CommandOptions::appendCategoryOptionNames(Index categoryIndex, List<UnownedStringSlice>& outNames) const +void CommandOptions::appendCategoryOptionNames( + Index categoryIndex, + List<UnownedStringSlice>& outNames) const { for (const auto& option : getOptionsForCategory(categoryIndex)) { @@ -550,28 +599,33 @@ void CommandOptions::appendCategoryOptionNames(Index categoryIndex, List<Unowned } } -void CommandOptions::getCategoryOptionNames(Index categoryIndex, List<UnownedStringSlice>& outNames) const +void CommandOptions::getCategoryOptionNames(Index categoryIndex, List<UnownedStringSlice>& outNames) + const { outNames.clear(); appendCategoryOptionNames(categoryIndex, outNames); } -void CommandOptions::splitUsage(const UnownedStringSlice& usageSlice, List<UnownedStringSlice>& outSlices) const +void CommandOptions::splitUsage( + const UnownedStringSlice& usageSlice, + List<UnownedStringSlice>& outSlices) const { const auto* cur = usageSlice.begin(); const auto* end = usageSlice.end(); while (cur < end) { - // Find < - while (cur < end && *cur != '<') cur++; + // Find < + while (cur < end && *cur != '<') + cur++; // If we found it look for the end if (cur < end && *cur == '<') { ++cur; auto start = cur; - while (cur < end && (CharUtil::isAlphaOrDigit(*cur) || *cur == '-' || *cur == '_') && *cur != '>') + while (cur < end && (CharUtil::isAlphaOrDigit(*cur) || *cur == '-' || *cur == '_') && + *cur != '>') { cur++; } @@ -594,7 +648,9 @@ void CommandOptions::splitUsage(const UnownedStringSlice& usageSlice, List<Unown } -void CommandOptions::findCategoryIndicesFromUsage(const UnownedStringSlice& slice, List<Index>& outCategories) const +void CommandOptions::findCategoryIndicesFromUsage( + const UnownedStringSlice& slice, + List<Index>& outCategories) const { List<UnownedStringSlice> categoryNames; splitUsage(slice, categoryNames); @@ -609,7 +665,10 @@ void CommandOptions::findCategoryIndicesFromUsage(const UnownedStringSlice& slic } } -Count CommandOptions::getOptionCountInRange(Index categoryIndex, UserValue start, UserValue nonInclEnd) const +Count CommandOptions::getOptionCountInRange( + Index categoryIndex, + UserValue start, + UserValue nonInclEnd) const { const UserIndex startIndex = UserIndex(start); const UserIndex endIndex = UserIndex(nonInclEnd); @@ -631,7 +690,8 @@ Count CommandOptions::getOptionCountInRange(Index categoryIndex, UserValue start return count; } -Count CommandOptions::getOptionCountInRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const +Count CommandOptions::getOptionCountInRange(LookupKind kind, UserValue start, UserValue nonInclEnd) + const { Index count = 0; @@ -671,7 +731,10 @@ Count CommandOptions::getOptionCountInRange(LookupKind kind, UserValue start, Us } -bool CommandOptions::hasContiguousUserValueRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const +bool CommandOptions::hasContiguousUserValueRange( + LookupKind kind, + UserValue start, + UserValue nonInclEnd) const { const Count rangeCount = Count(nonInclEnd) - Count(start); SLANG_ASSERT(rangeCount >= 0); @@ -686,5 +749,3 @@ bool CommandOptions::hasContiguousUserValueRange(LookupKind kind, UserValue star } } // namespace Slang - - diff --git a/source/core/slang-command-options.h b/source/core/slang-command-options.h index 8b6d7b0ce..9d7af44d9 100644 --- a/source/core/slang-command-options.h +++ b/source/core/slang-command-options.h @@ -2,13 +2,13 @@ #define SLANG_CORE_COMMAND_OPTIONS_H #include "slang-basic.h" -#include "slang-string-slice-pool.h" #include "slang-name-value.h" +#include "slang-string-slice-pool.h" namespace Slang { -/* For convenience we encode within "names" flags. +/* For convenience we encode within "names" flags. "-D..." means that -D *must* be followed by the value "-D?..." means that -D *can* be a prefix, or it might be followed with the arg */ @@ -23,29 +23,36 @@ struct CommandOptions enum class LookupKind : int32_t { - Category = -2, ///< Lookup a category name - Option = -1, ///< Lookup an option name (all options use the same lookup index even if in different categories) - Base = 0, ///< Lookup via category index + Category = -2, ///< Lookup a category name + Option = -1, ///< Lookup an option name (all options use the same lookup index even if in + ///< different categories) + Base = 0, ///< Lookup via category index }; - /// A key type that uses the combination of the lookup kind and a name index. - /// Maps to a target index that could be a category or an option index. + /// A key type that uses the combination of the lookup kind and a name index. + /// Maps to a target index that could be a category or an option index. struct NameKey { typedef NameKey ThisType; - SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return kind == rhs.kind && nameIndex == rhs.nameIndex; } + SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const + { + return kind == rhs.kind && nameIndex == rhs.nameIndex; + } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - HashCode getHashCode() const { return combineHash(Slang::getHashCode(kind), Slang::getHashCode(nameIndex)); } + HashCode getHashCode() const + { + return combineHash(Slang::getHashCode(kind), Slang::getHashCode(nameIndex)); + } - LookupKind kind; ///< The kind of lookup - Index nameIndex; ///< The name index in the pool + LookupKind kind; ///< The kind of lookup + Index nameIndex; ///< The name index in the pool }; enum class CategoryKind { - Option, ///< Command line option (like "-D") - Value, ///< One of a set of values (such as an enum or some other kind of list of values) + Option, ///< Command line option (like "-D") + Value, ///< One of a set of values (such as an enum or some other kind of list of values) }; struct ValuePair @@ -71,128 +78,179 @@ struct CommandOptions { enum Enum : Flags { - CanPrefix = 0x1, /// Allows -Dfsggf or -D fdsfsd - IsPrefix = 0x2, /// Is an option that can only be a prefix + CanPrefix = 0x1, /// Allows -Dfsggf or -D fdsfsd + IsPrefix = 0x2, /// Is an option that can only be a prefix }; }; struct Option { - UnownedStringSlice names; ///< Comma delimited list of names, first name is the default - UnownedStringSlice usage; ///< Describes usage, can be empty - UnownedStringSlice description; ///< A description of usage + UnownedStringSlice names; ///< Comma delimited list of names, first name is the default + UnownedStringSlice usage; ///< Describes usage, can be empty + UnownedStringSlice description; ///< A description of usage UserValue userValue = kInvalidUserValue; - Index categoryIndex = -1; ///< Category this option belongs to - Flags flags = 0; ///< Flags about this option + Index categoryIndex = -1; ///< Category this option belongs to + Flags flags = 0; ///< Flags about this option }; - /// Get the first name + /// Get the first name UnownedStringSlice getFirstNameForOption(Index optionIndex); - /// Get the first name for the category + /// Get the first name for the category UnownedStringSlice getFirstNameForCategory(Index categoryIndex); - /// Get a name key for an opton + /// Get a name key for an opton NameKey getNameKeyForOption(Index optionIndex); - /// Get a name key for a category + /// Get a name key for a category NameKey getNameKeyForCategory(Index optionIndex); - /// Add a category - Index addCategory(CategoryKind kind, const char* name, const char* description, UserValue userValue = kInvalidUserValue); - /// Use an already known category. It's an error if the category isn't found + /// Add a category + Index addCategory( + CategoryKind kind, + const char* name, + const char* description, + UserValue userValue = kInvalidUserValue); + /// Use an already known category. It's an error if the category isn't found void setCategory(const char* name); - void add(const char* name, const char* usage, const char* description, UserValue userValue = kInvalidUserValue); - void add(const UnownedStringSlice* names, Count namesCount, const char* usage, const char* description, UserValue userValue = kInvalidUserValue, Flags flags = 0); + void add( + const char* name, + const char* usage, + const char* description, + UserValue userValue = kInvalidUserValue); + void add( + const UnownedStringSlice* names, + Count namesCount, + const char* usage, + const char* description, + UserValue userValue = kInvalidUserValue, + Flags flags = 0); void addValue(const UnownedStringSlice& name, UserValue userValue = kInvalidUserValue); - void addValue(const UnownedStringSlice& name, const UnownedStringSlice& description, UserValue userValue = kInvalidUserValue); - void addValue(const char* name, const char* description, UserValue userValue = kInvalidUserValue); + void addValue( + const UnownedStringSlice& name, + const UnownedStringSlice& description, + UserValue userValue = kInvalidUserValue); + void addValue( + const char* name, + const char* description, + UserValue userValue = kInvalidUserValue); void addValue(const char* name, UserValue userValue = kInvalidUserValue); - void addValue(const UnownedStringSlice* names, Count namesCount, UserValue userValue = kInvalidUserValue); + void addValue( + const UnownedStringSlice* names, + Count namesCount, + UserValue userValue = kInvalidUserValue); - /// Add values (without UserValue association) + /// Add values (without UserValue association) void addValues(const ValuePair* pairs, Count pairsCount); - /// Add values + /// Add values void addValues(const ConstArrayView<NameValue>& values); void addValues(const ConstArrayView<NamesValue>& values); void addValues(const ConstArrayView<NamesDescriptionValue>& values); - /// Sometimes values are listed with *names* per value. This method will take into account the aliases + /// Sometimes values are listed with *names* per value. This method will take into account the + /// aliases void addValuesWithAliases(const ConstArrayView<NameValue>& values); - /// Get the target index based off the name and the kind - Index findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey = nullptr) const; - /// Given a kind and a user value lookup the target index + /// Get the target index based off the name and the kind + Index findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey = nullptr) const; + /// Given a kind and a user value lookup the target index Index findTargetIndexByUserValue(LookupKind kind, UserValue userValue) const; - /// Finds the category by name or -1 if not found - Index findCategoryByName(const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind::Category, name); } - /// Finds the option index by name or -1 if not found - Index findOptionByName(const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind::Option, name); } - /// Find the option index of a value, using it's category index and the name - Index findValueByName(Index categoryIndex, const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind(categoryIndex), name); } - - /// Get the category index from a user value - Index findCategoryByUserValue(UserValue userValue) const { return findTargetIndexByUserValue(LookupKind::Category, userValue); } - /// Can only get options - Index findOptionByUserValue(UserValue userValue) const { return findTargetIndexByUserValue(LookupKind::Option, userValue); } - /// Get a value associated with a category - Index findValueByUserValue(Index categoryIndex, UserValue userValue) const { return findTargetIndexByUserValue(LookupKind(categoryIndex), userValue); } - - /// Given a category user value, find the associated name - /// Returns -1 if not found - Index findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) const; - - /// Find a category by case insensitive name. Returns -1 if not found + /// Finds the category by name or -1 if not found + Index findCategoryByName(const UnownedStringSlice& name) const + { + return findTargetIndexByName(LookupKind::Category, name); + } + /// Finds the option index by name or -1 if not found + Index findOptionByName(const UnownedStringSlice& name) const + { + return findTargetIndexByName(LookupKind::Option, name); + } + /// Find the option index of a value, using it's category index and the name + Index findValueByName(Index categoryIndex, const UnownedStringSlice& name) const + { + return findTargetIndexByName(LookupKind(categoryIndex), name); + } + + /// Get the category index from a user value + Index findCategoryByUserValue(UserValue userValue) const + { + return findTargetIndexByUserValue(LookupKind::Category, userValue); + } + /// Can only get options + Index findOptionByUserValue(UserValue userValue) const + { + return findTargetIndexByUserValue(LookupKind::Option, userValue); + } + /// Get a value associated with a category + Index findValueByUserValue(Index categoryIndex, UserValue userValue) const + { + return findTargetIndexByUserValue(LookupKind(categoryIndex), userValue); + } + + /// Given a category user value, find the associated name + /// Returns -1 if not found + Index findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) + const; + + /// Find a category by case insensitive name. Returns -1 if not found Index findCategoryByCaseInsensitiveName(const UnownedStringSlice& slice) const; - - /// Given a category index returns all the options associated. + + /// Given a category index returns all the options associated. ConstArrayView<Option> getOptionsForCategory(Index categoryIndex) const; - /// Get the categories + /// Get the categories const List<Category>& getCategories() const { return m_categories; } - /// Get all the options + /// Get all the options const List<Option>& getOptions() const { return m_options; } - /// Get the option at the specified index + /// Get the option at the specified index const Option& getOptionAt(Index index) const { return m_options[index]; } - /// Find all of the categories in the usage slice - void findCategoryIndicesFromUsage(const UnownedStringSlice& usageSlice, List<Index>& outCategories) const; + /// Find all of the categories in the usage slice + void findCategoryIndicesFromUsage( + const UnownedStringSlice& usageSlice, + List<Index>& outCategories) const; - /// Splits usage into category slices - void splitUsage(const UnownedStringSlice& usageSlice, List<UnownedStringSlice>& outSlices) const; + /// Splits usage into category slices + void splitUsage(const UnownedStringSlice& usageSlice, List<UnownedStringSlice>& outSlices) + const; - /// Get all the option names associated with a category index + /// Get all the option names associated with a category index void getCategoryOptionNames(Index categoryIndex, List<UnownedStringSlice>& outNames) const; void appendCategoryOptionNames(Index categoryIndex, List<UnownedStringSlice>& outNames) const; - /// Set up a lookup kind from a category index + /// Set up a lookup kind from a category index static LookupKind makeLookupKind(Index categoryIndex) { return LookupKind(categoryIndex); } - /// Returns true, if all values from [start, end) are found for the kind + /// Returns true, if all values from [start, end) are found for the kind bool hasContiguousUserValueRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const; - /// Returns the number of options in the range + /// Returns the number of options in the range Count getOptionCountInRange(Index categoryIndex, UserValue start, UserValue nonInclEnd) const; Count getOptionCountInRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const; /// Ctor - CommandOptions() : - m_pool(StringSlicePool::Style::Default), - m_arena(1024 * 2) + CommandOptions() + : m_pool(StringSlicePool::Style::Default), m_arena(1024 * 2) { } - protected: - /// Returns name in the m_optionPool or -1 on error +protected: + /// Returns name in the m_optionPool or -1 on error SlangResult _addOptionName(const UnownedStringSlice& name, Flags flags, Index targetIndex); - SlangResult _addValueName(const UnownedStringSlice& name, Index categoryIndex, Index targetIndex); + SlangResult _addValueName( + const UnownedStringSlice& name, + Index categoryIndex, + Index targetIndex); SlangResult _addName(LookupKind kind, const UnownedStringSlice& name, Index targetIndex); SlangResult _addUserValue(LookupKind kind, UserValue userValue, Index targetIndex); @@ -205,18 +263,27 @@ struct CommandOptions UnownedStringSlice _addString(const char* text); UnownedStringSlice _addString(const UnownedStringSlice& slice); - Index _findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey) const; + Index _findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey) const; struct UserValueKey { typedef UserValueKey ThisType; - SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return kind == rhs.kind && userValue == rhs.userValue; } + SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const + { + return kind == rhs.kind && userValue == rhs.userValue; + } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - HashCode getHashCode() const { return combineHash(Slang::getHashCode(kind), Slang::getHashCode(userValue)); } + HashCode getHashCode() const + { + return combineHash(Slang::getHashCode(kind), Slang::getHashCode(userValue)); + } - LookupKind kind; ///< The kind of lookup - UserValue userValue; ///< The user value + LookupKind kind; ///< The kind of lookup + UserValue userValue; ///< The user value }; Index m_currentCategoryIndex = -1; @@ -226,14 +293,14 @@ struct CommandOptions // Holds a bit for all valid prefix sizes. Max prefix size is therefore 32 chars uint32_t m_prefixSizes = 0; - List<Option> m_options; ///< All of the entries describing each of the options - StringSlicePool m_pool; ///< Only holds options, and handle therefore matches up to m_entries + List<Option> m_options; ///< All of the entries describing each of the options + StringSlicePool m_pool; ///< Only holds options, and handle therefore matches up to m_entries Dictionary<NameKey, Index> m_nameMap; ///< Maps a name to an option index Dictionary<UserValueKey, Index> m_userValueMap; ///< Maps a user value (for a kind) to an index - MemoryArena m_arena; ///< For other misc storage + MemoryArena m_arena; ///< For other misc storage }; } // namespace Slang -#endif +#endif diff --git a/source/core/slang-common.h b/source/core/slang-common.h index 2952eccd2..2aec6f0ce 100644 --- a/source/core/slang-common.h +++ b/source/core/slang-common.h @@ -1,106 +1,107 @@ #pragma once +#include "slang-signal.h" #include "slang.h" #include <assert.h> - #include <stdint.h> -#include "slang-signal.h" - #define VARIADIC_TEMPLATE namespace Slang { - - typedef int32_t Int32; - typedef uint32_t UInt32; - typedef int64_t Int64; - typedef uint64_t UInt64; +typedef int32_t Int32; +typedef uint32_t UInt32; + +typedef int64_t Int64; +typedef uint64_t UInt64; - // Define - typedef SlangUInt UInt; - typedef SlangInt Int; +// Define +typedef SlangUInt UInt; +typedef SlangInt Int; - static const UInt kMaxUInt = ~UInt(0); - static const Int kMaxInt = Int(kMaxUInt >> 1); +static const UInt kMaxUInt = ~UInt(0); +static const Int kMaxInt = Int(kMaxUInt >> 1); // typedef unsigned short Word; - typedef intptr_t PtrInt; +typedef intptr_t PtrInt; - // TODO(JS): It looks like Index is actually 64 bit on 64 bit targets(!) - // Previous discussions landed on Index being int32_t. +// TODO(JS): It looks like Index is actually 64 bit on 64 bit targets(!) +// Previous discussions landed on Index being int32_t. - // Type used for indexing, in arrays/views etc. Signed. - typedef Int Index; - typedef UInt UIndex; - typedef Int Count; - typedef UInt UCount; +// Type used for indexing, in arrays/views etc. Signed. +typedef Int Index; +typedef UInt UIndex; +typedef Int Count; +typedef UInt UCount; - static const Index kMaxIndex = kMaxInt; +static const Index kMaxIndex = kMaxInt; - typedef uint8_t Byte; +typedef uint8_t Byte; - // TODO(JS): - // Perhaps these should be named Utf8, Utf16 and UnicodePoint/Rune/etc? For now, just keep it simple - // - typedef char Char8; - // 16 bit character. Note much like in utf8, a character may or may not represent a code point (it can be part of a code point). - typedef uint16_t Char16; +// TODO(JS): +// Perhaps these should be named Utf8, Utf16 and UnicodePoint/Rune/etc? For now, just keep it simple +// +typedef char Char8; +// 16 bit character. Note much like in utf8, a character may or may not represent a code point (it +// can be part of a code point). +typedef uint16_t Char16; - // Can always hold a unicode code point. - typedef uint32_t Char32; +// Can always hold a unicode code point. +typedef uint32_t Char32; - template <typename T> - inline T&& _Move(T & obj) - { - return static_cast<T&&>(obj); - } +template<typename T> +inline T&& _Move(T& obj) +{ + return static_cast<T&&>(obj); +} - template <typename T> - inline void Swap(T & v0, T & v1) - { - T tmp = _Move(v0); - v0 = _Move(v1); - v1 = _Move(tmp); - } +template<typename T> +inline void Swap(T& v0, T& v1) +{ + T tmp = _Move(v0); + v0 = _Move(v1); + v1 = _Move(tmp); +} - // Make these interfaces have more convenient names - typedef ISlangCastable ICastable; - typedef ISlangClonable IClonable; +// Make these interfaces have more convenient names +typedef ISlangCastable ICastable; +typedef ISlangClonable IClonable; - // Convenience function for using clonable - template <typename T> - SLANG_FORCE_INLINE T* clone(IClonable* clonable) { return (T*)clonable->clone(T::getTypeGuid()); } +// Convenience function for using clonable +template<typename T> +SLANG_FORCE_INLINE T* clone(IClonable* clonable) +{ + return (T*)clonable->clone(T::getTypeGuid()); +} - template <typename T> - inline bool isBitSet(T value, T bitToTest) - { - static_assert(sizeof(T) <= sizeof(uint32_t), "Only support up to 32 bit enums"); - return (T)((uint32_t)value & (uint32_t)bitToTest) == bitToTest; - } +template<typename T> +inline bool isBitSet(T value, T bitToTest) +{ + static_assert(sizeof(T) <= sizeof(uint32_t), "Only support up to 32 bit enums"); + return (T)((uint32_t)value & (uint32_t)bitToTest) == bitToTest; } +} // namespace Slang // SLANG_DEFER template<typename F> class SlangDeferImpl { F f; + public: SlangDeferImpl(F&& f) : f(Slang::_Move(f)) - {} - ~SlangDeferImpl() { - f(); } + ~SlangDeferImpl() { f(); } }; #ifndef SLANG_DEFER_LAMBDA #define SLANG_DEFER_LAMBDA(x) auto SLANG_CONCAT(slang_defer_, __LINE__) = SlangDeferImpl(x) -#define SLANG_DEFER(x) auto SLANG_CONCAT(slang_defer_,__LINE__) = SlangDeferImpl([&](){x;}) +#define SLANG_DEFER(x) auto SLANG_CONCAT(slang_defer_, __LINE__) = SlangDeferImpl([&]() { x; }) #endif // @@ -115,38 +116,38 @@ public: #else #define SLANG_COMPONENTWISE_EQUALITY_1(type) \ bool operator==(const type& other) const \ - { \ - const auto& [m1] = *this; \ - const auto& [o1] = other; \ - return m1 == o1; \ - } \ + { \ + const auto& [m1] = *this; \ + const auto& [o1] = other; \ + return m1 == o1; \ + } \ bool operator!=(const type& other) const \ - { \ - return !(*this == other); \ + { \ + return !(*this == other); \ } #define SLANG_COMPONENTWISE_EQUALITY_2(type) \ bool operator==(const type& other) const \ - { \ - const auto& [m1, m2] = *this; \ - const auto& [o1, o2] = other; \ - return m1 == o1 && m2 == o2; \ - } \ + { \ + const auto& [m1, m2] = *this; \ + const auto& [o1, o2] = other; \ + return m1 == o1 && m2 == o2; \ + } \ bool operator!=(const type& other) const \ - { \ - return !(*this == other); \ + { \ + return !(*this == other); \ } -#define SLANG_COMPONENTWISE_EQUALITY_3(type) \ - bool operator==(const type& other) const \ - { \ - const auto& [m1, m2, m3] = *this; \ - const auto& [o1, o2, o3] = other; \ +#define SLANG_COMPONENTWISE_EQUALITY_3(type) \ + bool operator==(const type& other) const \ + { \ + const auto& [m1, m2, m3] = *this; \ + const auto& [o1, o2, o3] = other; \ return m1 == o1 && m2 == o2 && m3 == o3; \ - } \ - bool operator!=(const type& other) const \ - { \ - return !(*this == other); \ + } \ + bool operator!=(const type& other) const \ + { \ + return !(*this == other); \ } #endif @@ -158,49 +159,43 @@ public: #endif #if SLANG_GCC -# define SLANG_EXHAUSTIVE_SWITCH_BEGIN \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic error \"-Wswitch-enum\""); -# define SLANG_EXHAUSTIVE_SWITCH_END \ - _Pragma("GCC diagnostic pop"); +#define SLANG_EXHAUSTIVE_SWITCH_BEGIN \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic error \"-Wswitch-enum\""); +#define SLANG_EXHAUSTIVE_SWITCH_END _Pragma("GCC diagnostic pop"); #elif SLANG_CLANG -# define SLANG_EXHAUSTIVE_SWITCH_BEGIN \ - _Pragma("clang diagnostic push"); \ - _Pragma("clang diagnostic error \"-Wswitch-enum\""); -# define SLANG_EXHAUSTIVE_SWITCH_END \ - _Pragma("clang diagnostic pop"); +#define SLANG_EXHAUSTIVE_SWITCH_BEGIN \ + _Pragma("clang diagnostic push"); \ + _Pragma("clang diagnostic error \"-Wswitch-enum\""); +#define SLANG_EXHAUSTIVE_SWITCH_END _Pragma("clang diagnostic pop"); #elif SLANG_VC -# define SLANG_EXHAUSTIVE_SWITCH_BEGIN \ - _Pragma("warning(push)"); \ - _Pragma("warning(error : 4062)"); -# define SLANG_EXHAUSTIVE_SWITCH_END \ - _Pragma("warning(pop)"); +#define SLANG_EXHAUSTIVE_SWITCH_BEGIN \ + _Pragma("warning(push)"); \ + _Pragma("warning(error : 4062)"); +#define SLANG_EXHAUSTIVE_SWITCH_END _Pragma("warning(pop)"); #else -# define SLANG_EXHAUSTIVE_SWITCH_BEGIN -# define SLANG_EXHAUSTIVE_SWITCH_END +#define SLANG_EXHAUSTIVE_SWITCH_BEGIN +#define SLANG_EXHAUSTIVE_SWITCH_END #endif #if SLANG_GCC -# define SLANG_ALLOW_DEPRECATED_BEGIN \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\""); -# define SLANG_ALLOW_DEPRECATED_END \ - _Pragma("GCC diagnostic pop"); +#define SLANG_ALLOW_DEPRECATED_BEGIN \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\""); +#define SLANG_ALLOW_DEPRECATED_END _Pragma("GCC diagnostic pop"); #elif SLANG_CLANG -# define SLANG_ALLOW_DEPRECATED_BEGIN \ - _Pragma("clang diagnostic push"); \ - _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\""); -# define SLANG_ALLOW_DEPRECATED_END \ - _Pragma("clang diagnostic pop"); +#define SLANG_ALLOW_DEPRECATED_BEGIN \ + _Pragma("clang diagnostic push"); \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\""); +#define SLANG_ALLOW_DEPRECATED_END _Pragma("clang diagnostic pop"); #elif SLANG_VC -# define SLANG_ALLOW_DEPRECATED_BEGIN \ - _Pragma("warning(push)"); \ - _Pragma("warning(disable : 4996)"); -# define SLANG_ALLOW_DEPRECATED_END \ - _Pragma("warning(pop)"); +#define SLANG_ALLOW_DEPRECATED_BEGIN \ + _Pragma("warning(push)"); \ + _Pragma("warning(disable : 4996)"); +#define SLANG_ALLOW_DEPRECATED_END _Pragma("warning(pop)"); #else -# define SLANG_ALLOW_DEPRECATED_BEGIN -# define SLANG_ALLOW_DEPRECATED_END +#define SLANG_ALLOW_DEPRECATED_BEGIN +#define SLANG_ALLOW_DEPRECATED_END #endif // @@ -208,16 +203,26 @@ public: // Do not rely on side effects of the condition being performed. // #if defined(__cpp_assume) -# define SLANG_ASSUME(X) [[assume(X)]] +#define SLANG_ASSUME(X) [[assume(X)]] #elif SLANG_GCC -# define SLANG_ASSUME(X) do{if(!(X)) __builtin_unreachable();} while(0) +#define SLANG_ASSUME(X) \ + do \ + { \ + if (!(X)) \ + __builtin_unreachable(); \ + } while (0) #elif SLANG_CLANG -# define SLANG_ASSUME(X) __builtin_assume(X) +#define SLANG_ASSUME(X) __builtin_assume(X) #elif SLANG_VC -# define SLANG_ASSUME(X) __assume(X) +#define SLANG_ASSUME(X) __assume(X) #else - [[noreturn]] inline void invokeUndefinedBehaviour() {} -# define SLANG_ASSUME(X) do{if(!(X)) invokeUndefinedBehaviour();} while(0) +[[noreturn]] inline void invokeUndefinedBehaviour() {} +#define SLANG_ASSUME(X) \ + do \ + { \ + if (!(X)) \ + invokeUndefinedBehaviour(); \ + } while (0) #endif // @@ -225,37 +230,51 @@ public: // assumptions in release builds // #ifdef _DEBUG -#define SLANG_ASSERT(VALUE) do{if(!(VALUE)) SLANG_ASSERT_FAILURE(#VALUE);} while(0) +#define SLANG_ASSERT(VALUE) \ + do \ + { \ + if (!(VALUE)) \ + SLANG_ASSERT_FAILURE(#VALUE); \ + } while (0) #else #define SLANG_ASSERT(VALUE) SLANG_ASSUME(VALUE) #endif -#define SLANG_RELEASE_ASSERT(VALUE) if(VALUE) {} else SLANG_ASSERT_FAILURE(#VALUE) +#define SLANG_RELEASE_ASSERT(VALUE) \ + if (VALUE) \ + { \ + } \ + else \ + SLANG_ASSERT_FAILURE(#VALUE) -template<typename T> void slang_use_obj(T&) {} +template<typename T> +void slang_use_obj(T&) +{ +} #define SLANG_UNREFERENCED_PARAMETER(P) slang_use_obj(P) #define SLANG_UNREFERENCED_VARIABLE(P) slang_use_obj(P) #if defined(SLANG_RT_DYNAMIC) #if defined(_MSC_VER) -# ifdef SLANG_RT_DYNAMIC_EXPORT -# define SLANG_RT_API SLANG_DLL_EXPORT -# else -# define SLANG_RT_API __declspec(dllimport) -# endif +#ifdef SLANG_RT_DYNAMIC_EXPORT +#define SLANG_RT_API SLANG_DLL_EXPORT +#else +#define SLANG_RT_API __declspec(dllimport) +#endif #else // TODO: need to consider compiler capabilities -//# ifdef SLANG_RT_DYNAMIC_EXPORT -# define SLANG_RT_API SLANG_DLL_EXPORT -//# endif +// # ifdef SLANG_RT_DYNAMIC_EXPORT +#define SLANG_RT_API SLANG_DLL_EXPORT +// # endif #endif #endif #if defined(_MSC_VER) -# define SLANG_ATTR_PRINTF(string_index, varargs_index) +#define SLANG_ATTR_PRINTF(string_index, varargs_index) #else -# define SLANG_ATTR_PRINTF(string_index, varargs_index) __attribute__((format(printf, string_index, varargs_index))) +#define SLANG_ATTR_PRINTF(string_index, varargs_index) \ + __attribute__((format(printf, string_index, varargs_index))) #endif #ifndef SLANG_RT_API diff --git a/source/core/slang-compression-system.h b/source/core/slang-compression-system.h index ecc5b1be9..806228f64 100644 --- a/source/core/slang-compression-system.h +++ b/source/core/slang-compression-system.h @@ -10,13 +10,14 @@ struct CompressionStyle { enum class Type { - Level, ///< Use the value specified in 'level' to control compression - BestSpeed, ///< Best for speed (typically lower compression ration) - BestCompression, ///< Best compression (typically slower) - Default, ///< Default compression (a good balance between speed and size) + Level, ///< Use the value specified in 'level' to control compression + BestSpeed, ///< Best for speed (typically lower compression ration) + BestCompression, ///< Best compression (typically slower) + Default, ///< Default compression (a good balance between speed and size) }; - Type m_type = Type::Default; ///< The type - float m_level = 1.0f; ///< 0 lowest compression, 1 highest compression (Ignored if m_type != Type::Level) + Type m_type = Type::Default; ///< The type + float m_level = + 1.0f; ///< 0 lowest compression, 1 highest compression (Ignored if m_type != Type::Level) }; enum class CompressionSystemType @@ -29,28 +30,41 @@ enum class CompressionSystemType class ICompressionSystem : public ISlangUnknown { - SLANG_COM_INTERFACE(0xcc935840, 0xe059, 0x4bb8, { 0xa2, 0x2d, 0x92, 0x7b, 0x3c, 0x73, 0x8f, 0x85 }) + SLANG_COM_INTERFACE( + 0xcc935840, + 0xe059, + 0x4bb8, + {0xa2, 0x2d, 0x92, 0x7b, 0x3c, 0x73, 0x8f, 0x85}) - /** Get the compression system type - @return The compression system type */ + /** Get the compression system type + @return The compression system type */ virtual SLANG_NO_THROW CompressionSystemType SLANG_MCALL getSystemType() = 0; - /** compress - @param src Points to the start of the data to compress - @param srcSizeInBytes The size of the source data to compress in bytes - @param outBlob The input data compressed - @return SLANG_OK if successful */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compress(const CompressionStyle* style, const void* src, size_t srcSizeInBytes, ISlangBlob** outBlob) = 0; - - /* decompress - @param compressed The start of the compressed data - @param compressedSizeInBytes The compressed size in bytes - @param decompressedSizeInBytes The size of the decompressed buffer. MUST be exactly the same as the original source size. - @param outDecompressed Where decompressed data is written - @return SLANG_OK if successful */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL decompress(const void* compressed, size_t compressedSizeInBytes, size_t decompressedSizeInBytes, void* outDecompressed) = 0; + /** compress + @param src Points to the start of the data to compress + @param srcSizeInBytes The size of the source data to compress in bytes + @param outBlob The input data compressed + @return SLANG_OK if successful */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compress( + const CompressionStyle* style, + const void* src, + size_t srcSizeInBytes, + ISlangBlob** outBlob) = 0; + + /* decompress + @param compressed The start of the compressed data + @param compressedSizeInBytes The compressed size in bytes + @param decompressedSizeInBytes The size of the decompressed buffer. MUST be exactly the same as + the original source size. + @param outDecompressed Where decompressed data is written + @return SLANG_OK if successful */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL decompress( + const void* compressed, + size_t compressedSizeInBytes, + size_t decompressedSizeInBytes, + void* outDecompressed) = 0; }; -} +} // namespace Slang #endif diff --git a/source/core/slang-crypto.cpp b/source/core/slang-crypto.cpp index 138454140..49371eaea 100644 --- a/source/core/slang-crypto.cpp +++ b/source/core/slang-crypto.cpp @@ -2,13 +2,14 @@ * MD5 implementation is based on: * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 * Original file header is at the bottom of this file. - * + * * SHA1 implementation is based on: * https://github.com/983/SHA1 * Original LICENSE is at the bottom of this file. */ #include "slang-crypto.h" + #include "../core/slang-char-util.h" namespace Slang @@ -32,7 +33,11 @@ namespace Slang return str; } -/*static*/ bool DigestUtil::stringToDigest(const char* str, SlangInt strLength, void *digest, SlangInt digestSize) +/*static*/ bool DigestUtil::stringToDigest( + const char* str, + SlangInt strLength, + void* digest, + SlangInt digestSize) { SLANG_ASSERT(str && strLength >= 0 && digest && digestSize >= 0); @@ -52,7 +57,8 @@ namespace Slang ::memset(digest, 0, digestSize); return false; } - data[i] = uint8_t(lower | upper << 4);; + data[i] = uint8_t(lower | upper << 4); + ; } return true; @@ -164,17 +170,17 @@ MD5::Digest MD5::finalize() * architectures that lack an AND-NOT instruction, just like in Colin Plumb's * implementation. */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) -#define H(x, y, z) (((x) ^ (y)) ^ (z)) -#define H2(x, y, z) ((x) ^ ((y) ^ (z))) -#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) /* * The MD5 transformation for all four rounds. */ -#define STEP(f, a, b, c, d, x, t, s) \ - (a) += f((b), (c), (d)) + (x) + (t); \ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ (a) += (b); @@ -182,14 +188,10 @@ MD5::Digest MD5::finalize() * SET reads 4 input bytes in little-endian byte order and stores them in a * properly aligned word in host byte order. */ -#define SET(n) \ - (m_block[(n)] = \ - (uint32_t)ptr[(n) * 4] | \ - ((uint32_t)ptr[(n) * 4 + 1] << 8) | \ - ((uint32_t)ptr[(n) * 4 + 2] << 16) | \ - ((uint32_t)ptr[(n) * 4 + 3] << 24)) -#define GET(n) \ - (m_block[(n)]) +#define SET(n) \ + (m_block[(n)] = (uint32_t)ptr[(n) * 4] | ((uint32_t)ptr[(n) * 4 + 1] << 8) | \ + ((uint32_t)ptr[(n) * 4 + 2] << 16) | ((uint32_t)ptr[(n) * 4 + 3] << 24)) +#define GET(n) (m_block[(n)]) const void* MD5::processBlock(const void* data, SlangInt size) { @@ -286,8 +288,7 @@ const void* MD5::processBlock(const void* data, SlangInt size) d += saved_d; ptr += 64; - } - while (size -= 64); + } while (size -= 64); m_a = a; m_b = b; @@ -405,14 +406,12 @@ void SHA1::addByte(uint8_t byte) void SHA1::processBlock(const uint8_t* ptr) { - auto rol32 = [](uint32_t x, uint32_t n) - { - return (x << n) | (x >> (32 - n)); - }; + auto rol32 = [](uint32_t x, uint32_t n) { return (x << n) | (x >> (32 - n)); }; auto makeWord = [](const uint8_t* p) { - return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; + return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | + (uint32_t)p[3]; }; const uint32_t c0 = 0x5a827999; @@ -433,23 +432,34 @@ void SHA1::processBlock(const uint8_t* ptr) w[i] = makeWord(ptr + i * 4); } -#define SHA1_LOAD(i) w[i&15] = rol32(w[(i + 13) & 15] ^ w[(i + 8) & 15] ^ w[(i + 2) & 15] ^ w[i & 15], 1); -#define SHA1_ROUND_0(v,u,x,y,z,i) z += ((u & (x ^ y)) ^ y) + w[i & 15] + c0 + rol32(v, 5); u = rol32(u, 30); -#define SHA1_ROUND_1(v,u,x,y,z,i) SHA1_LOAD(i) z += ((u & (x ^ y)) ^ y) + w[i & 15] + c0 + rol32(v, 5); u = rol32(u, 30); -#define SHA1_ROUND_2(v,u,x,y,z,i) SHA1_LOAD(i) z += (u ^ x ^ y) + w[i & 15] + c1 + rol32(v, 5); u = rol32(u, 30); -#define SHA1_ROUND_3(v,u,x,y,z,i) SHA1_LOAD(i) z += (((u | x) & y) | (u & x)) + w[i & 15] + c2 + rol32(v, 5); u = rol32(u, 30); -#define SHA1_ROUND_4(v,u,x,y,z,i) SHA1_LOAD(i) z += (u ^ x ^ y) + w[i & 15] + c3 + rol32(v, 5); u = rol32(u, 30); - - SHA1_ROUND_0(a, b, c, d, e, 0); - SHA1_ROUND_0(e, a, b, c, d, 1); - SHA1_ROUND_0(d, e, a, b, c, 2); - SHA1_ROUND_0(c, d, e, a, b, 3); - SHA1_ROUND_0(b, c, d, e, a, 4); - SHA1_ROUND_0(a, b, c, d, e, 5); - SHA1_ROUND_0(e, a, b, c, d, 6); - SHA1_ROUND_0(d, e, a, b, c, 7); - SHA1_ROUND_0(c, d, e, a, b, 8); - SHA1_ROUND_0(b, c, d, e, a, 9); +#define SHA1_LOAD(i) \ + w[i & 15] = rol32(w[(i + 13) & 15] ^ w[(i + 8) & 15] ^ w[(i + 2) & 15] ^ w[i & 15], 1); +#define SHA1_ROUND_0(v, u, x, y, z, i) \ + z += ((u & (x ^ y)) ^ y) + w[i & 15] + c0 + rol32(v, 5); \ + u = rol32(u, 30); +#define SHA1_ROUND_1(v, u, x, y, z, i) \ + SHA1_LOAD(i) z += ((u & (x ^ y)) ^ y) + w[i & 15] + c0 + rol32(v, 5); \ + u = rol32(u, 30); +#define SHA1_ROUND_2(v, u, x, y, z, i) \ + SHA1_LOAD(i) z += (u ^ x ^ y) + w[i & 15] + c1 + rol32(v, 5); \ + u = rol32(u, 30); +#define SHA1_ROUND_3(v, u, x, y, z, i) \ + SHA1_LOAD(i) z += (((u | x) & y) | (u & x)) + w[i & 15] + c2 + rol32(v, 5); \ + u = rol32(u, 30); +#define SHA1_ROUND_4(v, u, x, y, z, i) \ + SHA1_LOAD(i) z += (u ^ x ^ y) + w[i & 15] + c3 + rol32(v, 5); \ + u = rol32(u, 30); + + SHA1_ROUND_0(a, b, c, d, e, 0); + SHA1_ROUND_0(e, a, b, c, d, 1); + SHA1_ROUND_0(d, e, a, b, c, 2); + SHA1_ROUND_0(c, d, e, a, b, 3); + SHA1_ROUND_0(b, c, d, e, a, 4); + SHA1_ROUND_0(a, b, c, d, e, 5); + SHA1_ROUND_0(e, a, b, c, d, 6); + SHA1_ROUND_0(d, e, a, b, c, 7); + SHA1_ROUND_0(c, d, e, a, b, 8); + SHA1_ROUND_0(b, c, d, e, a, 9); SHA1_ROUND_0(a, b, c, d, e, 10); SHA1_ROUND_0(e, a, b, c, d, 11); SHA1_ROUND_0(d, e, a, b, c, 12); @@ -535,14 +545,14 @@ void SHA1::processBlock(const uint8_t* ptr) m_state[4] += e; } -/* static */SHA1::Digest SHA1::compute(const void* data, SlangInt size) +/* static */ SHA1::Digest SHA1::compute(const void* data, SlangInt size) { SHA1 sha1; sha1.update(data, size); return sha1.finalize(); } -} +} // namespace Slang /* @@ -584,12 +594,12 @@ void SHA1::processBlock(const uint8_t* ptr) /* * This is free and unencumbered software released into the public domain. - * + * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. - * + * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit @@ -597,7 +607,7 @@ void SHA1::processBlock(const uint8_t* ptr) * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -605,6 +615,6 @@ void SHA1::processBlock(const uint8_t* ptr) * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * + * * For more information, please refer to <http://unlicense.org> */ diff --git a/source/core/slang-crypto.h b/source/core/slang-crypto.h index feab88aa4..325130a85 100644 --- a/source/core/slang-crypto.h +++ b/source/core/slang-crypto.h @@ -1,184 +1,158 @@ #pragma once -#include "slang.h" -#include "../core/slang-string.h" #include "../core/slang-blob.h" #include "../core/slang-list.h" +#include "../core/slang-string.h" +#include "slang.h" namespace Slang { - struct DigestUtil - { - /// Convert a binary digest to a string (lower-case hexadecimal). - /// Returned string is double the length of the digest. - static String digestToString(const void* digest, SlangInt digestSize); - - /// Convert a string to a binary digest. - /// Expects a string of double the length of the digest size in hexadecimal format. - /// Sets the digest to all zeros if the string is invalid. - /// Returns true if string was converted successfully. - static bool stringToDigest(const char* str, SlangInt strLength, void *digest, SlangInt digestSize); - }; - - /// Represents a hash digest. Only sizes of multiple of 4 are supported. - template<SlangInt N> - class HashDigest - { - public: - static_assert(N % 4 == 0, "size must be multiple of 4"); - uint32_t data[N / 4] = { 0 }; +struct DigestUtil +{ + /// Convert a binary digest to a string (lower-case hexadecimal). + /// Returned string is double the length of the digest. + static String digestToString(const void* digest, SlangInt digestSize); + + /// Convert a string to a binary digest. + /// Expects a string of double the length of the digest size in hexadecimal format. + /// Sets the digest to all zeros if the string is invalid. + /// Returns true if string was converted successfully. + static bool stringToDigest( + const char* str, + SlangInt strLength, + void* digest, + SlangInt digestSize); +}; + +/// Represents a hash digest. Only sizes of multiple of 4 are supported. +template<SlangInt N> +class HashDigest +{ +public: + static_assert(N % 4 == 0, "size must be multiple of 4"); + uint32_t data[N / 4] = {0}; - HashDigest() = default; + HashDigest() = default; - HashDigest(const char* str) - { - DigestUtil::stringToDigest(str, ::strlen(str), data, N); - } + HashDigest(const char* str) { DigestUtil::stringToDigest(str, ::strlen(str), data, N); } - HashDigest(const String& str) - { - DigestUtil::stringToDigest(str.getBuffer(), str.getLength(), data, N); - } + HashDigest(const String& str) + { + DigestUtil::stringToDigest(str.getBuffer(), str.getLength(), data, N); + } - HashDigest(const UnownedStringSlice& str) - { - DigestUtil::stringToDigest(str.begin(), str.getLength(), data, N); - } + HashDigest(const UnownedStringSlice& str) + { + DigestUtil::stringToDigest(str.begin(), str.getLength(), data, N); + } - HashDigest(ISlangBlob* blob) + HashDigest(ISlangBlob* blob) + { + if (blob->getBufferSize() == N) { - if (blob->getBufferSize() == N) - { - ::memcpy(data, blob->getBufferPointer(), N); - } + ::memcpy(data, blob->getBufferPointer(), N); } + } - String toString() const - { - return DigestUtil::digestToString(data, N); - } + String toString() const { return DigestUtil::digestToString(data, N); } - ComPtr<ISlangBlob> toBlob() const - { - return RawBlob::create(data, sizeof(data)); - } + ComPtr<ISlangBlob> toBlob() const { return RawBlob::create(data, sizeof(data)); } - bool operator==(const HashDigest& other) const - { - return ::memcmp(data, other.data, sizeof(data)) == 0; - } + bool operator==(const HashDigest& other) const + { + return ::memcmp(data, other.data, sizeof(data)) == 0; + } - bool operator!=(const HashDigest& other) const - { - return !(*this == other); - } + bool operator!=(const HashDigest& other) const { return !(*this == other); } - uint32_t getHashCode() const - { - return data[0]; - } - }; + uint32_t getHashCode() const { return data[0]; } +}; - /// MD5 hash generator implementing https://www.ietf.org/rfc/rfc1321.txt - class MD5 - { - public: - using Digest = HashDigest<16>; +/// MD5 hash generator implementing https://www.ietf.org/rfc/rfc1321.txt +class MD5 +{ +public: + using Digest = HashDigest<16>; - MD5(); + MD5(); - void init(); - void update(const void* data, SlangSizeT size); - Digest finalize(); + void init(); + void update(const void* data, SlangSizeT size); + Digest finalize(); - static Digest compute(const void* data, SlangInt size); + static Digest compute(const void* data, SlangInt size); - private: - const void* processBlock(const void* data, SlangInt size); +private: + const void* processBlock(const void* data, SlangInt size); - uint32_t m_lo, m_hi; - uint32_t m_a, m_b, m_c, m_d; - uint32_t m_block[16]; - uint8_t m_buffer[64]; - }; + uint32_t m_lo, m_hi; + uint32_t m_a, m_b, m_c, m_d; + uint32_t m_block[16]; + uint8_t m_buffer[64]; +}; - /// SHA1 hash generator implementing https://www.ietf.org/rfc/rfc3174.txt - class SHA1 - { - public: - using Digest = HashDigest<20>; +/// SHA1 hash generator implementing https://www.ietf.org/rfc/rfc3174.txt +class SHA1 +{ +public: + using Digest = HashDigest<20>; - SHA1(); + SHA1(); - void init(); - void update(const void* data, SlangSizeT size); - Digest finalize(); + void init(); + void update(const void* data, SlangSizeT size); + Digest finalize(); - static Digest compute(const void* data, SlangInt size); + static Digest compute(const void* data, SlangInt size); - private: - void addByte(uint8_t x); - void processBlock(const uint8_t* ptr); +private: + void addByte(uint8_t x); + void processBlock(const uint8_t* ptr); - uint32_t m_index; - uint64_t m_bits; - uint32_t m_state[5]; - uint8_t m_buf[64]; - }; + uint32_t m_index; + uint64_t m_bits; + uint32_t m_state[5]; + uint8_t m_buf[64]; +}; - // Helper class for building hashes. - template<typename Hash> - struct DigestBuilder +// Helper class for building hashes. +template<typename Hash> +struct DigestBuilder +{ +public: + void append(const void* data, SlangInt size) { m_hash.update(data, size); } + + template< + typename T, + typename std::enable_if<std::is_arithmetic<T>::value || std::is_enum<T>::value, int>::type = + 0> + void append(const T value) { - public: - void append(const void* data, SlangInt size) - { - m_hash.update(data, size); - } + append(&value, sizeof(T)); + } - template<typename T, typename std::enable_if<std::is_arithmetic<T>::value || std::is_enum<T>::value, int>::type = 0> - void append(const T value) - { - append(&value, sizeof(T)); - } + void append(const String& str) { append(str.getBuffer(), str.getLength()); } - void append(const String& str) - { - append(str.getBuffer(), str.getLength()); - } - - void append(const StringSlice& str) - { - append(str.begin(), str.getLength()); - } + void append(const StringSlice& str) { append(str.begin(), str.getLength()); } - void append(const UnownedStringSlice& str) - { - append(str.begin(), str.getLength()); - } + void append(const UnownedStringSlice& str) { append(str.begin(), str.getLength()); } - void append(ISlangBlob* blob) - { - append(blob->getBufferPointer(), blob->getBufferSize()); - } + void append(ISlangBlob* blob) { append(blob->getBufferPointer(), blob->getBufferSize()); } - template<SlangInt N> - void append(const HashDigest<N>& digest) - { - append(digest.data, sizeof(digest.data)); - } + template<SlangInt N> + void append(const HashDigest<N>& digest) + { + append(digest.data, sizeof(digest.data)); + } - template<typename T, std::enable_if_t<std::has_unique_object_representations_v<T>, int> = 0> - void append(const List<T>& list) - { - append(list.getBuffer(), list.getCount() * sizeof(T)); - } + template<typename T, std::enable_if_t<std::has_unique_object_representations_v<T>, int> = 0> + void append(const List<T>& list) + { + append(list.getBuffer(), list.getCount() * sizeof(T)); + } - typename Hash::Digest finalize() - { - return m_hash.finalize(); - } + typename Hash::Digest finalize() { return m_hash.finalize(); } - private: - Hash m_hash; - }; -} +private: + Hash m_hash; +}; +} // namespace Slang diff --git a/source/core/slang-deflate-compression-system.cpp b/source/core/slang-deflate-compression-system.cpp index 4f1390240..1cbea01f0 100644 --- a/source/core/slang-deflate-compression-system.cpp +++ b/source/core/slang-deflate-compression-system.cpp @@ -3,13 +3,13 @@ #include "slang-com-helper.h" #include "slang-com-ptr.h" -// We don't want compress #define to clash +// We don't want compress #define to clash #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1 -#include <miniz.h> - #include "slang-blob.h" +#include <miniz.h> + namespace Slang { @@ -18,7 +18,7 @@ namespace Slang class DeflateCompressionSystemImpl : public RefObject, public ICompressionSystem { public: - // ISlangUnknown + // ISlangUnknown // override ref counting, as singleton SLANG_IUNKNOWN_QUERY_INTERFACE @@ -26,28 +26,45 @@ public: SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } // ICompressionSystem - virtual SLANG_NO_THROW CompressionSystemType SLANG_MCALL getSystemType() SLANG_OVERRIDE { return CompressionSystemType::Deflate; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compress(const CompressionStyle* style, const void* src, size_t srcSizeInBytes, ISlangBlob** outBlob) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL decompress(const void* compressed, size_t compressedSizeInBytes, size_t decompressedSizeInBytes, void* outDecompressed) SLANG_OVERRIDE; + virtual SLANG_NO_THROW CompressionSystemType SLANG_MCALL getSystemType() SLANG_OVERRIDE + { + return CompressionSystemType::Deflate; + } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compress( + const CompressionStyle* style, + const void* src, + size_t srcSizeInBytes, + ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL decompress( + const void* compressed, + size_t compressedSizeInBytes, + size_t decompressedSizeInBytes, + void* outDecompressed) SLANG_OVERRIDE; protected: - ICompressionSystem* getInterface(const Guid& guid); }; ICompressionSystem* DeflateCompressionSystemImpl::getInterface(const Guid& guid) { - return (guid == ISlangUnknown::getTypeGuid() || guid == ICompressionSystem::getTypeGuid()) ? static_cast<ICompressionSystem*>(this) : nullptr; + return (guid == ISlangUnknown::getTypeGuid() || guid == ICompressionSystem::getTypeGuid()) + ? static_cast<ICompressionSystem*>(this) + : nullptr; } -SlangResult DeflateCompressionSystemImpl::compress(const CompressionStyle* style, const void* src, size_t srcSizeInBytes, ISlangBlob** outBlob) +SlangResult DeflateCompressionSystemImpl::compress( + const CompressionStyle* style, + const void* src, + size_t srcSizeInBytes, + ISlangBlob** outBlob) { SLANG_UNUSED(style); size_t compressedSizeInBytes; const int flags = 0; - void* compressed = tdefl_compress_mem_to_heap(src, srcSizeInBytes, &compressedSizeInBytes, flags); + void* compressed = + tdefl_compress_mem_to_heap(src, srcSizeInBytes, &compressedSizeInBytes, flags); if (!compressed) { @@ -62,11 +79,20 @@ SlangResult DeflateCompressionSystemImpl::compress(const CompressionStyle* style return SLANG_OK; } -SlangResult DeflateCompressionSystemImpl::decompress(const void* compressed, size_t compressedSizeInBytes, size_t decompressedSizeInBytes, void* outDecompressed) +SlangResult DeflateCompressionSystemImpl::decompress( + const void* compressed, + size_t compressedSizeInBytes, + size_t decompressedSizeInBytes, + void* outDecompressed) { const int flags = TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - size_t size = tinfl_decompress_mem_to_mem(outDecompressed, decompressedSizeInBytes, compressed ,compressedSizeInBytes, flags); + size_t size = tinfl_decompress_mem_to_mem( + outDecompressed, + decompressedSizeInBytes, + compressed, + compressedSizeInBytes, + flags); if (size == TINFL_DECOMPRESS_MEM_TO_MEM_FAILED) { return SLANG_FAIL; @@ -75,7 +101,7 @@ SlangResult DeflateCompressionSystemImpl::decompress(const void* compressed, siz return SLANG_OK; } -/* static */ICompressionSystem* DeflateCompressionSystem::getSingleton() +/* static */ ICompressionSystem* DeflateCompressionSystem::getSingleton() { static DeflateCompressionSystemImpl impl; return &impl; diff --git a/source/core/slang-deflate-compression-system.h b/source/core/slang-deflate-compression-system.h index efed59e61..929ad153a 100644 --- a/source/core/slang-deflate-compression-system.h +++ b/source/core/slang-deflate-compression-system.h @@ -2,10 +2,8 @@ #define SLANG_DEFLATE_COMPRESSION_SYSTEM_H #include "slang-basic.h" - -#include "slang-compression-system.h" - #include "slang-com-ptr.h" +#include "slang-compression-system.h" namespace Slang { @@ -17,6 +15,6 @@ public: static ICompressionSystem* getSingleton(); }; -} +} // namespace Slang #endif diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h index 9c753ffcd..79f6dee30 100644 --- a/source/core/slang-dictionary.h +++ b/source/core/slang-dictionary.h @@ -1,786 +1,752 @@ #ifndef SLANG_CORE_DICTIONARY_H #define SLANG_CORE_DICTIONARY_H -#include "slang-list.h" -#include "slang-linked-list.h" +#include "../../external/unordered_dense/include/ankerl/unordered_dense.h" #include "slang-common.h" -#include "slang-uint-set.h" #include "slang-exception.h" -#include "slang-math.h" #include "slang-hash.h" - -#include "../../external/unordered_dense/include/ankerl/unordered_dense.h" +#include "slang-linked-list.h" +#include "slang-list.h" +#include "slang-math.h" +#include "slang-uint-set.h" #include <initializer_list> namespace Slang { - template<typename TKey, typename TValue> - class KeyValuePair +template<typename TKey, typename TValue> +class KeyValuePair +{ +public: + TKey key; + TValue value; + KeyValuePair() {} + KeyValuePair(const TKey& inKey, const TValue& inValue) { - public: - TKey key; - TValue value; - KeyValuePair() - {} - KeyValuePair(const TKey& inKey, const TValue& inValue) - { - key = inKey; - value = inValue; - } - KeyValuePair(TKey&& inKey, TValue&& inValue) - { - key = _Move(inKey); - value = _Move(inValue); - } - KeyValuePair(TKey&& inKey, const TValue& inValue) - { - key = _Move(inKey); - value = inValue; - } - KeyValuePair(const KeyValuePair<TKey, TValue>& that) - { - key = that.key; - value = that.value; - } - KeyValuePair(KeyValuePair<TKey, TValue>&& that) - { - operator=(_Move(that)); - } - KeyValuePair& operator=(KeyValuePair<TKey, TValue>&& that) - { - key = _Move(that.key); - value = _Move(that.value); - return *this; - } - KeyValuePair& operator=(const KeyValuePair<TKey, TValue>& that) - { - key = that.key; - value = that.value; - return *this; - } - HashCode getHashCode() const - { - return combineHash( - Slang::getHashCode(key), - Slang::getHashCode(value)); - } - bool operator==(const KeyValuePair<TKey, TValue>& that) const - { - return (key == that.key) && (value == that.value); - } - }; - - template<typename TKey, typename TValue> - inline KeyValuePair<TKey, TValue> KVPair(const TKey& k, const TValue& v) + key = inKey; + value = inValue; + } + KeyValuePair(TKey&& inKey, TValue&& inValue) { - return KeyValuePair<TKey, TValue>(k, v); + key = _Move(inKey); + value = _Move(inValue); } - - namespace KeyValueDetail { - - template <typename KEY, typename VALUE> - SLANG_FORCE_INLINE const KEY* getKey(const std::pair<KEY, VALUE>* in) + KeyValuePair(TKey&& inKey, const TValue& inValue) { - return &in->first; + key = _Move(inKey); + value = inValue; } - template <typename KEY, typename VALUE> - SLANG_FORCE_INLINE const KEY* getKey(const KeyValuePair<KEY, VALUE>* in) + KeyValuePair(const KeyValuePair<TKey, TValue>& that) { - return &in->key; + key = that.key; + value = that.value; } - - template <typename KEY, typename VALUE> - SLANG_FORCE_INLINE const VALUE* getValue(const std::pair<KEY, VALUE>* in) + KeyValuePair(KeyValuePair<TKey, TValue>&& that) { operator=(_Move(that)); } + KeyValuePair& operator=(KeyValuePair<TKey, TValue>&& that) + { + key = _Move(that.key); + value = _Move(that.value); + return *this; + } + KeyValuePair& operator=(const KeyValuePair<TKey, TValue>& that) + { + key = that.key; + value = that.value; + return *this; + } + HashCode getHashCode() const { - return &in->second; + return combineHash(Slang::getHashCode(key), Slang::getHashCode(value)); } - template <typename KEY, typename VALUE> - SLANG_FORCE_INLINE const VALUE* getValue(const KeyValuePair<KEY, VALUE>* in) + bool operator==(const KeyValuePair<TKey, TValue>& that) const { - return &in->value; + return (key == that.key) && (value == that.value); } +}; - } // namespace KeyValueDetail +template<typename TKey, typename TValue> +inline KeyValuePair<TKey, TValue> KVPair(const TKey& k, const TValue& v) +{ + return KeyValuePair<TKey, TValue>(k, v); +} + +namespace KeyValueDetail +{ + +template<typename KEY, typename VALUE> +SLANG_FORCE_INLINE const KEY* getKey(const std::pair<KEY, VALUE>* in) +{ + return &in->first; +} +template<typename KEY, typename VALUE> +SLANG_FORCE_INLINE const KEY* getKey(const KeyValuePair<KEY, VALUE>* in) +{ + return &in->key; +} + +template<typename KEY, typename VALUE> +SLANG_FORCE_INLINE const VALUE* getValue(const std::pair<KEY, VALUE>* in) +{ + return &in->second; +} +template<typename KEY, typename VALUE> +SLANG_FORCE_INLINE const VALUE* getValue(const KeyValuePair<KEY, VALUE>* in) +{ + return &in->value; +} - const float kMaxLoadFactor = 0.7f; +} // namespace KeyValueDetail - template<typename TKey, typename TValue, typename Hash = Slang::Hash<TKey>, typename KeyEqual = std::equal_to<TKey>> - class Dictionary +const float kMaxLoadFactor = 0.7f; + +template< + typename TKey, + typename TValue, + typename Hash = Slang::Hash<TKey>, + typename KeyEqual = std::equal_to<TKey>> +class Dictionary +{ + using InnerMap = ankerl::unordered_dense::map<TKey, TValue, Hash, KeyEqual>; + using ThisType = Dictionary<TKey, TValue, Hash, KeyEqual>; + InnerMap map; + +public: + Dictionary() = default; + Dictionary(const Dictionary&) = default; + Dictionary(Dictionary&&) = default; + ThisType& operator=(const ThisType&) = default; + ThisType& operator=(ThisType&&) = default; + Dictionary(std::initializer_list<typename InnerMap::value_type> inits) + : map(std::move(inits)) { - using InnerMap = ankerl::unordered_dense::map< - TKey, - TValue, - Hash, - KeyEqual>; - using ThisType = Dictionary<TKey, TValue, Hash, KeyEqual>; - InnerMap map; - public: - Dictionary() = default; - Dictionary(const Dictionary&) = default; - Dictionary(Dictionary&&) = default; - ThisType& operator=(const ThisType&) = default; - ThisType& operator=(ThisType&&) = default; - Dictionary(std::initializer_list<typename InnerMap::value_type> inits) - : map(std::move(inits)) - { - } + } - // - // Types - // - using Iterator = typename InnerMap::iterator; - using ConstIterator = typename InnerMap::const_iterator; - using KeyType = TKey; - using ValueType = TValue; + // + // Types + // + using Iterator = typename InnerMap::iterator; + using ConstIterator = typename InnerMap::const_iterator; + using KeyType = TKey; + using ValueType = TValue; - // - // Iterators - // + // + // Iterators + // - auto begin() { return map.begin(); } - auto begin() const { return map.begin(); } - auto end() { return map.end(); } - auto end() const { return map.end(); } + auto begin() { return map.begin(); } + auto begin() const { return map.begin(); } + auto end() { return map.end(); } + auto end() const { return map.end(); } - // - // Modifiers - // + // + // Modifiers + // - // Removes all values from the map - void clear() { map.clear(); } + // Removes all values from the map + void clear() { map.clear(); } - // Erases the value at the specified key if it exists - void remove(const TKey& key) { map.erase(key); } + // Erases the value at the specified key if it exists + void remove(const TKey& key) { map.erase(key); } - // Reserves enough space for the specified number of values - void reserve(Index size) { map.reserve(std::size_t(size)); }; + // Reserves enough space for the specified number of values + void reserve(Index size) { map.reserve(std::size_t(size)); }; - // Swap with another map - void swapWith(ThisType& rhs) { std::swap(*this, rhs); } + // Swap with another map + void swapWith(ThisType& rhs) { std::swap(*this, rhs); } - // - // Query capacity - // + // + // Query capacity + // - std::size_t getCount() const { return map.size(); } + std::size_t getCount() const { return map.size(); } - // - // Lookup - // + // + // Lookup + // - // Returns true if the map contains an equivalent key - template<typename K> - bool containsKey(const K& k) const { return map.contains(k); } + // Returns true if the map contains an equivalent key + template<typename K> + bool containsKey(const K& k) const + { + return map.contains(k); + } - // Returns a valid pointer to the requested element, or nullptr if it - // doesn't exist - template<typename K> - const TValue* tryGetValue(const K& key) const - { - auto i = map.find(key); - return i == map.end() ? nullptr : &(i->second); - } - // Returns a valid pointer to the requested element, or nullptr if it - // doesn't exist - template<typename K> - TValue* tryGetValue(const K& key) - { - auto i = map.find(key); - return i == map.end() ? nullptr : std::addressof(i->second); - } + // Returns a valid pointer to the requested element, or nullptr if it + // doesn't exist + template<typename K> + const TValue* tryGetValue(const K& key) const + { + auto i = map.find(key); + return i == map.end() ? nullptr : &(i->second); + } + // Returns a valid pointer to the requested element, or nullptr if it + // doesn't exist + template<typename K> + TValue* tryGetValue(const K& key) + { + auto i = map.find(key); + return i == map.end() ? nullptr : std::addressof(i->second); + } - // Returns true and copies the element into 'value' if present. - // Otherwise returns false and value unmodified. - template<typename K> - bool tryGetValue(const K& key, TValue& value) const - { - auto i = map.find(key); - if(i == map.end()) - return false; - value = i->second; - return true; - } + // Returns true and copies the element into 'value' if present. + // Otherwise returns false and value unmodified. + template<typename K> + bool tryGetValue(const K& key, TValue& value) const + { + auto i = map.find(key); + if (i == map.end()) + return false; + value = i->second; + return true; + } - // Returns a const reference to the value at the given key. Asserts if - // the value doesn't exist - const TValue& getValue(const TKey& key) const - { - if(const auto x = tryGetValue(key)) - return *x; - SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); - } + // Returns a const reference to the value at the given key. Asserts if + // the value doesn't exist + const TValue& getValue(const TKey& key) const + { + if (const auto x = tryGetValue(key)) + return *x; + SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); + } - // Returns a reference to the value at the given key. Asserts if the - // value doesn't exist - TValue& getValue(const TKey& key) - { - if(const auto x = tryGetValue(key)) - return *x; - SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); - } + // Returns a reference to the value at the given key. Asserts if the + // value doesn't exist + TValue& getValue(const TKey& key) + { + if (const auto x = tryGetValue(key)) + return *x; + SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); + } - // - // Combined Lookup and Insertion - // + // + // Combined Lookup and Insertion + // - // Tries to insert the given element, if a value was already present at - // the given key then returns a pointer to that element instead. - // Returns nullptr if insertion was successful. - TValue* tryGetValueOrAdd(const typename InnerMap::value_type& kvPair) - { - const auto& [iterator, inserted] = map.insert(kvPair); - return inserted ? nullptr : std::addressof(iterator->second); - } - // Tries to insert the given element, if a value was already present at - // the given key then returns a pointer to that element instead. - // Returns nullptr if insertion was successful. - TValue* tryGetValueOrAdd(typename InnerMap::value_type&& kvPair) - { - const auto& [iterator, inserted] = map.insert(std::move(kvPair)); - return inserted ? nullptr : std::addressof(iterator->second); - } - // Tries to insert the given element, if a value was already present at - // the given key then returns a pointer to that element instead. - // Returns nullptr if insertion was successful. - TValue* tryGetValueOrAdd(const TKey& key, const TValue& value) { return tryGetValueOrAdd({key, value}); } - - // Inserts the given value if it doesn't exist already - // Return a reference to the (possibly new) value in the map - TValue& getOrAddValue(const TKey& key, const TValue& defaultValue) - { - auto [iterator, inserted] = map.insert({key, defaultValue}); - return iterator->second; - } + // Tries to insert the given element, if a value was already present at + // the given key then returns a pointer to that element instead. + // Returns nullptr if insertion was successful. + TValue* tryGetValueOrAdd(const typename InnerMap::value_type& kvPair) + { + const auto& [iterator, inserted] = map.insert(kvPair); + return inserted ? nullptr : std::addressof(iterator->second); + } + // Tries to insert the given element, if a value was already present at + // the given key then returns a pointer to that element instead. + // Returns nullptr if insertion was successful. + TValue* tryGetValueOrAdd(typename InnerMap::value_type&& kvPair) + { + const auto& [iterator, inserted] = map.insert(std::move(kvPair)); + return inserted ? nullptr : std::addressof(iterator->second); + } + // Tries to insert the given element, if a value was already present at + // the given key then returns a pointer to that element instead. + // Returns nullptr if insertion was successful. + TValue* tryGetValueOrAdd(const TKey& key, const TValue& value) + { + return tryGetValueOrAdd({key, value}); + } - // Returns a reference to the value at the specified key, default - // initializing it if it doesn't already exist - TValue& operator[]( const TKey& key ) { return map[key]; } - // Returns a reference to the value at the specified key, default - // initializing it if it doesn't already exist - TValue& operator[]( TKey&& key ) { return map[std::move(key)]; } - - // - // Insertion - // - - // Returns true if the value was inserted, returns false if the map - // already has a value associated with this key - bool addIfNotExists(typename InnerMap::value_type&& kvPair) { return !tryGetValueOrAdd(std::move(kvPair)); } - // Returns true if the value was inserted, returns false if the map - // already has a value associated with this key - bool addIfNotExists(const typename InnerMap::value_type& kvPair) { return !tryGetValueOrAdd(kvPair); } - // Returns true if the value was inserted, returns false if the map - // already has a value associated with this key - bool addIfNotExists(const TKey& k, const TValue& v) { return addIfNotExists({k, v}); } - // Returns true if the value was inserted, returns false if the map - // already has a value associated with this key - bool addIfNotExists(TKey&& k, TValue&& v) { return addIfNotExists({std::move(k), std::move(v)}); } - - // Asserts if the key already exists in the dictionary - void add(typename InnerMap::value_type&& kvPair) - { - if (!addIfNotExists(std::move(kvPair))) - SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); - } - // Asserts if the key already exists in the dictionary - void add(const typename InnerMap::value_type& kvPair) - { - if (!addIfNotExists(kvPair)) - SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); - } - // Asserts if the key already exists in the dictionary - void add(const TKey& key, const TValue& value) { add({key, value}); } - // Asserts if the key already exists in the dictionary - void add(TKey&& key, TValue&& value) { add({std::move(key), std::move(value)}); } + // Inserts the given value if it doesn't exist already + // Return a reference to the (possibly new) value in the map + TValue& getOrAddValue(const TKey& key, const TValue& defaultValue) + { + auto [iterator, inserted] = map.insert({key, defaultValue}); + return iterator->second; + } - // Inserts into the dictionary or assigns if the key already exists - void set(const TKey& key, const TValue& value) { map.insert_or_assign(key, value); } - }; + // Returns a reference to the value at the specified key, default + // initializing it if it doesn't already exist + TValue& operator[](const TKey& key) { return map[key]; } + // Returns a reference to the value at the specified key, default + // initializing it if it doesn't already exist + TValue& operator[](TKey&& key) { return map[std::move(key)]; } + + // + // Insertion + // + + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(typename InnerMap::value_type&& kvPair) + { + return !tryGetValueOrAdd(std::move(kvPair)); + } + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(const typename InnerMap::value_type& kvPair) + { + return !tryGetValueOrAdd(kvPair); + } + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(const TKey& k, const TValue& v) { return addIfNotExists({k, v}); } + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(TKey&& k, TValue&& v) + { + return addIfNotExists({std::move(k), std::move(v)}); + } + + // Asserts if the key already exists in the dictionary + void add(typename InnerMap::value_type&& kvPair) + { + if (!addIfNotExists(std::move(kvPair))) + SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); + } + // Asserts if the key already exists in the dictionary + void add(const typename InnerMap::value_type& kvPair) + { + if (!addIfNotExists(kvPair)) + SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); + } + // Asserts if the key already exists in the dictionary + void add(const TKey& key, const TValue& value) { add({key, value}); } + // Asserts if the key already exists in the dictionary + void add(TKey&& key, TValue&& value) { add({std::move(key), std::move(value)}); } + + // Inserts into the dictionary or assigns if the key already exists + void set(const TKey& key, const TValue& value) { map.insert_or_assign(key, value); } +}; - /* We may want to rename this, as strictly speaking _Caps names are reserved */ - class _DummyClass - {}; +/* We may want to rename this, as strictly speaking _Caps names are reserved */ +class _DummyClass +{ +}; + +template<typename T, typename DictionaryType> +class HashSetBase +{ +protected: + DictionaryType dict; + +private: + template<typename... Args> + void init(const T& v, Args... args) + { + add(v); + init(args...); + } - template<typename T, typename DictionaryType> - class HashSetBase +public: + HashSetBase() {} + template<typename Arg, typename... Args> + HashSetBase(Arg arg, Args... args) + { + init(arg, args...); + } + HashSetBase(const HashSetBase& set) { operator=(set); } + HashSetBase(HashSetBase&& set) { operator=(_Move(set)); } + HashSetBase& operator=(const HashSetBase& set) + { + dict = set.dict; + return *this; + } + HashSetBase& operator=(HashSetBase&& set) + { + dict = _Move(set.dict); + return *this; + } + +public: + class Iterator { - protected: - DictionaryType dict; private: - template<typename... Args> - void init(const T& v, Args... args) - { - add(v); - init(args...); - } - public: - HashSetBase() - {} - template<typename Arg, typename... Args> - HashSetBase(Arg arg, Args... args) - { - init(arg, args...); - } - HashSetBase(const HashSetBase& set) - { - operator=(set); - } - HashSetBase(HashSetBase&& set) - { - operator=(_Move(set)); - } - HashSetBase& operator=(const HashSetBase& set) - { - dict = set.dict; - return *this; - } - HashSetBase& operator=(HashSetBase&& set) - { - dict = _Move(set.dict); - return *this; - } - public: - class Iterator - { - private: - typename DictionaryType::ConstIterator iter; - public: - Iterator() = default; - const T& operator*() const - { - return *KeyValueDetail::getKey(std::addressof(*iter)); - } - const T* operator->() const - { - return KeyValueDetail::getKey(std::addressof(*iter)); - } + typename DictionaryType::ConstIterator iter; - Iterator& operator++() - { - ++iter; - return *this; - } - Iterator operator++(int) - { - Iterator rs = *this; - operator++(); - return rs; - } - bool operator!=(const Iterator& that) const - { - return iter != that.iter; - } - bool operator==(const Iterator& that) const - { - return iter == that.iter; - } - Iterator(const typename DictionaryType::ConstIterator& _iter) - { - this->iter = _iter; - } - }; - Iterator begin() const - { - return Iterator(dict.begin()); - } - Iterator end() const - { - return Iterator(dict.end()); - } public: - auto getCount() const - { - return dict.getCount(); - } - void clear() - { - dict.clear(); - } - bool add(const T& obj) - { - return dict.addIfNotExists(obj, _DummyClass()); - } - bool add(T&& obj) - { - return dict.addIfNotExists(_Move(obj), _DummyClass()); - } - void remove(const T& obj) + Iterator() = default; + const T& operator*() const { return *KeyValueDetail::getKey(std::addressof(*iter)); } + const T* operator->() const { return KeyValueDetail::getKey(std::addressof(*iter)); } + + Iterator& operator++() { - dict.remove(obj); + ++iter; + return *this; } - bool contains(const T& obj) const + Iterator operator++(int) { - return dict.containsKey(obj); + Iterator rs = *this; + operator++(); + return rs; } + bool operator!=(const Iterator& that) const { return iter != that.iter; } + bool operator==(const Iterator& that) const { return iter == that.iter; } + Iterator(const typename DictionaryType::ConstIterator& _iter) { this->iter = _iter; } }; - template <typename T> - class HashSet : public HashSetBase<T, Dictionary<T, _DummyClass>> - {}; + Iterator begin() const { return Iterator(dict.begin()); } + Iterator end() const { return Iterator(dict.end()); } + +public: + auto getCount() const { return dict.getCount(); } + void clear() { dict.clear(); } + bool add(const T& obj) { return dict.addIfNotExists(obj, _DummyClass()); } + bool add(T&& obj) { return dict.addIfNotExists(_Move(obj), _DummyClass()); } + void remove(const T& obj) { dict.remove(obj); } + bool contains(const T& obj) const { return dict.containsKey(obj); } +}; +template<typename T> +class HashSet : public HashSetBase<T, Dictionary<T, _DummyClass>> +{ +}; - template <typename TKey, typename TValue> - class OrderedDictionary - { - friend class Iterator; - friend class ItemProxy; +template<typename TKey, typename TValue> +class OrderedDictionary +{ + friend class Iterator; + friend class ItemProxy; - private: - inline int getProbeOffset(int /*probeIdx*/) const - { - // quadratic probing - return 1; - } +private: + inline int getProbeOffset(int /*probeIdx*/) const + { + // quadratic probing + return 1; + } - private: - int m_bucketCountMinusOne; - int m_count; - UIntSet m_marks; +private: + int m_bucketCountMinusOne; + int m_count; + UIntSet m_marks; - LinkedList<KeyValuePair<TKey, TValue>> m_kvPairs; - LinkedNode<KeyValuePair<TKey, TValue>>** m_hashMap; - void deallocateAll() - { - if (m_hashMap) - delete[] m_hashMap; - m_hashMap = nullptr; - m_kvPairs.clear(); - } - inline bool isDeleted(int pos) const { return m_marks.contains((pos << 1) + 1); } - inline bool isEmpty(int pos) const { return !m_marks.contains((pos << 1)); } - inline void setDeleted(int pos, bool val) + LinkedList<KeyValuePair<TKey, TValue>> m_kvPairs; + LinkedNode<KeyValuePair<TKey, TValue>>** m_hashMap; + void deallocateAll() + { + if (m_hashMap) + delete[] m_hashMap; + m_hashMap = nullptr; + m_kvPairs.clear(); + } + inline bool isDeleted(int pos) const { return m_marks.contains((pos << 1) + 1); } + inline bool isEmpty(int pos) const { return !m_marks.contains((pos << 1)); } + inline void setDeleted(int pos, bool val) + { + if (val) + m_marks.add((pos << 1) + 1); + else + m_marks.remove((pos << 1) + 1); + } + inline void setEmpty(int pos, bool val) + { + if (val) + m_marks.remove((pos << 1)); + else + m_marks.add((pos << 1)); + } + struct FindPositionResult + { + int objectPosition; + int insertionPosition; + FindPositionResult() { - if (val) - m_marks.add((pos << 1) + 1); - else - m_marks.remove((pos << 1) + 1); + objectPosition = -1; + insertionPosition = -1; } - inline void setEmpty(int pos, bool val) + FindPositionResult(int objPos, int insertPos) { - if (val) - m_marks.remove((pos << 1)); - else - m_marks.add((pos << 1)); + objectPosition = objPos; + insertionPosition = insertPos; } - struct FindPositionResult + }; + template<typename T> + inline int getHashPos(T& key) const + { + const unsigned int hash = (unsigned int)getHashCode(key); + return ((unsigned int)(hash * 2654435761)) % m_bucketCountMinusOne; + } + template<typename T> + FindPositionResult findPosition(const T& key) const + { + int hashPos = getHashPos((T&)key); + int insertPos = -1; + int numProbes = 0; + while (numProbes <= m_bucketCountMinusOne) { - int objectPosition; - int insertionPosition; - FindPositionResult() + if (isEmpty(hashPos)) { - objectPosition = -1; - insertionPosition = -1; + if (insertPos == -1) + return FindPositionResult(-1, hashPos); + else + return FindPositionResult(-1, insertPos); } - FindPositionResult(int objPos, int insertPos) + else if (isDeleted(hashPos)) { - objectPosition = objPos; - insertionPosition = insertPos; + if (insertPos == -1) + insertPos = hashPos; } - }; - template <typename T> inline int getHashPos(T& key) const - { - const unsigned int hash = (unsigned int)getHashCode(key); - return ((unsigned int)(hash * 2654435761)) % m_bucketCountMinusOne; - } - template <typename T> FindPositionResult findPosition(const T& key) const - { - int hashPos = getHashPos((T&)key); - int insertPos = -1; - int numProbes = 0; - while (numProbes <= m_bucketCountMinusOne) + else if (m_hashMap[hashPos]->value.key == key) { - if (isEmpty(hashPos)) - { - if (insertPos == -1) - return FindPositionResult(-1, hashPos); - else - return FindPositionResult(-1, insertPos); - } - else if (isDeleted(hashPos)) - { - if (insertPos == -1) - insertPos = hashPos; - } - else if (m_hashMap[hashPos]->value.key == key) - { - return FindPositionResult(hashPos, -1); - } - numProbes++; - hashPos = (hashPos + getProbeOffset(numProbes)) & m_bucketCountMinusOne; + return FindPositionResult(hashPos, -1); } - if (insertPos != -1) - return FindPositionResult(-1, insertPos); - SLANG_ASSERT_FAILURE("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode."); + numProbes++; + hashPos = (hashPos + getProbeOffset(numProbes)) & m_bucketCountMinusOne; } - TValue& _insert(KeyValuePair<TKey, TValue>&& kvPair, int pos) - { - auto node = m_kvPairs.addLast(); - node->value = _Move(kvPair); - m_hashMap[pos] = node; - setEmpty(pos, false); - setDeleted(pos, false); - return node->value.value; - } - void maybeRehash() + if (insertPos != -1) + return FindPositionResult(-1, insertPos); + SLANG_ASSERT_FAILURE( + "Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode."); + } + TValue& _insert(KeyValuePair<TKey, TValue>&& kvPair, int pos) + { + auto node = m_kvPairs.addLast(); + node->value = _Move(kvPair); + m_hashMap[pos] = node; + setEmpty(pos, false); + setDeleted(pos, false); + return node->value.value; + } + void maybeRehash() + { + if (m_bucketCountMinusOne == -1 || m_count / (float)m_bucketCountMinusOne >= kMaxLoadFactor) { - if (m_bucketCountMinusOne == -1 || m_count / (float)m_bucketCountMinusOne >= kMaxLoadFactor) + int newSize = (m_bucketCountMinusOne + 1) * 2; + if (newSize == 0) { - int newSize = (m_bucketCountMinusOne + 1) * 2; - if (newSize == 0) - { - newSize = 128; - } - OrderedDictionary<TKey, TValue> newDict; - newDict.m_bucketCountMinusOne = newSize - 1; - newDict.m_hashMap = new LinkedNode<KeyValuePair<TKey, TValue>>*[newSize]; - newDict.m_marks.resizeAndClear(newSize * 2); - if (m_hashMap) + newSize = 128; + } + OrderedDictionary<TKey, TValue> newDict; + newDict.m_bucketCountMinusOne = newSize - 1; + newDict.m_hashMap = new LinkedNode<KeyValuePair<TKey, TValue>>*[newSize]; + newDict.m_marks.resizeAndClear(newSize * 2); + if (m_hashMap) + { + for (auto& kvPair : *this) { - for (auto& kvPair : *this) - { - newDict.add(_Move(kvPair)); - } + newDict.add(_Move(kvPair)); } - *this = _Move(newDict); } + *this = _Move(newDict); } + } - bool addIfNotExists(KeyValuePair<TKey, TValue>&& kvPair) + bool addIfNotExists(KeyValuePair<TKey, TValue>&& kvPair) + { + maybeRehash(); + auto pos = findPosition(kvPair.key); + if (pos.objectPosition != -1) + return false; + else if (pos.insertionPosition != -1) { - maybeRehash(); - auto pos = findPosition(kvPair.key); - if (pos.objectPosition != -1) - return false; - else if (pos.insertionPosition != -1) - { - m_count++; - _insert(_Move(kvPair), pos.insertionPosition); - return true; - } - else - SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation."); + m_count++; + _insert(_Move(kvPair), pos.insertionPosition); + return true; } - void add(KeyValuePair<TKey, TValue>&& kvPair) + else + SLANG_ASSERT_FAILURE( + "Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + void add(KeyValuePair<TKey, TValue>&& kvPair) + { + if (!addIfNotExists(_Move(kvPair))) + SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); + } + TValue& set(KeyValuePair<TKey, TValue>&& kvPair) + { + maybeRehash(); + auto pos = findPosition(kvPair.key); + if (pos.objectPosition != -1) { - if (!addIfNotExists(_Move(kvPair))) - SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); + m_hashMap[pos.objectPosition]->removeAndDelete(); + return _insert(_Move(kvPair), pos.objectPosition); } - TValue& set(KeyValuePair<TKey, TValue>&& kvPair) + else if (pos.insertionPosition != -1) { - maybeRehash(); - auto pos = findPosition(kvPair.key); - if (pos.objectPosition != -1) - { - m_hashMap[pos.objectPosition]->removeAndDelete(); - return _insert(_Move(kvPair), pos.objectPosition); - } - else if (pos.insertionPosition != -1) - { - m_count++; - return _insert(_Move(kvPair), pos.insertionPosition); - } - else - SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation."); + m_count++; + return _insert(_Move(kvPair), pos.insertionPosition); } + else + SLANG_ASSERT_FAILURE( + "Inconsistent find result returned. This is a bug in Dictionary implementation."); + } - public: - using Iterator = typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator; - using ConstIterator = typename LinkedList<KeyValuePair<TKey, TValue>>::ConstIterator; +public: + using Iterator = typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator; + using ConstIterator = typename LinkedList<KeyValuePair<TKey, TValue>>::ConstIterator; - Iterator begin() { return m_kvPairs.begin(); } - Iterator end() { return m_kvPairs.end(); } - ConstIterator begin() const { return m_kvPairs.begin(); } - ConstIterator end() const { return m_kvPairs.end(); } + Iterator begin() { return m_kvPairs.begin(); } + Iterator end() { return m_kvPairs.end(); } + ConstIterator begin() const { return m_kvPairs.begin(); } + ConstIterator end() const { return m_kvPairs.end(); } - public: - void add(const TKey& key, const TValue& value) - { - add(KeyValuePair<TKey, TValue>(key, value)); - } - void add(TKey&& key, TValue&& value) - { - add(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); - } - bool addIfNotExists(const TKey& key, const TValue& value) - { - return addIfNotExists(KeyValuePair<TKey, TValue>(key, value)); - } - bool addIfNotExists(TKey&& key, TValue&& value) - { - return addIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); - } - void remove(const TKey& key) - { - if (m_count > 0) - { - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - m_kvPairs.removeAndDelete(m_hashMap[pos.objectPosition]); - m_hashMap[pos.objectPosition] = 0; - setDeleted(pos.objectPosition, true); - m_count--; - } - } - } - void clear() - { - m_count = 0; - m_kvPairs.clear(); - m_marks.clear(); - } - template <typename T> bool containsKey(const T& key) const - { - if (m_bucketCountMinusOne == -1) - return false; - auto pos = findPosition(key); - return pos.objectPosition != -1; - } - template <typename T> TValue* tryGetValue(const T& key) const +public: + void add(const TKey& key, const TValue& value) { add(KeyValuePair<TKey, TValue>(key, value)); } + void add(TKey&& key, TValue&& value) + { + add(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); + } + bool addIfNotExists(const TKey& key, const TValue& value) + { + return addIfNotExists(KeyValuePair<TKey, TValue>(key, value)); + } + bool addIfNotExists(TKey&& key, TValue&& value) + { + return addIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); + } + void remove(const TKey& key) + { + if (m_count > 0) { - if (m_bucketCountMinusOne == -1) - return nullptr; auto pos = findPosition(key); if (pos.objectPosition != -1) { - return &(m_hashMap[pos.objectPosition]->value.value); + m_kvPairs.removeAndDelete(m_hashMap[pos.objectPosition]); + m_hashMap[pos.objectPosition] = 0; + setDeleted(pos.objectPosition, true); + m_count--; } - return nullptr; } - template <typename T> bool tryGetValue(const T& key, TValue& value) const - { - if (m_bucketCountMinusOne == -1) - return false; - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - value = m_hashMap[pos.objectPosition]->value.value; - return true; - } + } + void clear() + { + m_count = 0; + m_kvPairs.clear(); + m_marks.clear(); + } + template<typename T> + bool containsKey(const T& key) const + { + if (m_bucketCountMinusOne == -1) return false; - } - class ItemProxy + auto pos = findPosition(key); + return pos.objectPosition != -1; + } + template<typename T> + TValue* tryGetValue(const T& key) const + { + if (m_bucketCountMinusOne == -1) + return nullptr; + auto pos = findPosition(key); + if (pos.objectPosition != -1) { - private: - const OrderedDictionary<TKey, TValue>* dict; - TKey key; - - public: - ItemProxy(const TKey& _key, const OrderedDictionary<TKey, TValue>* _dict) - { - this->dict = _dict; - this->key = _key; - } - ItemProxy(TKey&& _key, const OrderedDictionary<TKey, TValue>* _dict) - { - this->dict = _dict; - this->key = _Move(_key); - } - TValue& getValue() const - { - auto pos = dict->findPosition(key); - if (pos.objectPosition != -1) - { - return dict->m_hashMap[pos.objectPosition]->value.value; - } - else - { - SLANG_ASSERT_FAILURE("The key does not exists in dictionary."); - } - } - inline TValue& operator()() const { return getValue(); } - operator TValue&() const { return getValue(); } - TValue& operator=(const TValue& val) - { - return ((OrderedDictionary<TKey, TValue>*)dict) - ->set(KeyValuePair<TKey, TValue>(_Move(key), val)); - } - TValue& operator=(TValue&& val) - { - return ((OrderedDictionary<TKey, TValue>*)dict) - ->set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val))); - } - }; - ItemProxy operator[](const TKey& key) const { return ItemProxy(key, this); } - ItemProxy operator[](TKey&& key) const { return ItemProxy(_Move(key), this); } - - int getCount() const { return m_count; } - KeyValuePair<TKey, TValue>& getFirst() const { return m_kvPairs.getFirst(); } - KeyValuePair<TKey, TValue>& getLast() const { return m_kvPairs.getLast(); } - - private: - template <typename... Args> - void init(const KeyValuePair<TKey, TValue>& kvPair, Args... args) + return &(m_hashMap[pos.objectPosition]->value.value); + } + return nullptr; + } + template<typename T> + bool tryGetValue(const T& key, TValue& value) const + { + if (m_bucketCountMinusOne == -1) + return false; + auto pos = findPosition(key); + if (pos.objectPosition != -1) { - add(kvPair); - init(args...); + value = m_hashMap[pos.objectPosition]->value.value; + return true; } + return false; + } + class ItemProxy + { + private: + const OrderedDictionary<TKey, TValue>* dict; + TKey key; public: - OrderedDictionary() - { - m_bucketCountMinusOne = -1; - m_count = 0; - m_hashMap = 0; - } - template <typename Arg, typename... Args> OrderedDictionary(Arg arg, Args... args) + ItemProxy(const TKey& _key, const OrderedDictionary<TKey, TValue>* _dict) { - init(arg, args...); + this->dict = _dict; + this->key = _key; } - OrderedDictionary(const OrderedDictionary<TKey, TValue>& other) - : m_bucketCountMinusOne(-1) - , m_count(0) - , m_hashMap(0) + ItemProxy(TKey&& _key, const OrderedDictionary<TKey, TValue>* _dict) { - *this = other; + this->dict = _dict; + this->key = _Move(_key); } - OrderedDictionary(OrderedDictionary<TKey, TValue>&& other) - : m_bucketCountMinusOne(-1) - , m_count(0) - , m_hashMap(0) + TValue& getValue() const { - *this = (_Move(other)); + auto pos = dict->findPosition(key); + if (pos.objectPosition != -1) + { + return dict->m_hashMap[pos.objectPosition]->value.value; + } + else + { + SLANG_ASSERT_FAILURE("The key does not exists in dictionary."); + } } - OrderedDictionary<TKey, TValue>& - operator=(const OrderedDictionary<TKey, TValue>& other) + inline TValue& operator()() const { return getValue(); } + operator TValue&() const { return getValue(); } + TValue& operator=(const TValue& val) { - if (this == &other) - return *this; - clear(); - for (auto& item : other) - add(item.key, item.value); - return *this; + return ((OrderedDictionary<TKey, TValue>*)dict) + ->set(KeyValuePair<TKey, TValue>(_Move(key), val)); } - OrderedDictionary<TKey, TValue>& - operator=(OrderedDictionary<TKey, TValue>&& other) + TValue& operator=(TValue&& val) { - if (this == &other) - return *this; - deallocateAll(); - m_bucketCountMinusOne = other.m_bucketCountMinusOne; - m_count = other.m_count; - m_hashMap = other.m_hashMap; - m_marks = _Move(other.m_marks); - other.m_hashMap = 0; - other.m_count = 0; - other.m_bucketCountMinusOne = -1; - m_kvPairs = _Move(other.m_kvPairs); - return *this; + return ((OrderedDictionary<TKey, TValue>*)dict) + ->set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val))); } - ~OrderedDictionary() { deallocateAll(); } }; + ItemProxy operator[](const TKey& key) const { return ItemProxy(key, this); } + ItemProxy operator[](TKey&& key) const { return ItemProxy(_Move(key), this); } - template <typename T> class OrderedHashSet : public HashSetBase<T, OrderedDictionary<T, _DummyClass>> + int getCount() const { return m_count; } + KeyValuePair<TKey, TValue>& getFirst() const { return m_kvPairs.getFirst(); } + KeyValuePair<TKey, TValue>& getLast() const { return m_kvPairs.getLast(); } + +private: + template<typename... Args> + void init(const KeyValuePair<TKey, TValue>& kvPair, Args... args) { - public: - T& getLast() - { - return this->dict.getLast().key; - } - void removeLast() - { - this->remove(getLast()); - } - }; -} + add(kvPair); + init(args...); + } + +public: + OrderedDictionary() + { + m_bucketCountMinusOne = -1; + m_count = 0; + m_hashMap = 0; + } + template<typename Arg, typename... Args> + OrderedDictionary(Arg arg, Args... args) + { + init(arg, args...); + } + OrderedDictionary(const OrderedDictionary<TKey, TValue>& other) + : m_bucketCountMinusOne(-1), m_count(0), m_hashMap(0) + { + *this = other; + } + OrderedDictionary(OrderedDictionary<TKey, TValue>&& other) + : m_bucketCountMinusOne(-1), m_count(0), m_hashMap(0) + { + *this = (_Move(other)); + } + OrderedDictionary<TKey, TValue>& operator=(const OrderedDictionary<TKey, TValue>& other) + { + if (this == &other) + return *this; + clear(); + for (auto& item : other) + add(item.key, item.value); + return *this; + } + OrderedDictionary<TKey, TValue>& operator=(OrderedDictionary<TKey, TValue>&& other) + { + if (this == &other) + return *this; + deallocateAll(); + m_bucketCountMinusOne = other.m_bucketCountMinusOne; + m_count = other.m_count; + m_hashMap = other.m_hashMap; + m_marks = _Move(other.m_marks); + other.m_hashMap = 0; + other.m_count = 0; + other.m_bucketCountMinusOne = -1; + m_kvPairs = _Move(other.m_kvPairs); + return *this; + } + ~OrderedDictionary() { deallocateAll(); } +}; + +template<typename T> +class OrderedHashSet : public HashSetBase<T, OrderedDictionary<T, _DummyClass>> +{ +public: + T& getLast() { return this->dict.getLast().key; } + void removeLast() { this->remove(getLast()); } +}; +} // namespace Slang #endif diff --git a/source/core/slang-exception.h b/source/core/slang-exception.h index 3c5621d7f..654ce0156 100644 --- a/source/core/slang-exception.h +++ b/source/core/slang-exception.h @@ -6,61 +6,55 @@ namespace Slang { - // NOTE! - // Exceptions should not generally be used in core/compiler-core, use the 'signal' mechanism - // ideally using the macros in the slang-signal.h such as `SLANG_UNEXPECTED` - // - // If core/compiler-core libraries are compiled with SLANG_DISABLE_EXCEPTIONS, - // these classes will *never* be thrown. - - class Exception - { - public: - String Message; - Exception() - {} - Exception(const String & message) - : Message(message) - { - } +// NOTE! +// Exceptions should not generally be used in core/compiler-core, use the 'signal' mechanism +// ideally using the macros in the slang-signal.h such as `SLANG_UNEXPECTED` +// +// If core/compiler-core libraries are compiled with SLANG_DISABLE_EXCEPTIONS, +// these classes will *never* be thrown. - virtual ~Exception() - {} - }; +class Exception +{ +public: + String Message; + Exception() {} + Exception(const String& message) + : Message(message) + { + } - class InvalidOperationException : public Exception - { - public: - InvalidOperationException() - {} - InvalidOperationException(const String & message) - : Exception(message) - { - } + virtual ~Exception() {} +}; + +class InvalidOperationException : public Exception +{ +public: + InvalidOperationException() {} + InvalidOperationException(const String& message) + : Exception(message) + { + } +}; - }; - - class InternalError : public Exception - { - public: - InternalError() - {} - InternalError(const String & message) - : Exception(message) - { - } - }; +class InternalError : public Exception +{ +public: + InternalError() {} + InternalError(const String& message) + : Exception(message) + { + } +}; - class AbortCompilationException : public Exception +class AbortCompilationException : public Exception +{ +public: + AbortCompilationException() {} + AbortCompilationException(const String& message) + : Exception(message) { - public: - AbortCompilationException() - {} - AbortCompilationException(const String & message) - : Exception(message) - { - } - }; -} + } +}; +} // namespace Slang #endif diff --git a/source/core/slang-file-system.cpp b/source/core/slang-file-system.cpp index d578e63d5..3e129f7bf 100644 --- a/source/core/slang-file-system.cpp +++ b/source/core/slang-file-system.cpp @@ -1,19 +1,24 @@ #include "slang-file-system.h" -#include "slang-com-ptr.h" #include "../core/slang-io.h" #include "../core/slang-string-util.h" +#include "slang-com-ptr.h" namespace Slang { -SLANG_FORCE_INLINE static SlangResult _checkExt(FileSystemStyle style) { return Index(style) >= Index(FileSystemStyle::Ext) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; } -SLANG_FORCE_INLINE static SlangResult _checkMutable(FileSystemStyle style) { return Index(style) >= Index(FileSystemStyle::Mutable) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; } +SLANG_FORCE_INLINE static SlangResult _checkExt(FileSystemStyle style) +{ + return Index(style) >= Index(FileSystemStyle::Ext) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; +} +SLANG_FORCE_INLINE static SlangResult _checkMutable(FileSystemStyle style) +{ + return Index(style) >= Index(FileSystemStyle::Mutable) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; +} SLANG_FORCE_INLINE static bool _canCast(FileSystemStyle style, const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ISlangCastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangCastable::getTypeGuid() || guid == ISlangFileSystem::getTypeGuid()) { return true; @@ -35,11 +40,14 @@ static FileSystemStyle _getFileSystemStyle(ISlangFileSystem* system, ComPtr<ISla FileSystemStyle style = FileSystemStyle::Load; - if (SLANG_SUCCEEDED(system->queryInterface(ISlangMutableFileSystem::getTypeGuid(), (void**)out.writeRef()))) + if (SLANG_SUCCEEDED( + system->queryInterface(ISlangMutableFileSystem::getTypeGuid(), (void**)out.writeRef()))) { - style = FileSystemStyle::Mutable; + style = FileSystemStyle::Mutable; } - else if (SLANG_SUCCEEDED(system->queryInterface(ISlangFileSystemExt::getTypeGuid(), (void**)out.writeRef()))) + else if (SLANG_SUCCEEDED(system->queryInterface( + ISlangFileSystemExt::getTypeGuid(), + (void**)out.writeRef()))) { style = FileSystemStyle::Ext; } @@ -54,17 +62,21 @@ static FileSystemStyle _getFileSystemStyle(ISlangFileSystem* system, ComPtr<ISla } // Calcuate a combined path, just using Path:: string processing -static SlangResult _calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +static SlangResult _calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) { String relPath; switch (fromPathType) { - case SLANG_PATH_TYPE_FILE: + case SLANG_PATH_TYPE_FILE: { relPath = Path::combine(Path::getParentDirectory(fromPath), path); break; } - case SLANG_PATH_TYPE_DIRECTORY: + case SLANG_PATH_TYPE_DIRECTORY: { relPath = Path::combine(fromPath, path); break; @@ -77,9 +89,9 @@ static SlangResult _calcCombinedPath(SlangPathType fromPathType, const char* fro /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! OSFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ -/* static */OSFileSystem OSFileSystem::g_load(FileSystemStyle::Load); -/* static */OSFileSystem OSFileSystem::g_ext(FileSystemStyle::Ext); -/* static */OSFileSystem OSFileSystem::g_mutable(FileSystemStyle::Mutable); +/* static */ OSFileSystem OSFileSystem::g_load(FileSystemStyle::Load); +/* static */ OSFileSystem OSFileSystem::g_ext(FileSystemStyle::Ext); +/* static */ OSFileSystem OSFileSystem::g_mutable(FileSystemStyle::Mutable); void* OSFileSystem::castAs(const Guid& guid) { @@ -126,8 +138,8 @@ SlangResult OSFileSystem::getPath(PathKind pathKind, const char* path, ISlangBlo switch (pathKind) { - case PathKind::OperatingSystem: - case PathKind::Display: + case PathKind::OperatingSystem: + case PathKind::Display: { // It's possible canonical path fail... if (SLANG_SUCCEEDED(getPath(PathKind::Canonical, path, outPath))) @@ -137,14 +149,14 @@ SlangResult OSFileSystem::getPath(PathKind pathKind, const char* path, ISlangBlo // If so try simplified return getPath(PathKind::Simplified, path, outPath); } - case PathKind::Canonical: + case PathKind::Canonical: { String canonicalPath; SLANG_RETURN_ON_FAIL(Path::getCanonical(_fixPathDelimiters(path), canonicalPath)); *outPath = StringUtil::createStringBlob(canonicalPath).detach(); return SLANG_OK; } - case PathKind::Simplified: + case PathKind::Simplified: { String simplifiedPath = Path::simplify(path); *outPath = StringUtil::createStringBlob(simplifiedPath).detach(); @@ -155,7 +167,11 @@ SlangResult OSFileSystem::getPath(PathKind pathKind, const char* path, ISlangBlo return SLANG_E_NOT_AVAILABLE; } -SlangResult OSFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +SlangResult OSFileSystem::calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) { SLANG_RETURN_ON_FAIL(_checkExt(m_style)); @@ -173,7 +189,8 @@ SlangResult SLANG_MCALL OSFileSystem::getPathType(const char* pathIn, SlangPathT SlangResult OSFileSystem::loadFile(char const* pathIn, ISlangBlob** outBlob) { - // Default implementation that uses the `core` libraries facilities for talking to the OS filesystem. + // Default implementation that uses the `core` libraries facilities for talking to the OS + // filesystem. // // TODO: we might want to conditionally compile these in, so that // a user could create a build of Slang that doesn't include any OS @@ -191,7 +208,10 @@ SlangResult OSFileSystem::loadFile(char const* pathIn, ISlangBlob** outBlob) return SLANG_OK; } -SlangResult OSFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) +SlangResult OSFileSystem::enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) { SLANG_RETURN_ON_FAIL(_checkExt(m_style)); @@ -205,17 +225,16 @@ SlangResult OSFileSystem::enumeratePathContents(const char* path, FileSystemCont SlangPathType pathType; switch (type) { - case Path::Type::File: pathType = SLANG_PATH_TYPE_FILE; break; - case Path::Type::Directory: pathType = SLANG_PATH_TYPE_DIRECTORY; break; - default: return; + case Path::Type::File: pathType = SLANG_PATH_TYPE_FILE; break; + case Path::Type::Directory: pathType = SLANG_PATH_TYPE_DIRECTORY; break; + default: return; } m_callback(pathType, m_buffer.getBuffer(), m_userData); } - Visitor(FileSystemContentsCallBack callback, void* userData) : - m_callback(callback), - m_userData(userData) + Visitor(FileSystemContentsCallBack callback, void* userData) + : m_callback(callback), m_userData(userData) { } StringBuilder m_buffer; @@ -234,7 +253,8 @@ SlangResult OSFileSystem::saveFile(const char* pathIn, const void* data, size_t SLANG_RETURN_ON_FAIL(_checkMutable(m_style)); const String path = _fixPathDelimiters(pathIn); FileStream stream; - SLANG_RETURN_ON_FAIL(stream.init(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite)); + SLANG_RETURN_ON_FAIL( + stream.init(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite)); SLANG_RETURN_ON_FAIL(stream.write(data, size)); return SLANG_OK; } @@ -262,16 +282,15 @@ SlangResult OSFileSystem::createDirectory(const char* path) // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CacheFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!! -/* static */ const Result CacheFileSystem::s_compressedResultToResult[] = -{ - SLANG_E_UNINITIALIZED, - SLANG_OK, ///< Ok - SLANG_E_NOT_FOUND, ///< File not found - SLANG_E_CANNOT_OPEN, ///< CannotOpen, - SLANG_FAIL, ///< Fail +/* static */ const Result CacheFileSystem::s_compressedResultToResult[] = { + SLANG_E_UNINITIALIZED, + SLANG_OK, ///< Ok + SLANG_E_NOT_FOUND, ///< File not found + SLANG_E_CANNOT_OPEN, ///< CannotOpen, + SLANG_FAIL, ///< Fail }; -/* static */CacheFileSystem::CompressedResult CacheFileSystem::toCompressedResult(Result res) +/* static */ CacheFileSystem::CompressedResult CacheFileSystem::toCompressedResult(Result res) { if (SLANG_SUCCEEDED(res)) { @@ -279,9 +298,9 @@ SlangResult OSFileSystem::createDirectory(const char* path) } switch (res) { - case SLANG_E_CANNOT_OPEN: return CompressedResult::CannotOpen; - case SLANG_E_NOT_FOUND: return CompressedResult::NotFound; - default: return CompressedResult::Fail; + case SLANG_E_CANNOT_OPEN: return CompressedResult::CannotOpen; + case SLANG_E_NOT_FOUND: return CompressedResult::NotFound; + default: return CompressedResult::Fail; } } @@ -312,7 +331,10 @@ void* CacheFileSystem::getObject(const Guid& guid) return nullptr; } -CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle) +CacheFileSystem::CacheFileSystem( + ISlangFileSystem* fileSystem, + UniqueIdentityMode uniqueIdentityMode, + PathStyle pathStyle) { setInnerFileSystem(fileSystem, uniqueIdentityMode, pathStyle); } @@ -323,13 +345,16 @@ CacheFileSystem::~CacheFileSystem() delete pathInfo; } -void CacheFileSystem::setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle) +void CacheFileSystem::setInnerFileSystem( + ISlangFileSystem* fileSystem, + UniqueIdentityMode uniqueIdentityMode, + PathStyle pathStyle) { m_fileSystem = fileSystem; m_uniqueIdentityMode = uniqueIdentityMode; m_pathStyle = pathStyle; - + m_fileSystemExt.setNull(); if (fileSystem) @@ -343,19 +368,21 @@ void CacheFileSystem::setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIde switch (m_uniqueIdentityMode) { - case UniqueIdentityMode::Default: - case UniqueIdentityMode::FileSystemExt: + case UniqueIdentityMode::Default: + case UniqueIdentityMode::FileSystemExt: { - // If it's not a complete file system, we will default to SimplifyAndHash style by default - m_uniqueIdentityMode = m_fileSystemExt ? UniqueIdentityMode::FileSystemExt : UniqueIdentityMode::SimplifyPathAndHash; + // If it's not a complete file system, we will default to SimplifyAndHash style by + // default + m_uniqueIdentityMode = m_fileSystemExt ? UniqueIdentityMode::FileSystemExt + : UniqueIdentityMode::SimplifyPathAndHash; break; } - default: break; + default: break; } if (pathStyle == PathStyle::Default) { - // We'll assume it's simplify-able + // We'll assume it's simplify-able m_pathStyle = PathStyle::Simplifiable; // If we have fileSystemExt, we defer to that if (m_fileSystemExt) @@ -390,19 +417,22 @@ static bool _canSimplifyPath(CacheFileSystem::UniqueIdentityMode mode) typedef CacheFileSystem::UniqueIdentityMode UniqueIdentityMode; switch (mode) { - case UniqueIdentityMode::SimplifyPath: - case UniqueIdentityMode::SimplifyPathAndHash: + case UniqueIdentityMode::SimplifyPath: + case UniqueIdentityMode::SimplifyPathAndHash: { return true; } - default: + default: { return false; } } } -SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) +SlangResult CacheFileSystem::enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) { if (m_fileSystemExt) { @@ -430,8 +460,9 @@ SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemC for (const auto& [currentPath, pathInfo] : m_pathMap) { - // NOTE! The currentPath can be a *non* simplified path (the m_pathMap is the cache of paths simplified and other to a file/directory) - // Also note that there will always be the simplified version of the path in cache. + // NOTE! The currentPath can be a *non* simplified path (the m_pathMap is the cache of paths + // simplified and other to a file/directory) Also note that there will always be the + // simplified version of the path in cache. // If it doesn't start with simplified path, then it can't be a hit if (!currentPath.startsWith(simplifiedPath)) @@ -439,7 +470,9 @@ SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemC continue; } - UnownedStringSlice remaining(currentPath.getBuffer() + simplifiedPath.getLength(), currentPath.end()); + UnownedStringSlice remaining( + currentPath.getBuffer() + simplifiedPath.getLength(), + currentPath.end()); // If it starts with a / delimiter strip it if (remaining.getLength() > 0 && remaining[0] == '/') @@ -447,16 +480,17 @@ SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemC remaining = UnownedStringSlice(remaining.begin() + 1, remaining.end()); } - // If it has a path separator then it's either not simplified - so we ignore (we only want to invoke on the simplified path version as there is only one - // of these for every PathInfo) - // or it is a child file/directory, and so we ignore that too. + // If it has a path separator then it's either not simplified - so we ignore (we only want + // to invoke on the simplified path version as there is only one of these for every + // PathInfo) or it is a child file/directory, and so we ignore that too. if (remaining.indexOf('/') >= 0 || remaining.indexOf('\\') >= 0) { continue; } - // We *know* that remaining comes from the end of currentPath .We also know currentPath is zero terminated. - // So we can just use (normally this would be a problem because UnownedStringSlice is generally *not* followed by zero termination. + // We *know* that remaining comes from the end of currentPath .We also know currentPath is + // zero terminated. So we can just use (normally this would be a problem because + // UnownedStringSlice is generally *not* followed by zero termination. const char* foundPath = remaining.begin(); // Let's check that fact... SLANG_ASSERT(foundPath[remaining.getLength()] == 0); @@ -474,35 +508,42 @@ SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemC } -SlangResult CacheFileSystem::_calcUniqueIdentity(const String& path, String& outUniqueIdentity, ComPtr<ISlangBlob>& outFileContents) +SlangResult CacheFileSystem::_calcUniqueIdentity( + const String& path, + String& outUniqueIdentity, + ComPtr<ISlangBlob>& outFileContents) { switch (m_uniqueIdentityMode) { - case UniqueIdentityMode::FileSystemExt: + case UniqueIdentityMode::FileSystemExt: { // Try getting the uniqueIdentity by asking underlying file system ComPtr<ISlangBlob> uniqueIdentity; - SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef())); + SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity( + path.getBuffer(), + uniqueIdentity.writeRef())); // Get the path as a string outUniqueIdentity = StringUtil::getString(uniqueIdentity); return SLANG_OK; } - case UniqueIdentityMode::Path: + case UniqueIdentityMode::Path: { outUniqueIdentity = path; return SLANG_OK; } - case UniqueIdentityMode::SimplifyPath: + case UniqueIdentityMode::SimplifyPath: { outUniqueIdentity = Path::simplify(path); // If it still has relative elements can't uniquely identify, so give up return Path::hasRelativeElement(outUniqueIdentity) ? SLANG_FAIL : SLANG_OK; } - case UniqueIdentityMode::SimplifyPathAndHash: - case UniqueIdentityMode::Hash: + case UniqueIdentityMode::SimplifyPathAndHash: + case UniqueIdentityMode::Hash: { - // If m_uniqueIdentityMode is SimplifyPathAndHash, the path will already be simplified before this function is hit (and it hasn't been found - // via path lookup). That being the case only option left is to 'hash' (or fallback to backing impls uniqueIdentity impl) + // If m_uniqueIdentityMode is SimplifyPathAndHash, the path will already be simplified + // before this function is hit (and it hasn't been found via path lookup). That being + // the case only option left is to 'hash' (or fallback to backing impls uniqueIdentity + // impl) // If we don't have a file system -> assume cannot be found if (m_fileSystem == nullptr) @@ -519,27 +560,32 @@ SlangResult CacheFileSystem::_calcUniqueIdentity(const String& path, String& out // If that failed, we may be able to do something if m_fileSystemExt is available if (SLANG_FAILED(res)) { - // If we have m_fileSystemExt interface we can just use it's implementation, as a fallback. - // Doing so will mean the uniqueIdentity will work if say it's a directory + // If we have m_fileSystemExt interface we can just use it's implementation, as a + // fallback. Doing so will mean the uniqueIdentity will work if say it's a directory if (m_fileSystemExt) { ComPtr<ISlangBlob> uniqueIdentity; - SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef())); + SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity( + path.getBuffer(), + uniqueIdentity.writeRef())); // Get the path as a string outUniqueIdentity = StringUtil::getString(uniqueIdentity); return SLANG_OK; } - - // If we can't access as a file (or use the backing implementations impl), we are in a tricky situation. - // The ISlangFileSystem interface provides no way to determine if the path is a directory for example - - // so there is no way of determining if something along the path exists. - // + + // If we can't access as a file (or use the backing implementations impl), we are in + // a tricky situation. The ISlangFileSystem interface provides no way to determine + // if the path is a directory for example - so there is no way of determining if + // something along the path exists. + // // So we just return the error. return res; } - + // Calculate the hash on the contents - const StableHashCode64 hash = getStableHashCode64((const char*)outFileContents->getBufferPointer(), outFileContents->getBufferSize()); + const StableHashCode64 hash = getStableHashCode64( + (const char*)outFileContents->getBufferPointer(), + outFileContents->getBufferSize()); String hashString = Path::getFileName(path); hashString = hashString.toLower(); @@ -582,8 +628,8 @@ CacheFileSystem::PathInfo* CacheFileSystem::_resolveUniqueIdentityCacheInfo(cons // At this point they must have same uniqueIdentity SLANG_ASSERT(pathInfo->getUniqueIdentity() == uniqueIdentity); - // If we have the file contents (because of calc-ing uniqueIdentity), and there isn't a read file blob already - // store the data as if read, so doesn't get read again + // If we have the file contents (because of calc-ing uniqueIdentity), and there isn't a read + // file blob already store the data as if read, so doesn't get read again if (fileContents && !pathInfo->m_fileBlob) { pathInfo->m_fileBlob = fileContents; @@ -595,7 +641,8 @@ CacheFileSystem::PathInfo* CacheFileSystem::_resolveUniqueIdentityCacheInfo(cons CacheFileSystem::PathInfo* CacheFileSystem::_resolveSimplifiedPathCacheInfo(const String& path) { - // If we can simplify the path, try looking up in path cache with simplified path (as long as it's different!) + // If we can simplify the path, try looking up in path cache with simplified path (as long as + // it's different!) if (_canSimplifyPath(m_uniqueIdentityMode)) { const String simplifiedPath = Path::simplify(path); @@ -607,7 +654,7 @@ CacheFileSystem::PathInfo* CacheFileSystem::_resolveSimplifiedPathCacheInfo(cons } } - return _resolveUniqueIdentityCacheInfo(path); + return _resolveUniqueIdentityCacheInfo(path); } CacheFileSystem::PathInfo* CacheFileSystem::_resolvePathCacheInfo(const String& path) @@ -636,10 +683,11 @@ SlangResult CacheFileSystem::loadFile(char const* pathIn, ISlangBlob** blobOut) { return SLANG_FAIL; } - + if (info->m_loadFileResult == CompressedResult::Uninitialized) { - info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(path.getBuffer(), info->m_fileBlob.writeRef())); + info->m_loadFileResult = toCompressedResult( + m_fileSystem->loadFile(path.getBuffer(), info->m_fileBlob.writeRef())); } *blobOut = info->m_fileBlob; @@ -663,16 +711,20 @@ SlangResult CacheFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob* return SLANG_OK; } -SlangResult CacheFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +SlangResult CacheFileSystem::calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) { // Just defer to contained implementation switch (m_pathStyle) { - case PathStyle::FileSystemExt: + case PathStyle::FileSystemExt: { return m_fileSystemExt->calcCombinedPath(fromPathType, fromPath, path, pathOut); } - default: + default: { // Just use the default implementation return _calcCombinedPath(fromPathType, fromPath, path, pathOut); @@ -680,20 +732,25 @@ SlangResult CacheFileSystem::calcCombinedPath(SlangPathType fromPathType, const } } -SlangResult CacheFileSystem::_getPathType(PathInfo* info, const char* inPath, SlangPathType* outPathType) +SlangResult CacheFileSystem::_getPathType( + PathInfo* info, + const char* inPath, + SlangPathType* outPathType) { if (info->m_getPathTypeResult == CompressedResult::Uninitialized) { if (m_fileSystemExt) { - info->m_getPathTypeResult = toCompressedResult(m_fileSystemExt->getPathType(inPath, &info->m_pathType)); + info->m_getPathTypeResult = + toCompressedResult(m_fileSystemExt->getPathType(inPath, &info->m_pathType)); } else { // Okay try to load the file if (info->m_loadFileResult == CompressedResult::Uninitialized) { - info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(inPath, info->m_fileBlob.writeRef())); + info->m_loadFileResult = + toCompressedResult(m_fileSystem->loadFile(inPath, info->m_fileBlob.writeRef())); } // Make the getPathResult the same as the load result @@ -722,9 +779,9 @@ SlangResult CacheFileSystem::getPath(PathKind kind, const char* path, ISlangBlob { switch (kind) { - case PathKind::Simplified: return _getSimplifiedPath(path, outPath); - case PathKind::Canonical: return _getCanonicalPath(path, outPath); - default: break; + case PathKind::Simplified: return _getSimplifiedPath(path, outPath); + case PathKind::Canonical: return _getCanonicalPath(path, outPath); + default: break; } if (m_fileSystemExt) @@ -746,17 +803,17 @@ SlangResult CacheFileSystem::_getSimplifiedPath(const char* path, ISlangBlob** o // If we have a ISlangFileSystemExt we can just pass on the request to it switch (m_pathStyle) { - case PathStyle::FileSystemExt: + case PathStyle::FileSystemExt: { return m_fileSystemExt->getPath(PathKind::Simplified, path, outSimplifiedPath); } - case PathStyle::Simplifiable: + case PathStyle::Simplifiable: { String simplifiedPath = Path::simplify(path); *outSimplifiedPath = StringUtil::createStringBlob(simplifiedPath).detach(); return SLANG_OK; } - default: return SLANG_E_NOT_IMPLEMENTED; + default: return SLANG_E_NOT_IMPLEMENTED; } } @@ -764,7 +821,7 @@ SlangResult CacheFileSystem::_getCanonicalPath(const char* path, ISlangBlob** ou { *outCanonicalPath = nullptr; - // A file must exist to get a canonical path... + // A file must exist to get a canonical path... PathInfo* info = _resolvePathCacheInfo(path); if (!info) { @@ -781,7 +838,8 @@ SlangResult CacheFileSystem::_getCanonicalPath(const char* path, ISlangBlob** ou // Try getting the canonicalPath by asking underlying file system ComPtr<ISlangBlob> canonicalPathBlob; - SlangResult res = m_fileSystemExt->getPath(PathKind::Canonical, path, canonicalPathBlob.writeRef()); + SlangResult res = + m_fileSystemExt->getPath(PathKind::Canonical, path, canonicalPathBlob.writeRef()); if (SLANG_SUCCEEDED(res)) { @@ -808,9 +866,11 @@ SlangResult CacheFileSystem::_getCanonicalPath(const char* path, ISlangBlob** ou /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RelativeFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -RelativeFileSystem::RelativeFileSystem(ISlangFileSystem* fileSystem, const String& relativePath, bool stripPath) : - m_relativePath(relativePath), - m_stripPath(stripPath) +RelativeFileSystem::RelativeFileSystem( + ISlangFileSystem* fileSystem, + const String& relativePath, + bool stripPath) + : m_relativePath(relativePath), m_stripPath(stripPath) { m_style = _getFileSystemStyle(fileSystem, m_fileSystem); @@ -849,7 +909,11 @@ void* RelativeFileSystem::castAs(const Guid& guid) return getObject(guid); } -SlangResult RelativeFileSystem::_calcCombinedPathInner(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** outPath) +SlangResult RelativeFileSystem::_calcCombinedPathInner( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** outPath) { ISlangFileSystemExt* fileSystem = _getExt(); if (fileSystem) @@ -866,14 +930,15 @@ SlangResult RelativeFileSystem::_getCanonicalPath(const char* path, String& outP { if (m_stripPath) { - // We are just using the filename. There is no path that could go outside of the the relative path so we can use as is + // We are just using the filename. There is no path that could go outside of the the + // relative path so we can use as is outPath = Path::getFileName(path); } else { // NOTE that we don't want the canonical path to be absolute with a leading "/" // because paths specified which aren't absolute, would produce a different path. - // + // // Ie we want (and get with these options) // "a" -> "a" // "/a" -> "a". @@ -881,15 +946,16 @@ SlangResult RelativeFileSystem::_getCanonicalPath(const char* path, String& outP // If we allowed the root to be included then... // "a" -> "a" // "/a" -> "/a" - // + // // Two identical paths would match to different paths, which wouldn't be canonical. - // - // This could be fixed by making all paths absolute with '/' too, but it's easier to just make all not - // have "/" + // + // This could be fixed by making all paths absolute with '/' too, but it's easier to just + // make all not have "/" StringBuilder canonicalPath; // We want the input path to be local to this file system - SLANG_RETURN_ON_FAIL(Path::simplify(path, Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, canonicalPath)); + SLANG_RETURN_ON_FAIL( + Path::simplify(path, Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, canonicalPath)); outPath = canonicalPath; } return SLANG_OK; @@ -901,10 +967,14 @@ SlangResult RelativeFileSystem::_getFixedPath(const char* path, String& outPath) String canonicalPath; SLANG_RETURN_ON_FAIL(_getCanonicalPath(path, canonicalPath)); - - SLANG_RETURN_ON_FAIL(_calcCombinedPathInner(SLANG_PATH_TYPE_DIRECTORY, m_relativePath.getBuffer(), canonicalPath.getBuffer(), blob.writeRef())); + + SLANG_RETURN_ON_FAIL(_calcCombinedPathInner( + SLANG_PATH_TYPE_DIRECTORY, + m_relativePath.getBuffer(), + canonicalPath.getBuffer(), + blob.writeRef())); outPath = StringUtil::getString(blob); - + return SLANG_OK; } @@ -915,20 +985,28 @@ SlangResult RelativeFileSystem::loadFile(char const* path, ISlangBlob** outBlob) return m_fileSystem->loadFile(fixedPath.getBuffer(), outBlob); } -SlangResult RelativeFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) +SlangResult RelativeFileSystem::getFileUniqueIdentity( + const char* path, + ISlangBlob** outUniqueIdentity) { auto fileSystem = _getExt(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); return fileSystem->getFileUniqueIdentity(fixedPath.getBuffer(), outUniqueIdentity); } -SlangResult RelativeFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** outPath) +SlangResult RelativeFileSystem::calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** outPath) { auto fileSystem = _getExt(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedFromPath; SLANG_RETURN_ON_FAIL(_getFixedPath(fromPath, fixedFromPath)); @@ -939,7 +1017,8 @@ SlangResult RelativeFileSystem::calcCombinedPath(SlangPathType fromPathType, con SlangResult RelativeFileSystem::getPathType(const char* path, SlangPathType* outPathType) { auto fileSystem = _getExt(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); @@ -949,28 +1028,30 @@ SlangResult RelativeFileSystem::getPathType(const char* path, SlangPathType* out SlangResult RelativeFileSystem::getPath(PathKind kind, const char* path, ISlangBlob** outPath) { auto fileSystem = _getExt(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; - + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; + switch (kind) { - case PathKind::Simplified: + case PathKind::Simplified: { return fileSystem->getPath(kind, path, outPath); } - case PathKind::Display: + case PathKind::Display: { // If not backed by OS, just use simplified path, else use the Operating system path - kind = (fileSystem->getOSPathKind() == OSPathKind::None) ? PathKind::Simplified : PathKind::OperatingSystem; + kind = (fileSystem->getOSPathKind() == OSPathKind::None) ? PathKind::Simplified + : PathKind::OperatingSystem; return getPath(kind, path, outPath); } - case PathKind::Canonical: - { + case PathKind::Canonical: + { String canonicalPath; - SLANG_RETURN_ON_FAIL(_getCanonicalPath(path, canonicalPath)); + SLANG_RETURN_ON_FAIL(_getCanonicalPath(path, canonicalPath)); *outPath = StringBlob::moveCreate(canonicalPath).detach(); return SLANG_OK; } - case PathKind::OperatingSystem: + case PathKind::OperatingSystem: { String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); @@ -984,15 +1065,20 @@ SlangResult RelativeFileSystem::getPath(PathKind kind, const char* path, ISlangB void RelativeFileSystem::clearCache() { auto fileSystem = _getExt(); - if (!fileSystem) return; + if (!fileSystem) + return; fileSystem->clearCache(); } -SlangResult RelativeFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) +SlangResult RelativeFileSystem::enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) { auto fileSystem = _getExt(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); @@ -1002,7 +1088,8 @@ SlangResult RelativeFileSystem::enumeratePathContents(const char* path, FileSyst SlangResult RelativeFileSystem::saveFile(const char* path, const void* data, size_t size) { auto fileSystem = _getMutable(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); @@ -1012,8 +1099,9 @@ SlangResult RelativeFileSystem::saveFile(const char* path, const void* data, siz SlangResult RelativeFileSystem::saveFileBlob(const char* path, ISlangBlob* dataBlob) { auto fileSystem = _getMutable(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; - + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; + String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); return fileSystem->saveFileBlob(fixedPath.getBuffer(), dataBlob); @@ -1022,7 +1110,8 @@ SlangResult RelativeFileSystem::saveFileBlob(const char* path, ISlangBlob* dataB SlangResult RelativeFileSystem::remove(const char* path) { auto fileSystem = _getMutable(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); @@ -1032,11 +1121,12 @@ SlangResult RelativeFileSystem::remove(const char* path) SlangResult RelativeFileSystem::createDirectory(const char* path) { auto fileSystem = _getMutable(); - if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED; + if (!fileSystem) + return SLANG_E_NOT_IMPLEMENTED; String fixedPath; SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); return fileSystem->createDirectory(fixedPath.getBuffer()); } -} +} // namespace Slang diff --git a/source/core/slang-file-system.h b/source/core/slang-file-system.h index dad2731d9..7ed500eb9 100644 --- a/source/core/slang-file-system.h +++ b/source/core/slang-file-system.h @@ -1,67 +1,81 @@ #ifndef SLANG_FILE_SYSTEM_H_INCLUDED #define SLANG_FILE_SYSTEM_H_INCLUDED -#include "slang.h" -#include "slang-com-helper.h" -#include "slang-com-ptr.h" - #include "../core/slang-blob.h" - -#include "../core/slang-string-util.h" #include "../core/slang-dictionary.h" +#include "../core/slang-string-util.h" +#include "slang-com-helper.h" +#include "slang-com-ptr.h" +#include "slang.h" namespace Slang { enum class FileSystemStyle { - Load, ///< Equivalent to ISlangFileSystem - Ext, ///< Equivalent to ISlangFileSystemExt - Mutable, ///< Equivalent to ISlangModifyableFileSystem + Load, ///< Equivalent to ISlangFileSystem + Ext, ///< Equivalent to ISlangFileSystemExt + Mutable, ///< Equivalent to ISlangModifyableFileSystem }; // Can be used for all styles of file system class OSFileSystem : public ISlangMutableFileSystem { public: - // ISlangUnknown + // ISlangUnknown // override ref counting, as DefaultFileSystem is singleton - SLANG_IUNKNOWN_QUERY_INTERFACE + SLANG_IUNKNOWN_QUERY_INTERFACE SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } // ISlangCastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // ISlangFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) + SLANG_OVERRIDE; // ISlangFileSystemExt - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE {} - virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE; - virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE { return OSPathKind::Direct; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) SLANG_OVERRIDE; + virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE + { + return OSPathKind::Direct; + } // ISlangModifyableFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE; - /// Get a default instance + /// Get a default instance static ISlangFileSystem* getLoadSingleton() { return &g_load; } static ISlangFileSystemExt* getExtSingleton() { return &g_ext; } static ISlangMutableFileSystem* getMutableSingleton() { return &g_mutable; } private: - /// Make so not constructible - OSFileSystem(FileSystemStyle style): - m_style(style) - {} + OSFileSystem(FileSystemStyle style) + : m_style(style) + { + } virtual ~OSFileSystem() {} @@ -75,51 +89,52 @@ private: static OSFileSystem g_mutable; }; -/* Wraps an underlying ISlangFileSystem or ISlangFileSystemExt and provides caching, +/* Wraps an underlying ISlangFileSystem or ISlangFileSystemExt and provides caching, as well as emulation of methods if only has ISlangFileSystem interface. Will query capabilities of the interface on the constructor. -NOTE! That this behavior is the same as previously in that.... -1) calcRelativePath, just returns the path as processed by the Path:: methods +NOTE! That this behavior is the same as previously in that.... +1) calcRelativePath, just returns the path as processed by the Path:: methods 2) getUniqueIdentity behavior depends on the UniqueIdentityMode. */ -class CacheFileSystem: public ISlangFileSystemExt, public ComBaseObject +class CacheFileSystem : public ISlangFileSystemExt, public ComBaseObject { - public: - SLANG_CLASS_GUID(0x2f4d1d03, 0xa0d1, 0x434b, { 0x87, 0x7a, 0x65, 0x5, 0xa4, 0xa0, 0x9a, 0x3b }) +public: + SLANG_CLASS_GUID(0x2f4d1d03, 0xa0d1, 0x434b, {0x87, 0x7a, 0x65, 0x5, 0xa4, 0xa0, 0x9a, 0x3b}) enum class PathStyle { - Default, ///< Pass to say use the default - Simplifiable, ///< It can be simplified by Path::Simplify - FileSystemExt, ///< Use file system + Default, ///< Pass to say use the default + Simplifiable, ///< It can be simplified by Path::Simplify + FileSystemExt, ///< Use file system }; enum UniqueIdentityMode { - Default, ///< If passed, will default to the others depending on what kind of ISlangFileSystem is passed in - Path, ///< Just use the path as is (old style slang behavior) - SimplifyPath, ///< Use the input path 'simplified' (ie removing . and .. aspects) - Hash, ///< Use hashing - SimplifyPathAndHash, ///< Tries simplifying path first, and if that doesn't work it hashes - FileSystemExt, ///< Use the file system extended interface. + Default, ///< If passed, will default to the others depending on what kind of + ///< ISlangFileSystem is passed in + Path, ///< Just use the path as is (old style slang behavior) + SimplifyPath, ///< Use the input path 'simplified' (ie removing . and .. aspects) + Hash, ///< Use hashing + SimplifyPathAndHash, ///< Tries simplifying path first, and if that doesn't work it hashes + FileSystemExt, ///< Use the file system extended interface. }; /* Cannot change order/add members without changing s_compressedResultToResult */ - enum class CompressedResult: uint8_t - { - Uninitialized, ///< Holds no value - Ok, ///< Ok - NotFound, ///< File not found - CannotOpen, ///< Cannot open - Fail, ///< Generic failure + enum class CompressedResult : uint8_t + { + Uninitialized, ///< Holds no value + Ok, ///< Ok + NotFound, ///< File not found + CannotOpen, ///< Cannot open + Fail, ///< Generic failure CountOf, }; struct PathInfo { - PathInfo(const String& uniqueIdentity): - m_uniqueIdentity(uniqueIdentity) + PathInfo(const String& uniqueIdentity) + : m_uniqueIdentity(uniqueIdentity) { m_loadFileResult = CompressedResult::Uninitialized; m_getPathTypeResult = CompressedResult::Uninitialized; @@ -151,72 +166,106 @@ class CacheFileSystem: public ISlangFileSystemExt, public ComBaseObject virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // ISlangFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) + SLANG_OVERRIDE; // ISlangFileSystemExt - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* outPathType) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPath(PathKind kind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPathType(const char* path, SlangPathType* outPathType) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPath(PathKind kind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE; - virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE { return m_osPathKind; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) SLANG_OVERRIDE; + virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE + { + return m_osPathKind; + } - /// Get the unique identity mode + /// Get the unique identity mode UniqueIdentityMode getUniqueIdentityMode() const { return m_uniqueIdentityMode; } - /// Get the path style + /// Get the path style PathStyle getPathStyle() const { return m_pathStyle; } - /// Set the inner file system - void setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, PathStyle pathStyle = PathStyle::Default); - - /// Ctor - explicit CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, PathStyle pathStyle = PathStyle::Default); - /// Dtor + /// Set the inner file system + void setInnerFileSystem( + ISlangFileSystem* fileSystem, + UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, + PathStyle pathStyle = PathStyle::Default); + + /// Ctor + explicit CacheFileSystem( + ISlangFileSystem* fileSystem, + UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, + PathStyle pathStyle = PathStyle::Default); + /// Dtor virtual ~CacheFileSystem(); static CompressedResult toCompressedResult(Result res); - static Result toResult(CompressedResult compRes) { return s_compressedResultToResult[int(compRes)]; } + static Result toResult(CompressedResult compRes) + { + return s_compressedResultToResult[int(compRes)]; + } static const Result s_compressedResultToResult[int(CompressedResult::CountOf)]; protected: - void* getInterface(const Guid& guid); void* getObject(const Guid& guid); SlangResult _getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath); SlangResult _getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath); - /// Given a path, works out a uniqueIdentity, based on the uniqueIdentityMode. - /// outFileContents will be set if file had to be read to produce the uniqueIdentity (ie with Hash) - /// If the file doesn't have to be read, then outFileContents will be nullptr, even if it is backed by a file. - SlangResult _calcUniqueIdentity(const String& path, String& outUniqueIdentity, ComPtr<ISlangBlob>& outFileContents); - - /// For a given path gets a PathInfo. Can return nullptr, if it is not possible to create the PathInfo for some reason + /// Given a path, works out a uniqueIdentity, based on the uniqueIdentityMode. + /// outFileContents will be set if file had to be read to produce the uniqueIdentity (ie with + /// Hash) If the file doesn't have to be read, then outFileContents will be nullptr, even if it + /// is backed by a file. + SlangResult _calcUniqueIdentity( + const String& path, + String& outUniqueIdentity, + ComPtr<ISlangBlob>& outFileContents); + + /// For a given path gets a PathInfo. Can return nullptr, if it is not possible to create the + /// PathInfo for some reason PathInfo* _resolvePathCacheInfo(const String& path); - /// Turns the path into a uniqueIdentity, and then tries to look up in the uniqueIdentityMap. + /// Turns the path into a uniqueIdentity, and then tries to look up in the uniqueIdentityMap. PathInfo* _resolveUniqueIdentityCacheInfo(const String& path); - /// Will simplify the path (if possible) to lookup on the pathCache else will create on uniqueIdentityMap + /// Will simplify the path (if possible) to lookup on the pathCache else will create on + /// uniqueIdentityMap PathInfo* _resolveSimplifiedPathCacheInfo(const String& path); SlangResult _getPathType(PathInfo* pathInfo, const char* inPath, SlangPathType* pathTypeOut); - /* TODO: This may be improved by mapping to a ISlangBlob. This makes output fast and easy, and if constructed - as a StringBlob, we can just static_cast to get as a string to use internally, instead of constantly converting. - It is probably the case we cannot do dynamic_cast on ISlangBlob if we don't know where constructed -> if outside of slang codebase - doing such a cast can cause an exception. So we *never* want to do dynamic cast from blobs which could be created by external code. */ + /* TODO: This may be improved by mapping to a ISlangBlob. This makes output fast and easy, and + if constructed as a StringBlob, we can just static_cast to get as a string to use internally, + instead of constantly converting. It is probably the case we cannot do dynamic_cast on + ISlangBlob if we don't know where constructed -> if outside of slang codebase doing such a cast + can cause an exception. So we *never* want to do dynamic cast from blobs which could be created + by external code. */ - Dictionary<String, PathInfo*> m_pathMap; ///< Maps a path to a PathInfo (and unique identity) - Dictionary<String, PathInfo*> m_uniqueIdentityMap; ///< Maps a unique identity for a file to its contents. This OWNs the PathInfo. + Dictionary<String, PathInfo*> m_pathMap; ///< Maps a path to a PathInfo (and unique identity) + Dictionary<String, PathInfo*> m_uniqueIdentityMap; ///< Maps a unique identity for a file to its + ///< contents. This OWNs the PathInfo. - UniqueIdentityMode m_uniqueIdentityMode; ///< Determines how the 'uniqueIdentity' is produced. Cannot be Default in usage. - PathStyle m_pathStyle; ///< Style of paths + UniqueIdentityMode m_uniqueIdentityMode; ///< Determines how the 'uniqueIdentity' is produced. + ///< Cannot be Default in usage. + PathStyle m_pathStyle; ///< Style of paths - ComPtr<ISlangFileSystem> m_fileSystem; ///< Must always be set - ComPtr<ISlangFileSystemExt> m_fileSystemExt; ///< Optionally set -> if nullptr will fall back on the m_fileSystem and emulate all the other methods of ISlangFileSystemExt + ComPtr<ISlangFileSystem> m_fileSystem; ///< Must always be set + ComPtr<ISlangFileSystemExt> + m_fileSystemExt; ///< Optionally set -> if nullptr will fall back on the m_fileSystem and + ///< emulate all the other methods of ISlangFileSystemExt - OSPathKind m_osPathKind = OSPathKind::None; ///< OS path kind + OSPathKind m_osPathKind = OSPathKind::None; ///< OS path kind }; class RelativeFileSystem : public ISlangMutableFileSystem, public ComBaseObject @@ -225,54 +274,88 @@ public: SLANG_COM_BASE_IUNKNOWN_ALL // ISlangFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) + SLANG_OVERRIDE; // ISlangCastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // ISlangFileSystemExt - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* outPathType) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPathType(const char* path, SlangPathType* outPathType) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE; - virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE { return m_osPathKind; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) SLANG_OVERRIDE; + virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE + { + return m_osPathKind; + } // ISlangModifyableFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE; - /// stripPath will remove any path for an access, making an access always just - /// access the *filename* from the input path, in the contained filesystem at the relative path - RelativeFileSystem(ISlangFileSystem* fileSystem, const String& relativePath, bool stripPath = false); + /// stripPath will remove any path for an access, making an access always just + /// access the *filename* from the input path, in the contained filesystem at the relative path + RelativeFileSystem( + ISlangFileSystem* fileSystem, + const String& relativePath, + bool stripPath = false); protected: - - ISlangFileSystemExt* _getExt() { return Index(m_style) >= Index(FileSystemStyle::Ext) ? reinterpret_cast<ISlangFileSystemExt*>(m_fileSystem.get()) : nullptr; } - ISlangMutableFileSystem* _getMutable() { return Index(m_style) >= Index(FileSystemStyle::Mutable) ? reinterpret_cast<ISlangMutableFileSystem*>(m_fileSystem.get()) : nullptr; } - - SlangResult _calcCombinedPathInner(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut); - - /// Get the fixed path to the item for the backing file system. + ISlangFileSystemExt* _getExt() + { + return Index(m_style) >= Index(FileSystemStyle::Ext) + ? reinterpret_cast<ISlangFileSystemExt*>(m_fileSystem.get()) + : nullptr; + } + ISlangMutableFileSystem* _getMutable() + { + return Index(m_style) >= Index(FileSystemStyle::Mutable) + ? reinterpret_cast<ISlangMutableFileSystem*>(m_fileSystem.get()) + : nullptr; + } + + SlangResult _calcCombinedPathInner( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut); + + /// Get the fixed path to the item for the backing file system. SlangResult _getFixedPath(const char* path, String& outPath); - + SlangResult _getCanonicalPath(const char* path, String& outPath); ISlangUnknown* getInterface(const Guid& guid); void* getObject(const Guid& guid); - bool m_stripPath; ///< If set any path prior to an item will be stripped (making the directory in effect flat) + bool m_stripPath; ///< If set any path prior to an item will be stripped (making the directory + ///< in effect flat) FileSystemStyle m_style; - ComPtr<ISlangFileSystem> m_fileSystem; ///< NOTE! Has to match what's in style, such style can be reached via reinterpret_cast + ComPtr<ISlangFileSystem> m_fileSystem; ///< NOTE! Has to match what's in style, such style can + ///< be reached via reinterpret_cast String m_relativePath; - OSPathKind m_osPathKind = OSPathKind::None; ///< OS path kind + OSPathKind m_osPathKind = OSPathKind::None; ///< OS path kind }; -} +} // namespace Slang #endif // SLANG_FILE_SYSTEM_H_INCLUDED diff --git a/source/core/slang-free-list.cpp b/source/core/slang-free-list.cpp index d364b548c..215004a74 100644 --- a/source/core/slang-free-list.cpp +++ b/source/core/slang-free-list.cpp @@ -1,232 +1,232 @@ #include "slang-free-list.h" -//#include "list.h" +// #include "list.h" -namespace Slang { +namespace Slang +{ FreeList::~FreeList() { - _deallocateBlocks(m_activeBlocks); - _deallocateBlocks(m_freeBlocks); + _deallocateBlocks(m_activeBlocks); + _deallocateBlocks(m_freeBlocks); } void FreeList::_init() { - m_top = nullptr; - m_end = nullptr; - - m_activeBlocks = nullptr; - m_freeBlocks = nullptr; - - m_freeElements = nullptr; - - m_elementSize = 0; - m_alignment = 1; - m_blockSize = 0; - m_blockAllocationSize = 0; + m_top = nullptr; + m_end = nullptr; + + m_activeBlocks = nullptr; + m_freeBlocks = nullptr; + + m_freeElements = nullptr; + + m_elementSize = 0; + m_alignment = 1; + m_blockSize = 0; + m_blockAllocationSize = 0; } void FreeList::_init(size_t elementSize, size_t alignment, size_t elemsPerBlock) { - alignment = (alignment < sizeof(void*)) ? sizeof(void*) : alignment; + alignment = (alignment < sizeof(void*)) ? sizeof(void*) : alignment; - // Alignment must be a power of 2 - assert(((alignment - 1) & alignment) == 0); + // Alignment must be a power of 2 + assert(((alignment - 1) & alignment) == 0); - // The elementSize must at least be at least the same size as the alignment - elementSize = (elementSize >= alignment) ? elementSize : alignment; - m_blockSize = elementSize * elemsPerBlock; - m_elementSize = elementSize; - m_alignment = alignment; + // The elementSize must at least be at least the same size as the alignment + elementSize = (elementSize >= alignment) ? elementSize : alignment; + m_blockSize = elementSize * elemsPerBlock; + m_elementSize = elementSize; + m_alignment = alignment; - // Calculate the block size need, correcting for alignment - const size_t alignedBlockSize = (alignment <= DEFAULT_ALIGNMENT) ? - _calcAlignedBlockSize(DEFAULT_ALIGNMENT) : - _calcAlignedBlockSize(alignment); + // Calculate the block size need, correcting for alignment + const size_t alignedBlockSize = (alignment <= DEFAULT_ALIGNMENT) + ? _calcAlignedBlockSize(DEFAULT_ALIGNMENT) + : _calcAlignedBlockSize(alignment); - // Make the block struct size aligned - m_blockAllocationSize = m_blockSize + alignedBlockSize; + // Make the block struct size aligned + m_blockAllocationSize = m_blockSize + alignedBlockSize; - m_top = nullptr; - m_end = nullptr; + m_top = nullptr; + m_end = nullptr; - m_activeBlocks = nullptr; - m_freeBlocks = nullptr; ///< Blocks that there are no allocations in + m_activeBlocks = nullptr; + m_freeBlocks = nullptr; ///< Blocks that there are no allocations in - m_freeElements = nullptr; + m_freeElements = nullptr; } void FreeList::init(size_t elementSize, size_t alignment, size_t elemsPerBlock) { - _deallocateBlocks(m_activeBlocks); - _deallocateBlocks(m_freeBlocks); - _init(elementSize, alignment, elemsPerBlock); + _deallocateBlocks(m_activeBlocks); + _deallocateBlocks(m_freeBlocks); + _init(elementSize, alignment, elemsPerBlock); } void FreeList::swapWith(ThisType& rhs) { - Swap(m_top, rhs.m_top); - Swap(m_end, rhs.m_end); - - Swap(m_activeBlocks, rhs.m_activeBlocks); - Swap(m_freeBlocks, rhs.m_freeBlocks); - - Swap(m_freeElements, rhs.m_freeElements); - - Swap(m_elementSize, rhs.m_elementSize); - Swap(m_alignment, rhs.m_alignment); - Swap(m_blockSize, rhs.m_blockSize); - Swap(m_blockAllocationSize, rhs.m_blockAllocationSize); + Swap(m_top, rhs.m_top); + Swap(m_end, rhs.m_end); + + Swap(m_activeBlocks, rhs.m_activeBlocks); + Swap(m_freeBlocks, rhs.m_freeBlocks); + + Swap(m_freeElements, rhs.m_freeElements); + + Swap(m_elementSize, rhs.m_elementSize); + Swap(m_alignment, rhs.m_alignment); + Swap(m_blockSize, rhs.m_blockSize); + Swap(m_blockAllocationSize, rhs.m_blockAllocationSize); } void FreeList::_deallocateBlocks(Block* block) { - while (block) - { - Block* next = block->m_next; + while (block) + { + Block* next = block->m_next; #ifdef SLANG_FREE_LIST_INIT_MEM - Memory::set(block, 0xfd, m_blockAllocationSize); + Memory::set(block, 0xfd, m_blockAllocationSize); #endif - ::free(block); // deallocate(block, m_blockAllocationSize); - block = next; - } + ::free(block); // deallocate(block, m_blockAllocationSize); + block = next; + } } bool FreeList::isValidAllocation(const void* dataIn) const { - uint8_t* data = (uint8_t*)dataIn; - - Block* block = m_activeBlocks; - while (block) - { - uint8_t* start = block->m_data; - uint8_t* end = start + m_blockSize; - - if (data >= start && data < end) - { - // Check it's aligned correctly - if ((data - start) % m_elementSize) - { - return false; - } - - // Non allocated data is between top and end - if (data >= m_top && data < m_end) - { - return false; - } - - // It can't be in the free list - Element* ele = m_freeElements; - while (ele) - { - if (ele == (Element*)data) - { - return false; - } - - ele = ele->m_next; - } - return true; - } - - block = block->m_next; - } - // It's not in an active block -> it cannot be a valid allocation - return false; + uint8_t* data = (uint8_t*)dataIn; + + Block* block = m_activeBlocks; + while (block) + { + uint8_t* start = block->m_data; + uint8_t* end = start + m_blockSize; + + if (data >= start && data < end) + { + // Check it's aligned correctly + if ((data - start) % m_elementSize) + { + return false; + } + + // Non allocated data is between top and end + if (data >= m_top && data < m_end) + { + return false; + } + + // It can't be in the free list + Element* ele = m_freeElements; + while (ele) + { + if (ele == (Element*)data) + { + return false; + } + + ele = ele->m_next; + } + return true; + } + + block = block->m_next; + } + // It's not in an active block -> it cannot be a valid allocation + return false; } void* FreeList::_allocate() { - Block* block = m_freeBlocks; - if (block) - { - /// Remove from the free blocks - m_freeBlocks = block->m_next; - } - else - { - //block = (Block*)m_allocator->allocate(m_blockAllocationSize); - block = (Block*)::malloc(m_blockAllocationSize); - if (!block) - { - // Allocation failed... doh - return nullptr; - } - // Do the alignment - { - size_t fix = (size_t(block) + sizeof(Block) + m_alignment - 1) & ~(m_alignment - 1); - block->m_data = (uint8_t*)fix; - } - } - - // Attach to the active blocks - block->m_next = m_activeBlocks; - m_activeBlocks = block; - - // Set up top and end - m_end = block->m_data + m_blockSize; - - // Return the first element - uint8_t* element = block->m_data; - m_top = element + m_elementSize; - - SLANG_FREE_LIST_INIT_ALLOCATE(element) - - return element; + Block* block = m_freeBlocks; + if (block) + { + /// Remove from the free blocks + m_freeBlocks = block->m_next; + } + else + { + // block = (Block*)m_allocator->allocate(m_blockAllocationSize); + block = (Block*)::malloc(m_blockAllocationSize); + if (!block) + { + // Allocation failed... doh + return nullptr; + } + // Do the alignment + { + size_t fix = (size_t(block) + sizeof(Block) + m_alignment - 1) & ~(m_alignment - 1); + block->m_data = (uint8_t*)fix; + } + } + + // Attach to the active blocks + block->m_next = m_activeBlocks; + m_activeBlocks = block; + + // Set up top and end + m_end = block->m_data + m_blockSize; + + // Return the first element + uint8_t* element = block->m_data; + m_top = element + m_elementSize; + + SLANG_FREE_LIST_INIT_ALLOCATE(element) + + return element; } void FreeList::deallocateAll() { - Block* block = m_activeBlocks; - if (block) - { - // Find the end block - while (block->m_next) - { + Block* block = m_activeBlocks; + if (block) + { + // Find the end block + while (block->m_next) + { #ifdef SLANG_FREE_LIST_INIT_MEM - Memory::set(block->m_data, 0xfd, m_blockSize); + Memory::set(block->m_data, 0xfd, m_blockSize); #endif - block = block->m_next; - } - // Attach to the freeblocks - block->m_next = m_freeBlocks; - // The list is now all freelists - m_freeBlocks = m_activeBlocks; - // There are no active blocks - m_activeBlocks = nullptr; - } - - m_top = nullptr; - m_end = nullptr; + block = block->m_next; + } + // Attach to the freeblocks + block->m_next = m_freeBlocks; + // The list is now all freelists + m_freeBlocks = m_activeBlocks; + // There are no active blocks + m_activeBlocks = nullptr; + } + + m_top = nullptr; + m_end = nullptr; } void FreeList::reset() { - _deallocateBlocks(m_activeBlocks); - _deallocateBlocks(m_freeBlocks); + _deallocateBlocks(m_activeBlocks); + _deallocateBlocks(m_freeBlocks); - m_top = nullptr; - m_end = nullptr; + m_top = nullptr; + m_end = nullptr; - m_activeBlocks = nullptr; - m_freeBlocks = nullptr; + m_activeBlocks = nullptr; + m_freeBlocks = nullptr; - m_freeElements = nullptr; + m_freeElements = nullptr; } void FreeList::_initAllocate(void* mem) { - ::memset(mem, 0xcd, m_elementSize); + ::memset(mem, 0xcd, m_elementSize); } void FreeList::_initDeallocate(void* mem) { - ::memset(mem, 0xfd, m_elementSize); + ::memset(mem, 0xfd, m_elementSize); } } // namespace Slang - diff --git a/source/core/slang-free-list.h b/source/core/slang-free-list.h index 5c4e55607..74b3d63ea 100644 --- a/source/core/slang-free-list.h +++ b/source/core/slang-free-list.h @@ -1,145 +1,157 @@ #ifndef SLANG_CORE_FREE_LIST_H #define SLANG_CORE_FREE_LIST_H -#include "slang.h" - #include "slang-common.h" +#include "slang.h" #include <stdlib.h> #include <string.h> -namespace Slang { +namespace Slang +{ #if SLANG_DEBUG -# define SLANG_FREE_LIST_INIT_MEM +#define SLANG_FREE_LIST_INIT_MEM #endif #ifdef SLANG_FREE_LIST_INIT_MEM -# define SLANG_FREE_LIST_INIT_ALLOCATE(ptr) _initAllocate(ptr); -# define SLANG_FREE_LIST_INIT_DEALLOCATE(ptr) _initDeallocate(ptr); +#define SLANG_FREE_LIST_INIT_ALLOCATE(ptr) _initAllocate(ptr); +#define SLANG_FREE_LIST_INIT_DEALLOCATE(ptr) _initDeallocate(ptr); #else -# define SLANG_FREE_LIST_INIT_ALLOCATE(ptr) -# define SLANG_FREE_LIST_INIT_DEALLOCATE(ptr) +#define SLANG_FREE_LIST_INIT_ALLOCATE(ptr) +#define SLANG_FREE_LIST_INIT_DEALLOCATE(ptr) #endif -/*! \brief A freelist is a simple and fast memory allocator that can allocate and free in any order identically sized blocks. +/*! \brief A freelist is a simple and fast memory allocator that can allocate and free in any order +identically sized blocks. -\details A free list is a memory allocation system that performs allocations/deallocations very quickly for elements which are -all the same size. -In a freelist all elements are the same size, and elements can be allocated and freed in any order, as long as every deallocation -matches every allocation. Both allocation and deallocation are O(1), and generally just a few instructions. The underlying -memory allocator will allocate in large blocks, with multiple elements amortizing a more costly large allocation against lots -of fast small element allocations. */ +\details A free list is a memory allocation system that performs allocations/deallocations very +quickly for elements which are all the same size. In a freelist all elements are the same size, and +elements can be allocated and freed in any order, as long as every deallocation matches every +allocation. Both allocation and deallocation are O(1), and generally just a few instructions. The +underlying memory allocator will allocate in large blocks, with multiple elements amortizing a more +costly large allocation against lots of fast small element allocations. */ class FreeList { - public: - typedef FreeList ThisType; - - enum { DEFAULT_ALIGNMENT = sizeof(void*) }; - - /// Free elements are held in a singly linked list. The minimum size of an element is therefore a pointer - struct Element - { - Element* m_next; - }; - struct Block - { - Block* m_next; ///< The next block - uint8_t* m_data; ///< The list of the elements each m_elementSize in size - }; - - /// Allocate a single element - SLANG_FORCE_INLINE void* allocate(); - /// Deallocate a block that was previously allocated with allocate - SLANG_FORCE_INLINE void deallocate(void* data); - - /// Returns true if this is from a valid allocation - bool isValidAllocation(const void* dataIn) const; - - /// Get the element size - SLANG_FORCE_INLINE size_t getElementSize() const { return m_elementSize; } - /// Get the total size of each individual block allocation in bytes - SLANG_FORCE_INLINE size_t getBlockSize() const { return m_blockSize; } - - /// Deallocates all elements - void deallocateAll(); - /// Deallocates all, and frees any backing memory (put in initial state) - void reset(); - - /// Initialize. If called on an already initialized heap, the heap will be deallocated. - void init(size_t elementSize, size_t alignment, size_t elemsPerBlock); - - /// Swap this with rhs - void swapWith(ThisType& rhs); - - /// Default Ctor - FreeList() { _init(); } - /// Ctor - FreeList(size_t elementSize, size_t alignment, size_t elemsPerBlock) { _init(elementSize, alignment, elemsPerBlock); } - /// Dtor - ~FreeList(); - - protected: - /// Initializes assuming freelist is not constructed - void _init(size_t elementSize, size_t alignment, size_t elemsPerBlock); - void* _allocate(); - void _deallocateBlocks(Block* block); - /// Initializes setting everything to empty (doesn't free anything if already allocated) - void _init(); - - SLANG_FORCE_INLINE static size_t _calcAlignedBlockSize(size_t align) { return (sizeof(Block) + align - 1) & ~(align - 1); } - - void _initAllocate(void* mem); - void _initDeallocate(void* mem); - - uint8_t* m_top; ///< The top position of the current block - uint8_t* m_end; ///< The end of the current block - - Block* m_activeBlocks; ///< The blocks there are potentially allocations from - Block* m_freeBlocks; ///< Blocks that there are no allocations in - - Element* m_freeElements; ///< A singly linked list of elements available - - size_t m_elementSize; - size_t m_alignment; - size_t m_blockSize; - size_t m_blockAllocationSize; ///< The actual allocation size. Maybe bigger than m_blockSize if alignment requires it. +public: + typedef FreeList ThisType; + + enum + { + DEFAULT_ALIGNMENT = sizeof(void*) + }; + + /// Free elements are held in a singly linked list. The minimum size of an element is therefore + /// a pointer + struct Element + { + Element* m_next; + }; + struct Block + { + Block* m_next; ///< The next block + uint8_t* m_data; ///< The list of the elements each m_elementSize in size + }; + + /// Allocate a single element + SLANG_FORCE_INLINE void* allocate(); + /// Deallocate a block that was previously allocated with allocate + SLANG_FORCE_INLINE void deallocate(void* data); + + /// Returns true if this is from a valid allocation + bool isValidAllocation(const void* dataIn) const; + + /// Get the element size + SLANG_FORCE_INLINE size_t getElementSize() const { return m_elementSize; } + /// Get the total size of each individual block allocation in bytes + SLANG_FORCE_INLINE size_t getBlockSize() const { return m_blockSize; } + + /// Deallocates all elements + void deallocateAll(); + /// Deallocates all, and frees any backing memory (put in initial state) + void reset(); + + /// Initialize. If called on an already initialized heap, the heap will be deallocated. + void init(size_t elementSize, size_t alignment, size_t elemsPerBlock); + + /// Swap this with rhs + void swapWith(ThisType& rhs); + + /// Default Ctor + FreeList() { _init(); } + /// Ctor + FreeList(size_t elementSize, size_t alignment, size_t elemsPerBlock) + { + _init(elementSize, alignment, elemsPerBlock); + } + /// Dtor + ~FreeList(); + +protected: + /// Initializes assuming freelist is not constructed + void _init(size_t elementSize, size_t alignment, size_t elemsPerBlock); + void* _allocate(); + void _deallocateBlocks(Block* block); + /// Initializes setting everything to empty (doesn't free anything if already allocated) + void _init(); + + SLANG_FORCE_INLINE static size_t _calcAlignedBlockSize(size_t align) + { + return (sizeof(Block) + align - 1) & ~(align - 1); + } + + void _initAllocate(void* mem); + void _initDeallocate(void* mem); + + uint8_t* m_top; ///< The top position of the current block + uint8_t* m_end; ///< The end of the current block + + Block* m_activeBlocks; ///< The blocks there are potentially allocations from + Block* m_freeBlocks; ///< Blocks that there are no allocations in + + Element* m_freeElements; ///< A singly linked list of elements available + + size_t m_elementSize; + size_t m_alignment; + size_t m_blockSize; + size_t m_blockAllocationSize; ///< The actual allocation size. Maybe bigger than m_blockSize if + ///< alignment requires it. }; // -------------------------------------------------------------------------- SLANG_FORCE_INLINE void* FreeList::allocate() { - // First see if there are any freeElements ready to go - { - Element* element = m_freeElements; - if (element) - { - m_freeElements = element->m_next; - SLANG_FREE_LIST_INIT_ALLOCATE(element) - return element; - } - } - if (m_top >= m_end) - { - return _allocate(); - } - void* data = (void*)m_top; - SLANG_FREE_LIST_INIT_ALLOCATE(data) - - m_top += m_elementSize; - return data; + // First see if there are any freeElements ready to go + { + Element* element = m_freeElements; + if (element) + { + m_freeElements = element->m_next; + SLANG_FREE_LIST_INIT_ALLOCATE(element) + return element; + } + } + if (m_top >= m_end) + { + return _allocate(); + } + void* data = (void*)m_top; + SLANG_FREE_LIST_INIT_ALLOCATE(data) + + m_top += m_elementSize; + return data; } // -------------------------------------------------------------------------- SLANG_FORCE_INLINE void FreeList::deallocate(void* data) { - assert(isValidAllocation(data)); + assert(isValidAllocation(data)); - SLANG_FREE_LIST_INIT_DEALLOCATE(data) + SLANG_FREE_LIST_INIT_DEALLOCATE(data) - // Put onto the singly linked free element list - Element* ele = (Element*)data; - ele->m_next = m_freeElements; - m_freeElements = ele; + // Put onto the singly linked free element list + Element* ele = (Element*)data; + ele->m_next = m_freeElements; + m_freeElements = ele; } } // namespace Slang diff --git a/source/core/slang-func-ptr.h b/source/core/slang-func-ptr.h index c861bc6b8..271b51ae1 100644 --- a/source/core/slang-func-ptr.h +++ b/source/core/slang-func-ptr.h @@ -6,7 +6,8 @@ namespace Slang { -template <typename TResult, typename... Arguments> class FuncPtr : public RefObject +template<typename TResult, typename... Arguments> +class FuncPtr : public RefObject { public: virtual TResult operator()(Arguments...) const = 0; @@ -15,7 +16,7 @@ public: virtual ~FuncPtr() {} }; -template <typename TResult, typename... Arguments> +template<typename TResult, typename... Arguments> class CdeclFuncPtr : public FuncPtr<TResult, Arguments...> { public: @@ -27,7 +28,8 @@ private: public: CdeclFuncPtr(FuncType func) : funcPtr(func) - {} + { + } virtual FuncPtr<TResult, Arguments...>* clone() override { auto rs = new CdeclFuncPtr<TResult, Arguments...>(funcPtr); @@ -46,7 +48,7 @@ public: } }; -template <typename Class, typename TResult, typename... Arguments> +template<typename Class, typename TResult, typename... Arguments> class MemberFuncPtr : public FuncPtr<TResult, Arguments...> { public: @@ -58,9 +60,9 @@ private: public: MemberFuncPtr(Class* obj, FuncType func) - : funcPtr(func) - , object(obj) - {} + : funcPtr(func), object(obj) + { + } virtual FuncPtr<TResult, Arguments...>* clone() override { auto rs = new MemberFuncPtr<Class, TResult, Arguments...>(object, funcPtr); @@ -81,7 +83,7 @@ public: } }; -template <typename F, typename TResult, typename... Arguments> +template<typename F, typename TResult, typename... Arguments> class LambdaFuncPtr : public FuncPtr<TResult, Arguments...> { private: @@ -90,7 +92,8 @@ private: public: LambdaFuncPtr(const F& _func) : func(_func) - {} + { + } virtual TResult operator()(Arguments... params) const override { return func(params...); } virtual FuncPtr<TResult, Arguments...>* clone() override { @@ -103,7 +106,8 @@ public: } }; -template <typename TResult, typename... Arguments> class Func +template<typename TResult, typename... Arguments> +class Func { private: RefPtr<FuncPtr<TResult, Arguments...>> funcPtr; @@ -114,12 +118,13 @@ public: { funcPtr = new CdeclFuncPtr<TResult, Arguments...>(func); } - template <typename Class> + template<typename Class> Func(Class* object, typename MemberFuncPtr<Class, TResult, Arguments...>::FuncType func) { funcPtr = new MemberFuncPtr<Class, TResult, Arguments...>(object, func); } - template <typename TFuncObj> Func(const TFuncObj& func) + template<typename TFuncObj> + Func(const TFuncObj& func) { funcPtr = new LambdaFuncPtr<TFuncObj, TResult, Arguments...>(func); } @@ -128,13 +133,14 @@ public: funcPtr = new CdeclFuncPtr<TResult, Arguments...>(func); return *this; } - template <typename Class> + template<typename Class> Func& operator=(const MemberFuncPtr<Class, TResult, Arguments...>& func) { funcPtr = new MemberFuncPtr<Class, TResult, Arguments...>(func); return *this; } - template <typename TFuncObj> Func& operator=(const TFuncObj& func) + template<typename TFuncObj> + Func& operator=(const TFuncObj& func) { funcPtr = new LambdaFuncPtr<TFuncObj, TResult, Arguments...>(func); return *this; @@ -147,7 +153,8 @@ public: // template<typename... Arguments> // using Action = Func<void, Arguments...>; -template <typename... Arguments> class Action : public Func<void, Arguments...> +template<typename... Arguments> +class Action : public Func<void, Arguments...> { private: RefPtr<FuncPtr<void, Arguments...>> funcPtr; @@ -159,12 +166,13 @@ public: { funcPtr = new CdeclFuncPtr<void, Arguments...>(func); } - template <typename Class> + template<typename Class> Action(Class* object, typename MemberFuncPtr<Class, void, Arguments...>::FuncType func) { funcPtr = new MemberFuncPtr<Class, void, Arguments...>(object, func); } - template <typename TFuncObj> Action(const TFuncObj& func) + template<typename TFuncObj> + Action(const TFuncObj& func) { funcPtr = new LambdaFuncPtr<TFuncObj, void, Arguments...>(func); } @@ -173,13 +181,14 @@ public: funcPtr = new CdeclFuncPtr<void, Arguments...>(func); return *this; } - template <typename Class> + template<typename Class> Action& operator=(const MemberFuncPtr<Class, void, Arguments...>& func) { funcPtr = new MemberFuncPtr<Class, void, Arguments...>(func); return *this; } - template <typename TFuncObj> Action& operator=(const TFuncObj& func) + template<typename TFuncObj> + Action& operator=(const TFuncObj& func) { funcPtr = new LambdaFuncPtr<TFuncObj, void, Arguments...>(func); return *this; diff --git a/source/core/slang-hash.h b/source/core/slang-hash.h index 12239221b..ebe3d1973 100644 --- a/source/core/slang-hash.h +++ b/source/core/slang-hash.h @@ -1,225 +1,226 @@ #ifndef SLANG_CORE_HASH_H #define SLANG_CORE_HASH_H +#include "../../external/unordered_dense/include/ankerl/unordered_dense.h" #include "slang-math.h" #include "slang.h" -#include "../../external/unordered_dense/include/ankerl/unordered_dense.h" - #include <cstring> #include <type_traits> namespace Slang { - // - // Types - // - - // A fixed 64bit wide hash on all targets. - typedef uint64_t HashCode64; - typedef HashCode64 HashCode; - // A fixed 32bit wide hash on all targets. - typedef uint32_t HashCode32; - - // - // Some helpers to determine which hash to use for a type - // - - // Forward declare Hash - template<typename T> struct Hash; - - template<typename T, typename = void> - constexpr static bool HasSlangHash = false; - template<typename T> - constexpr static bool HasSlangHash< - T, - std::enable_if_t<std::is_convertible_v< - decltype((std::declval<const T&>()).getHashCode()), - HashCode64>>> - = true; - - // Does the hashmap implementation provide a uniform hash for this type. - template<typename T, typename = void> - constexpr static bool HasWyhash = false; - template<typename T> - constexpr static bool HasWyhash<T, typename ankerl::unordered_dense::hash<T>::is_avalanching> = true; - - // We want to have an associated type 'is_avalanching = void' iff we have a - // hash with good uniformity, the two specializations here add that member - // when appropriate (since we can't declare an associated type with - // constexpr if or something terse like that) - template <typename T, typename = void> - struct DetectAvalanchingHash {}; - template <typename T> - struct DetectAvalanchingHash<T, std::enable_if_t<HasWyhash<T>>> - { - using is_avalanching = void; - }; - // Have we marked 'getHashCode' as having good uniformity properties. - template <typename T> - struct DetectAvalanchingHash<T, std::enable_if_t<T::kHasUniformHash>> - { - using is_avalanching = void; - }; +// +// Types +// + +// A fixed 64bit wide hash on all targets. +typedef uint64_t HashCode64; +typedef HashCode64 HashCode; +// A fixed 32bit wide hash on all targets. +typedef uint32_t HashCode32; + +// +// Some helpers to determine which hash to use for a type +// + +// Forward declare Hash +template<typename T> +struct Hash; + +template<typename T, typename = void> +constexpr static bool HasSlangHash = false; +template<typename T> +constexpr static bool HasSlangHash< + T, + std::enable_if_t< + std::is_convertible_v<decltype((std::declval<const T&>()).getHashCode()), HashCode64>>> = + true; + +// Does the hashmap implementation provide a uniform hash for this type. +template<typename T, typename = void> +constexpr static bool HasWyhash = false; +template<typename T> +constexpr static bool HasWyhash<T, typename ankerl::unordered_dense::hash<T>::is_avalanching> = + true; + +// We want to have an associated type 'is_avalanching = void' iff we have a +// hash with good uniformity, the two specializations here add that member +// when appropriate (since we can't declare an associated type with +// constexpr if or something terse like that) +template<typename T, typename = void> +struct DetectAvalanchingHash +{ +}; +template<typename T> +struct DetectAvalanchingHash<T, std::enable_if_t<HasWyhash<T>>> +{ + using is_avalanching = void; +}; +// Have we marked 'getHashCode' as having good uniformity properties. +template<typename T> +struct DetectAvalanchingHash<T, std::enable_if_t<T::kHasUniformHash>> +{ + using is_avalanching = void; +}; - // A helper for hashing according to the bit representation - template<typename T, typename U> - struct BitCastHash : DetectAvalanchingHash<U> +// A helper for hashing according to the bit representation +template<typename T, typename U> +struct BitCastHash : DetectAvalanchingHash<U> +{ + auto operator()(const T& t) const { - auto operator()(const T& t) const - { - // Doesn't discard or invent bits - static_assert(sizeof(T) == sizeof(U)); - // Can we copy bytes to and fro - static_assert(std::is_trivially_copyable_v<T>); - static_assert(std::is_trivially_copyable_v<U>); - // Because we construct a U to memcpy into - static_assert(std::is_trivially_constructible_v<U>); - - U u; - memcpy(&u, &t, sizeof(T)); - return Hash<U>{}(u); - } - }; + // Doesn't discard or invent bits + static_assert(sizeof(T) == sizeof(U)); + // Can we copy bytes to and fro + static_assert(std::is_trivially_copyable_v<T>); + static_assert(std::is_trivially_copyable_v<U>); + // Because we construct a U to memcpy into + static_assert(std::is_trivially_constructible_v<U>); + + U u; + memcpy(&u, &t, sizeof(T)); + return Hash<U>{}(u); + } +}; - // - // Our hashing functor which disptaches to the most appropriate hashing - // function for the type - // +// +// Our hashing functor which disptaches to the most appropriate hashing +// function for the type +// - template<typename T> - struct Hash : DetectAvalanchingHash<T> +template<typename T> +struct Hash : DetectAvalanchingHash<T> +{ + auto operator()(const T& t) const { - auto operator()(const T& t) const + // Our preference is for any hash we've defined ourselves + if constexpr (HasSlangHash<T>) + return t.getHashCode(); + // Otherwise fall back to any good hash provided by the hashmap + // library + else if constexpr (HasWyhash<T>) + return ankerl::unordered_dense::hash<T>{}(t); + // Otherwise fail + else { - // Our preference is for any hash we've defined ourselves - if constexpr (HasSlangHash<T>) - return t.getHashCode(); - // Otherwise fall back to any good hash provided by the hashmap - // library - else if constexpr (HasWyhash<T>) - return ankerl::unordered_dense::hash<T>{}(t); - // Otherwise fail - else - { - // !sizeof(T*) is a 'false' which is dependent on T (pending P2593R0) - static_assert(!sizeof(T*), "No hash implementation found for this type"); - // This is to avoid the return type being deduced as 'void' and creating further errors. - return HashCode64(0); - } + // !sizeof(T*) is a 'false' which is dependent on T (pending P2593R0) + static_assert(!sizeof(T*), "No hash implementation found for this type"); + // This is to avoid the return type being deduced as 'void' and creating further errors. + return HashCode64(0); } - }; - - // Specializations for float and double which hash 0 and -0 to distinct values - template<> - struct Hash<float> : BitCastHash<float, uint32_t> {}; - template<> - struct Hash<double> : BitCastHash<double, uint64_t> {}; - - // - // Utility functions for using hashes - // - - // A wrapper for Hash<TKey> - template<typename TKey> - auto getHashCode(const TKey& key) - { - return Hash<TKey>{}(key); - } - - inline HashCode64 getHashCode(const char* buffer, std::size_t len) - { - return ankerl::unordered_dense::detail::wyhash::hash(buffer, len); - } - - template<typename T> - HashCode64 hashObjectBytes(const T& t) - { - static_assert(std::has_unique_object_representations_v<T>, - "This type must have a unique object representation to use hashObjectBytes"); - return getHashCode(reinterpret_cast<const char*>(&t), sizeof(t)); } +}; - // Use in a struct to declare a uniform hash which doens't care about the - // structure of the members. -# define SLANG_BYTEWISE_HASHABLE \ - static constexpr bool kHasUniformHash = true; \ - ::Slang::HashCode64 getHashCode() const \ - { \ - return ::Slang::hashObjectBytes(*this); \ - } +// Specializations for float and double which hash 0 and -0 to distinct values +template<> +struct Hash<float> : BitCastHash<float, uint32_t> +{ +}; +template<> +struct Hash<double> : BitCastHash<double, uint64_t> +{ +}; -# define SLANG_COMPONENTWISE_HASHABLE_1 \ - auto getHashCode() const \ - { \ - const auto& [m1] = *this; \ - return Slang::getHashCode(m1); \ - } +// +// Utility functions for using hashes +// -# define SLANG_COMPONENTWISE_HASHABLE_2 \ - auto getHashCode() const \ - { \ - const auto& [m1, m2] = *this; \ - return combineHash(::Slang::getHashCode(m1), ::Slang::getHashCode(m2)); \ - } +// A wrapper for Hash<TKey> +template<typename TKey> +auto getHashCode(const TKey& key) +{ + return Hash<TKey>{}(key); +} - inline HashCode64 combineHash(HashCode64 h) - { - return h; +inline HashCode64 getHashCode(const char* buffer, std::size_t len) +{ + return ankerl::unordered_dense::detail::wyhash::hash(buffer, len); +} + +template<typename T> +HashCode64 hashObjectBytes(const T& t) +{ + static_assert( + std::has_unique_object_representations_v<T>, + "This type must have a unique object representation to use hashObjectBytes"); + return getHashCode(reinterpret_cast<const char*>(&t), sizeof(t)); +} + +// Use in a struct to declare a uniform hash which doens't care about the +// structure of the members. +#define SLANG_BYTEWISE_HASHABLE \ + static constexpr bool kHasUniformHash = true; \ + ::Slang::HashCode64 getHashCode() const \ + { \ + return ::Slang::hashObjectBytes(*this); \ } - inline HashCode32 combineHash(HashCode32 h) - { - return h; +#define SLANG_COMPONENTWISE_HASHABLE_1 \ + auto getHashCode() const \ + { \ + const auto& [m1] = *this; \ + return Slang::getHashCode(m1); \ } - // A left fold of a mixing operation - template<typename H1, typename H2, typename... Hs> - auto combineHash(H1 n, H2 m, Hs... args) - { - // TODO: restrict the types here more, currently we tend to throw - // unhashed integers in here along with proper hashes of objects. - static_assert(std::is_convertible_v<H1, HashCode64> || std::is_convertible_v<H1, HashCode32>); - static_assert(std::is_convertible_v<H2, HashCode64> || std::is_convertible_v<H2, HashCode32>); - return combineHash((n * 16777619) ^ m, args...); +#define SLANG_COMPONENTWISE_HASHABLE_2 \ + auto getHashCode() const \ + { \ + const auto& [m1, m2] = *this; \ + return combineHash(::Slang::getHashCode(m1), ::Slang::getHashCode(m2)); \ } - struct Hasher - { - public: - Hasher() {} +inline HashCode64 combineHash(HashCode64 h) +{ + return h; +} - /// Hash the given `value` and combine it into this hash state - template<typename T> - void hashValue(T const& value) - { - // TODO: Eventually, we should replace `getHashCode` - // with a "hash into" operation that takes the value - // and a `Hasher`. +inline HashCode32 combineHash(HashCode32 h) +{ + return h; +} - m_hashCode = combineHash(m_hashCode, getHashCode(value)); - } +// A left fold of a mixing operation +template<typename H1, typename H2, typename... Hs> +auto combineHash(H1 n, H2 m, Hs... args) +{ + // TODO: restrict the types here more, currently we tend to throw + // unhashed integers in here along with proper hashes of objects. + static_assert(std::is_convertible_v<H1, HashCode64> || std::is_convertible_v<H1, HashCode32>); + static_assert(std::is_convertible_v<H2, HashCode64> || std::is_convertible_v<H2, HashCode32>); + return combineHash((n * 16777619) ^ m, args...); +} - /// Combine the given `hash` code into the hash state. - /// - /// Note: users should prefer to use `hashValue` or `hashObject` - /// when possible, as they may be able to ensure a higher-quality - /// hash result (e.g., by using more bits to represent the state - /// during hashing than are used for the final hash code). - /// - void addHash(HashCode hash) - { - m_hashCode = combineHash(m_hashCode, hash); - } +struct Hasher +{ +public: + Hasher() {} - HashCode getResult() const - { - return m_hashCode; - } + /// Hash the given `value` and combine it into this hash state + template<typename T> + void hashValue(T const& value) + { + // TODO: Eventually, we should replace `getHashCode` + // with a "hash into" operation that takes the value + // and a `Hasher`. - private: - HashCode m_hashCode = 0; - }; -} + m_hashCode = combineHash(m_hashCode, getHashCode(value)); + } + + /// Combine the given `hash` code into the hash state. + /// + /// Note: users should prefer to use `hashValue` or `hashObject` + /// when possible, as they may be able to ensure a higher-quality + /// hash result (e.g., by using more bits to represent the state + /// during hashing than are used for the final hash code). + /// + void addHash(HashCode hash) { m_hashCode = combineHash(m_hashCode, hash); } + + HashCode getResult() const { return m_hashCode; } + +private: + HashCode m_hashCode = 0; +}; +} // namespace Slang #endif diff --git a/source/core/slang-hex-dump-util.cpp b/source/core/slang-hex-dump-util.cpp index 46fe825ac..b400fb15b 100644 --- a/source/core/slang-hex-dump-util.cpp +++ b/source/core/slang-hex-dump-util.cpp @@ -1,14 +1,12 @@ // slang-hex-dump-util.cpp #include "slang-hex-dump-util.h" -#include "slang-common.h" -#include "slang-string-util.h" -#include "slang-writer.h" - #include "slang-char-util.h" - #include "slang-com-helper.h" +#include "slang-common.h" #include "slang-hash.h" +#include "slang-string-util.h" +#include "slang-writer.h" namespace Slang { @@ -17,19 +15,26 @@ static const UnownedStringSlice s_start = UnownedStringSlice::fromLiteral("--STA static const UnownedStringSlice s_end = UnownedStringSlice::fromLiteral("--END--"); static const char s_hex[] = "0123456789abcdef"; -/* static */SlangResult HexDumpUtil::dumpWithMarkers(const List<uint8_t>& data, int maxBytesPerLine, ISlangWriter* writer) +/* static */ SlangResult HexDumpUtil::dumpWithMarkers( + const List<uint8_t>& data, + int maxBytesPerLine, + ISlangWriter* writer) { return dumpWithMarkers(data.getBuffer(), data.getCount(), maxBytesPerLine, writer); } -/* static */SlangResult HexDumpUtil::dumpWithMarkers(const uint8_t* data, size_t dataCount, int maxBytesPerLine, ISlangWriter* writer) +/* static */ SlangResult HexDumpUtil::dumpWithMarkers( + const uint8_t* data, + size_t dataCount, + int maxBytesPerLine, + ISlangWriter* writer) { WriterHelper helper(writer); SLANG_RETURN_ON_FAIL(helper.write(s_start.begin(), s_start.getLength())); SLANG_RETURN_ON_FAIL(helper.print(" %zu", dataCount)); const StableHashCode32 hash = getStableHashCode32((const char*)data, dataCount); - SLANG_RETURN_ON_FAIL(helper.print(" %d\n", hash.hash )); + SLANG_RETURN_ON_FAIL(helper.print(" %d\n", hash.hash)); SLANG_RETURN_ON_FAIL(dump(data, dataCount, maxBytesPerLine, writer)); @@ -38,7 +43,7 @@ static const char s_hex[] = "0123456789abcdef"; return SLANG_OK; } -/* static */void HexDumpUtil::dump(uint32_t value, ISlangWriter* writer) +/* static */ void HexDumpUtil::dump(uint32_t value, ISlangWriter* writer) { char c[9]; for (int i = 0; i < 8; ++i) @@ -50,12 +55,19 @@ static const char s_hex[] = "0123456789abcdef"; } -/* static */SlangResult HexDumpUtil::dump(const List<uint8_t>& data, int maxBytesPerLine, ISlangWriter* writer) +/* static */ SlangResult HexDumpUtil::dump( + const List<uint8_t>& data, + int maxBytesPerLine, + ISlangWriter* writer) { return dump(data.getBuffer(), data.getCount(), maxBytesPerLine, writer); } -SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, int maxBytesPerLine, ISlangWriter* writer) +SlangResult HexDumpUtil::dumpSourceBytes( + const uint8_t* data, + size_t dataCount, + int maxBytesPerLine, + ISlangWriter* writer) { const uint8_t* cur = data; const uint8_t* end = data + dataCount; @@ -95,13 +107,17 @@ SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, return SLANG_OK; } -/* static */SlangResult HexDumpUtil::dump(const uint8_t* data, size_t dataCount, int maxBytesPerLine, ISlangWriter* writer) +/* static */ SlangResult HexDumpUtil::dump( + const uint8_t* data, + size_t dataCount, + int maxBytesPerLine, + ISlangWriter* writer) { int maxCharsPerLine = 2 * maxBytesPerLine + 1 + maxBytesPerLine + 1; const uint8_t* cur = data; const uint8_t* end = data + dataCount; - + while (cur < end) { size_t count = size_t(end - cur); @@ -121,7 +137,7 @@ SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, for (size_t i = count; i < size_t(maxBytesPerLine); ++i) { *dst++ = ' '; - *dst++ = ' '; + *dst++ = ' '; } *dst++ = ' '; @@ -130,9 +146,7 @@ SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, { char c = char(cur[i]); - if ((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= 32 && (c & 0x80) == 0)) { } @@ -154,7 +168,9 @@ SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, return SLANG_OK; } -/* static */SlangResult HexDumpUtil::parse(const UnownedStringSlice& lines, List<uint8_t>& outBytes) +/* static */ SlangResult HexDumpUtil::parse( + const UnownedStringSlice& lines, + List<uint8_t>& outBytes) { outBytes.clear(); @@ -164,7 +180,7 @@ SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, const char* cur = line.begin(); const char* end = line.end(); - while(cur + 2 <= end) + while (cur + 2 <= end) { const char c = cur[0]; if (c == ' ' || c == '\n' || c == '\r' || c == '\t') @@ -188,7 +204,10 @@ SlangResult HexDumpUtil::dumpSourceBytes(const uint8_t* data, size_t dataCount, return SLANG_OK; } -static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& ioRemaining, UnownedStringSlice& outLine) +static SlangResult _findLine( + const UnownedStringSlice& find, + UnownedStringSlice& ioRemaining, + UnownedStringSlice& outLine) { // Find the start line UnownedStringSlice line; @@ -203,7 +222,10 @@ static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& return SLANG_FAIL; } -/* static */SlangResult HexDumpUtil::findStartAndEndLines(const UnownedStringSlice& lines, UnownedStringSlice& outStart, UnownedStringSlice& outEnd) +/* static */ SlangResult HexDumpUtil::findStartAndEndLines( + const UnownedStringSlice& lines, + UnownedStringSlice& outStart, + UnownedStringSlice& outEnd) { UnownedStringSlice remaining(lines); SLANG_RETURN_ON_FAIL(_findLine(s_start, remaining, outStart)); @@ -211,7 +233,9 @@ static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& return SLANG_OK; } -/* static */SlangResult HexDumpUtil::parseWithMarkers(const UnownedStringSlice& lines, List<uint8_t>& outBytes) +/* static */ SlangResult HexDumpUtil::parseWithMarkers( + const UnownedStringSlice& lines, + List<uint8_t>& outBytes) { UnownedStringSlice startLine, endLine; SLANG_RETURN_ON_FAIL(findStartAndEndLines(lines, startLine, endLine)); @@ -234,7 +258,8 @@ static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& SLANG_RETURN_ON_FAIL(parse(UnownedStringSlice(startLine.end(), endLine.begin()), outBytes)); // Calc the hash - const StableHashCode32 readHash = getStableHashCode32((const char*)outBytes.begin(), outBytes.getCount()); + const StableHashCode32 readHash = + getStableHashCode32((const char*)outBytes.begin(), outBytes.getCount()); if (readHash != hash || size_t(outBytes.getCount()) != size) { @@ -243,4 +268,4 @@ static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& return SLANG_OK; } -} +} // namespace Slang diff --git a/source/core/slang-hex-dump-util.h b/source/core/slang-hex-dump-util.h index 037355f2d..cfa2c4bb1 100644 --- a/source/core/slang-hex-dump-util.h +++ b/source/core/slang-hex-dump-util.h @@ -2,9 +2,8 @@ #define SLANG_HEX_DUMP_UTIL_H #include "slang-common.h" -#include "slang-string.h" - #include "slang-list.h" +#include "slang-string.h" #include "slang.h" namespace Slang @@ -12,30 +11,48 @@ namespace Slang struct HexDumpUtil { - /// Dump out bytes in source format - as in - /// 0x10, 0xab, - static SlangResult dumpSourceBytes(const uint8_t* data, size_t dataCount, int maxBytesPerLine, ISlangWriter* writer); - - /// Dump data to writer, with lines starting with hex data + /// Dump out bytes in source format - as in + /// 0x10, 0xab, + static SlangResult dumpSourceBytes( + const uint8_t* data, + size_t dataCount, + int maxBytesPerLine, + ISlangWriter* writer); + + /// Dump data to writer, with lines starting with hex data static SlangResult dump(const List<uint8_t>& data, int numBytesPerLine, ISlangWriter* writer); - static SlangResult dump(const uint8_t* data, size_t dataCount, int numBytesPerLine, ISlangWriter* writer); + static SlangResult dump( + const uint8_t* data, + size_t dataCount, + int numBytesPerLine, + ISlangWriter* writer); - /// Dump a single value + /// Dump a single value static void dump(uint32_t value, ISlangWriter* writer); - static SlangResult dumpWithMarkers(const List<uint8_t>& data, int numBytesPerLine, ISlangWriter* writer); + static SlangResult dumpWithMarkers( + const List<uint8_t>& data, + int numBytesPerLine, + ISlangWriter* writer); - static SlangResult dumpWithMarkers(const uint8_t* data, size_t dataSize, int numBytesPerLine, ISlangWriter* writer); + static SlangResult dumpWithMarkers( + const uint8_t* data, + size_t dataSize, + int numBytesPerLine, + ISlangWriter* writer); - /// Parses lines formatted by dump, back into bytes + /// Parses lines formatted by dump, back into bytes static SlangResult parse(const UnownedStringSlice& lines, List<uint8_t>& outBytes); static SlangResult parseWithMarkers(const UnownedStringSlice& lines, List<uint8_t>& outBytes); - static SlangResult findStartAndEndLines(const UnownedStringSlice& lines, UnownedStringSlice& outStart, UnownedStringSlice& outEnd); + static SlangResult findStartAndEndLines( + const UnownedStringSlice& lines, + UnownedStringSlice& outStart, + UnownedStringSlice& outEnd); }; -} +} // namespace Slang #endif diff --git a/source/core/slang-http.cpp b/source/core/slang-http.cpp index 58f37666a..fa7ca952b 100644 --- a/source/core/slang-http.cpp +++ b/source/core/slang-http.cpp @@ -1,10 +1,10 @@ #include "slang-http.h" -#include "slang-string-util.h" - #include "slang-process.h" +#include "slang-string-util.h" -namespace Slang { +namespace Slang +{ static const UnownedStringSlice g_headerEnd = UnownedStringSlice::fromLiteral("\r\n\r\n"); static const UnownedStringSlice g_contentLength = UnownedStringSlice::fromLiteral("Content-Length"); @@ -25,11 +25,11 @@ void HTTPHeader::reset() m_arena.deallocateAll(); } -/* static */SlangResult HTTPHeader::readHeaderText(BufferedReadStream* stream, Index& outEndIndex) +/* static */ SlangResult HTTPHeader::readHeaderText(BufferedReadStream* stream, Index& outEndIndex) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/ - while(true) + while (true) { SLANG_RETURN_ON_FAIL(stream->update()); @@ -49,9 +49,10 @@ void HTTPHeader::reset() } } -/* static */Index HTTPHeader::findHeaderEnd(BufferedReadStream* stream) +/* static */ Index HTTPHeader::findHeaderEnd(BufferedReadStream* stream) { - // This could be more efficient - it just searches until there are enough bytes to have termination + // This could be more efficient - it just searches until there are enough bytes to have + // termination auto bytes = stream->getView(); UnownedStringSlice input((const char*)bytes.begin(), (const char*)bytes.end()); @@ -59,7 +60,7 @@ void HTTPHeader::reset() return (index >= 0) ? (index + g_headerEnd.getLength()) : index; } -/* static */SlangResult HTTPHeader::parse(const UnownedStringSlice& inSlice, HTTPHeader& out) +/* static */ SlangResult HTTPHeader::parse(const UnownedStringSlice& inSlice, HTTPHeader& out) { out.reset(); @@ -70,8 +71,11 @@ void HTTPHeader::reset() { slice = slice.head(slice.getLength() - g_headerEnd.getLength()); } - // Allocate on on the arena, so when we reference other slices, they are part of this allocation. - out.m_header = UnownedStringSlice(out.m_arena.allocateString(slice.begin(), slice.getLength()), slice.getLength()); + // Allocate on on the arena, so when we reference other slices, they are part of this + // allocation. + out.m_header = UnownedStringSlice( + out.m_arena.allocateString(slice.begin(), slice.getLength()), + slice.getLength()); } // Okay, we need to split into lines, and then examine the contents @@ -88,7 +92,7 @@ void HTTPHeader::reset() const UnownedStringSlice value = line.tail(index + 1).trim(); // Add the pair - Pair pair{ key, value }; + Pair pair{key, value}; // We could check if key is already used. Some values can be repeated I believe. // So we just allow for now. @@ -138,7 +142,7 @@ void HTTPHeader::reset() return SLANG_OK; } -/* static */SlangResult HTTPHeader::read(BufferedReadStream* stream, HTTPHeader& out) +/* static */ SlangResult HTTPHeader::read(BufferedReadStream* stream, HTTPHeader& out) { Index endIndex; SLANG_RETURN_ON_FAIL(readHeaderText(stream, endIndex)); @@ -167,8 +171,10 @@ void HTTPHeader::append(StringBuilder& out) const // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types - auto mimeType = m_mimeType.getLength() ? m_mimeType : UnownedStringSlice::fromLiteral("text/plain"); - auto encoding = m_encoding.getLength() ? m_encoding : UnownedStringSlice::fromLiteral("UTF-8"); + auto mimeType = + m_mimeType.getLength() ? m_mimeType : UnownedStringSlice::fromLiteral("text/plain"); + auto encoding = + m_encoding.getLength() ? m_encoding : UnownedStringSlice::fromLiteral("UTF-8"); out << mimeType << "; "; out << "charset=" << encoding; @@ -195,11 +201,11 @@ void HTTPHeader::append(StringBuilder& out) const /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! HTTPPacketConnection !!!!!!!!!!!!!!!!!!!!!!! */ -HTTPPacketConnection::HTTPPacketConnection(BufferedReadStream* readStream, Stream* writeStream) : - m_readStream(readStream), - m_writeStream(writeStream), - m_readState(ReadState::Header), - m_readResult(SLANG_OK) +HTTPPacketConnection::HTTPPacketConnection(BufferedReadStream* readStream, Stream* writeStream) + : m_readStream(readStream) + , m_writeStream(writeStream) + , m_readState(ReadState::Header) + , m_readResult(SLANG_OK) { } @@ -241,11 +247,11 @@ SlangResult HTTPPacketConnection::update() { switch (m_readState) { - case ReadState::Closed: return SLANG_OK; - case ReadState::Error: return m_readResult; - default: break; + case ReadState::Closed: return SLANG_OK; + case ReadState::Error: return m_readResult; + default: break; } - + SLANG_RETURN_ON_FAIL(_updateReadResult(m_readStream->update())); // Note will only indicate end if the buffer *and* backing stream are end/empty @@ -266,7 +272,7 @@ SlangResult HTTPPacketConnection::update() switch (m_readState) { - case ReadState::Header: + case ReadState::Header: { SLANG_RETURN_ON_FAIL(_handleHeader()); // We might be able to progress through content, if we have the header @@ -276,19 +282,20 @@ SlangResult HTTPPacketConnection::update() } break; } - case ReadState::Content: + case ReadState::Content: { _handleContent(); break; } - default: break; + default: break; } return m_readResult; } -namespace { // anonymous +namespace +{ // anonymous // Handles binary backoff like sleeping mechanism. struct SleepState @@ -315,7 +322,8 @@ struct SleepState // If we hit the count change the interval if (m_count >= countThreshold) { - m_intervalInMs = (m_intervalInMs == 0) ? 1 : Math::Min(m_intervalInMs * 2, maxIntervalInMs); + m_intervalInMs = + (m_intervalInMs == 0) ? 1 : Math::Min(m_intervalInMs * 2, maxIntervalInMs); // Reset the count m_count = 0; } @@ -325,7 +333,7 @@ struct SleepState Int m_count = 0; }; -} // anonymous +} // namespace SlangResult HTTPPacketConnection::waitForResult(Int timeOutInMs) { @@ -342,8 +350,7 @@ SlangResult HTTPPacketConnection::waitForResult(Int timeOutInMs) SleepState sleepState; - while (m_readState == ReadState::Header || - m_readState == ReadState::Content) + while (m_readState == ReadState::Header || m_readState == ReadState::Content) { const auto prevCount = m_readStream->getCount(); diff --git a/source/core/slang-http.h b/source/core/slang-http.h index 11d834bd8..44a0d4ccc 100644 --- a/source/core/slang-http.h +++ b/source/core/slang-http.h @@ -1,22 +1,19 @@ #ifndef SLANG_CORE_HTTP_H #define SLANG_CORE_HTTP_H -#include "slang.h" - -#include "slang-string.h" +#include "slang-com-helper.h" +#include "slang-com-ptr.h" #include "slang-list.h" - #include "slang-memory-arena.h" - #include "slang-stream.h" +#include "slang-string.h" +#include "slang.h" -#include "slang-com-helper.h" -#include "slang-com-ptr.h" - -namespace Slang { +namespace Slang +{ -/// All of the contained UnownedStringSlice can be stored in m_header. This can be checked via testing if -/// the memory overlaps. +/// All of the contained UnownedStringSlice can be stored in m_header. This can be checked via +/// testing if the memory overlaps. /// /// The m_arena can be used to store slices in an ad-hoc manner to keep in scope with the Header. struct HTTPHeader @@ -27,45 +24,46 @@ struct HTTPHeader UnownedStringSlice value; }; - /// Append the header (including termination) to out + /// Append the header (including termination) to out void append(StringBuilder& out) const; - /// Reset the contents + /// Reset the contents void reset(); SLANG_INLINE Index indexOfKey(const UnownedStringSlice& slice) const; - /// Ctor - HTTPHeader() : - m_arena(1024) + /// Ctor + HTTPHeader() + : m_arena(1024) { } - /// Reads from stream until the buffer contains all of the header. The outEndIndex will point - /// past the header termination. + /// Reads from stream until the buffer contains all of the header. The outEndIndex will point + /// past the header termination. static SlangResult readHeaderText(BufferedReadStream* stream, Index& outEndIndex); - /// Returns the index of the end of the header (index of first byte *after* the header), or < if doesn't have an end + /// Returns the index of the end of the header (index of first byte *after* the header), or < if + /// doesn't have an end static Index findHeaderEnd(BufferedReadStream* stream); - /// Parse the slice (holding a header) into out. - /// Will allocate the slice on the array and store in m_header. - /// Slices will reference sections of m_header, that may be useful in some scenarios. + /// Parse the slice (holding a header) into out. + /// Will allocate the slice on the array and store in m_header. + /// Slices will reference sections of m_header, that may be useful in some scenarios. static SlangResult parse(const UnownedStringSlice& slice, HTTPHeader& out); - /// Read from buffered stream header, and place parsed header into out + /// Read from buffered stream header, and place parsed header into out static SlangResult read(BufferedReadStream* stream, HTTPHeader& out); - size_t m_contentLength; ///< Content length in bytes + size_t m_contentLength; ///< Content length in bytes - UnownedStringSlice m_mimeType; ///< The mime type - UnownedStringSlice m_encoding; ///< The character encoding + UnownedStringSlice m_mimeType; ///< The mime type + UnownedStringSlice m_encoding; ///< The character encoding - UnownedStringSlice m_header; ///< Optionally holds the whole of the header + UnownedStringSlice m_header; ///< Optionally holds the whole of the header - List<Pair> m_valuePairs; /// All of the value pairs + List<Pair> m_valuePairs; /// All of the value pairs - MemoryArena m_arena; ///< Used to store backing memory + MemoryArena m_arena; ///< Used to store backing memory private: // Disable @@ -76,15 +74,16 @@ private: // ----------------------------------------------------------------- Index HTTPHeader::indexOfKey(const UnownedStringSlice& slice) const { - return m_valuePairs.findFirstIndex([&](const HTTPHeader::Pair& pair) -> bool { return pair.key == slice; }); + return m_valuePairs.findFirstIndex( + [&](const HTTPHeader::Pair& pair) -> bool { return pair.key == slice; }); } /// Implements a way to communicate over Streams via the HTTP *protocol*. /// /// Allows for reading without blocking, via calls to 'update'. When a complete /// HTTP 'packet' (combination of header and content) is available, the ReadState will -/// become 'Done'. For this to work without blocking it relies on the stream backing the BufferedReadStream -/// to be non blocking. +/// become 'Done'. For this to work without blocking it relies on the stream backing the +/// BufferedReadStream to be non blocking. /// /// If it is only necessary to respond on complete packets 'waitForContent' can be used. /// If this returns and ReadState is Done, then getHeader holds the current header, and getContent @@ -93,50 +92,66 @@ Index HTTPHeader::indexOfKey(const UnownedStringSlice& slice) const /// Once the packet has been processed 'consumeContent' can be used. Once consumeContent is called /// both contents of getContent and getReadHeader will no longer be valid. /// -/// Ie using the slice returned from getContent *after* consumeContent is called is *undefined behavior*. -/// +/// Ie using the slice returned from getContent *after* consumeContent is called is *undefined +/// behavior*. +/// /// NOTE! that this does not implement HTTP over TCP/IP. /// That said it could be used to communicate via the HTTP protocol over TCP/IP /// if the Streams supplied were TCP/IP sockets. class HTTPPacketConnection : public RefObject { public: - enum class ReadState { - Header, ///< Reading reader - Content, ///< Reading content (ie header is read) - Done, ///< The content is read - Closed, ///< The read stream is closed - no further packets can be read - Error, ///< In an error state - no further packets can be read + Header, ///< Reading reader + Content, ///< Reading content (ie header is read) + Done, ///< The content is read + Closed, ///< The read stream is closed - no further packets can be read + Error, ///< In an error state - no further packets can be read }; - /// Update state + /// Update state SlangResult update(); - /// Get the current read staet + /// Get the current read staet ReadState getReadState() const { return m_readState; } - /// Get the read header - const HTTPHeader& getReadHeader() const { SLANG_ASSERT(hasHeader()); return m_readHeader; } - /// Get the content - ConstArrayView<Byte> getContent() const { SLANG_ASSERT(m_readState == ReadState::Done); return ConstArrayView<Byte>((const Byte*)m_readStream->getBuffer(), m_readHeader.m_contentLength); } + /// Get the read header + const HTTPHeader& getReadHeader() const + { + SLANG_ASSERT(hasHeader()); + return m_readHeader; + } + /// Get the content + ConstArrayView<Byte> getContent() const + { + SLANG_ASSERT(m_readState == ReadState::Done); + return ConstArrayView<Byte>( + (const Byte*)m_readStream->getBuffer(), + m_readHeader.m_contentLength); + } - /// Write. Will potentially block if write stream is blocking. + /// Write. Will potentially block if write stream is blocking. SlangResult write(const void* content, size_t sizeInBytes); - /// Blocks until some result - a packet, closure, or some kind of error or timeout. - /// TimeOut of -1 means no timeout. + /// Blocks until some result - a packet, closure, or some kind of error or timeout. + /// TimeOut of -1 means no timeout. SlangResult waitForResult(Int timeOutInMs = -1); - /// Consume the content - so can read next content + /// Consume the content - so can read next content void consumeContent(); - /// True if connection is active. - bool isActive() const { return m_readState != ReadState::Error && m_readState != ReadState::Closed; } + /// True if connection is active. + bool isActive() const + { + return m_readState != ReadState::Error && m_readState != ReadState::Closed; + } - bool hasHeader() const { return m_readState == ReadState::Content || m_readState == ReadState::Done; } - /// True if has content (implies has header) - bool hasContent() const { return m_readState == ReadState::Done; } + bool hasHeader() const + { + return m_readState == ReadState::Content || m_readState == ReadState::Done; + } + /// True if has content (implies has header) + bool hasContent() const { return m_readState == ReadState::Done; } - /// Ctor + /// Ctor HTTPPacketConnection(BufferedReadStream* readStream, Stream* writeStream); protected: diff --git a/source/core/slang-implicit-directory-collector.cpp b/source/core/slang-implicit-directory-collector.cpp index d116ed8f9..a08597e6f 100644 --- a/source/core/slang-implicit-directory-collector.cpp +++ b/source/core/slang-implicit-directory-collector.cpp @@ -7,8 +7,10 @@ namespace Slang // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ImplicitDirectoryCollector !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -ImplicitDirectoryCollector::ImplicitDirectoryCollector(const String& canonicalPath, bool directoryExists) : - m_directoryExists(directoryExists) +ImplicitDirectoryCollector::ImplicitDirectoryCollector( + const String& canonicalPath, + bool directoryExists) + : m_directoryExists(directoryExists) { if (!isRootPath(canonicalPath.getUnownedSlice())) { @@ -19,7 +21,7 @@ ImplicitDirectoryCollector::ImplicitDirectoryCollector(const String& canonicalPa } } -/* static */bool ImplicitDirectoryCollector::isRootPath(const UnownedStringSlice& path) +/* static */ bool ImplicitDirectoryCollector::isRootPath(const UnownedStringSlice& path) { const auto length = path.getLength(); if (length == 0) @@ -34,7 +36,9 @@ ImplicitDirectoryCollector::ImplicitDirectoryCollector(const String& canonicalPa return false; } -void ImplicitDirectoryCollector::addRemainingPath(SlangPathType pathType, const UnownedStringSlice& inPathRemainder) +void ImplicitDirectoryCollector::addRemainingPath( + SlangPathType pathType, + const UnownedStringSlice& inPathRemainder) { // If it's zero length we probably don't want to add it if (inPathRemainder.getLength() == 0) @@ -51,7 +55,8 @@ void ImplicitDirectoryCollector::addRemainingPath(SlangPathType pathType, const if (slashIndex >= 0) { pathType = SLANG_PATH_TYPE_DIRECTORY; - pathRemainder = UnownedStringSlice(pathRemainder.begin(), pathRemainder.begin() + slashIndex); + pathRemainder = + UnownedStringSlice(pathRemainder.begin(), pathRemainder.begin() + slashIndex); } const Index countIndex = m_map.findOrAdd(pathRemainder, pathType); @@ -60,7 +65,9 @@ void ImplicitDirectoryCollector::addRemainingPath(SlangPathType pathType, const SLANG_ASSERT(SlangPathType(m_map.getValueAt(countIndex)) == pathType); } -void ImplicitDirectoryCollector::addPath(SlangPathType pathType, const UnownedStringSlice& canonicalPath) +void ImplicitDirectoryCollector::addPath( + SlangPathType pathType, + const UnownedStringSlice& canonicalPath) { if (canonicalPath != toSlice(".") && hasPrefix(canonicalPath)) { @@ -69,7 +76,9 @@ void ImplicitDirectoryCollector::addPath(SlangPathType pathType, const UnownedSt } } -SlangResult ImplicitDirectoryCollector::enumerate(FileSystemContentsCallBack callback, void* userData) +SlangResult ImplicitDirectoryCollector::enumerate( + FileSystemContentsCallBack callback, + void* userData) { const Int count = m_map.getCount(); diff --git a/source/core/slang-implicit-directory-collector.h b/source/core/slang-implicit-directory-collector.h index 3b3505df2..72f3894dd 100644 --- a/source/core/slang-implicit-directory-collector.h +++ b/source/core/slang-implicit-directory-collector.h @@ -2,69 +2,77 @@ #define SLANG_CORE_IMPLICIT_DIRECTORY_COLLECTOR_H #include "slang-basic.h" - #include "slang-string-slice-index-map.h" namespace Slang { -/* This class helps to find the contents and/or existence of an implicit directory.This finds the contents of a directory. +/* This class helps to find the contents and/or existence of an implicit directory.This finds the +contents of a directory. -This is achieved by using a path prefix that any contained path must at least match. If the remainder of the path contains a folder - - detectable because it's not a leaf and so contains a delimiter - that directory is added. As a sub folder may contain many - files, and the directory itself may also be defined, it is necessary to dedup. The deduping is handled by the StringSliceIndexMap. */ +This is achieved by using a path prefix that any contained path must at least match. If the +remainder of the path contains a folder + - detectable because it's not a leaf and so contains a delimiter - that directory is added. As a +sub folder may contain many files, and the directory itself may also be defined, it is necessary to +dedup. The deduping is handled by the StringSliceIndexMap. */ class ImplicitDirectoryCollector { public: - enum class State { - None, ///< Neither the directory or content have been found - DirectoryExists, ///< The directory exists - HasContent, ///< If it has content, the directory must exist + None, ///< Neither the directory or content have been found + DirectoryExists, ///< The directory exists + HasContent, ///< If it has content, the directory must exist }; - /// Get the current state - State getState() const { return (m_map.getCount() > 0) ? State::HasContent : (m_directoryExists ? State::DirectoryExists : State::None); } - /// True if collector at least has the specified state + /// Get the current state + State getState() const + { + return (m_map.getCount() > 0) ? State::HasContent + : (m_directoryExists ? State::DirectoryExists : State::None); + } + /// True if collector at least has the specified state bool hasState(State state) { return Index(getState()) >= Index(state); } - /// Set that it exists + /// Set that it exists void setDirectoryExists(bool directoryExists) { m_directoryExists = directoryExists; } - /// Get if it exists (implicitly or explicitly) + /// Get if it exists (implicitly or explicitly) bool getDirectoryExists() const { return m_directoryExists || m_map.getCount() > 0; } - /// True if the path matches the prefix - bool hasPrefix(const UnownedStringSlice& path) const { return path.startsWith(m_prefix.getUnownedSlice()); } + /// True if the path matches the prefix + bool hasPrefix(const UnownedStringSlice& path) const + { + return path.startsWith(m_prefix.getUnownedSlice()); + } - /// True if the directory has content + /// True if the directory has content bool hasContent() const { return m_map.getCount() > 0; } - /// Gets the remainder or path after the prefix + /// Gets the remainder or path after the prefix UnownedStringSlice getRemainder(const UnownedStringSlice& path) const { SLANG_ASSERT(hasPrefix(path)); return UnownedStringSlice(path.begin() + m_prefix.getLength(), path.end()); } - /// Add a remaining path + /// Add a remaining path void addRemainingPath(SlangPathType pathType, const UnownedStringSlice& inPathRemainder); - /// Add a path + /// Add a path void addPath(SlangPathType pathType, const UnownedStringSlice& canonicalPath); - /// Enumerate the contents + /// Enumerate the contents SlangResult enumerate(FileSystemContentsCallBack callback, void* userData); - /// Ctor + /// Ctor ImplicitDirectoryCollector(const String& canonicalPath, bool directoryExists = false); static bool isRootPath(const UnownedStringSlice& path); - protected: +protected: StringSliceIndexMap m_map; String m_prefix; bool m_directoryExists; }; -} +} // namespace Slang #endif diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index edd21639b..25c4c9389 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -1,15 +1,14 @@ #define _CRT_SECURE_NO_WARNINGS 1 #include "slang-io.h" -#include "slang-exception.h" +#include "slang-char-util.h" #include "slang-com-helper.h" - +#include "slang-exception.h" #include "slang-string-util.h" -#include "slang-char-util.h" #ifndef __STDC__ -# define __STDC__ 1 +#define __STDC__ 1 #endif #include <sys/stat.h> @@ -24,1366 +23,1392 @@ #endif #if defined(__linux__) || defined(__CYGWIN__) || SLANG_APPLE_FAMILY || SLANG_WASM -# include <fcntl.h> -# include <unistd.h> +#include <fcntl.h> +#include <unistd.h> // For Path::find -# include <fnmatch.h> - -# include <dirent.h> -# include <sys/stat.h> -# include <sys/file.h> -# include <ftw.h> // for nftw +#include <dirent.h> +#include <fnmatch.h> +#include <ftw.h> // for nftw +#include <sys/file.h> +#include <sys/stat.h> #endif #if SLANG_APPLE_FAMILY -# include <mach-o/dyld.h> +#include <mach-o/dyld.h> #endif +#include <filesystem> #include <limits.h> /* PATH_MAX */ #include <stdio.h> #include <stdlib.h> -#include <filesystem> namespace Slang { - /* static */SlangResult File::remove(const String& fileName) - { +/* static */ SlangResult File::remove(const String& fileName) +{ #ifdef _WIN32 - // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea - if (DeleteFileA(fileName.getBuffer())) - { - return SLANG_OK; - } - return SLANG_FAIL; + // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea + if (DeleteFileA(fileName.getBuffer())) + { + return SLANG_OK; + } + return SLANG_FAIL; #else - // https://linux.die.net/man/3/remove - if (::remove(fileName.getBuffer()) == 0) - { - return SLANG_OK; - } - return SLANG_FAIL; -#endif + // https://linux.die.net/man/3/remove + if (::remove(fileName.getBuffer()) == 0) + { + return SLANG_OK; } + return SLANG_FAIL; +#endif +} #ifdef _WIN32 - /* static */SlangResult File::generateTemporary(const UnownedStringSlice& inPrefix, Slang::String& outFileName) - { - // https://docs.microsoft.com/en-us/windows/win32/fileio/creating-and-using-a-temporary-file - - String tempPath; - { - int count = MAX_PATH + 1; - while (true) - { - char* chars = tempPath.prepareForAppend(count); - // Gets the temp path env string (no guarantee it's a valid path). - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha - DWORD ret = ::GetTempPathA(count - 1, chars); - if (ret == 0) - { - return SLANG_FAIL; - } - if (ret > DWORD(count - 1)) - { - count = ret + 1; - continue; - } - tempPath.appendInPlace(chars, count); - break; - } - } - - if (!File::exists(tempPath)) - { - return SLANG_FAIL; - } - - const String prefix(inPrefix); - String tempFileName; +/* static */ SlangResult File::generateTemporary( + const UnownedStringSlice& inPrefix, + Slang::String& outFileName) +{ + // https://docs.microsoft.com/en-us/windows/win32/fileio/creating-and-using-a-temporary-file + String tempPath; + { + int count = MAX_PATH + 1; + while (true) { - int count = MAX_PATH + 1; - char* chars = tempFileName.prepareForAppend(count); - - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea - // Generates a temporary file name. - // Will create a file with this name. - DWORD ret = ::GetTempFileNameA(tempPath.getBuffer(), prefix.getBuffer(), 0, chars); - + char* chars = tempPath.prepareForAppend(count); + // Gets the temp path env string (no guarantee it's a valid path). + // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha + DWORD ret = ::GetTempPathA(count - 1, chars); if (ret == 0) { return SLANG_FAIL; } - tempFileName.appendInPlace(chars, ::strlen(chars)); + if (ret > DWORD(count - 1)) + { + count = ret + 1; + continue; + } + tempPath.appendInPlace(chars, count); + break; } + } - SLANG_ASSERT(File::exists(tempFileName)); - - outFileName = tempFileName; - return SLANG_OK; + if (!File::exists(tempPath)) + { + return SLANG_FAIL; } -#else - /* static */SlangResult File::generateTemporary(const UnownedStringSlice& inPrefix, Slang::String& outFileName) + + const String prefix(inPrefix); + String tempFileName; + { - StringBuilder builder; - builder << "/tmp/" << inPrefix << "-XXXXXX"; + int count = MAX_PATH + 1; + char* chars = tempFileName.prepareForAppend(count); - List<char> buffer; - auto copySize = builder.getLength(); - buffer.setCount(copySize + 1); - // Satisfy GCC - SLANG_ASSUME(copySize < PTRDIFF_MAX && copySize > 0); - ::memcpy(buffer.getBuffer(), builder.getBuffer(), copySize); - buffer[copySize] = 0; + // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea + // Generates a temporary file name. + // Will create a file with this name. + DWORD ret = ::GetTempFileNameA(tempPath.getBuffer(), prefix.getBuffer(), 0, chars); - int handle = mkstemp(buffer.getBuffer()); - if (handle == -1) + if (ret == 0) { return SLANG_FAIL; } + tempFileName.appendInPlace(chars, ::strlen(chars)); + } - // Close the handle.. - close(handle); - - outFileName = buffer.getBuffer(); - SLANG_ASSERT(File::exists(outFileName)); + SLANG_ASSERT(File::exists(tempFileName)); - return SLANG_OK; + outFileName = tempFileName; + return SLANG_OK; +} +#else +/* static */ SlangResult File::generateTemporary( + const UnownedStringSlice& inPrefix, + Slang::String& outFileName) +{ + StringBuilder builder; + builder << "/tmp/" << inPrefix << "-XXXXXX"; + + List<char> buffer; + auto copySize = builder.getLength(); + buffer.setCount(copySize + 1); + // Satisfy GCC + SLANG_ASSUME(copySize < PTRDIFF_MAX && copySize > 0); + ::memcpy(buffer.getBuffer(), builder.getBuffer(), copySize); + buffer[copySize] = 0; + + int handle = mkstemp(buffer.getBuffer()); + if (handle == -1) + { + return SLANG_FAIL; } + + // Close the handle.. + close(handle); + + outFileName = buffer.getBuffer(); + SLANG_ASSERT(File::exists(outFileName)); + + return SLANG_OK; +} #endif - /* static */SlangResult File::makeExecutable(const String& fileName) - { +/* static */ SlangResult File::makeExecutable(const String& fileName) +{ #ifdef _WIN32 - SLANG_UNUSED(fileName); - // As long as file extension is executable, it can be executed - return SLANG_OK; + SLANG_UNUSED(fileName); + // As long as file extension is executable, it can be executed + return SLANG_OK; #else - struct stat st; - if(::stat(fileName.getBuffer(), &st) != 0) - { - return SLANG_FAIL; - } - if(st.st_mode & S_IXUSR) - { - return SLANG_OK; - } - // It would probably be slightly neater to set all executable bits - // aside from those in umask.. - if(::chmod(fileName.getBuffer(), st.st_mode & 07777 | S_IXUSR) != 0) - { - return SLANG_FAIL; - } + struct stat st; + if (::stat(fileName.getBuffer(), &st) != 0) + { + return SLANG_FAIL; + } + if (st.st_mode & S_IXUSR) + { return SLANG_OK; -#endif } + // It would probably be slightly neater to set all executable bits + // aside from those in umask.. + if (::chmod(fileName.getBuffer(), st.st_mode & 07777 | S_IXUSR) != 0) + { + return SLANG_FAIL; + } + return SLANG_OK; +#endif +} - bool File::exists(const String& fileName) - { +bool File::exists(const String& fileName) +{ #ifdef _WIN32 - struct _stat32 statVar; - return ::_wstat32(((String)fileName).toWString(), &statVar) != -1; + struct _stat32 statVar; + return ::_wstat32(((String)fileName).toWString(), &statVar) != -1; #else - struct stat statVar; - return ::stat(fileName.getBuffer(), &statVar) == 0; + struct stat statVar; + return ::stat(fileName.getBuffer(), &statVar) == 0; #endif - } - - String Path::replaceExt(const String& path, const char* newExt) - { - StringBuilder sb(path.getLength() + 10); - Index dotPos = findExtIndex(path); +} - if (dotPos < 0) - dotPos = path.getLength(); - sb.append(path.getBuffer(), dotPos); - sb.append('.'); - sb.append(newExt); - return sb.produceString(); - } +String Path::replaceExt(const String& path, const char* newExt) +{ + StringBuilder sb(path.getLength() + 10); + Index dotPos = findExtIndex(path); + + if (dotPos < 0) + dotPos = path.getLength(); + sb.append(path.getBuffer(), dotPos); + sb.append('.'); + sb.append(newExt); + return sb.produceString(); +} - /* static */ Index Path::findLastSeparatorIndex(UnownedStringSlice const& path) +/* static */ Index Path::findLastSeparatorIndex(UnownedStringSlice const& path) +{ + const char* chars = path.begin(); + for (Index i = path.getLength() - 1; i >= 0; --i) { - const char* chars = path.begin(); - for (Index i = path.getLength() - 1; i >= 0; --i) + const char c = chars[i]; + if (c == '/' || c == '\\') { - const char c = chars[i]; - if (c == '/' || c == '\\') - { - return i; - } + return i; } - return -1; } + return -1; +} - /* static */Index Path::findExtIndex(UnownedStringSlice const& path) - { - const Index sepIndex = findLastSeparatorIndex(path); +/* static */ Index Path::findExtIndex(UnownedStringSlice const& path) +{ + const Index sepIndex = findLastSeparatorIndex(path); - const Index dotIndex = path.lastIndexOf('.'); - if (sepIndex >= 0) - { - // Index has to be in the last part of the path - return (dotIndex > sepIndex) ? dotIndex : -1; - } - else - { - return dotIndex; - } + const Index dotIndex = path.lastIndexOf('.'); + if (sepIndex >= 0) + { + // Index has to be in the last part of the path + return (dotIndex > sepIndex) ? dotIndex : -1; } - - String Path::getFileName(const String& path) + else { - Index pos = findLastSeparatorIndex(path); - if (pos >= 0) - { - pos = pos + 1; - return path.subString(pos, path.getLength() - pos); - } - else - { - return path; - } + return dotIndex; } +} - /* static */String Path::getFileNameWithoutExt(const String& path) +String Path::getFileName(const String& path) +{ + Index pos = findLastSeparatorIndex(path); + if (pos >= 0) { - Index sepIndex = findLastSeparatorIndex(path); - sepIndex = (sepIndex < 0) ? 0 : (sepIndex + 1); - Index dotIndex = findExtIndex(path); - dotIndex = (dotIndex < 0) ? path.getLength() : dotIndex; - - return path.subString(sepIndex, dotIndex - sepIndex); + pos = pos + 1; + return path.subString(pos, path.getLength() - pos); } - - /* static*/ String Path::getPathWithoutExt(const String& path) + else { - Index dotPos = findExtIndex(path); - if (dotPos >= 0) - return path.subString(0, dotPos); - else - return path; + return path; } +} + +/* static */ String Path::getFileNameWithoutExt(const String& path) +{ + Index sepIndex = findLastSeparatorIndex(path); + sepIndex = (sepIndex < 0) ? 0 : (sepIndex + 1); + Index dotIndex = findExtIndex(path); + dotIndex = (dotIndex < 0) ? path.getLength() : dotIndex; + + return path.subString(sepIndex, dotIndex - sepIndex); +} - UnownedStringSlice Path::getPathExt(const UnownedStringSlice& path) +/* static*/ String Path::getPathWithoutExt(const String& path) +{ + Index dotPos = findExtIndex(path); + if (dotPos >= 0) + return path.subString(0, dotPos); + else + return path; +} + +UnownedStringSlice Path::getPathExt(const UnownedStringSlice& path) +{ + const Index dotPos = findExtIndex(path); + if (dotPos >= 0) { - const Index dotPos = findExtIndex(path); - if (dotPos >= 0) - { - return path.subString(dotPos + 1, path.getLength() - dotPos - 1); - } - else - { - // Note that the caller can identify if path has no extension or just a . - // as if it's a dot a zero length slice is returned in path - // If it's not then a default slice is returned (which doesn't point into path). - // - // Granted this is a little obscure and perhaps should be improved. - return UnownedStringSlice(); - } + return path.subString(dotPos + 1, path.getLength() - dotPos - 1); } - - String Path::getParentDirectory(const String& path) + else { - Index pos = findLastSeparatorIndex(path); - if (pos >= 0) - return path.subString(0, pos); - else - return ""; + // Note that the caller can identify if path has no extension or just a . + // as if it's a dot a zero length slice is returned in path + // If it's not then a default slice is returned (which doesn't point into path). + // + // Granted this is a little obscure and perhaps should be improved. + return UnownedStringSlice(); } +} - /* static */void Path::append(StringBuilder& ioBuilder, const UnownedStringSlice& path) +String Path::getParentDirectory(const String& path) +{ + Index pos = findLastSeparatorIndex(path); + if (pos >= 0) + return path.subString(0, pos); + else + return ""; +} + +/* static */ void Path::append(StringBuilder& ioBuilder, const UnownedStringSlice& path) +{ + if (ioBuilder.getLength() == 0) { - if (ioBuilder.getLength() == 0) - { - ioBuilder.append(path); - return; - } - if (path.getLength() > 0) + ioBuilder.append(path); + return; + } + if (path.getLength() > 0) + { + // If ioBuilder doesn't end in a delimiter, add one + if (!isDelimiter(ioBuilder[ioBuilder.getLength() - 1])) { - // If ioBuilder doesn't end in a delimiter, add one - if (!isDelimiter(ioBuilder[ioBuilder.getLength() - 1])) + // Determine the preferred delimiter to use based on existing path. + char preferedDelimiter = kOSCanonicalPathDelimiter; + if (kOSAlternativePathDelimiter != preferedDelimiter) { - // Determine the preferred delimiter to use based on existing path. - char preferedDelimiter = kOSCanonicalPathDelimiter; - if (kOSAlternativePathDelimiter != preferedDelimiter) + // If we found the existing path uses the alternative delimiter, we will + // use that instead of the canonical one. + constexpr Index kMaxDelimiterSearchRange = 32; + for (Index i = 0; i < Math::Min(kMaxDelimiterSearchRange, ioBuilder.getLength()); + i++) { - // If we found the existing path uses the alternative delimiter, we will - // use that instead of the canonical one. - constexpr Index kMaxDelimiterSearchRange = 32; - for (Index i = 0; i < Math::Min(kMaxDelimiterSearchRange, ioBuilder.getLength()); i++) + if (ioBuilder[i] == kOSAlternativePathDelimiter) { - if (ioBuilder[i] == kOSAlternativePathDelimiter) - { - preferedDelimiter = kOSAlternativePathDelimiter; - break; - } + preferedDelimiter = kOSAlternativePathDelimiter; + break; } } - ioBuilder.append(preferedDelimiter); } - // Check that path doesn't start with a path delimiter - SLANG_ASSERT(!isDelimiter(path[0])); - // Append the path - ioBuilder.append(path); + ioBuilder.append(preferedDelimiter); } + // Check that path doesn't start with a path delimiter + SLANG_ASSERT(!isDelimiter(path[0])); + // Append the path + ioBuilder.append(path); } +} - /* static */void Path::combineIntoBuilder(const UnownedStringSlice& path1, const UnownedStringSlice& path2, StringBuilder& outBuilder) +/* static */ void Path::combineIntoBuilder( + const UnownedStringSlice& path1, + const UnownedStringSlice& path2, + StringBuilder& outBuilder) +{ + outBuilder.clear(); + outBuilder.append(path1); + append(outBuilder, path2); +} + +String Path::combine(const String& path1, const String& path2) +{ + if (path1.getLength() == 0) { - outBuilder.clear(); - outBuilder.append(path1); - append(outBuilder, path2); + return path2; } - String Path::combine(const String& path1, const String& path2) + StringBuilder sb; + combineIntoBuilder(path1.getUnownedSlice(), path2.getUnownedSlice(), sb); + return sb.produceString(); +} +String Path::combine(const String& path1, const String& path2, const String& path3) +{ + StringBuilder sb; + sb.append(path1); + append(sb, path2.getUnownedSlice()); + append(sb, path3.getUnownedSlice()); + return sb.produceString(); +} + +/* static */ bool Path::isDriveSpecification(const UnownedStringSlice& element) +{ + switch (element.getLength()) { - if (path1.getLength() == 0) + case 0: { - return path2; + // We'll just assume it is + return true; } - - StringBuilder sb; - combineIntoBuilder(path1.getUnownedSlice(), path2.getUnownedSlice(), sb); - return sb.produceString(); - } - String Path::combine(const String& path1, const String& path2, const String& path3) - { - StringBuilder sb; - sb.append(path1); - append(sb, path2.getUnownedSlice()); - append(sb, path3.getUnownedSlice()); - return sb.produceString(); - } - - /* static */ bool Path::isDriveSpecification(const UnownedStringSlice& element) - { - switch (element.getLength()) + case 2: { - case 0: - { - // We'll just assume it is - return true; - } - case 2: - { - // Look for a windows like drive spec - const char firstChar = element[0]; - return element[1] == ':' && ((firstChar >= 'a' && firstChar <= 'z') || (firstChar >= 'A' && firstChar <= 'Z')); - } - default: return false; + // Look for a windows like drive spec + const char firstChar = element[0]; + return element[1] == ':' && ((firstChar >= 'a' && firstChar <= 'z') || + (firstChar >= 'A' && firstChar <= 'Z')); } + default: return false; } +} - UnownedStringSlice Path::getFirstElement(const UnownedStringSlice& in) - { - const char* end = in.end(); - const char* cur = in.begin(); - // Find delimiter or the end - while (cur < end && !Path::isDelimiter(*cur)) ++cur; - return UnownedStringSlice(in.begin(), cur); - } +UnownedStringSlice Path::getFirstElement(const UnownedStringSlice& in) +{ + const char* end = in.end(); + const char* cur = in.begin(); + // Find delimiter or the end + while (cur < end && !Path::isDelimiter(*cur)) + ++cur; + return UnownedStringSlice(in.begin(), cur); +} - /* static */bool Path::isAbsolute(const UnownedStringSlice& path) +/* static */ bool Path::isAbsolute(const UnownedStringSlice& path) +{ + if (path.getLength() > 0 && isDelimiter(path[0])) { - if (path.getLength() > 0 && isDelimiter(path[0])) - { - return true; - } + return true; + } #if SLANG_WINDOWS_FAMILY - // Check for the \\ network drive style - if (path.getLength() >= 2 && path[0] == '\\' && path[1] == '\\') - { - return true; - } - - // Check for drive - if (isDriveSpecification(getFirstElement(path))) - { - return true; - } -#endif - - return false; + // Check for the \\ network drive style + if (path.getLength() >= 2 && path[0] == '\\' && path[1] == '\\') + { + return true; } - /* static */void Path::split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut) + // Check for drive + if (isDriveSpecification(getFirstElement(path))) { - splitOut.clear(); + return true; + } +#endif - const char* start = path.begin(); - const char* end = path.end(); + return false; +} - while (start < end) - { - const char* cur = start; - // Find the split - while (cur < end && !isDelimiter(*cur)) cur++; +/* static */ void Path::split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut) +{ + splitOut.clear(); - splitOut.add(UnownedStringSlice(start, cur)); + const char* start = path.begin(); + const char* end = path.end(); - // Next - start = cur + 1; - } + while (start < end) + { + const char* cur = start; + // Find the split + while (cur < end && !isDelimiter(*cur)) + cur++; - // Okay if the end is empty. And we aren't with a spec like // or c:/ , then drop the final slash - if (splitOut.getCount() > 1 && splitOut.getLast().getLength() == 0) - { - if (splitOut.getCount() == 2 && isDriveSpecification(splitOut[0])) - { - return; - } - // Remove the last - splitOut.removeLast(); - } + splitOut.add(UnownedStringSlice(start, cur)); + + // Next + start = cur + 1; } - /* static */bool Path::hasRelativeElement(const UnownedStringSlice& path) + // Okay if the end is empty. And we aren't with a spec like // or c:/ , then drop the final + // slash + if (splitOut.getCount() > 1 && splitOut.getLast().getLength() == 0) { - List<UnownedStringSlice> splitPath; - split(path, splitPath); - - for (const auto& cur : splitPath) + if (splitOut.getCount() == 2 && isDriveSpecification(splitOut[0])) { - if (cur == "." || cur == "..") - { - return true; - } + return; } - return false; + // Remove the last + splitOut.removeLast(); } +} - /* static */SlangResult Path::simplify(const UnownedStringSlice& path, SimplifyStyle style, StringBuilder& outPath) +/* static */ bool Path::hasRelativeElement(const UnownedStringSlice& path) +{ + List<UnownedStringSlice> splitPath; + split(path, splitPath); + + for (const auto& cur : splitPath) { - if (path.getLength() == 0) + if (cur == "." || cur == "..") { - return SLANG_FAIL; + return true; } + } + return false; +} - List<UnownedStringSlice> splitPath; - split(UnownedStringSlice(path), splitPath); +/* static */ SlangResult Path::simplify( + const UnownedStringSlice& path, + SimplifyStyle style, + StringBuilder& outPath) +{ + if (path.getLength() == 0) + { + return SLANG_FAIL; + } - simplify(splitPath); + List<UnownedStringSlice> splitPath; + split(UnownedStringSlice(path), splitPath); - const auto simplifyIntegral = SimplifyIntegral(style); + simplify(splitPath); - // If it has a relative part then it's not absolute - if ((simplifyIntegral & SimplifyFlag::AbsoluteOnly) && - splitPath.indexOf(UnownedStringSlice::fromLiteral("..")) >= 0) - { - return SLANG_E_NOT_FOUND; - } + const auto simplifyIntegral = SimplifyIntegral(style); - // We allow splitPath.getCount() == 0, because - // the original path could have been '.' or './.' - // - // Special handling this case is in Path::join + // If it has a relative part then it's not absolute + if ((simplifyIntegral & SimplifyFlag::AbsoluteOnly) && + splitPath.indexOf(UnownedStringSlice::fromLiteral("..")) >= 0) + { + return SLANG_E_NOT_FOUND; + } - // If we want the path produced such that is *not* output with a root (ie SimplifyFlag::NoRoot) - // we detect if we a rooted path (ie in effect starting with "/") and so splitPath[0] == "" - // and remove that part from when doing the join. - if ((simplifyIntegral & SimplifyFlag::NoRoot) && - (splitPath.getCount() && splitPath[0].getLength() == 0)) - { - // If we allow without a root, we remove from the join - Path::join(splitPath.getBuffer() + 1, splitPath.getCount() - 1, outPath); - } - else - { - Path::join(splitPath.getBuffer(), splitPath.getCount(), outPath); - } + // We allow splitPath.getCount() == 0, because + // the original path could have been '.' or './.' + // + // Special handling this case is in Path::join - return SLANG_OK; + // If we want the path produced such that is *not* output with a root (ie SimplifyFlag::NoRoot) + // we detect if we a rooted path (ie in effect starting with "/") and so splitPath[0] == "" + // and remove that part from when doing the join. + if ((simplifyIntegral & SimplifyFlag::NoRoot) && + (splitPath.getCount() && splitPath[0].getLength() == 0)) + { + // If we allow without a root, we remove from the join + Path::join(splitPath.getBuffer() + 1, splitPath.getCount() - 1, outPath); } - - /* static */void Path::simplify(List<UnownedStringSlice>& ioSplit) + else { - // Strictly speaking we could do something about case on platforms like window, but here we won't worry about that - for (Index i = 0; i < ioSplit.getCount(); i++) - { - const UnownedStringSlice& cur = ioSplit[i]; - if (cur == "." && ioSplit.getCount() > 1) - { - // Just remove it - ioSplit.removeAt(i); - i--; - } - else if (cur == ".." && i > 0) - { - // Can we remove this and the one before ? - UnownedStringSlice& before = ioSplit[i - 1]; - if (before == ".." || (i == 1 && isDriveSpecification(before))) - { - // Can't do it, but we allow relative, so just leave for now - continue; - } - ioSplit.removeRange(i - 1, 2); - i -= 2; - } - } + Path::join(splitPath.getBuffer(), splitPath.getCount(), outPath); } - /* static */void Path::join(const UnownedStringSlice* slices, Index count, StringBuilder& out) - { - out.clear(); + return SLANG_OK; +} - if (count == 0) - { - out << "."; - } - else if (count == 1 && slices[0].getLength() == 0) +/* static */ void Path::simplify(List<UnownedStringSlice>& ioSplit) +{ + // Strictly speaking we could do something about case on platforms like window, but here we + // won't worry about that + for (Index i = 0; i < ioSplit.getCount(); i++) + { + const UnownedStringSlice& cur = ioSplit[i]; + if (cur == "." && ioSplit.getCount() > 1) { - // It's the root - out << kPathDelimiter; + // Just remove it + ioSplit.removeAt(i); + i--; } - else + else if (cur == ".." && i > 0) { - StringUtil::join(slices, count, kPathDelimiter, out); + // Can we remove this and the one before ? + UnownedStringSlice& before = ioSplit[i - 1]; + if (before == ".." || (i == 1 && isDriveSpecification(before))) + { + // Can't do it, but we allow relative, so just leave for now + continue; + } + ioSplit.removeRange(i - 1, 2); + i -= 2; } } +} +/* static */ void Path::join(const UnownedStringSlice* slices, Index count, StringBuilder& out) +{ + out.clear(); - /* static */String Path::simplify(const UnownedStringSlice& path) + if (count == 0) { - List<UnownedStringSlice> splitPath; - split(path, splitPath); - simplify(splitPath); - - // Reconstruct the string - StringBuilder builder; - join(splitPath.getBuffer(), splitPath.getCount(), builder); - return builder.toString(); + out << "."; } - - bool Path::createDirectory(const String& path) + else if (count == 1 && slices[0].getLength() == 0) + { + // It's the root + out << kPathDelimiter; + } + else { + StringUtil::join(slices, count, kPathDelimiter, out); + } +} + + +/* static */ String Path::simplify(const UnownedStringSlice& path) +{ + List<UnownedStringSlice> splitPath; + split(path, splitPath); + simplify(splitPath); + + // Reconstruct the string + StringBuilder builder; + join(splitPath.getBuffer(), splitPath.getCount(), builder); + return builder.toString(); +} + +bool Path::createDirectory(const String& path) +{ #if defined(_WIN32) - return _wmkdir(path.toWString()) == 0; + return _wmkdir(path.toWString()) == 0; #else - return mkdir(path.getBuffer(), 0777) == 0; + return mkdir(path.getBuffer(), 0777) == 0; #endif - } +} - bool Path::createDirectoryRecursive(const String& path) +bool Path::createDirectoryRecursive(const String& path) +{ + String finalPath = Path::simplify(path); + if (finalPath.getLength() == 0) { - String finalPath = Path::simplify(path); - if (finalPath.getLength() == 0) - { - return false; - } - - List<String> pathList; - - // Check whether the parent directories exist, and add to the pathList if they are - // not, we will create all the directories from back of the list. - String parentDir = finalPath; - for(;;) - { - if (parentDir.getLength() == 0 || File::exists(parentDir)) - { - break; - } - else - { - pathList.add(parentDir); - parentDir = Path::getParentDirectory(parentDir); - } - } + return false; + } - // If there are no directories to create, then we are done - if (pathList.getCount() == 0) - { - return true; - } + List<String> pathList; - // Traverse from back of the list, because that is most outer directory. - Int i = 0; - for (i = pathList.getCount() - 1; i >= 0; i--) + // Check whether the parent directories exist, and add to the pathList if they are + // not, we will create all the directories from back of the list. + String parentDir = finalPath; + for (;;) + { + if (parentDir.getLength() == 0 || File::exists(parentDir)) { - if (!createDirectory(pathList[i])) - { - break; - } + break; } - - // Something wrong when creating parent directories - if (i > 0) + else { - // Remove the directories if we've created - if (i != pathList.getCount() - 1) - remove(pathList[i]); - - return false; + pathList.add(parentDir); + parentDir = Path::getParentDirectory(parentDir); } + } + // If there are no directories to create, then we are done + if (pathList.getCount() == 0) + { return true; } - /* static */SlangResult Path::getPathType(const String& path, SlangPathType* pathTypeOut) + // Traverse from back of the list, because that is most outer directory. + Int i = 0; + for (i = pathList.getCount() - 1; i >= 0; i--) { -#ifdef _WIN32 - // https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx - struct _stat32 statVar; - if (::_wstat32(String(path).toWString(), &statVar) == 0) + if (!createDirectory(pathList[i])) { - if (statVar.st_mode & _S_IFDIR) - { - *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY; - return SLANG_OK; - } - else if (statVar.st_mode & _S_IFREG) - { - *pathTypeOut = SLANG_PATH_TYPE_FILE; - return SLANG_OK; - } - return SLANG_FAIL; + break; } + } - return SLANG_E_NOT_FOUND; -#else - struct stat statVar; - if (::stat(path.getBuffer(), &statVar) == 0) - { - if (S_ISDIR(statVar.st_mode)) - { - *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY; - return SLANG_OK; - } - if (S_ISREG(statVar.st_mode)) - { - *pathTypeOut = SLANG_PATH_TYPE_FILE; - return SLANG_OK; - } - return SLANG_FAIL; - } + // Something wrong when creating parent directories + if (i > 0) + { + // Remove the directories if we've created + if (i != pathList.getCount() - 1) + remove(pathList[i]); - return SLANG_E_NOT_FOUND; -#endif + return false; } + return true; +} - /* static */SlangResult Path::getCanonical(const String& path, String& canonicalPathOut) +/* static */ SlangResult Path::getPathType(const String& path, SlangPathType* pathTypeOut) +{ +#ifdef _WIN32 + // https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx + struct _stat32 statVar; + if (::_wstat32(String(path).toWString(), &statVar) == 0) { -#if defined(_WIN32) - // https://msdn.microsoft.com/en-us/library/506720ff.aspx - wchar_t* absPath = ::_wfullpath(nullptr, path.toWString(), 0); - if (!absPath) + if (statVar.st_mode & _S_IFDIR) { - return SLANG_FAIL; + *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY; + return SLANG_OK; } - - canonicalPathOut = String::fromWString(absPath); - ::free(absPath); - return SLANG_OK; -#else -# if 1 - - // http://man7.org/linux/man-pages/man3/realpath.3.html - char* canonicalPath = ::realpath(path.begin(), nullptr); - if (canonicalPath) + else if (statVar.st_mode & _S_IFREG) { - canonicalPathOut = canonicalPath; - ::free(canonicalPath); + *pathTypeOut = SLANG_PATH_TYPE_FILE; return SLANG_OK; } return SLANG_FAIL; -# else - // This is a mechanism to get an approximation of canonical path if we don't have 'realpath' - // We only can get if the file exists. This checks that the ../. etc are really valid - SlangPathType pathType; - SLANG_RETURN_ON_FAIL(getPathType(path, &pathType)); - if (isAbsolute(path)) + } + + return SLANG_E_NOT_FOUND; +#else + struct stat statVar; + if (::stat(path.getBuffer(), &statVar) == 0) + { + if (S_ISDIR(statVar.st_mode)) { - // If it's absolute, we can just simplify as is - canonicalPathOut = Path::simplify(path); + *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY; return SLANG_OK; } - else + if (S_ISREG(statVar.st_mode)) { - char buffer[PATH_MAX]; - // https://linux.die.net/man/3/getcwd - const char* getCwdPath = getcwd(buffer, SLANG_COUNT_OF(buffer)); - if (!getCwdPath) - { - return SLANG_FAIL; - } - - // Okay combine the paths - String combinedPaths = Path::combine(String(getCwdPath), path); - // Simplify - canonicalPathOut = Path::simplify(combinedPaths); + *pathTypeOut = SLANG_PATH_TYPE_FILE; return SLANG_OK; } -# endif -#endif + return SLANG_FAIL; } - String Path::getCurrentPath() + return SLANG_E_NOT_FOUND; +#endif +} + + +/* static */ SlangResult Path::getCanonical(const String& path, String& canonicalPathOut) +{ +#if defined(_WIN32) + // https://msdn.microsoft.com/en-us/library/506720ff.aspx + wchar_t* absPath = ::_wfullpath(nullptr, path.toWString(), 0); + if (!absPath) { - Slang::String path; - getCanonical(".", path); - return path; + return SLANG_FAIL; } - String Path::getRelativePath(String base, String path) + canonicalPathOut = String::fromWString(absPath); + ::free(absPath); + return SLANG_OK; +#else +#if 1 + + // http://man7.org/linux/man-pages/man3/realpath.3.html + char* canonicalPath = ::realpath(path.begin(), nullptr); + if (canonicalPath) { - std::filesystem::path p1(base.getBuffer()); - std::filesystem::path p2(path.getBuffer()); - std::error_code ec; - auto result = std::filesystem::relative(p2, p1, ec); - if (ec) - return path; - return String(UnownedStringSlice(result.generic_u8string().c_str())); + canonicalPathOut = canonicalPath; + ::free(canonicalPath); + return SLANG_OK; } - - SlangResult Path::remove(const String& path) + return SLANG_FAIL; +#else + // This is a mechanism to get an approximation of canonical path if we don't have 'realpath' + // We only can get if the file exists. This checks that the ../. etc are really valid + SlangPathType pathType; + SLANG_RETURN_ON_FAIL(getPathType(path, &pathType)); + if (isAbsolute(path)) + { + // If it's absolute, we can just simplify as is + canonicalPathOut = Path::simplify(path); + return SLANG_OK; + } + else { + char buffer[PATH_MAX]; + // https://linux.die.net/man/3/getcwd + const char* getCwdPath = getcwd(buffer, SLANG_COUNT_OF(buffer)); + if (!getCwdPath) + { + return SLANG_FAIL; + } + + // Okay combine the paths + String combinedPaths = Path::combine(String(getCwdPath), path); + // Simplify + canonicalPathOut = Path::simplify(combinedPaths); + return SLANG_OK; + } +#endif +#endif +} + +String Path::getCurrentPath() +{ + Slang::String path; + getCanonical(".", path); + return path; +} + +String Path::getRelativePath(String base, String path) +{ + std::filesystem::path p1(base.getBuffer()); + std::filesystem::path p2(path.getBuffer()); + std::error_code ec; + auto result = std::filesystem::relative(p2, p1, ec); + if (ec) + return path; + return String(UnownedStringSlice(result.generic_u8string().c_str())); +} + +SlangResult Path::remove(const String& path) +{ #ifdef _WIN32 - // Need to determine if its a file or directory + // Need to determine if its a file or directory - SlangPathType pathType; - SLANG_RETURN_ON_FAIL(getPathType(path, &pathType)); + SlangPathType pathType; + SLANG_RETURN_ON_FAIL(getPathType(path, &pathType)); - switch (pathType) + switch (pathType) + { + case SLANG_PATH_TYPE_FILE: { - case SLANG_PATH_TYPE_FILE: + // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea + if (DeleteFileA(path.getBuffer())) { - // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea - if (DeleteFileA(path.getBuffer())) - { - return SLANG_OK; - } - break; + return SLANG_OK; } - case SLANG_PATH_TYPE_DIRECTORY: + break; + } + case SLANG_PATH_TYPE_DIRECTORY: + { + // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya + if (RemoveDirectoryA(path.getBuffer())) { - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya - if (RemoveDirectoryA(path.getBuffer())) - { - return SLANG_OK; - } - break; + return SLANG_OK; } - default: break; + break; } + default: break; + } - return SLANG_FAIL; + return SLANG_FAIL; #else - // https://linux.die.net/man/3/remove - if (::remove(path.getBuffer()) == 0) - { - return SLANG_OK; - } - return SLANG_FAIL; -#endif + // https://linux.die.net/man/3/remove + if (::remove(path.getBuffer()) == 0) + { + return SLANG_OK; } + return SLANG_FAIL; +#endif +} - /* static */SlangResult Path::removeNonEmpty(const String& path) +/* static */ SlangResult Path::removeNonEmpty(const String& path) +{ + if (File::exists(path) == false) { - if (File::exists(path) == false) - { - return SLANG_OK; - } + return SLANG_OK; + } - StringBuilder msgBuilder; - // Path::remove() doesn't support remove a non-empty directory, so we need to implement - // a simple function to remove the directory recursively. + StringBuilder msgBuilder; + // Path::remove() doesn't support remove a non-empty directory, so we need to implement + // a simple function to remove the directory recursively. #ifdef _WIN32 - // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa - // Note: the fromPath requires a double-null-terminated string. - String newPath = path; - newPath.append('\0'); - SHFILEOPSTRUCTA file_op = { - NULL, - FO_DELETE, - newPath.begin(), - nullptr, - FOF_NOCONFIRMATION | - FOF_NOERRORUI | - FOF_SILENT, - false, - 0, - nullptr }; - int ret = SHFileOperationA(&file_op); - if (ret) - { - return SLANG_FAIL; - } + // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa + // Note: the fromPath requires a double-null-terminated string. + String newPath = path; + newPath.append('\0'); + SHFILEOPSTRUCTA file_op = { + NULL, + FO_DELETE, + newPath.begin(), + nullptr, + FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT, + false, + 0, + nullptr}; + int ret = SHFileOperationA(&file_op); + if (ret) + { + return SLANG_FAIL; + } #else - auto unlink_cb = [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int - { - SLANG_UNUSED(sb) - SLANG_UNUSED(typeflag) - SLANG_UNUSED(ftwbuf) - int rv = ::remove(fpath); - if (rv) - { - perror(fpath); - } - return rv; - }; - // https://linux.die.net/man/3/nftw - int ret = ::nftw(path.begin(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS); - if (ret) - { - return SLANG_FAIL; - } + auto unlink_cb = + [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int + { + SLANG_UNUSED(sb) + SLANG_UNUSED(typeflag) + SLANG_UNUSED(ftwbuf) + int rv = ::remove(fpath); + if (rv) + { + perror(fpath); + } + return rv; + }; + // https://linux.die.net/man/3/nftw + int ret = ::nftw(path.begin(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS); + if (ret) + { + return SLANG_FAIL; + } #endif - return SLANG_OK; - } + return SLANG_OK; +} #if defined(_WIN32) - /* static */SlangResult Path::find(const String& directoryPath, const char* pattern, Visitor* visitor) - { - pattern = pattern ? pattern : "*"; - String searchPath = Path::combine(directoryPath, pattern); +/* static */ SlangResult Path::find( + const String& directoryPath, + const char* pattern, + Visitor* visitor) +{ + pattern = pattern ? pattern : "*"; + String searchPath = Path::combine(directoryPath, pattern); - WIN32_FIND_DATAW fileData; + WIN32_FIND_DATAW fileData; - HANDLE findHandle = FindFirstFileW(searchPath.toWString(), &fileData); - if (findHandle == INVALID_HANDLE_VALUE) - { - return SLANG_E_NOT_FOUND; - } + HANDLE findHandle = FindFirstFileW(searchPath.toWString(), &fileData); + if (findHandle == INVALID_HANDLE_VALUE) + { + return SLANG_E_NOT_FOUND; + } - do + do + { + if (!((wcscmp(fileData.cFileName, L".") == 0) || (wcscmp(fileData.cFileName, L"..") == 0))) { - if (!((wcscmp(fileData.cFileName, L".") == 0) || - (wcscmp(fileData.cFileName, L"..") == 0))) - { - const Type type = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? Type::Directory : Type::File; + const Type type = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? Type::Directory + : Type::File; - String filename = String::fromWString(fileData.cFileName); - visitor->accept(type, filename.getUnownedSlice()); - } + String filename = String::fromWString(fileData.cFileName); + visitor->accept(type, filename.getUnownedSlice()); } - while (FindNextFileW(findHandle, &fileData) != 0); + } while (FindNextFileW(findHandle, &fileData) != 0); - ::FindClose(findHandle); - return SLANG_OK; - } + ::FindClose(findHandle); + return SLANG_OK; +} #else - /* static */SlangResult Path::find(const String& directoryPath, const char* pattern, Visitor* visitor) +/* static */ SlangResult Path::find( + const String& directoryPath, + const char* pattern, + Visitor* visitor) +{ + DIR* directory = opendir(directoryPath.getBuffer()); + + if (!directory) { - DIR* directory = opendir(directoryPath.getBuffer()); + return SLANG_E_NOT_FOUND; + } - if (!directory) + StringBuilder builder; + for (;;) + { + dirent* entry = readdir(directory); + if (entry == nullptr) { - return SLANG_E_NOT_FOUND; + break; } - StringBuilder builder; - for (;;) + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - dirent* entry = readdir(directory); - if (entry == nullptr) - { - break; - } - - if (strcmp(entry->d_name, ".") == 0 || - strcmp(entry->d_name, "..") == 0) - { - continue; - } + continue; + } - // If there is a pattern, check if it matches, and if it doesn't ignore it - if (pattern && fnmatch(pattern, entry->d_name, 0) != 0) - { - continue; - } + // If there is a pattern, check if it matches, and if it doesn't ignore it + if (pattern && fnmatch(pattern, entry->d_name, 0) != 0) + { + continue; + } - const UnownedStringSlice filename(entry->d_name); + const UnownedStringSlice filename(entry->d_name); - // Produce the full path, to do stat - Path::combineIntoBuilder(directoryPath.getUnownedSlice(), filename, builder); + // Produce the full path, to do stat + Path::combineIntoBuilder(directoryPath.getUnownedSlice(), filename, builder); - // fprintf(stderr, "stat(%s)\n", path.getBuffer()); - struct stat fileInfo; - if (stat(builder.getBuffer(), &fileInfo) != 0) - { - continue; - } - - Type type = Type::Unknown; - if (S_ISDIR(fileInfo.st_mode)) - { - type = Type::Directory; - } - else if (S_ISREG(fileInfo.st_mode)) - { - type = Type::File; - } + // fprintf(stderr, "stat(%s)\n", path.getBuffer()); + struct stat fileInfo; + if (stat(builder.getBuffer(), &fileInfo) != 0) + { + continue; + } - visitor->accept(type, filename); + Type type = Type::Unknown; + if (S_ISDIR(fileInfo.st_mode)) + { + type = Type::Directory; + } + else if (S_ISREG(fileInfo.st_mode)) + { + type = Type::File; } - closedir(directory); - return SLANG_OK; + visitor->accept(type, filename); } + + closedir(directory); + return SLANG_OK; +} #endif - bool Path::equals(String path1, String path2) - { - Path::getCanonical(path1, path1); - Path::getCanonical(path2, path2); +bool Path::equals(String path1, String path2) +{ + Path::getCanonical(path1, path1); + Path::getCanonical(path2, path2); #if SLANG_WINDOWS_FAMILY - return path1.getUnownedSlice().caseInsensitiveEquals(path2.getUnownedSlice()); + return path1.getUnownedSlice().caseInsensitiveEquals(path2.getUnownedSlice()); #else - return path1 == path2; + return path1 == path2; #endif - } +} - /// Gets the path to the executable that was invoked that led to the current threads execution - /// If run from a shared library/dll will be the path of the executable that loaded said library - /// @param outPath Pointer to buffer to hold the path. - /// @param ioPathSize Size of the buffer to hold the path (including zero terminator). - /// @return SLANG_OK on success, SLANG_E_BUFFER_TOO_SMALL if buffer is too small. If ioPathSize is changed it will be the required size - static SlangResult _calcExectuablePath(char* outPath, size_t* ioSize) - { - SLANG_ASSERT(ioSize); - const size_t bufferSize = *ioSize; - SLANG_ASSERT(bufferSize > 0); +/// Gets the path to the executable that was invoked that led to the current threads execution +/// If run from a shared library/dll will be the path of the executable that loaded said library +/// @param outPath Pointer to buffer to hold the path. +/// @param ioPathSize Size of the buffer to hold the path (including zero terminator). +/// @return SLANG_OK on success, SLANG_E_BUFFER_TOO_SMALL if buffer is too small. If ioPathSize is +/// changed it will be the required size +static SlangResult _calcExectuablePath(char* outPath, size_t* ioSize) +{ + SLANG_ASSERT(ioSize); + const size_t bufferSize = *ioSize; + SLANG_ASSERT(bufferSize > 0); #if SLANG_WINDOWS_FAMILY - // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamea + // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamea - DWORD res = ::GetModuleFileNameA(::GetModuleHandle(nullptr), outPath, DWORD(bufferSize)); - // If it fits it's the size not including terminator. So must be less than bufferSize - if (res < bufferSize) - { - return SLANG_OK; - } - return SLANG_E_BUFFER_TOO_SMALL; + DWORD res = ::GetModuleFileNameA(::GetModuleHandle(nullptr), outPath, DWORD(bufferSize)); + // If it fits it's the size not including terminator. So must be less than bufferSize + if (res < bufferSize) + { + return SLANG_OK; + } + return SLANG_E_BUFFER_TOO_SMALL; #elif SLANG_LINUX_FAMILY -# if defined(__linux__) || defined(__CYGWIN__) - // https://linux.die.net/man/2/readlink - // Mark last byte with 0, so can check overrun - ssize_t resSize = ::readlink("/proc/self/exe", outPath, bufferSize); - if (resSize < 0) - { - return SLANG_FAIL; - } - if (size_t(resSize) >= bufferSize) - { - return SLANG_E_BUFFER_TOO_SMALL; - } - // Zero terminate - outPath[resSize - 1] = 0; - return SLANG_OK; -# else - String text = Slang::File::readAllText("/proc/self/maps"); - Index startIndex = text.indexOf('/'); - if (startIndex == Index(-1)) - { - return SLANG_FAIL; - } - Index endIndex = text.indexOf("\n", startIndex); - endIndex = (endIndex == Index(-1)) ? text.getLength() : endIndex; +#if defined(__linux__) || defined(__CYGWIN__) + // https://linux.die.net/man/2/readlink + // Mark last byte with 0, so can check overrun + ssize_t resSize = ::readlink("/proc/self/exe", outPath, bufferSize); + if (resSize < 0) + { + return SLANG_FAIL; + } + if (size_t(resSize) >= bufferSize) + { + return SLANG_E_BUFFER_TOO_SMALL; + } + // Zero terminate + outPath[resSize - 1] = 0; + return SLANG_OK; +#else + String text = Slang::File::readAllText("/proc/self/maps"); + Index startIndex = text.indexOf('/'); + if (startIndex == Index(-1)) + { + return SLANG_FAIL; + } + Index endIndex = text.indexOf("\n", startIndex); + endIndex = (endIndex == Index(-1)) ? text.getLength() : endIndex; - auto path = text.subString(startIndex, endIndex - startIndex); + auto path = text.subString(startIndex, endIndex - startIndex); - if (path.getLength() < bufferSize) - { - ::memcpy(outPath, path.begin(), path.getLength()); - outPath[path.getLength()] = 0; - return SLANG_OK; - } + if (path.getLength() < bufferSize) + { + ::memcpy(outPath, path.begin(), path.getLength()); + outPath[path.getLength()] = 0; + return SLANG_OK; + } - *ioSize = path.getLength() + 1; - return SLANG_E_BUFFER_TOO_SMALL; -# endif + *ioSize = path.getLength() + 1; + return SLANG_E_BUFFER_TOO_SMALL; +#endif #elif SLANG_APPLE_FAMILY - // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html - uint32_t size = uint32_t(*ioSize); - switch (_NSGetExecutablePath(outPath, &size)) + // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html + uint32_t size = uint32_t(*ioSize); + switch (_NSGetExecutablePath(outPath, &size)) + { + case 0: return SLANG_OK; + case -1: { - case 0: return SLANG_OK; - case -1: - { - *ioSize = size; - return SLANG_E_BUFFER_TOO_SMALL; - } - default: break; + *ioSize = size; + return SLANG_E_BUFFER_TOO_SMALL; } - return SLANG_FAIL; + default: break; + } + return SLANG_FAIL; #else - SLANG_UNUSED(outPath); - return SLANG_E_NOT_IMPLEMENTED; + SLANG_UNUSED(outPath); + return SLANG_E_NOT_IMPLEMENTED; #endif - } +} - static String _getExecutablePath() +static String _getExecutablePath() +{ + List<char> buffer; + // Guess an initial buffer size + buffer.setCount(1024); + + while (true) { - List<char> buffer; - // Guess an initial buffer size - buffer.setCount(1024); + const size_t size = size_t(buffer.getCount()); + size_t bufferSize = size; + SlangResult res = _calcExectuablePath(buffer.getBuffer(), &bufferSize); - while (true) + if (SLANG_SUCCEEDED(res)) { - const size_t size = size_t(buffer.getCount()); - size_t bufferSize = size; - SlangResult res = _calcExectuablePath(buffer.getBuffer(), &bufferSize); - - if (SLANG_SUCCEEDED(res)) - { - return String(buffer.getBuffer()); - } - - if (res != SLANG_E_BUFFER_TOO_SMALL) - { - // Couldn't determine the executable string - return String(); - } - - // If bufferSize changed it should be the exact fit size, else we just make the buffer bigger by a guess (50% bigger) - bufferSize = (bufferSize > size) ? bufferSize : (bufferSize + bufferSize / 2); - buffer.setCount(Index(bufferSize)); + return String(buffer.getBuffer()); } - } - - /* static */String Path::getExecutablePath() - { - // TODO(JS): It would be better if we lazily evaluated this, and then returned the same string on subsequent calls, because it has to do - // a fair amount of work depending on target. - // This was how previous code worked, with a static variable. Unfortunately this led to a memory leak being reported - because reporting - // is done before a global variable is released. - // It would be good to have a mechanism that allows 'core' library source free memory in some controlled manner. - return _getExecutablePath(); - } - - SlangResult File::readAllText(const Slang::String& fileName, String& outText) - { - RefPtr<FileStream> stream(new FileStream); - SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); - StreamReader reader; - SLANG_RETURN_ON_FAIL(reader.init(stream)); - SLANG_RETURN_ON_FAIL(reader.readToEnd(outText)); + if (res != SLANG_E_BUFFER_TOO_SMALL) + { + // Couldn't determine the executable string + return String(); + } - return SLANG_OK; + // If bufferSize changed it should be the exact fit size, else we just make the buffer + // bigger by a guess (50% bigger) + bufferSize = (bufferSize > size) ? bufferSize : (bufferSize + bufferSize / 2); + buffer.setCount(Index(bufferSize)); } +} - SlangResult File::readAllBytes(const Slang::String& path, Slang::List<unsigned char>& out) - { - FileStream stream; - SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); +/* static */ String Path::getExecutablePath() +{ + // TODO(JS): It would be better if we lazily evaluated this, and then returned the same string + // on subsequent calls, because it has to do a fair amount of work depending on target. This was + // how previous code worked, with a static variable. Unfortunately this led to a memory leak + // being reported - because reporting is done before a global variable is released. It would be + // good to have a mechanism that allows 'core' library source free memory in some controlled + // manner. + return _getExecutablePath(); +} - const Int64 start = stream.getPosition(); - stream.seek(SeekOrigin::End, 0); - const Int64 end = stream.getPosition(); - stream.seek(SeekOrigin::Start, start); +SlangResult File::readAllText(const Slang::String& fileName, String& outText) +{ + RefPtr<FileStream> stream(new FileStream); + SLANG_RETURN_ON_FAIL( + stream->init(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); - const Int64 positionSizeInBytes = end - start; + StreamReader reader; + SLANG_RETURN_ON_FAIL(reader.init(stream)); + SLANG_RETURN_ON_FAIL(reader.readToEnd(outText)); - if (UInt64(positionSizeInBytes) > UInt64(kMaxIndex)) - { - // It's too large to fit in memory. - return SLANG_FAIL; - } + return SLANG_OK; +} - const Index sizeInBytes = Index(positionSizeInBytes); +SlangResult File::readAllBytes(const Slang::String& path, Slang::List<unsigned char>& out) +{ + FileStream stream; + SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); - out.setCount(sizeInBytes); + const Int64 start = stream.getPosition(); + stream.seek(SeekOrigin::End, 0); + const Int64 end = stream.getPosition(); + stream.seek(SeekOrigin::Start, start); - size_t readSizeInBytes; - SLANG_RETURN_ON_FAIL(stream.read(out.getBuffer(), sizeInBytes, readSizeInBytes)); + const Int64 positionSizeInBytes = end - start; - // If not all read just return an error - return (size_t(sizeInBytes) == readSizeInBytes) ? SLANG_OK : SLANG_FAIL; + if (UInt64(positionSizeInBytes) > UInt64(kMaxIndex)) + { + // It's too large to fit in memory. + return SLANG_FAIL; } - SlangResult File::readAllBytes(const String& path, ScopedAllocation& out) - { - FileStream stream; - SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); + const Index sizeInBytes = Index(positionSizeInBytes); - const Int64 start = stream.getPosition(); - stream.seek(SeekOrigin::End, 0); - const Int64 end = stream.getPosition(); - stream.seek(SeekOrigin::Start, start); + out.setCount(sizeInBytes); - const Int64 positionSizeInBytes = end - start; + size_t readSizeInBytes; + SLANG_RETURN_ON_FAIL(stream.read(out.getBuffer(), sizeInBytes, readSizeInBytes)); - if (UInt64(positionSizeInBytes) > UInt64(~size_t(0))) - { - // It's too large to fit in memory. - return SLANG_FAIL; - } + // If not all read just return an error + return (size_t(sizeInBytes) == readSizeInBytes) ? SLANG_OK : SLANG_FAIL; +} - const size_t sizeInBytes = size_t(positionSizeInBytes); +SlangResult File::readAllBytes(const String& path, ScopedAllocation& out) +{ + FileStream stream; + SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); - void* data = out.allocateTerminated(sizeInBytes); - if (!data) - { - return SLANG_E_OUT_OF_MEMORY; - } + const Int64 start = stream.getPosition(); + stream.seek(SeekOrigin::End, 0); + const Int64 end = stream.getPosition(); + stream.seek(SeekOrigin::Start, start); - size_t readSizeInBytes; - SLANG_RETURN_ON_FAIL(stream.read(data, sizeInBytes, readSizeInBytes)); + const Int64 positionSizeInBytes = end - start; - // If not all read just return an error - return (sizeInBytes == readSizeInBytes) ? SLANG_OK : SLANG_FAIL; + if (UInt64(positionSizeInBytes) > UInt64(~size_t(0))) + { + // It's too large to fit in memory. + return SLANG_FAIL; } - SlangResult File::writeAllBytes(const String& path, const void* data, size_t size) + const size_t sizeInBytes = size_t(positionSizeInBytes); + + void* data = out.allocateTerminated(sizeInBytes); + if (!data) { - FileStream stream; - SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Create, FileAccess::Write, FileShare::ReadWrite)); - SLANG_RETURN_ON_FAIL(stream.write(data, size)); - return SLANG_OK; + return SLANG_E_OUT_OF_MEMORY; } - SlangResult File::writeAllText(const Slang::String& fileName, const Slang::String& text) - { - RefPtr<FileStream> stream = new FileStream; - SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create)); + size_t readSizeInBytes; + SLANG_RETURN_ON_FAIL(stream.read(data, sizeInBytes, readSizeInBytes)); - StreamWriter writer; - SLANG_RETURN_ON_FAIL(writer.init(stream)); - SLANG_RETURN_ON_FAIL(writer.write(text)); + // If not all read just return an error + return (sizeInBytes == readSizeInBytes) ? SLANG_OK : SLANG_FAIL; +} - return SLANG_OK; - } +SlangResult File::writeAllBytes(const String& path, const void* data, size_t size) +{ + FileStream stream; + SLANG_RETURN_ON_FAIL( + stream.init(path, FileMode::Create, FileAccess::Write, FileShare::ReadWrite)); + SLANG_RETURN_ON_FAIL(stream.write(data, size)); + return SLANG_OK; +} + +SlangResult File::writeAllText(const Slang::String& fileName, const Slang::String& text) +{ + RefPtr<FileStream> stream = new FileStream; + SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create)); - SlangResult File::writeAllTextIfChanged(const String& fileName, UnownedStringSlice text) + StreamWriter writer; + SLANG_RETURN_ON_FAIL(writer.init(stream)); + SLANG_RETURN_ON_FAIL(writer.write(text)); + + return SLANG_OK; +} + +SlangResult File::writeAllTextIfChanged(const String& fileName, UnownedStringSlice text) +{ + String existingContent; + auto result = File::readAllText(fileName, existingContent); + if (SLANG_FAILED(result) || existingContent != text) { - String existingContent; - auto result = File::readAllText(fileName, existingContent); - if (SLANG_FAILED(result) || existingContent != text) - { - return File::writeNativeText(fileName, text.begin(), text.getLength()); - } - return SLANG_OK; + return File::writeNativeText(fileName, text.begin(), text.getLength()); } + return SLANG_OK; +} - /* static */SlangResult File::writeNativeText(const String& path, const void* data, size_t size) +/* static */ SlangResult File::writeNativeText(const String& path, const void* data, size_t size) +{ + FILE* file = fopen(path.getBuffer(), "w"); + if (!file) { - FILE* file = fopen(path.getBuffer(), "w"); - if (!file) - { - return SLANG_FAIL; - } + return SLANG_FAIL; + } - const auto count = fwrite(data, size, 1, file); - fclose(file); + const auto count = fwrite(data, size, 1, file); + fclose(file); - return (count == 1) ? SLANG_OK : SLANG_FAIL; - } + return (count == 1) ? SLANG_OK : SLANG_FAIL; +} - String URI::getPath() const - { - Index startIndex = uri.indexOf("://"); - if (startIndex == -1) - return String(); - startIndex += 3; - Index endIndex = uri.indexOf('?'); - if (endIndex == -1) - endIndex = uri.getLength(); - StringBuilder sb; +String URI::getPath() const +{ + Index startIndex = uri.indexOf("://"); + if (startIndex == -1) + return String(); + startIndex += 3; + Index endIndex = uri.indexOf('?'); + if (endIndex == -1) + endIndex = uri.getLength(); + StringBuilder sb; #if SLANG_WINDOWS_FAMILY - if (uri[startIndex] == '/') - startIndex++; + if (uri[startIndex] == '/') + startIndex++; #endif - for (Index i = startIndex; i < endIndex;) + for (Index i = startIndex; i < endIndex;) + { + auto ch = uri[i]; + if (ch == '%') { - auto ch = uri[i]; - if (ch == '%') - { - Int charVal = CharUtil::getHexDigitValue(uri[i + 1]) * 16 + - CharUtil::getHexDigitValue(uri[i + 2]); - sb.appendChar((char)charVal); - i += 3; - } - else - { - sb.appendChar(uri[i]); - i++; - } + Int charVal = CharUtil::getHexDigitValue(uri[i + 1]) * 16 + + CharUtil::getHexDigitValue(uri[i + 2]); + sb.appendChar((char)charVal); + i += 3; + } + else + { + sb.appendChar(uri[i]); + i++; } - return sb.produceString(); } + return sb.produceString(); +} - StringSlice URI::getProtocol() const - { - Index separatorIndex = uri.indexOf("://"); - if (separatorIndex != -1) - return uri.subString(0, separatorIndex); - return StringSlice(); - } +StringSlice URI::getProtocol() const +{ + Index separatorIndex = uri.indexOf("://"); + if (separatorIndex != -1) + return uri.subString(0, separatorIndex); + return StringSlice(); +} - bool URI::isSafeURIChar(char ch) - { - return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || - ch == '-' || ch == '_' || ch == '/' || ch == '.'; - } +bool URI::isSafeURIChar(char ch) +{ + return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || + ch == '-' || ch == '_' || ch == '/' || ch == '.'; +} - URI URI::fromLocalFilePath(UnownedStringSlice path) - { - URI uri; - StringBuilder sb; - sb << "file://"; +URI URI::fromLocalFilePath(UnownedStringSlice path) +{ + URI uri; + StringBuilder sb; + sb << "file://"; #if SLANG_WINDOWS_FAMILY - sb << "/"; + sb << "/"; #endif - for (auto ch : path) + for (auto ch : path) + { + if (isSafeURIChar(ch)) { - if (isSafeURIChar(ch)) - { - sb.appendChar(ch); - } - else if (ch == '\\') - { - sb.appendChar('/'); - } - else - { - char buffer[32]; - int length = intToAscii(buffer, (int)ch, 16); - sb << "%" << UnownedStringSlice(buffer, length); - } + sb.appendChar(ch); + } + else if (ch == '\\') + { + sb.appendChar('/'); + } + else + { + char buffer[32]; + int length = intToAscii(buffer, (int)ch, 16); + sb << "%" << UnownedStringSlice(buffer, length); } - return URI::fromString(sb.getUnownedSlice()); } + return URI::fromString(sb.getUnownedSlice()); +} - URI URI::fromString(UnownedStringSlice uriString) - { - URI uri; - uri.uri = uriString; - return uri; - } +URI URI::fromString(UnownedStringSlice uriString) +{ + URI uri; + uri.uri = uriString; + return uri; +} - SlangResult LockFile::open(const String& fileName) - { +SlangResult LockFile::open(const String& fileName) +{ #if SLANG_WINDOWS_FAMILY - m_fileHandle = ::CreateFileW( - fileName.toWString(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL - ); - m_isOpen = m_fileHandle != INVALID_HANDLE_VALUE; + m_fileHandle = ::CreateFileW( + fileName.toWString(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + m_isOpen = m_fileHandle != INVALID_HANDLE_VALUE; #else - m_fileHandle = ::open(fileName.getBuffer(), O_RDWR | O_CREAT, 0600); - m_isOpen = m_fileHandle != -1; + m_fileHandle = ::open(fileName.getBuffer(), O_RDWR | O_CREAT, 0600); + m_isOpen = m_fileHandle != -1; #endif - return m_isOpen ? SLANG_OK : SLANG_E_CANNOT_OPEN; - } + return m_isOpen ? SLANG_OK : SLANG_E_CANNOT_OPEN; +} - void LockFile::close() - { - if (!m_isOpen) - return; +void LockFile::close() +{ + if (!m_isOpen) + return; #if SLANG_WINDOWS_FAMILY - ::CloseHandle(m_fileHandle); + ::CloseHandle(m_fileHandle); #else - ::close(m_fileHandle); + ::close(m_fileHandle); #endif - m_isOpen = false; - } + m_isOpen = false; +} - SlangResult LockFile::tryLock(LockType lockType) - { - if (!m_isOpen) - return SLANG_E_CANNOT_OPEN; +SlangResult LockFile::tryLock(LockType lockType) +{ + if (!m_isOpen) + return SLANG_E_CANNOT_OPEN; - SlangResult result = SLANG_OK; + SlangResult result = SLANG_OK; #if SLANG_WINDOWS_FAMILY - OVERLAPPED overlapped = {0}; - DWORD flags = lockType == LockType::Shared ? LOCKFILE_FAIL_IMMEDIATELY : (LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY); - if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0) - { - result = SLANG_E_TIME_OUT; - } + OVERLAPPED overlapped = {0}; + DWORD flags = lockType == LockType::Shared + ? LOCKFILE_FAIL_IMMEDIATELY + : (LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY); + if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0) + { + result = SLANG_E_TIME_OUT; + } #else - int operation = lockType == LockType::Shared ? (LOCK_SH | LOCK_NB) : (LOCK_EX | LOCK_NB); - if (::flock(m_fileHandle, operation) != 0) - { - result = SLANG_E_TIME_OUT; - } -#endif - return result; + int operation = lockType == LockType::Shared ? (LOCK_SH | LOCK_NB) : (LOCK_EX | LOCK_NB); + if (::flock(m_fileHandle, operation) != 0) + { + result = SLANG_E_TIME_OUT; } +#endif + return result; +} - SlangResult LockFile::lock(LockType lockType) - { - if (!m_isOpen) - return SLANG_E_CANNOT_OPEN; +SlangResult LockFile::lock(LockType lockType) +{ + if (!m_isOpen) + return SLANG_E_CANNOT_OPEN; - SlangResult result = SLANG_OK; + SlangResult result = SLANG_OK; #if SLANG_WINDOWS_FAMILY - OVERLAPPED overlapped = {0}; - overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); - DWORD flags = lockType == LockType::Shared ? 0 : LOCKFILE_EXCLUSIVE_LOCK; - if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0) + OVERLAPPED overlapped = {0}; + overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); + DWORD flags = lockType == LockType::Shared ? 0 : LOCKFILE_EXCLUSIVE_LOCK; + if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0) + { + auto err = ::GetLastError(); + if (err == ERROR_IO_PENDING) { - auto err = ::GetLastError(); - if (err == ERROR_IO_PENDING) - { - DWORD bytes; - if (::GetOverlappedResult(m_fileHandle, &overlapped, &bytes, TRUE) == 0) - { - result = SLANG_E_INTERNAL_FAIL; - } - } - else + DWORD bytes; + if (::GetOverlappedResult(m_fileHandle, &overlapped, &bytes, TRUE) == 0) { result = SLANG_E_INTERNAL_FAIL; } } - ::CloseHandle(overlapped.hEvent); -#else - int operation = lockType == LockType::Shared ? LOCK_SH : LOCK_EX; - if (::flock(m_fileHandle, operation) != 0) + else { result = SLANG_E_INTERNAL_FAIL; } + } + ::CloseHandle(overlapped.hEvent); +#else + int operation = lockType == LockType::Shared ? LOCK_SH : LOCK_EX; + if (::flock(m_fileHandle, operation) != 0) + { + result = SLANG_E_INTERNAL_FAIL; + } #endif - return result; + return result; } - SlangResult LockFile::unlock() - { - if (!m_isOpen) - return SLANG_E_CANNOT_OPEN; +SlangResult LockFile::unlock() +{ + if (!m_isOpen) + return SLANG_E_CANNOT_OPEN; #if SLANG_WINDOWS_FAMILY - OVERLAPPED overlapped = {0}; - if (::UnlockFileEx(m_fileHandle, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0) - { - return SLANG_E_INTERNAL_FAIL; - } + OVERLAPPED overlapped = {0}; + if (::UnlockFileEx(m_fileHandle, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0) + { + return SLANG_E_INTERNAL_FAIL; + } #else - if (::flock(m_fileHandle, LOCK_UN) != 0) - { - return SLANG_E_INTERNAL_FAIL; - } + if (::flock(m_fileHandle, LOCK_UN) != 0) + { + return SLANG_E_INTERNAL_FAIL; + } #endif - return SLANG_OK; + return SLANG_OK; } - LockFile::LockFile() - : m_isOpen(false) - {} +LockFile::LockFile() + : m_isOpen(false) +{ +} - LockFile::~LockFile() - { - close(); - } +LockFile::~LockFile() +{ + close(); } +} // namespace Slang diff --git a/source/core/slang-io.h b/source/core/slang-io.h index 676635a36..73dfd31d7 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -1,326 +1,350 @@ #ifndef SLANG_CORE_IO_H #define SLANG_CORE_IO_H -#include "slang-string.h" +#include "slang-blob.h" +#include "slang-secure-crt.h" #include "slang-stream.h" +#include "slang-string.h" #include "slang-text-io.h" -#include "slang-secure-crt.h" -#include "slang-blob.h" namespace Slang { - class File - { - public: - static bool exists(const String& fileName); +class File +{ +public: + static bool exists(const String& fileName); - static SlangResult readAllText(const String& fileName, String& outString); + static SlangResult readAllText(const String& fileName, String& outString); - static SlangResult readAllBytes(const String& fileName, List<unsigned char>& out); - static SlangResult readAllBytes(const String& fileName, ScopedAllocation& out); + static SlangResult readAllBytes(const String& fileName, List<unsigned char>& out); + static SlangResult readAllBytes(const String& fileName, ScopedAllocation& out); - static SlangResult writeAllText(const String& fileName, const String& text); + static SlangResult writeAllText(const String& fileName, const String& text); - static SlangResult writeAllTextIfChanged(const String& fileName, UnownedStringSlice text); + static SlangResult writeAllTextIfChanged(const String& fileName, UnownedStringSlice text); - /// Write as text in native form for the target (so typically may change line endings ) - static SlangResult writeNativeText(const String& filename, const void* data, size_t size); + /// Write as text in native form for the target (so typically may change line endings ) + static SlangResult writeNativeText(const String& filename, const void* data, size_t size); - static SlangResult writeAllBytes(const String& fileName, const void* data, size_t size); + static SlangResult writeAllBytes(const String& fileName, const void* data, size_t size); - static SlangResult remove(const String& fileName); + static SlangResult remove(const String& fileName); - static SlangResult makeExecutable(const String& fileName); + static SlangResult makeExecutable(const String& fileName); - /// Creates a temporary file typically in some way based on the prefix - /// The file will be *created* with the outFileName, on success. - /// It's creation in necessary to lock that particular name. - static SlangResult generateTemporary(const UnownedStringSlice& prefix, String& outFileName); - }; + /// Creates a temporary file typically in some way based on the prefix + /// The file will be *created* with the outFileName, on success. + /// It's creation in necessary to lock that particular name. + static SlangResult generateTemporary(const UnownedStringSlice& prefix, String& outFileName); +}; - class Path - { - public: - typedef uint32_t SimplifyIntegral; +class Path +{ +public: + typedef uint32_t SimplifyIntegral; - struct SimplifyFlag + struct SimplifyFlag + { + enum Enum : SimplifyIntegral { - enum Enum : SimplifyIntegral - { - /// Can only simplify to an absolute path. Will return an error if not possible. - /// Useful to constrain a path, such as when wanting something like 'chroot'. - AbsoluteOnly = 0x1, - /// If the simplified path is a root path, remove the root. - /// Will mean that for example - /// "/" -> "." - /// "/a/.." -> "." - /// "/a" -> "a" - /// Its worth noting that a path prefixed "/" will never be returned and if *just* the root it specified - /// it will return as ".". - NoRoot = 0x2, - }; + /// Can only simplify to an absolute path. Will return an error if not possible. + /// Useful to constrain a path, such as when wanting something like 'chroot'. + AbsoluteOnly = 0x1, + /// If the simplified path is a root path, remove the root. + /// Will mean that for example + /// "/" -> "." + /// "/a/.." -> "." + /// "/a" -> "a" + /// Its worth noting that a path prefixed "/" will never be returned and if *just* the + /// root it specified it will return as ".". + NoRoot = 0x2, }; + }; - // A more convenient typesafe way to specify the SimplifyFlag combinations - enum SimplifyStyle : SimplifyIntegral - { - Normal = 0, - AbsoluteOnly = SimplifyFlag::AbsoluteOnly, - NoRoot = SimplifyFlag::NoRoot, - AbsoluteOnlyAndNoRoot = SimplifyFlag::AbsoluteOnly | SimplifyFlag::NoRoot, - }; + // A more convenient typesafe way to specify the SimplifyFlag combinations + enum SimplifyStyle : SimplifyIntegral + { + Normal = 0, + AbsoluteOnly = SimplifyFlag::AbsoluteOnly, + NoRoot = SimplifyFlag::NoRoot, + AbsoluteOnlyAndNoRoot = SimplifyFlag::AbsoluteOnly | SimplifyFlag::NoRoot, + }; - enum class Type - { - Unknown, - File, - Directory, - }; + enum class Type + { + Unknown, + File, + Directory, + }; - typedef uint32_t TypeFlags; - struct TypeFlag + typedef uint32_t TypeFlags; + struct TypeFlag + { + enum Enum : TypeFlags { - enum Enum : TypeFlags - { - Unknown = TypeFlags(1) << int(Type::Unknown), - File = TypeFlags(1) << int(Type::File), - Directory = TypeFlags(1) << int(Type::Directory), - }; + Unknown = TypeFlags(1) << int(Type::Unknown), + File = TypeFlags(1) << int(Type::File), + Directory = TypeFlags(1) << int(Type::Directory), }; + }; - class Visitor - { - public: - virtual void accept(Type type, const UnownedStringSlice& filename) = 0; - }; + class Visitor + { + public: + virtual void accept(Type type, const UnownedStringSlice& filename) = 0; + }; - static const char kPathDelimiter = '/'; + static const char kPathDelimiter = '/'; #if SLANG_WINDOWS_FAMILY - static const char kOSCanonicalPathDelimiter = '\\'; - static const char kOSAlternativePathDelimiter = '/'; + static const char kOSCanonicalPathDelimiter = '\\'; + static const char kOSAlternativePathDelimiter = '/'; #else - static const char kOSCanonicalPathDelimiter = '/'; - static const char kOSAlternativePathDelimiter = '/'; + static const char kOSCanonicalPathDelimiter = '/'; + static const char kOSAlternativePathDelimiter = '/'; #endif - /// Finds all all the items in the specified directory, that matches the pattern. - /// - /// @param directoryPath The directory to do the search in. If the directory is not found, SLANG_E_NOT_FOUND is returned - /// @param pattern. The pattern to match against. The pattern matching is targtet specific (ie window matching is different to linux/unix). Passing nullptr means no matching. - /// @return is SLANG_E_NOT_FOUND if the directoryPath is not found - static SlangResult find(const String& directoryPath, const char* pattern, Visitor* visitor); - - /// Returns -1 if no separator is found - static Index findLastSeparatorIndex(String const& path) { return findLastSeparatorIndex(path.getUnownedSlice()); } - static Index findLastSeparatorIndex(UnownedStringSlice const& path); - /// Finds the index of the last dot in a path, else returns -1 - static Index findExtIndex(String const& path) { return findExtIndex(path.getUnownedSlice()); } - static Index findExtIndex(UnownedStringSlice const& path); - - /// True if isn't just a name (ie has any path separator) - /// Note this is no the same as having a 'parent' as '/thing' 'has a path', but it doesn't have a parent. - static bool hasPath(const UnownedStringSlice& path) { return findLastSeparatorIndex(path) >= 0; } - static bool hasPath(const String& path) { return findLastSeparatorIndex(path) >= 0; } - - static String replaceExt(const String& path, const char* newExt); - static String getFileName(const String& path); - static String getPathWithoutExt(const String& path); - - static String getPathExt(const String& path) { return getPathExt(path.getUnownedSlice()); } - static UnownedStringSlice getPathExt(const UnownedStringSlice& path); - - static String getParentDirectory(const String& path); - - static String getFileNameWithoutExt(const String& path); - - static String combine(const String& path1, const String& path2); - static String combine(const String& path1, const String& path2, const String& path3); - - /// Combine path sections and store the result in outBuilder - static void combineIntoBuilder(const UnownedStringSlice& path1, const UnownedStringSlice& path2, StringBuilder& outBuilder); - - /// Append a path, taking into account path separators onto the end of ioBuilder - static void append(StringBuilder& ioBuilder, const UnownedStringSlice& path); - - static bool createDirectory(const String& path); - static bool createDirectoryRecursive(const String& path); - - /// Accept either style of delimiter - SLANG_FORCE_INLINE static bool isDelimiter(char c) { return c == '/' || c == '\\'; } - - /// True if the element appears to be a drive specification (where element is the prefix to a path that isn't a directory) - /// @param pathPrefix The path prefix to test if it's a drive specification - static bool isDriveSpecification(const UnownedStringSlice& pathPrefix); - - /// Splits the path into it's individual bits - /// Absolute paths of the form "/" will become [""] - /// Absolute paths of the form "a:/" will become ["a:", ""] - /// A drive specification of the form "a:" will become ["a:"] - /// Relative paths that are in effect "." will become [] - static void split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut); - - /// Strips .. and . as much as it can - static String simplify(const UnownedStringSlice& path); - static String simplify(const String& path) { return simplify(path.getUnownedSlice()); } - - /// Given a path simplifies it such the the resultant path is absolute (ie contains no . or ..) - /// Same behavior as simplify around the root - static SlangResult simplify(const UnownedStringSlice& path, SimplifyStyle style, StringBuilder& outPath); - static SlangResult simplify(const String& path, SimplifyStyle style, StringBuilder& outPath) { return simplify(path.getUnownedSlice(), style, outPath); } - static SlangResult simplify(const char* path, SimplifyStyle style, StringBuilder& outPath) { return simplify(UnownedStringSlice(path), style, outPath); } - - /// Simplifies the path split up - static void simplify(List<UnownedStringSlice>& ioSplit); - - /// Join the parts of the path to produce an output path - static void join(const UnownedStringSlice* slices, Index count, StringBuilder& out); - - /// Returns true if the path is absolute - static bool isAbsolute(const UnownedStringSlice& path); - static bool isAbsolute(const String& path) { return isAbsolute(path.getUnownedSlice()); } - - /// Returns true if path contains contains an element of . or .. - static bool hasRelativeElement(const UnownedStringSlice& path); - static bool hasRelativeElement(const String& path) { return hasRelativeElement(path.getUnownedSlice()); } - - /// Determines the type of file at the path - /// @param path The path to test - /// @param outPathType Holds the object type at the path on success - /// @return SLANG_OK on success - static SlangResult getPathType(const String& path, SlangPathType* outPathType); - - /// Determines the canonical equivalent path to path. - /// The path returned should reference the identical object - and two different references to the same path should return the same canonical path - /// @param path Path to get the canonical path for - /// @param outCanonicalPath The canonical path for 'path' is call is successful - /// @return SLANG_OK on success - static SlangResult getCanonical(const String& path, String& outCanonicalPath); - - /// Returns the current working directory - /// @return The path in platform native format. Returns empty string if failed. - static String getCurrentPath(); - - /// Returns the executable path - /// @return The path in platform native format. Returns empty string if failed. - static String getExecutablePath(); - - /// Returns the first element of the path or an empty slice if there is none - /// This broadly equivalent to returning the first element of split - /// @param path Path to extract first element from - /// @return The first element of the path, or empty - static UnownedStringSlice getFirstElement(const UnownedStringSlice& path); - - /// Remove a file or directory at specified path. The directory must be empty for it to be removed - /// @param path - /// @return SLANG_OK if file or directory is removed - static SlangResult remove(const String& path); + /// Finds all all the items in the specified directory, that matches the pattern. + /// + /// @param directoryPath The directory to do the search in. If the directory is not found, + /// SLANG_E_NOT_FOUND is returned + /// @param pattern. The pattern to match against. The pattern matching is targtet specific (ie + /// window matching is different to linux/unix). Passing nullptr means no matching. + /// @return is SLANG_E_NOT_FOUND if the directoryPath is not found + static SlangResult find(const String& directoryPath, const char* pattern, Visitor* visitor); + + /// Returns -1 if no separator is found + static Index findLastSeparatorIndex(String const& path) + { + return findLastSeparatorIndex(path.getUnownedSlice()); + } + static Index findLastSeparatorIndex(UnownedStringSlice const& path); + /// Finds the index of the last dot in a path, else returns -1 + static Index findExtIndex(String const& path) { return findExtIndex(path.getUnownedSlice()); } + static Index findExtIndex(UnownedStringSlice const& path); + + /// True if isn't just a name (ie has any path separator) + /// Note this is no the same as having a 'parent' as '/thing' 'has a path', but it doesn't have + /// a parent. + static bool hasPath(const UnownedStringSlice& path) + { + return findLastSeparatorIndex(path) >= 0; + } + static bool hasPath(const String& path) { return findLastSeparatorIndex(path) >= 0; } + + static String replaceExt(const String& path, const char* newExt); + static String getFileName(const String& path); + static String getPathWithoutExt(const String& path); + + static String getPathExt(const String& path) { return getPathExt(path.getUnownedSlice()); } + static UnownedStringSlice getPathExt(const UnownedStringSlice& path); + + static String getParentDirectory(const String& path); + + static String getFileNameWithoutExt(const String& path); + + static String combine(const String& path1, const String& path2); + static String combine(const String& path1, const String& path2, const String& path3); + + /// Combine path sections and store the result in outBuilder + static void combineIntoBuilder( + const UnownedStringSlice& path1, + const UnownedStringSlice& path2, + StringBuilder& outBuilder); + + /// Append a path, taking into account path separators onto the end of ioBuilder + static void append(StringBuilder& ioBuilder, const UnownedStringSlice& path); + + static bool createDirectory(const String& path); + static bool createDirectoryRecursive(const String& path); + + /// Accept either style of delimiter + SLANG_FORCE_INLINE static bool isDelimiter(char c) { return c == '/' || c == '\\'; } + + /// True if the element appears to be a drive specification (where element is the prefix to a + /// path that isn't a directory) + /// @param pathPrefix The path prefix to test if it's a drive specification + static bool isDriveSpecification(const UnownedStringSlice& pathPrefix); + + /// Splits the path into it's individual bits + /// Absolute paths of the form "/" will become [""] + /// Absolute paths of the form "a:/" will become ["a:", ""] + /// A drive specification of the form "a:" will become ["a:"] + /// Relative paths that are in effect "." will become [] + static void split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut); + + /// Strips .. and . as much as it can + static String simplify(const UnownedStringSlice& path); + static String simplify(const String& path) { return simplify(path.getUnownedSlice()); } + + /// Given a path simplifies it such the the resultant path is absolute (ie contains no . or ..) + /// Same behavior as simplify around the root + static SlangResult simplify( + const UnownedStringSlice& path, + SimplifyStyle style, + StringBuilder& outPath); + static SlangResult simplify(const String& path, SimplifyStyle style, StringBuilder& outPath) + { + return simplify(path.getUnownedSlice(), style, outPath); + } + static SlangResult simplify(const char* path, SimplifyStyle style, StringBuilder& outPath) + { + return simplify(UnownedStringSlice(path), style, outPath); + } - /// Remove a file or directory at specified path. The directory can be non-empty. - /// @param path - /// @return SLANG_OK if file or directory is removed - static SlangResult removeNonEmpty(const String& path); + /// Simplifies the path split up + static void simplify(List<UnownedStringSlice>& ioSplit); - static bool equals(String path1, String path2); + /// Join the parts of the path to produce an output path + static void join(const UnownedStringSlice* slices, Index count, StringBuilder& out); - /// Turn `path` into a relative path from base. - static String getRelativePath(String base, String path); - }; + /// Returns true if the path is absolute + static bool isAbsolute(const UnownedStringSlice& path); + static bool isAbsolute(const String& path) { return isAbsolute(path.getUnownedSlice()); } - struct URI + /// Returns true if path contains contains an element of . or .. + static bool hasRelativeElement(const UnownedStringSlice& path); + static bool hasRelativeElement(const String& path) { - String uri; - bool operator==(const URI& other) const { return uri == other.uri; } - bool operator!=(const URI& other) const { return uri != other.uri; } + return hasRelativeElement(path.getUnownedSlice()); + } + + /// Determines the type of file at the path + /// @param path The path to test + /// @param outPathType Holds the object type at the path on success + /// @return SLANG_OK on success + static SlangResult getPathType(const String& path, SlangPathType* outPathType); + + /// Determines the canonical equivalent path to path. + /// The path returned should reference the identical object - and two different references to + /// the same path should return the same canonical path + /// @param path Path to get the canonical path for + /// @param outCanonicalPath The canonical path for 'path' is call is successful + /// @return SLANG_OK on success + static SlangResult getCanonical(const String& path, String& outCanonicalPath); + + /// Returns the current working directory + /// @return The path in platform native format. Returns empty string if failed. + static String getCurrentPath(); + + /// Returns the executable path + /// @return The path in platform native format. Returns empty string if failed. + static String getExecutablePath(); + + /// Returns the first element of the path or an empty slice if there is none + /// This broadly equivalent to returning the first element of split + /// @param path Path to extract first element from + /// @return The first element of the path, or empty + static UnownedStringSlice getFirstElement(const UnownedStringSlice& path); + + /// Remove a file or directory at specified path. The directory must be empty for it to be + /// removed + /// @param path + /// @return SLANG_OK if file or directory is removed + static SlangResult remove(const String& path); + + /// Remove a file or directory at specified path. The directory can be non-empty. + /// @param path + /// @return SLANG_OK if file or directory is removed + static SlangResult removeNonEmpty(const String& path); + + static bool equals(String path1, String path2); + + /// Turn `path` into a relative path from base. + static String getRelativePath(String base, String path); +}; + +struct URI +{ + String uri; + bool operator==(const URI& other) const { return uri == other.uri; } + bool operator!=(const URI& other) const { return uri != other.uri; } - HashCode getHashCode() const { return uri.getHashCode(); } + HashCode getHashCode() const { return uri.getHashCode(); } - bool isLocalFile() { return uri.startsWith("file://"); }; - String getPath() const; - StringSlice getProtocol() const; + bool isLocalFile() { return uri.startsWith("file://"); }; + String getPath() const; + StringSlice getProtocol() const; - static URI fromLocalFilePath(UnownedStringSlice path); - static URI fromString(UnownedStringSlice uriString); - static bool isSafeURIChar(char ch); - }; + static URI fromLocalFilePath(UnownedStringSlice path); + static URI fromString(UnownedStringSlice uriString); + static bool isSafeURIChar(char ch); +}; - /// Helper class abstracting lock files. - /// Uses LockFileEx() on windows systems and flock() on POSIX systems. - class LockFile +/// Helper class abstracting lock files. +/// Uses LockFileEx() on windows systems and flock() on POSIX systems. +class LockFile +{ +public: + enum class LockType { - public: - enum class LockType - { - Exclusive, - Shared, - }; + Exclusive, + Shared, + }; - /// Open the lock file. This will create the file if it doesn't exist yet. - /// @param fileName File name to open. - /// @return SLANG_OK on success. - SlangResult open(const String& fileName); + /// Open the lock file. This will create the file if it doesn't exist yet. + /// @param fileName File name to open. + /// @return SLANG_OK on success. + SlangResult open(const String& fileName); - /// Closes the lock file. - void close(); + /// Closes the lock file. + void close(); - /// Returns true if the lock file is open. - bool isOpen() const { return m_isOpen; } + /// Returns true if the lock file is open. + bool isOpen() const { return m_isOpen; } - /// Acquire the lock in non-blocking mode. - /// @param lockType Lock type (Exclusive or Shared). - /// @return SLANG_OK on success. SLANG_E_TIME_OUT if the lock is already held. - SlangResult tryLock(LockType lockType = LockType::Exclusive); + /// Acquire the lock in non-blocking mode. + /// @param lockType Lock type (Exclusive or Shared). + /// @return SLANG_OK on success. SLANG_E_TIME_OUT if the lock is already held. + SlangResult tryLock(LockType lockType = LockType::Exclusive); - /// Acquire the lock in blocking mode. - /// @param lockType Lock type (Exclusive or Shared). - /// @return SLANG_OK on success. - SlangResult lock(LockType lockType = LockType::Exclusive); + /// Acquire the lock in blocking mode. + /// @param lockType Lock type (Exclusive or Shared). + /// @return SLANG_OK on success. + SlangResult lock(LockType lockType = LockType::Exclusive); - /// Release the lock. - /// @return SLANG_OK on success. - SlangResult unlock(); + /// Release the lock. + /// @return SLANG_OK on success. + SlangResult unlock(); - LockFile(); - ~LockFile(); + LockFile(); + ~LockFile(); - private: - LockFile(const LockFile&) = delete; - LockFile(LockFile&&) = delete; - LockFile& operator=(const LockFile&) = delete; - LockFile& operator=(LockFile&&) = delete; +private: + LockFile(const LockFile&) = delete; + LockFile(LockFile&&) = delete; + LockFile& operator=(const LockFile&) = delete; + LockFile& operator=(LockFile&&) = delete; #if SLANG_WINDOWS_FAMILY - void* m_fileHandle; + void* m_fileHandle; #else - int m_fileHandle; + int m_fileHandle; #endif - bool m_isOpen; - }; + bool m_isOpen; +}; - class LockFileGuard +class LockFileGuard +{ +public: + LockFileGuard(LockFile& lockFile, LockFile::LockType lockType = LockFile::LockType::Exclusive) + : m_lockFile(lockFile) { - public: - LockFileGuard(LockFile& lockFile, LockFile::LockType lockType = LockFile::LockType::Exclusive) - : m_lockFile(lockFile) - { - m_lockFile.lock(lockType); - } + m_lockFile.lock(lockType); + } - ~LockFileGuard() - { - m_lockFile.unlock(); - } + ~LockFileGuard() { m_lockFile.unlock(); } - private: - LockFileGuard(const LockFileGuard&) = delete; - LockFileGuard(LockFileGuard&&) = delete; - LockFileGuard& operator=(const LockFileGuard&) = delete; - LockFileGuard& operator=(LockFileGuard&&) = delete; +private: + LockFileGuard(const LockFileGuard&) = delete; + LockFileGuard(LockFileGuard&&) = delete; + LockFileGuard& operator=(const LockFileGuard&) = delete; + LockFileGuard& operator=(LockFileGuard&&) = delete; - LockFile& m_lockFile; - }; + LockFile& m_lockFile; +}; -} +} // namespace Slang #endif diff --git a/source/core/slang-linked-list.h b/source/core/slang-linked-list.h index ff8f7ce40..a8ebdf1b2 100644 --- a/source/core/slang-linked-list.h +++ b/source/core/slang-linked-list.h @@ -1,21 +1,22 @@ #ifndef SLANG_CORE_LINKED_LIST_H #define SLANG_CORE_LINKED_LIST_H -#include "slang.h" - #include "slang-allocator.h" #include "slang-list.h" +#include "slang.h" + #include <type_traits> namespace Slang { -template <typename T> +template<typename T> class LinkedList; -template <typename T> +template<typename T> class LinkedNode { - template <typename T1> friend class LinkedList; + template<typename T1> + friend class LinkedList; private: LinkedNode<T>* prev = nullptr; @@ -25,9 +26,7 @@ private: public: T value; LinkedNode(LinkedList<T>* lnk) - : list(lnk) - { - }; + : list(lnk){}; LinkedNode<T>* getPrevious() { return prev; }; LinkedNode<T>* getNext() { return next; }; const LinkedNode<T>* getNext() const { return next; }; @@ -82,12 +81,14 @@ public: } }; -template <typename T> class LinkedList +template<typename T> +class LinkedList { - template <typename T1> friend class LinkedNode; + template<typename T1> + friend class LinkedNode; private: - LinkedNode<T>* head, *tail; + LinkedNode<T>*head, *tail; int count; public: @@ -96,7 +97,7 @@ public: { public: using Node = std::conditional_t<Const, const LinkedNode<T>, LinkedNode<T>>; - Node* current, *next; + Node *current, *next; void setCurrent(Node* cur) { current = cur; @@ -107,8 +108,7 @@ public: } GenIterator() { current = next = nullptr; } GenIterator(Node* cur) { setCurrent(cur); } - std::conditional_t<Const, const T&, T&> - operator*() const { return current->value; } + std::conditional_t<Const, const T&, T&> operator*() const { return current->value; } GenIterator& operator++() { setCurrent(next); @@ -134,22 +134,17 @@ public: public: LinkedList() - : head(0) - , tail(0) - , count(0) - {} + : head(0), tail(0), count(0) + { + } ~LinkedList() { clear(); } LinkedList(const LinkedList<T>& link) - : head(0) - , tail(0) - , count(0) + : head(0), tail(0), count(0) { this->operator=(link); } LinkedList(LinkedList<T>&& link) - : head(0) - , tail(0) - , count(0) + : head(0), tail(0), count(0) { this->operator=(_Move(link)); } @@ -179,7 +174,8 @@ public: } return *this; } - template <typename IteratorFunc> void forEach(const IteratorFunc& f) + template<typename IteratorFunc> + void forEach(const IteratorFunc& f) { auto p = head; while (p) diff --git a/source/core/slang-list.h b/source/core/slang-list.h index b1c67e438..d27afd415 100644 --- a/source/core/slang-list.h +++ b/source/core/slang-list.h @@ -1,11 +1,10 @@ #ifndef SLANG_CORE_LIST_H #define SLANG_CORE_LIST_H -#include "slang.h" - #include "slang-allocator.h" -#include "slang-math.h" #include "slang-array-view.h" +#include "slang-math.h" +#include "slang.h" #include <algorithm> #include <new> @@ -14,626 +13,629 @@ namespace Slang { - // List is container of values of a type held consecutively in memory (much like std::vector) - // - // Note that in this implementation, the underlying memory is backed via an allocation of T[capacity] - // This means that all values have to be in a valid state *even if they are not used* (ie indices >= m_count must be valid) - // - // Also note this implementation does not necessarily 'initialize' an element which is no longer used, - // and this may lead to surprising behavior. Say the list contains a single smart pointer, and the last element is removed (say with removeLast). - // The smart pointer will *not* be released. The smart pointer will be released if the that index is used (via say an add) or - // the List goes out of scope. - template<typename T, typename TAllocator = StandardAllocator> - class List - { - private: - static const Index kInitialCount = 16; - - public: - typedef List ThisType; - - List() - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - } - template<typename... Args> - List(const T& val, Args... args) - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - _init(val, args...); - } - List(const List<T>& list) - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - this->operator=(list); - } - List(List<T>&& list) - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - this->operator=(static_cast<List<T>&&>(list)); - } - List(ArrayView<T> view) - : List() - { - addRange(view); - } - static List<T> makeRepeated(const T& val, Index count) - { - List<T> rs; - rs.setCount(count); - for (Index i = 0; i < count; i++) - rs[i] = val; - return rs; - } - ~List() - { - _deallocateBuffer(); - } - List<T>& operator=(const List<T>& list) - { - clearAndDeallocate(); - addRange(list); - return *this; - } +// List is container of values of a type held consecutively in memory (much like std::vector) +// +// Note that in this implementation, the underlying memory is backed via an allocation of +// T[capacity] This means that all values have to be in a valid state *even if they are not used* +// (ie indices >= m_count must be valid) +// +// Also note this implementation does not necessarily 'initialize' an element which is no longer +// used, and this may lead to surprising behavior. Say the list contains a single smart pointer, and +// the last element is removed (say with removeLast). The smart pointer will *not* be released. The +// smart pointer will be released if the that index is used (via say an add) or the List goes out of +// scope. +template<typename T, typename TAllocator = StandardAllocator> +class List +{ +private: + static const Index kInitialCount = 16; - List<T>& operator=(List<T>&& list) - { - // Could just do a swap here, and memory would be freed on rhs dtor +public: + typedef List ThisType; - _deallocateBuffer(); - m_count = list.m_count; - m_capacity = list.m_capacity; - m_buffer = list.m_buffer; - - list.m_buffer = nullptr; - list.m_count = 0; - list.m_capacity = 0; - return *this; - } + List() + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + } + template<typename... Args> + List(const T& val, Args... args) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + _init(val, args...); + } + List(const List<T>& list) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + this->operator=(list); + } + List(List<T>&& list) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + this->operator=(static_cast<List<T>&&>(list)); + } + List(ArrayView<T> view) + : List() + { + addRange(view); + } + static List<T> makeRepeated(const T& val, Index count) + { + List<T> rs; + rs.setCount(count); + for (Index i = 0; i < count; i++) + rs[i] = val; + return rs; + } + ~List() { _deallocateBuffer(); } + List<T>& operator=(const List<T>& list) + { + clearAndDeallocate(); + addRange(list); + return *this; + } - const T* begin() const { return m_buffer; } - const T* end() const { return m_buffer + m_count; } + List<T>& operator=(List<T>&& list) + { + // Could just do a swap here, and memory would be freed on rhs dtor - T* begin() { return m_buffer; } - T* end() { return m_buffer + m_count; } + _deallocateBuffer(); + m_count = list.m_count; + m_capacity = list.m_capacity; + m_buffer = list.m_buffer; - const T& getFirst() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - - T& getFirst() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } + list.m_buffer = nullptr; + list.m_count = 0; + list.m_capacity = 0; + return *this; + } - const T& getLast() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } + const T* begin() const { return m_buffer; } + const T* end() const { return m_buffer + m_count; } - T& getLast() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } + T* begin() { return m_buffer; } + T* end() { return m_buffer + m_count; } - void removeLast() - { - SLANG_ASSERT(m_count > 0); - m_count--; - } + const T& getFirst() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } - inline void swapWith(List<T, TAllocator>& other) - { - T* buffer = m_buffer; - m_buffer = other.m_buffer; - other.m_buffer = buffer; + T& getFirst() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } - auto bufferSize = m_capacity; - m_capacity = other.m_capacity; - other.m_capacity = bufferSize; + const T& getLast() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } - auto count = m_count; - m_count = other.m_count; - other.m_count = count; - } + T& getLast() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } - T* detachBuffer() - { - T* rs = m_buffer; - m_buffer = nullptr; - m_count = 0; - m_capacity = 0; - return rs; - } - void attachBuffer(T* buffer, Index count, Index capacity) - { - // Can only attach a buffer if there isn't a buffer already associated - SLANG_ASSERT(m_buffer == nullptr); - SLANG_ASSERT(count <= capacity); - m_buffer = buffer; - m_count = count; - m_capacity = capacity; - } + void removeLast() + { + SLANG_ASSERT(m_count > 0); + m_count--; + } - inline ArrayView<T> getArrayView() const - { - return ArrayView<T>(m_buffer, m_count); - } + inline void swapWith(List<T, TAllocator>& other) + { + T* buffer = m_buffer; + m_buffer = other.m_buffer; + other.m_buffer = buffer; - inline ArrayView<T> getArrayView(Index start, Index count) const - { - SLANG_ASSERT(start >= 0 && count >= 0 && start + count <= m_count); - return ArrayView<T>(m_buffer + start, count); - } + auto bufferSize = m_capacity; + m_capacity = other.m_capacity; + other.m_capacity = bufferSize; - void _maybeReserveForAdd() - { - if (m_capacity <= m_count) - { - Index newBufferSize = kInitialCount; - if (m_capacity) - newBufferSize = (m_capacity << 1); + auto count = m_count; + m_count = other.m_count; + other.m_count = count; + } - reserve(newBufferSize); - } - } + T* detachBuffer() + { + T* rs = m_buffer; + m_buffer = nullptr; + m_count = 0; + m_capacity = 0; + return rs; + } + void attachBuffer(T* buffer, Index count, Index capacity) + { + // Can only attach a buffer if there isn't a buffer already associated + SLANG_ASSERT(m_buffer == nullptr); + SLANG_ASSERT(count <= capacity); + m_buffer = buffer; + m_count = count; + m_capacity = capacity; + } - void add(T&& obj) - { - _maybeReserveForAdd(); - m_buffer[m_count++] = static_cast<T&&>(obj); - } + inline ArrayView<T> getArrayView() const { return ArrayView<T>(m_buffer, m_count); } - void add(const T& obj) + inline ArrayView<T> getArrayView(Index start, Index count) const + { + SLANG_ASSERT(start >= 0 && count >= 0 && start + count <= m_count); + return ArrayView<T>(m_buffer + start, count); + } + + void _maybeReserveForAdd() + { + if (m_capacity <= m_count) { - _maybeReserveForAdd(); - m_buffer[m_count++] = obj; + Index newBufferSize = kInitialCount; + if (m_capacity) + newBufferSize = (m_capacity << 1); + + reserve(newBufferSize); } + } - Index getCount() const { return m_count; } - Index getCapacity() const { return m_capacity; } + void add(T&& obj) + { + _maybeReserveForAdd(); + m_buffer[m_count++] = static_cast<T&&>(obj); + } + + void add(const T& obj) + { + _maybeReserveForAdd(); + m_buffer[m_count++] = obj; + } - const T* getBuffer() const { return m_buffer; } - T* getBuffer() { return m_buffer; } + Index getCount() const { return m_count; } + Index getCapacity() const { return m_capacity; } - bool operator==(const ThisType& rhs) const + const T* getBuffer() const { return m_buffer; } + T* getBuffer() { return m_buffer; } + + bool operator==(const ThisType& rhs) const + { + if (&rhs == this) { - if (&rhs == this) - { - return true; - } - const Index count = getCount(); - if (count != rhs.getCount()) + return true; + } + const Index count = getCount(); + if (count != rhs.getCount()) + { + return false; + } + for (Index i = 0; i < count; ++i) + { + if ((*this)[i] != rhs[i]) { return false; } - for (Index i = 0; i < count; ++i) - { - if ((*this)[i] != rhs[i]) - { - return false; - } - } - return true; } - SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + return true; + } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - void insert(Index idx, const T& val) { insertRange(idx, &val, 1); } + void insert(Index idx, const T& val) { insertRange(idx, &val, 1); } - void insertRange(Index idx, const T* vals, Index n) + void insertRange(Index idx, const T* vals, Index n) + { + if (m_capacity < m_count + n) { - if (m_capacity < m_count + n) - { - Index newBufferCount = kInitialCount; - while (newBufferCount < m_count + n) - newBufferCount = newBufferCount << 1; + Index newBufferCount = kInitialCount; + while (newBufferCount < m_count + n) + newBufferCount = newBufferCount << 1; - T* newBuffer = _allocate(newBufferCount); - if (m_capacity) + T* newBuffer = _allocate(newBufferCount); + if (m_capacity) + { + /*if (std::has_trivial_copy_assign<T>::value && + std::has_trivial_destructor<T>::value) { - /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) - { - memcpy(newBuffer, buffer, sizeof(T) * id); - memcpy(newBuffer + id + n, buffer + id, sizeof(T) * (_count - id)); - } - else*/ - { - for (Index i = 0; i < idx; i++) - newBuffer[i] = m_buffer[i]; - for (Index i = idx; i < m_count; i++) - newBuffer[i + n] = T(static_cast<T&&>(m_buffer[i])); - } - _deallocateBuffer(); + memcpy(newBuffer, buffer, sizeof(T) * id); + memcpy(newBuffer + id + n, buffer + id, sizeof(T) * (_count - id)); } - m_buffer = newBuffer; - m_capacity = newBufferCount; - } - else - { - /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) - memmove(buffer + id + n, buffer + id, sizeof(T) * (_count - id)); else*/ { - for (Index i = m_count; i > idx; i--) - m_buffer[i + n - 1] = static_cast<T&&>(m_buffer[i - 1]); + for (Index i = 0; i < idx; i++) + newBuffer[i] = m_buffer[i]; + for (Index i = idx; i < m_count; i++) + newBuffer[i + n] = T(static_cast<T&&>(m_buffer[i])); } + _deallocateBuffer(); } + m_buffer = newBuffer; + m_capacity = newBufferCount; + } + else + { /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) - memcpy(buffer + id, vals, sizeof(T) * n); + memmove(buffer + id + n, buffer + id, sizeof(T) * (_count - id)); else*/ - for (Index i = 0; i < n; i++) - m_buffer[idx + i] = vals[i]; - - m_count += n; + { + for (Index i = m_count; i > idx; i--) + m_buffer[i + n - 1] = static_cast<T&&>(m_buffer[i - 1]); + } } + /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) + memcpy(buffer + id, vals, sizeof(T) * n); + else*/ + for (Index i = 0; i < n; i++) + m_buffer[idx + i] = vals[i]; - void insertRange(Index id, const List<T>& list) { insertRange(id, list.m_buffer, list.m_count); } + m_count += n; + } - void addRange(ArrayView<T> list) { insertRange(m_count, list.getBuffer(), list.getCount()); } + void insertRange(Index id, const List<T>& list) + { + insertRange(id, list.m_buffer, list.m_count); + } - void addRange(const T* vals, Index n) { insertRange(m_count, vals, n); } + void addRange(ArrayView<T> list) { insertRange(m_count, list.getBuffer(), list.getCount()); } - void addRange(const List<T>& list) { insertRange(m_count, list.m_buffer, list.m_count); } + void addRange(const T* vals, Index n) { insertRange(m_count, vals, n); } - void removeRange(Index idx, Index count) - { - SLANG_ASSERT(idx >= 0 && idx <= m_count); + void addRange(const List<T>& list) { insertRange(m_count, list.m_buffer, list.m_count); } - const Index actualDeleteCount = ((idx + count) >= m_count)? (m_count - idx) : count; - for (Index i = idx + actualDeleteCount; i < m_count; i++) - m_buffer[i - actualDeleteCount] = static_cast<T&&>(m_buffer[i]); - m_count -= actualDeleteCount; - } + void removeRange(Index idx, Index count) + { + SLANG_ASSERT(idx >= 0 && idx <= m_count); + + const Index actualDeleteCount = ((idx + count) >= m_count) ? (m_count - idx) : count; + for (Index i = idx + actualDeleteCount; i < m_count; i++) + m_buffer[i - actualDeleteCount] = static_cast<T&&>(m_buffer[i]); + m_count -= actualDeleteCount; + } - void removeAt(Index id) { removeRange(id, 1); } + void removeAt(Index id) { removeRange(id, 1); } - void remove(const T& val) - { - Index idx = indexOf(val); - if (idx != -1) - removeAt(idx); - } + void remove(const T& val) + { + Index idx = indexOf(val); + if (idx != -1) + removeAt(idx); + } - void reverse() + void reverse() + { + for (Index i = 0; i < (m_count >> 1); i++) { - for (Index i = 0; i < (m_count >> 1); i++) - { - swapElements(m_buffer, i, m_count - i - 1); - } + swapElements(m_buffer, i, m_count - i - 1); } + } - void fastRemove(const T& val) + void fastRemove(const T& val) + { + Index idx = indexOf(val); + if (idx >= 0) { - Index idx = indexOf(val); - if (idx >= 0) - { - fastRemoveAt(idx); - } + fastRemoveAt(idx); } + } - void fastRemoveAt(Index idx) + void fastRemoveAt(Index idx) + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + // We do not test for idx == m_count - 1 (ie the move is to current index). With the + // assumption that any reasonable move implementation tests and ignores this case + if (idx != m_count - 1) { - SLANG_ASSERT(idx >= 0 && idx < m_count); - // We do not test for idx == m_count - 1 (ie the move is to current index). With the assumption that any reasonable move implementation - // tests and ignores this case - if (idx != m_count - 1) - { - m_buffer[idx] = _Move(m_buffer[m_count - 1]); - } - m_count--; + m_buffer[idx] = _Move(m_buffer[m_count - 1]); } + m_count--; + } - void clear() { m_count = 0; } + void clear() { m_count = 0; } - void clearAndDeallocate() - { - _deallocateBuffer(); - m_count = m_capacity = 0; - } + void clearAndDeallocate() + { + _deallocateBuffer(); + m_count = m_capacity = 0; + } - void reserve(Index size) + void reserve(Index size) + { + // The cast for this comparison is needed, otherwise some compilers erroneously detect + // the possiblity of a zero sized allocation (possible if m_capacity is assumed to be + // negative). + if (UIndex(size) > UIndex(m_capacity)) { - // The cast for this comparison is needed, otherwise some compilers erroneously detect - // the possiblity of a zero sized allocation (possible if m_capacity is assumed to be negative). - if(UIndex(size) > UIndex(m_capacity)) + T* newBuffer = _allocate(size); + if (m_capacity) { - T* newBuffer = _allocate(size); - if (m_capacity) + /*if (std::has_trivial_copy_assign<T>::value && + std::has_trivial_destructor<T>::value) memcpy(newBuffer, buffer, _count * + sizeof(T)); else*/ { - /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) - memcpy(newBuffer, buffer, _count * sizeof(T)); - else*/ + for (Index i = 0; i < m_count; i++) + newBuffer[i] = static_cast<T&&>(m_buffer[i]); + + // Default-initialize the remaining elements + for (Index i = m_count; i < size; i++) { - for (Index i = 0; i < m_count; i++) - newBuffer[i] = static_cast<T&&>(m_buffer[i]); - - // Default-initialize the remaining elements - for(Index i = m_count; i < size; i++) - { - new(newBuffer + i) T(); - } + new (newBuffer + i) T(); } - _deallocateBuffer(); } - m_buffer = newBuffer; - m_capacity = size; + _deallocateBuffer(); } + m_buffer = newBuffer; + m_capacity = size; } + } - void growToCount(Index count) + void growToCount(Index count) + { + Index newBufferCount = Index(1) << Math::Log2Ceil((unsigned int)count); + if (m_capacity < newBufferCount) { - Index newBufferCount = Index(1) << Math::Log2Ceil((unsigned int)count); - if (m_capacity < newBufferCount) - { - reserve(newBufferCount); - } - m_count = count; + reserve(newBufferCount); } + m_count = count; + } - void setCount(Index count) - { - reserve(count); - m_count = count; - } + void setCount(Index count) + { + reserve(count); + m_count = count; + } - void unsafeShrinkToCount(Index count) { m_count = count; } + void unsafeShrinkToCount(Index count) { m_count = count; } - void compress() + void compress() + { + if (m_capacity > m_count && m_count > 0) { - if (m_capacity > m_count && m_count > 0) - { - T* newBuffer = _allocate(m_count); - for (Index i = 0; i < m_count; i++) - newBuffer[i] = static_cast<T&&>(m_buffer[i]); + T* newBuffer = _allocate(m_count); + for (Index i = 0; i < m_count; i++) + newBuffer[i] = static_cast<T&&>(m_buffer[i]); - _deallocateBuffer(); - m_buffer = newBuffer; - m_capacity = m_count; - } + _deallocateBuffer(); + m_buffer = newBuffer; + m_capacity = m_count; } + } - SLANG_FORCE_INLINE const T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } + SLANG_FORCE_INLINE const T& operator[](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } - SLANG_FORCE_INLINE T& operator [](Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } + SLANG_FORCE_INLINE T& operator[](Index idx) + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } - template<typename Func> - Index findFirstIndex(const Func& predicate) const + template<typename Func> + Index findFirstIndex(const Func& predicate) const + { + for (Index i = 0; i < m_count; i++) { - for (Index i = 0; i < m_count; i++) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; + if (predicate(m_buffer[i])) + return i; } + return -1; + } - template<typename T2> - Index indexOf(const T2& val) const + template<typename T2> + Index indexOf(const T2& val) const + { + for (Index i = 0; i < m_count; i++) { - for (Index i = 0; i < m_count; i++) - { - if (m_buffer[i] == val) - return i; - } - return -1; + if (m_buffer[i] == val) + return i; } + return -1; + } - template<typename Func> - Index findLastIndex(const Func& predicate) const + template<typename Func> + Index findLastIndex(const Func& predicate) const + { + for (Index i = m_count - 1; i >= 0; i--) { - for (Index i = m_count - 1; i >= 0; i--) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; + if (predicate(m_buffer[i])) + return i; } + return -1; + } - template<typename T2> - Index lastIndexOf(const T2& val) const + template<typename T2> + Index lastIndexOf(const T2& val) const + { + for (Index i = m_count - 1; i >= 0; i--) { - for (Index i = m_count - 1; i >= 0; i--) - { - if(m_buffer[i] == val) - return i; - } - return -1; + if (m_buffer[i] == val) + return i; } + return -1; + } - bool contains(const T& val) const { return indexOf(val) != Index(-1); } - - void sort() - { - sort([](const T& t1, const T& t2){return t1 < t2;}); - } + bool contains(const T& val) const { return indexOf(val) != Index(-1); } - template<typename Comparer> - void sort(Comparer compare) - { - //insertionSort(buffer, 0, _count - 1); - //quickSort(buffer, 0, _count - 1, compare); - std::sort(m_buffer, m_buffer + m_count, compare); - } + void sort() + { + sort([](const T& t1, const T& t2) { return t1 < t2; }); + } - void stableSort() - { - stableSort([](const T& t1, const T& t2){return t1 < t2;}); - } + template<typename Comparer> + void sort(Comparer compare) + { + // insertionSort(buffer, 0, _count - 1); + // quickSort(buffer, 0, _count - 1, compare); + std::sort(m_buffer, m_buffer + m_count, compare); + } - template<typename Comparer> - void stableSort(Comparer compare) - { - std::stable_sort(m_buffer, m_buffer + m_count, compare); - } + void stableSort() + { + stableSort([](const T& t1, const T& t2) { return t1 < t2; }); + } - template <typename IterateFunc> - void forEach(IterateFunc f) const - { - for (Index i = 0; i < m_count; i++) - f(m_buffer[i]); - } + template<typename Comparer> + void stableSort(Comparer compare) + { + std::stable_sort(m_buffer, m_buffer + m_count, compare); + } - template<typename Comparer> - void quickSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) - { - static const Index kMinQSortSize = 32; + template<typename IterateFunc> + void forEach(IterateFunc f) const + { + for (Index i = 0; i < m_count; i++) + f(m_buffer[i]); + } - if(startIndex < endIndex) - { - if (endIndex - startIndex < kMinQSortSize) - insertionSort(vals, startIndex, endIndex, comparer); - else - { - Index pivotIndex = (startIndex + endIndex) >> 1; - Index pivotNewIndex = partition(vals, startIndex, endIndex, pivotIndex, comparer); - quickSort(vals, startIndex, pivotNewIndex - 1, comparer); - quickSort(vals, pivotNewIndex + 1, endIndex, comparer); - } - } + template<typename Comparer> + void quickSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) + { + static const Index kMinQSortSize = 32; - } - template<typename Comparer> - Index partition(T* vals, Index left, Index right, Index pivotIndex, Comparer comparer) + if (startIndex < endIndex) { - T pivotValue = vals[pivotIndex]; - swapElements(vals, right, pivotIndex); - Index storeIndex = left; - for (Index i = left; i < right; i++) + if (endIndex - startIndex < kMinQSortSize) + insertionSort(vals, startIndex, endIndex, comparer); + else { - if (comparer(vals[i], pivotValue)) - { - swapElements(vals, i, storeIndex); - storeIndex++; - } + Index pivotIndex = (startIndex + endIndex) >> 1; + Index pivotNewIndex = partition(vals, startIndex, endIndex, pivotIndex, comparer); + quickSort(vals, startIndex, pivotNewIndex - 1, comparer); + quickSort(vals, pivotNewIndex + 1, endIndex, comparer); } - swapElements(vals, storeIndex, right); - return storeIndex; } - template<typename Comparer> - void insertionSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) + } + template<typename Comparer> + Index partition(T* vals, Index left, Index right, Index pivotIndex, Comparer comparer) + { + T pivotValue = vals[pivotIndex]; + swapElements(vals, right, pivotIndex); + Index storeIndex = left; + for (Index i = left; i < right; i++) { - for (Index i = startIndex + 1; i <= endIndex; i++) + if (comparer(vals[i], pivotValue)) { - T insertValue = static_cast<T&&>(vals[i]); - Index insertIndex = i - 1; - while (insertIndex >= startIndex && comparer(insertValue, vals[insertIndex])) - { - vals[insertIndex + 1] = static_cast<T&&>(vals[insertIndex]); - insertIndex--; - } - vals[insertIndex + 1] = static_cast<T&&>(insertValue); + swapElements(vals, i, storeIndex); + storeIndex++; } } - - inline void swapElements(T* vals, Index index1, Index index2) + swapElements(vals, storeIndex, right); + return storeIndex; + } + template<typename Comparer> + void insertionSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) + { + for (Index i = startIndex + 1; i <= endIndex; i++) { - if (index1 != index2) + T insertValue = static_cast<T&&>(vals[i]); + Index insertIndex = i - 1; + while (insertIndex >= startIndex && comparer(insertValue, vals[insertIndex])) { - T tmp = static_cast<T&&>(vals[index1]); - vals[index1] = static_cast<T&&>(vals[index2]); - vals[index2] = static_cast<T&&>(tmp); + vals[insertIndex + 1] = static_cast<T&&>(vals[insertIndex]); + insertIndex--; } + vals[insertIndex + 1] = static_cast<T&&>(insertValue); } + } - template<typename T2, typename Comparer> - Index binarySearch(const T2& obj, Comparer comparer) const + inline void swapElements(T* vals, Index index1, Index index2) + { + if (index1 != index2) { - Index imin = 0, imax = m_count - 1; - while (imax >= imin) - { - Index imid = imin + ((imax - imin)>>1); - int compareResult = comparer(m_buffer[imid], obj); - if (compareResult == 0) - return imid; - else if (compareResult < 0) - imin = imid + 1; - else - imax = imid - 1; - } - // TODO: The return value on a failed search should be - // the bitwise negation of the index where `obj` should - // be inserted to be in the proper sorted location. - return -1; + T tmp = static_cast<T&&>(vals[index1]); + vals[index1] = static_cast<T&&>(vals[index2]); + vals[index2] = static_cast<T&&>(tmp); } + } - template<typename T2> - Index binarySearch(const T2& obj) - { - return binarySearch(obj, - [](T & curObj, const T2 & thatObj)->int - { - if (curObj < thatObj) - return -1; - else if (curObj == thatObj) - return 0; - else - return 1; - }); + template<typename T2, typename Comparer> + Index binarySearch(const T2& obj, Comparer comparer) const + { + Index imin = 0, imax = m_count - 1; + while (imax >= imin) + { + Index imid = imin + ((imax - imin) >> 1); + int compareResult = comparer(m_buffer[imid], obj); + if (compareResult == 0) + return imid; + else if (compareResult < 0) + imin = imid + 1; + else + imax = imid - 1; } - private: - T* m_buffer; ///< A new T[N] allocated buffer. NOTE! All elements up to capacity are in some valid form for T. - Index m_capacity; ///< The total capacity of elements - Index m_count; ///< The amount of elements + // TODO: The return value on a failed search should be + // the bitwise negation of the index where `obj` should + // be inserted to be in the proper sorted location. + return -1; + } - void _deallocateBuffer() - { - if (m_buffer) + template<typename T2> + Index binarySearch(const T2& obj) + { + return binarySearch( + obj, + [](T& curObj, const T2& thatObj) -> int { - AllocateMethod<T, TAllocator>::deallocateArray(m_buffer, m_capacity); - m_buffer = nullptr; - } - } - static inline T* _allocate(Index count) - { - return AllocateMethod<T, TAllocator>::allocateArray(count); - } - static void _free(T* buffer, Index count) - { - return AllocateMethod<T, TAllocator>::deallocateArray(buffer, count); - } + if (curObj < thatObj) + return -1; + else if (curObj == thatObj) + return 0; + else + return 1; + }); + } - template<typename... Args> - void _init(const T& val, Args... args) +private: + T* m_buffer; ///< A new T[N] allocated buffer. NOTE! All elements up to capacity are in some + ///< valid form for T. + Index m_capacity; ///< The total capacity of elements + Index m_count; ///< The amount of elements + + void _deallocateBuffer() + { + if (m_buffer) { - add(val); - _init(args...); + AllocateMethod<T, TAllocator>::deallocateArray(m_buffer, m_capacity); + m_buffer = nullptr; } - - void _init() {} - }; - - template<typename T> - T calcMin(const List<T>& list) + } + static inline T* _allocate(Index count) { - T minVal = list.getFirst(); - for (Index i = 1; i < list.getCount(); i++) - if (list[i] < minVal) - minVal = list[i]; - return minVal; + return AllocateMethod<T, TAllocator>::allocateArray(count); + } + static void _free(T* buffer, Index count) + { + return AllocateMethod<T, TAllocator>::deallocateArray(buffer, count); } - template<typename T> - T calcMax(const List<T>& list) + template<typename... Args> + void _init(const T& val, Args... args) { - T maxVal = list.getFirst(); - for (Index i = 1; i< list.getCount(); i++) - if (list[i] > maxVal) - maxVal = list[i]; - return maxVal; + add(val); + _init(args...); } + + void _init() {} +}; + +template<typename T> +T calcMin(const List<T>& list) +{ + T minVal = list.getFirst(); + for (Index i = 1; i < list.getCount(); i++) + if (list[i] < minVal) + minVal = list[i]; + return minVal; +} + +template<typename T> +T calcMax(const List<T>& list) +{ + T maxVal = list.getFirst(); + for (Index i = 1; i < list.getCount(); i++) + if (list[i] > maxVal) + maxVal = list[i]; + return maxVal; } +} // namespace Slang #endif diff --git a/source/core/slang-lz4-compression-system.cpp b/source/core/slang-lz4-compression-system.cpp index 1e2ab9558..bb777fae6 100644 --- a/source/core/slang-lz4-compression-system.cpp +++ b/source/core/slang-lz4-compression-system.cpp @@ -1,10 +1,9 @@ #include "slang-lz4-compression-system.h" +#include "slang-blob.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" -#include "slang-blob.h" - #include <lz4.h> namespace Slang @@ -12,31 +11,47 @@ namespace Slang // Allocate static const storage for the various interface IDs that the Slang API needs to expose -class LZ4CompressionSystemImpl : public RefObject, public ICompressionSystem +class LZ4CompressionSystemImpl : public RefObject, public ICompressionSystem { public: - // ISlangUnknown + // ISlangUnknown // override ref counting, as singleton SLANG_IUNKNOWN_QUERY_INTERFACE SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } // ICompressionSystem - virtual SLANG_NO_THROW CompressionSystemType SLANG_MCALL getSystemType() SLANG_OVERRIDE { return CompressionSystemType::LZ4; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compress(const CompressionStyle* style, const void* src, size_t srcSizeInBytes, ISlangBlob** outBlob) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL decompress(const void* compressed, size_t compressedSizeInBytes, size_t decompressedSizeInBytes, void* outDecompressed) SLANG_OVERRIDE; + virtual SLANG_NO_THROW CompressionSystemType SLANG_MCALL getSystemType() SLANG_OVERRIDE + { + return CompressionSystemType::LZ4; + } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compress( + const CompressionStyle* style, + const void* src, + size_t srcSizeInBytes, + ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL decompress( + const void* compressed, + size_t compressedSizeInBytes, + size_t decompressedSizeInBytes, + void* outDecompressed) SLANG_OVERRIDE; protected: - ICompressionSystem* getInterface(const Guid& guid); }; ICompressionSystem* LZ4CompressionSystemImpl::getInterface(const Guid& guid) { - return (guid == ISlangUnknown::getTypeGuid() || guid == ICompressionSystem::getTypeGuid()) ? static_cast<ICompressionSystem*>(this) : nullptr; + return (guid == ISlangUnknown::getTypeGuid() || guid == ICompressionSystem::getTypeGuid()) + ? static_cast<ICompressionSystem*>(this) + : nullptr; } -SlangResult LZ4CompressionSystemImpl::compress(const CompressionStyle* style, const void* src, size_t srcSizeInBytes, ISlangBlob** outBlob) +SlangResult LZ4CompressionSystemImpl::compress( + const CompressionStyle* style, + const void* src, + size_t srcSizeInBytes, + ISlangBlob** outBlob) { SLANG_UNUSED(style); const size_t compressedBound = LZ4_compressBound(int(srcSizeInBytes)); @@ -44,7 +59,11 @@ SlangResult LZ4CompressionSystemImpl::compress(const CompressionStyle* style, co ScopedAllocation alloc; void* compressedData = alloc.allocate(compressedBound); - const int compressedSize = LZ4_compress_default((const char*)src, (char*)compressedData, int(srcSizeInBytes), int(compressedBound)); + const int compressedSize = LZ4_compress_default( + (const char*)src, + (char*)compressedData, + int(srcSizeInBytes), + int(compressedBound)); alloc.reallocate(compressedSize); auto blob = RawBlob::moveCreate(alloc); @@ -53,15 +72,23 @@ SlangResult LZ4CompressionSystemImpl::compress(const CompressionStyle* style, co return SLANG_OK; } -SlangResult LZ4CompressionSystemImpl::decompress(const void* compressed, size_t compressedSizeInBytes, size_t decompressedSizeInBytes, void* outDecompressed) +SlangResult LZ4CompressionSystemImpl::decompress( + const void* compressed, + size_t compressedSizeInBytes, + size_t decompressedSizeInBytes, + void* outDecompressed) { - const int decompressedSize = LZ4_decompress_safe((const char*)compressed, (char*)outDecompressed, int(compressedSizeInBytes), int(decompressedSizeInBytes)); + const int decompressedSize = LZ4_decompress_safe( + (const char*)compressed, + (char*)outDecompressed, + int(compressedSizeInBytes), + int(decompressedSizeInBytes)); SLANG_UNUSED(decompressedSize); SLANG_ASSERT(size_t(decompressedSize) == decompressedSizeInBytes); return SLANG_OK; } -/* static */ICompressionSystem* LZ4CompressionSystem::getSingleton() +/* static */ ICompressionSystem* LZ4CompressionSystem::getSingleton() { static LZ4CompressionSystemImpl impl; return &impl; diff --git a/source/core/slang-lz4-compression-system.h b/source/core/slang-lz4-compression-system.h index d74fbd61a..bfc039b54 100644 --- a/source/core/slang-lz4-compression-system.h +++ b/source/core/slang-lz4-compression-system.h @@ -2,10 +2,8 @@ #define SLANG_LZ4_COMPRESSION_SYSTEM_H #include "slang-basic.h" - -#include "slang-compression-system.h" - #include "slang-com-ptr.h" +#include "slang-compression-system.h" namespace Slang { @@ -17,6 +15,6 @@ public: static ICompressionSystem* getSingleton(); }; -} +} // namespace Slang #endif diff --git a/source/core/slang-math.h b/source/core/slang-math.h index 51ada76a9..e977dc37d 100644 --- a/source/core/slang-math.h +++ b/source/core/slang-math.h @@ -2,264 +2,272 @@ #define SLANG_CORE_MATH_H #include "slang.h" + #include <cmath> namespace Slang { - // Some handy constants +// Some handy constants - // The largest positive (or negative) number -# define SLANG_HALF_MAX 65504.0f - // Smallest (denormalized) value. 1 / 2^24 -# define SLANG_HALF_SUB_NORMAL_MIN (1.0f / 16777216.0f) +// The largest positive (or negative) number +#define SLANG_HALF_MAX 65504.0f +// Smallest (denormalized) value. 1 / 2^24 +#define SLANG_HALF_SUB_NORMAL_MIN (1.0f / 16777216.0f) - class Math - { - public: - // Use to fix type punning issues with strict aliasing - union FloatIntUnion - { - float fvalue; - int ivalue; +class Math +{ +public: + // Use to fix type punning issues with strict aliasing + union FloatIntUnion + { + float fvalue; + int ivalue; - SLANG_FORCE_INLINE static FloatIntUnion makeFromInt(int i) { FloatIntUnion cast; cast.ivalue = i; return cast; } - SLANG_FORCE_INLINE static FloatIntUnion makeFromFloat(float f) { FloatIntUnion cast; cast.fvalue = f; return cast; } - }; - union DoubleInt64Union + SLANG_FORCE_INLINE static FloatIntUnion makeFromInt(int i) { - double dvalue; - int64_t ivalue; - SLANG_FORCE_INLINE static DoubleInt64Union makeFromInt64(int64_t i) { DoubleInt64Union cast; cast.ivalue = i; return cast; } - SLANG_FORCE_INLINE static DoubleInt64Union makeFromDouble(double d) { DoubleInt64Union cast; cast.dvalue = d; return cast; } - }; - - static const float Pi; - - template <typename T> - static T Abs(T a) + FloatIntUnion cast; + cast.ivalue = i; + return cast; + } + SLANG_FORCE_INLINE static FloatIntUnion makeFromFloat(float f) + { + FloatIntUnion cast; + cast.fvalue = f; + return cast; + } + }; + union DoubleInt64Union + { + double dvalue; + int64_t ivalue; + SLANG_FORCE_INLINE static DoubleInt64Union makeFromInt64(int64_t i) { - return (a < 0) ? -a : a; + DoubleInt64Union cast; + cast.ivalue = i; + return cast; } + SLANG_FORCE_INLINE static DoubleInt64Union makeFromDouble(double d) + { + DoubleInt64Union cast; + cast.dvalue = d; + return cast; + } + }; - template<typename T> - static T Min(const T& v1, const T&v2) - { - return v1<v2?v1:v2; - } - template<typename T> - static T Max(const T& v1, const T&v2) - { - return v1>v2?v1:v2; - } - template<typename T> - static T Min(const T& v1, const T&v2, const T&v3) - { - return Min(v1, Min(v2, v3)); - } - template<typename T> - static T Max(const T& v1, const T&v2, const T&v3) - { - return Max(v1, Max(v2, v3)); - } - template<typename T> - static T Clamp(const T& val, const T& vmin, const T&vmax) - { - if (val < vmin) return vmin; - else if (val > vmax) return vmax; - else return val; - } + static const float Pi; - static inline int FastFloor(float x) - { - int i = (int)x; - return i - (i > x); - } + template<typename T> + static T Abs(T a) + { + return (a < 0) ? -a : a; + } - static inline int FastFloor(double x) - { - int i = (int)x; - return i - (i > x); - } + template<typename T> + static T Min(const T& v1, const T& v2) + { + return v1 < v2 ? v1 : v2; + } + template<typename T> + static T Max(const T& v1, const T& v2) + { + return v1 > v2 ? v1 : v2; + } + template<typename T> + static T Min(const T& v1, const T& v2, const T& v3) + { + return Min(v1, Min(v2, v3)); + } + template<typename T> + static T Max(const T& v1, const T& v2, const T& v3) + { + return Max(v1, Max(v2, v3)); + } + template<typename T> + static T Clamp(const T& val, const T& vmin, const T& vmax) + { + if (val < vmin) + return vmin; + else if (val > vmax) + return vmax; + else + return val; + } - static inline int IsNaN(float x) - { - return std::isnan(x); - } + static inline int FastFloor(float x) + { + int i = (int)x; + return i - (i > x); + } - static inline int IsInf(float x) - { - return std::isinf(x); - } + static inline int FastFloor(double x) + { + int i = (int)x; + return i - (i > x); + } - static inline unsigned int Ones32(unsigned int x) - { - /* 32-bit recursive reduction using SWAR... - but first step is mapping 2-bit values - into sum of 2 1-bit values in sneaky way - */ - x -= ((x >> 1) & 0x55555555); - x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); - x = (((x >> 4) + x) & 0x0f0f0f0f); - x += (x >> 8); - x += (x >> 16); - return(x & 0x0000003f); - } + static inline int IsNaN(float x) { return std::isnan(x); } - static inline unsigned int Log2Floor(unsigned int x) - { - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return(Ones32(x >> 1)); - } + static inline int IsInf(float x) { return std::isinf(x); } - static inline unsigned int Log2Ceil(unsigned int x) - { - int y = (x & (x - 1)); - y |= -y; - y >>= (32 - 1); - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return(Ones32(x >> 1) - y); - } - /* - static inline int Log2(float x) - { - unsigned int ix = (unsigned int&)x; - unsigned int exp = (ix >> 23) & 0xFF; - int log2 = (unsigned int)(exp) - 127; + static inline unsigned int Ones32(unsigned int x) + { + /* 32-bit recursive reduction using SWAR... + but first step is mapping 2-bit values + into sum of 2 1-bit values in sneaky way + */ + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return (x & 0x0000003f); + } - return log2; - } - */ + static inline unsigned int Log2Floor(unsigned int x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return (Ones32(x >> 1)); + } - static bool AreNearlyEqual(double a, double b, double epsilon) - { - // If they are equal then we are done - if (a == b) - { - return true; - } + static inline unsigned int Log2Ceil(unsigned int x) + { + int y = (x & (x - 1)); + y |= -y; + y >>= (32 - 1); + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return (Ones32(x >> 1) - y); + } + /* + static inline int Log2(float x) + { + unsigned int ix = (unsigned int&)x; + unsigned int exp = (ix >> 23) & 0xFF; + int log2 = (unsigned int)(exp) - 127; - const double absA = Abs(a); - const double absB = Abs(b); - const double diff = Abs(a - b); + return log2; + } + */ - // https://en.wikipedia.org/wiki/Double_precision_floating-point_format - const double minNormal = 2.2250738585072014e-308; - // Either a or b are very close to being zero, so doing relative comparison isn't really appropriate - if (a == 0.0 || b == 0.0 || (absA + absB < minNormal)) - { - return diff < (epsilon * minNormal); - } - else - { - // Calculate a relative relative error - return diff < epsilon * (absA + absB); - } + static bool AreNearlyEqual(double a, double b, double epsilon) + { + // If they are equal then we are done + if (a == b) + { + return true; } - template <typename T> - static T getLowestBit(T val) + const double absA = Abs(a); + const double absB = Abs(b); + const double diff = Abs(a - b); + + // https://en.wikipedia.org/wiki/Double_precision_floating-point_format + const double minNormal = 2.2250738585072014e-308; + // Either a or b are very close to being zero, so doing relative comparison isn't really + // appropriate + if (a == 0.0 || b == 0.0 || (absA + absB < minNormal)) + { + return diff < (epsilon * minNormal); + } + else { - return val & (-val); + // Calculate a relative relative error + return diff < epsilon * (absA + absB); } - }; - inline int FloatAsInt(float val) - { - return Math::FloatIntUnion::makeFromFloat(val).ivalue; - } - inline float IntAsFloat(int val) - { - return Math::FloatIntUnion::makeFromInt(val).fvalue; - } + } + + template<typename T> + static T getLowestBit(T val) + { + return val & (-val); + } +}; +inline int FloatAsInt(float val) +{ + return Math::FloatIntUnion::makeFromFloat(val).ivalue; +} +inline float IntAsFloat(int val) +{ + return Math::FloatIntUnion::makeFromInt(val).fvalue; +} - SLANG_FORCE_INLINE int64_t DoubleAsInt64(double val) +SLANG_FORCE_INLINE int64_t DoubleAsInt64(double val) +{ + return Math::DoubleInt64Union::makeFromDouble(val).ivalue; +} +SLANG_FORCE_INLINE double Int64AsDouble(int64_t value) +{ + return Math::DoubleInt64Union::makeFromInt64(value).dvalue; +} + +inline unsigned short FloatToHalf(float val) +{ + const auto x = FloatAsInt(val); + + unsigned short bits = (x >> 16) & 0x8000; + unsigned short m = (x >> 12) & 0x07ff; + unsigned int e = (x >> 23) & 0xff; + if (e < 103) + return bits; + if (e > 142) { - return Math::DoubleInt64Union::makeFromDouble(val).ivalue; + bits |= 0x7c00u; + bits |= e == 255 && (x & 0x007fffffu); + return bits; } - SLANG_FORCE_INLINE double Int64AsDouble(int64_t value) + if (e < 113) { - return Math::DoubleInt64Union::makeFromInt64(value).dvalue; + m |= 0x0800u; + bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); + return bits; } + bits |= ((e - 112) << 10) | (m >> 1); + bits += m & 1; + return bits; +} - inline unsigned short FloatToHalf(float val) - { - const auto x = FloatAsInt(val); - - unsigned short bits = (x >> 16) & 0x8000; - unsigned short m = (x >> 12) & 0x07ff; - unsigned int e = (x >> 23) & 0xff; - if (e < 103) - return bits; - if (e > 142) - { - bits |= 0x7c00u; - bits |= e == 255 && (x & 0x007fffffu); - return bits; - } - if (e < 113) - { - m |= 0x0800u; - bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); - return bits; - } - bits |= ((e - 112) << 10) | (m >> 1); - bits += m & 1; - return bits; - } +inline float HalfToFloat(unsigned short input) +{ + static const auto magic = Math::FloatIntUnion::makeFromInt((127 + (127 - 15)) << 23); + static const auto was_infnan = Math::FloatIntUnion::makeFromInt((127 + 16) << 23); + Math::FloatIntUnion o; + o.ivalue = (input & 0x7fff) << 13; // exponent/mantissa bits + o.fvalue *= magic.fvalue; // exponent adjust + if (o.fvalue >= was_infnan.fvalue) // make sure Inf/NaN survive + o.ivalue |= 255 << 23; + o.ivalue |= (input & 0x8000) << 16; // sign bit + return o.fvalue; +} - inline float HalfToFloat(unsigned short input) - { - static const auto magic = Math::FloatIntUnion::makeFromInt((127 + (127 - 15)) << 23); - static const auto was_infnan = Math::FloatIntUnion::makeFromInt((127 + 16) << 23); - Math::FloatIntUnion o; - o.ivalue = (input & 0x7fff) << 13; // exponent/mantissa bits - o.fvalue *= magic.fvalue; // exponent adjust - if (o.fvalue >= was_infnan.fvalue) // make sure Inf/NaN survive - o.ivalue |= 255 << 23; - o.ivalue |= (input & 0x8000) << 16; // sign bit - return o.fvalue; - } +class Random +{ +private: + unsigned int seed; - class Random - { - private: - unsigned int seed; - public: - Random(int seed) - { - this->seed = seed; - } - int Next() // random between 0 and RandMax (currently 0x7fff) - { - return ((seed = ((seed << 12) + 150889L) % 714025) & 0x7fff); - } - int Next(int min, int max) // inclusive min, exclusive max - { - unsigned int a = ((seed = ((seed << 12) + 150889L) % 714025) & 0xFFFF); - unsigned int b = ((seed = ((seed << 12) + 150889L) % 714025) & 0xFFFF); - unsigned int r = (a << 16) + b; - return min + r % (max - min); - } - float NextFloat() - { - return ((Next() << 15) + Next()) / ((float)(1 << 30)); - } - float NextFloat(float valMin, float valMax) - { - return valMin + (valMax - valMin) * NextFloat(); - } - static int RandMax() - { - return 0x7fff; - } - }; -} +public: + Random(int seed) { this->seed = seed; } + int Next() // random between 0 and RandMax (currently 0x7fff) + { + return ((seed = ((seed << 12) + 150889L) % 714025) & 0x7fff); + } + int Next(int min, int max) // inclusive min, exclusive max + { + unsigned int a = ((seed = ((seed << 12) + 150889L) % 714025) & 0xFFFF); + unsigned int b = ((seed = ((seed << 12) + 150889L) % 714025) & 0xFFFF); + unsigned int r = (a << 16) + b; + return min + r % (max - min); + } + float NextFloat() { return ((Next() << 15) + Next()) / ((float)(1 << 30)); } + float NextFloat(float valMin, float valMax) { return valMin + (valMax - valMin) * NextFloat(); } + static int RandMax() { return 0x7fff; } +}; +} // namespace Slang -#endif +#endif diff --git a/source/core/slang-memory-arena.cpp b/source/core/slang-memory-arena.cpp index 6a13addb6..cb1d3c577 100644 --- a/source/core/slang-memory-arena.cpp +++ b/source/core/slang-memory-arena.cpp @@ -1,7 +1,8 @@ #include "slang-memory-arena.h" -namespace Slang { +namespace Slang +{ MemoryArena::MemoryArena() { @@ -34,13 +35,13 @@ void MemoryArena::init(size_t blockPayloadSize, size_t blockAlignment) reset(); _initialize(blockPayloadSize, blockAlignment); } - + void MemoryArena::_initialize(size_t blockPayloadSize, size_t alignment) { // Alignment must be a power of 2 assert(((alignment - 1) & alignment) == 0); - // Ensure it's alignment is at least kMinAlignment + // Ensure it's alignment is at least kMinAlignment alignment = (alignment < kMinAlignment) ? kMinAlignment : alignment; const size_t alignMask = alignment - 1; @@ -52,12 +53,13 @@ void MemoryArena::_initialize(size_t blockPayloadSize, size_t alignment) // If alignment required is larger then the backing allocators then // make larger to ensure when alignment correction takes place it will be aligned - const size_t blockAllocSize = (alignment > kMinAlignment) ? (blockPayloadSize + alignment) : blockPayloadSize; - + const size_t blockAllocSize = + (alignment > kMinAlignment) ? (blockPayloadSize + alignment) : blockPayloadSize; + m_blockAllocSize = blockAllocSize; m_blockAlignment = alignment; m_availableBlocks = nullptr; - + m_blockFreeList.init(sizeof(Block), sizeof(void*), 16); _resetCurrentBlock(); @@ -137,9 +139,11 @@ void MemoryArena::_deallocateBlocks(Block* start) bool MemoryArena::_isNormalBlock(Block* block) { - // The size of the block in total is from m_alloc to the m_end (ie the size that is passed into _newBlock) + // The size of the block in total is from m_alloc to the m_end (ie the size that is passed into + // _newBlock) const size_t blockSize = size_t(block->m_end - block->m_alloc); - return (blockSize == m_blockAllocSize) && ((size_t(block->m_start) & (m_blockAlignment - 1)) == 0); + return (blockSize == m_blockAllocSize) && + ((size_t(block->m_start) & (m_blockAlignment - 1)) == 0); } void MemoryArena::_deallocateBlock(Block* block) @@ -169,7 +173,7 @@ void MemoryArena::deallocateAll() _deallocateBlock(block); block = next; } - + // Reset current block _resetCurrentBlock(); } @@ -341,14 +345,17 @@ void* MemoryArena::_allocateAlignedFromNewBlock(size_t size, size_t alignment) // There are two scenarios // a) Allocate a new normal block and make current // b) Allocate a new 'odd-sized' block and make current - // - // That by always allocating a new block if odd-sized, we lose more efficiency in terms of storage (the previous block - // may not have been used much). BUT doing so makes it easy to rewind - as the blocks are always in order of allocation. // - // An improvement might be to have some abstraction that sits on top that can do this tracking (or have the blocks - // themselves record if they alias over a previously used block - but we don't bother with this here. - // If the alignment is greater than regular alignment we need to handle specially - if (allocSize > m_blockPayloadSize || (alignment > m_blockAlignment && allocSize + alignment > m_blockPayloadSize)) + // That by always allocating a new block if odd-sized, we lose more efficiency in terms of + // storage (the previous block may not have been used much). BUT doing so makes it easy to + // rewind - as the blocks are always in order of allocation. + // + // An improvement might be to have some abstraction that sits on top that can do this tracking + // (or have the blocks themselves record if they alias over a previously used block - but we + // don't bother with this here. If the alignment is greater than regular alignment we need to + // handle specially + if (allocSize > m_blockPayloadSize || + (alignment > m_blockAlignment && allocSize + alignment > m_blockPayloadSize)) { // This is an odd-sized block so just allocate the whole thing. block = _newBlock(allocSize, alignment); @@ -366,10 +373,10 @@ void* MemoryArena::_allocateAlignedFromNewBlock(size_t size, size_t alignment) return nullptr; } - // Make the current block + // Make the current block _addCurrentBlock(block); - // Align the memory + // Align the memory uint8_t* memory = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); // It must be aligned @@ -413,14 +420,14 @@ void MemoryArena::_rewindToCursor(const void* cursorIn) deallocateAll(); return; } - + // Find the block that contains the allocation Block* cursorBlock = _findNonCurrent(cursorIn); assert(cursorBlock); if (!cursorBlock) { // If not found it means this address is NOT part any of the active used heap! - // Probably an invalid cursor + // Probably an invalid cursor return; } @@ -436,7 +443,7 @@ void MemoryArena::_rewindToCursor(const void* cursorIn) } // The cursor block is now the current block - m_usedBlocks = cursorBlock; + m_usedBlocks = cursorBlock; _setCurrentBlock(cursorBlock); const uint8_t* cursor = (const uint8_t*)cursorIn; @@ -450,13 +457,12 @@ void MemoryArena::_rewindToCursor(const void* cursorIn) size_t MemoryArena::calcTotalMemoryUsed() const { return (m_usedBlocks ? _calcBlocksUsedMemory(m_usedBlocks->m_next) : 0) + - size_t(m_current - m_start); + size_t(m_current - m_start); } size_t MemoryArena::calcTotalMemoryAllocated() const { - return _calcBlocksAllocatedMemory(m_usedBlocks) + - _calcBlocksAllocatedMemory(m_availableBlocks); + return _calcBlocksAllocatedMemory(m_usedBlocks) + _calcBlocksAllocatedMemory(m_availableBlocks); } diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h index cbd0fdc56..03631befe 100644 --- a/source/core/slang-memory-arena.h +++ b/source/core/slang-memory-arena.h @@ -1,179 +1,194 @@ #ifndef SLANG_CORE_MEMORY_ARENA_H #define SLANG_CORE_MEMORY_ARENA_H +#include "slang-free-list.h" #include "slang.h" #include <stdlib.h> #include <string.h> - #include <type_traits> -#include "slang-free-list.h" +namespace Slang +{ -namespace Slang { +/** MemoryArena provides provides very fast allocation of small blocks, by aggregating many small +allocations over smaller amount of larger blocks. A typical small unaligned allocation is a pointer +bump. -/** MemoryArena provides provides very fast allocation of small blocks, by aggregating many small allocations -over smaller amount of larger blocks. A typical small unaligned allocation is a pointer bump. +Allocations are made contiguously from the current block. If there is no space in the current block, +the next block (which is unused) if available is checked. If that works, an allocation is made from +the next block. If not a new block is allocated that can hold at least the allocation with required +alignment. -Allocations are made contiguously from the current block. If there is no space in the current block, the -next block (which is unused) if available is checked. If that works, an allocation is made from the next block. -If not a new block is allocated that can hold at least the allocation with required alignment. - -All memory allocated can be deallocated very quickly and without a client having to track any memory. -All memory allocated will be freed on destruction - or with reset. +All memory allocated can be deallocated very quickly and without a client having to track any +memory. All memory allocated will be freed on destruction - or with reset. -A memory arena can have requests larger than the block size. When that happens they will just be allocated -from the heap. As such 'odd blocks' are seen as unusual and potentially wasteful so they are deallocated -when deallocateAll is called, whereas regular size blocks will remain allocated for fast subsequent allocation. +A memory arena can have requests larger than the block size. When that happens they will just be +allocated from the heap. As such 'odd blocks' are seen as unusual and potentially wasteful so they +are deallocated when deallocateAll is called, whereas regular size blocks will remain allocated for +fast subsequent allocation. It is intentional that blocks information is stored separately from the allocations that store the -user data. This is so that alignment permitting, block allocations sizes can be passed directly to underlying allocator. -For large power of 2 backing allocations this might mean a page/pages directly allocated by the OS for example. -Also means better cache coherency when traversing blocks -> as generally they will be contiguous in memory. - -Note that allocateUnaligned can be used for slightly faster aligned allocations. All blocks allocated internally -are aligned to the blockAlignment passed to the constructor. If subsequent allocations (of any type) sizes are of that -alignment or larger then no alignment fixing is required (because allocations are contiguous) and so 'allocateUnaligned' -will return allocations of blockAlignment alignment. - -If many 'odd' allocations occur it probably means that the block size should be increased. +user data. This is so that alignment permitting, block allocations sizes can be passed directly to +underlying allocator. For large power of 2 backing allocations this might mean a page/pages directly +allocated by the OS for example. Also means better cache coherency when traversing blocks -> as +generally they will be contiguous in memory. + +Note that allocateUnaligned can be used for slightly faster aligned allocations. All blocks +allocated internally are aligned to the blockAlignment passed to the constructor. If subsequent +allocations (of any type) sizes are of that alignment or larger then no alignment fixing is required +(because allocations are contiguous) and so 'allocateUnaligned' will return allocations of +blockAlignment alignment. + +If many 'odd' allocations occur it probably means that the block size should be increased. */ class MemoryArena { public: typedef MemoryArena ThisType; - /** The minimum alignment of the backing memory allocator. - NOTE! That this should not be greater than the alignment of the underlying allocator, and should never be less than sizeof(void*). - */ - static const size_t kMinAlignment = sizeof(void*); - /** Determines if an allocation is consistent with an allocation from this arena. - - The test cannot say definitively if this was such an allocation, because the exact details - of each allocation are not kept. - @param alloc The start of the allocation - @param sizeInBytes The size of the allocation in bytes - @return true if allocation could have been from this Arena */ + /** The minimum alignment of the backing memory allocator. + NOTE! That this should not be greater than the alignment of the underlying allocator, and should + never be less than sizeof(void*). + */ + static const size_t kMinAlignment = sizeof(void*); + /** Determines if an allocation is consistent with an allocation from this arena. + + The test cannot say definitively if this was such an allocation, because the exact details + of each allocation are not kept. + @param alloc The start of the allocation + @param sizeInBytes The size of the allocation in bytes + @return true if allocation could have been from this Arena */ bool isValid(const void* alloc, size_t sizeInBytes) const; - /** Initialize the arena with specified block size and alignment - If the arena has been previously initialized will free and deallocate all memory */ + /** Initialize the arena with specified block size and alignment + If the arena has been previously initialized will free and deallocate all memory */ void init(size_t blockSizeInBytes, size_t blockAlignment = kMinAlignment); - /** Allocate some memory of at least size bytes without having any specific alignment. + /** Allocate some memory of at least size bytes without having any specific alignment. - Can be used for slightly faster *aligned* allocations if caveats in class description are met. Alignment is kMinAlignment or better. + Can be used for slightly faster *aligned* allocations if caveats in class description are met. + Alignment is kMinAlignment or better. - @param size The size of the allocation requested (in bytes and must be > 0). - @return The allocation. Can be nullptr if backing allocator was not able to request required memory */ + @param size The size of the allocation requested (in bytes and must be > 0). + @return The allocation. Can be nullptr if backing allocator was not able to request required + memory */ void* allocate(size_t sizeInBytes); - /** Same as allocate, but zeros memory before returning - @param size The size of the allocation requested (in bytes and must be > 0). - @return The allocation. Can be nullptr if backing allocator was not able to request required memory */ - void* allocateAndZero(size_t sizeInBytes); - - /** Allocate some aligned memory of at least size bytes - @param size Size of allocation wanted (must be > 0). - @param alignment Alignment of allocation - must be a power of 2. - @return The allocation (or nullptr if unable to allocate). Will be at least 'alignment' alignment or better. */ + /** Same as allocate, but zeros memory before returning + @param size The size of the allocation requested (in bytes and must be > 0). + @return The allocation. Can be nullptr if backing allocator was not able to request required + memory */ + void* allocateAndZero(size_t sizeInBytes); + + /** Allocate some aligned memory of at least size bytes + @param size Size of allocation wanted (must be > 0). + @param alignment Alignment of allocation - must be a power of 2. + @return The allocation (or nullptr if unable to allocate). Will be at least 'alignment' + alignment or better. */ void* allocateAligned(size_t sizeInBytes, size_t alignment); - /** Allocate some aligned memory of at least size bytes - @param sizeInBytes Size of allocation wanted (must be > 0). - @return The allocation (or nullptr if unable to allocate). */ + /** Allocate some aligned memory of at least size bytes + @param sizeInBytes Size of allocation wanted (must be > 0). + @return The allocation (or nullptr if unable to allocate). */ void* allocateUnaligned(size_t sizeInBytes); - /** Allocate some aligned memory of at least size bytes, without alignment, and only from current block. - @param sizeInBytes Size of allocation wanted. - @return The allocation (or nullptr if unable to allocate in current block). */ + /** Allocate some aligned memory of at least size bytes, without alignment, and only from + current block. + @param sizeInBytes Size of allocation wanted. + @return The allocation (or nullptr if unable to allocate in current block). */ void* allocateCurrentUnaligned(size_t sizeInBytes); - /** Allocates a null terminated string. + /** Allocates a null terminated string. - NOTE, it is not possible to rewind to a zero length string allocation (because such a strings memory is not held on the arena) + NOTE, it is not possible to rewind to a zero length string allocation (because such a strings + memory is not held on the arena) - @param str A null-terminated string - @return A copy of the string held on the arena */ + @param str A null-terminated string + @return A copy of the string held on the arena */ const char* allocateString(const char* str); - /** Allocates a null terminated string. - @param chars Pointer to first character - @param charCount The amount of characters NOT including terminating 0. - @return A copy of the string held on the arena. */ + /** Allocates a null terminated string. + @param chars Pointer to first character + @param charCount The amount of characters NOT including terminating 0. + @return A copy of the string held on the arena. */ const char* allocateString(const char* chars, size_t numChars); - /// Allocate space for the specified type, with appropriate alignment. Note: Constructor for type is *NOT* executed. - template <typename T> + /// Allocate space for the specified type, with appropriate alignment. Note: Constructor for + /// type is *NOT* executed. + template<typename T> T* allocate(); - /// Allocate an array of a specified type. NOTE Constructor of T is *NOT* executed. - template <typename T> + /// Allocate an array of a specified type. NOTE Constructor of T is *NOT* executed. + template<typename T> T* allocateArray(size_t numElems); - /// Allocate an array of a specified type, and copy array passed into it. - template <typename T> - T* allocateAndCopyArray(const T* src, size_t numElems); + /// Allocate an array of a specified type, and copy array passed into it. + template<typename T> + T* allocateAndCopyArray(const T* src, size_t numElems); - /// Allocate an array of a specified type, and zero it. - template <typename T> + /// Allocate an array of a specified type, and zero it. + template<typename T> T* allocateAndZeroArray(size_t numElems); - /** Deallocates all allocated memory. That backing memory will generally not be released so - subsequent allocation will be fast, and from the same memory. Note though that 'odd' blocks - will be deallocated. */ + /** Deallocates all allocated memory. That backing memory will generally not be released so + subsequent allocation will be fast, and from the same memory. Note though that 'odd' blocks + will be deallocated. */ void deallocateAll(); - /// Resets to the initial state when constructed (and all backing memory will be deallocated) + /// Resets to the initial state when constructed (and all backing memory will be deallocated) void reset(); - /// Adjusts such that the next allocate will be at least to the block alignment. + /// Adjusts such that the next allocate will be at least to the block alignment. void adjustToBlockAlignment(); - - /// Gets the block alignment that is passed at initialization otherwise 0 an invalid block alignment. + + /// Gets the block alignment that is passed at initialization otherwise 0 an invalid block + /// alignment. size_t getBlockAlignment() const { return m_blockAlignment; } - /// Get the default block payload size + /// Get the default block payload size size_t getBlockPayloadSize() const { return m_blockPayloadSize; } - /// Estimate of total amount of memory used in bytes. The number can never be smaller than actual used memory but may be larger + /// Estimate of total amount of memory used in bytes. The number can never be smaller than + /// actual used memory but may be larger size_t calcTotalMemoryUsed() const; - /// Total memory allocated in bytes + /// Total memory allocated in bytes size_t calcTotalMemoryAllocated() const; - /// Get the current allocation cursor (memory address where subsequent allocations will be placed if space within the current block) - /// The address of an allocated block can be used as a cursor to rewind to, such that it and all subsequent allocations will be deallocated + /// Get the current allocation cursor (memory address where subsequent allocations will be + /// placed if space within the current block) The address of an allocated block can be used as a + /// cursor to rewind to, such that it and all subsequent allocations will be deallocated void* getCursor() const { return m_current; } - /// Rewind (and effectively deallocate) all allocations *after* the cursor + /// Rewind (and effectively deallocate) all allocations *after* the cursor void rewindToCursor(const void* cursor); - /// Add a block such that it will be freed when everything else is freed. + /// Add a block such that it will be freed when everything else is freed. void addExternalBlock(void* data, size_t size); - // Swap this with rhs + // Swap this with rhs void swapWith(ThisType& rhs); - /// Default Ctor + /// Default Ctor MemoryArena(); - /// Construct with block size and alignment. Block alignment must be a power of 2. + /// Construct with block size and alignment. Block alignment must be a power of 2. MemoryArena(size_t blockPayloadSize, size_t blockAlignment = kMinAlignment); - /// Dtor + /// Dtor ~MemoryArena(); protected: struct Block { - Block* m_next; ///< Singly linked list of blocks - uint8_t* m_alloc; ///< Allocation start (ie what to free) - uint8_t* m_start; ///< Start of payload (takes into account alignment) - uint8_t* m_end; ///< End of payload (m_start to m_end defines payload) + Block* m_next; ///< Singly linked list of blocks + uint8_t* m_alloc; ///< Allocation start (ie what to free) + uint8_t* m_start; ///< Start of payload (takes into account alignment) + uint8_t* m_end; ///< End of payload (m_start to m_end defines payload) }; void _initialize(size_t blockPayloadSize, size_t blockAlignment); - /// Delete the linked list of blocks specified by start + /// Delete the linked list of blocks specified by start void _deallocateBlocks(Block* start); - /// Delete the linked list of blocks payloads specified by start + /// Delete the linked list of blocks payloads specified by start void _deallocateBlocksPayload(Block* start); void _resetCurrentBlock(); @@ -182,44 +197,48 @@ protected: void _deallocateBlock(Block* block); - /// Create a new block with regular block alignment + /// Create a new block with regular block alignment Block* _newNormalBlock(); - /// Allocates a new block with allocSize and alignment + /// Allocates a new block with allocSize and alignment Block* _newBlock(size_t allocSizeInBytes, size_t alignment); void* _allocateAlignedFromNewBlock(size_t sizeInBytes, size_t alignment); void* _allocateAlignedFromNewBlockAndZero(size_t sizeInBytes, size_t alignment); - /// Find block that contains data/size that is _NOT_ current (ie not first block in m_usedBlocks) + /// Find block that contains data/size that is _NOT_ current (ie not first block in + /// m_usedBlocks) Block* _findNonCurrent(const void* data, size_t sizeInBytes) const; Block* _findNonCurrent(const void* data) const; - /// Find a block that contains data starting from block. Returns null ptr if not found + /// Find a block that contains data starting from block. Returns null ptr if not found Block* _findInBlocks(Block* block, const void* data) const; Block* _findInBlocks(Block* block, const void* data, size_t sizeInBytes) const; size_t _calcBlocksUsedMemory(const Block* block) const; size_t _calcBlocksAllocatedMemory(const Block* block) const; - /// Returns true if block can be classed as normal (right size and same or better alignment) + /// Returns true if block can be classed as normal (right size and same or better alignment) bool _isNormalBlock(Block* block); - /// Handles the rewinding of the cursor for the more complicated cases + /// Handles the rewinding of the cursor for the more complicated cases void _rewindToCursor(const void* cursor); - uint8_t* m_start; ///< The start of the current block (pointed to by m_usedBlocks) - uint8_t* m_end; ///< The end of the current block - uint8_t* m_current; ///< The current position in current block + uint8_t* m_start; ///< The start of the current block (pointed to by m_usedBlocks) + uint8_t* m_end; ///< The end of the current block + uint8_t* m_current; ///< The current position in current block + + size_t m_blockPayloadSize; ///< The size of the payload of a block + size_t m_blockAllocSize; ///< The size of a block allocation (must be the same size or bigger + ///< than m_blockPayloadSize) + size_t m_blockAlignment; ///< The alignment applied to used blocks - size_t m_blockPayloadSize; ///< The size of the payload of a block - size_t m_blockAllocSize; ///< The size of a block allocation (must be the same size or bigger than m_blockPayloadSize) - size_t m_blockAlignment; ///< The alignment applied to used blocks + Block* m_availableBlocks; ///< Standard sized blocks that are available + Block* + m_usedBlocks; ///< Singly linked list of used blocks. The first one is the 'current block' + ///< and m_next is the previously allocated blocks. nullptr terminated. - Block* m_availableBlocks; ///< Standard sized blocks that are available - Block* m_usedBlocks; ///< Singly linked list of used blocks. The first one is the 'current block' and m_next is the previously allocated blocks. nullptr terminated. - - FreeList m_blockFreeList; ///< Holds all of the blocks for fast allocation/free + FreeList m_blockFreeList; ///< Holds all of the blocks for fast allocation/free - private: +private: // Disable MemoryArena(const ThisType& rhs) = delete; void operator=(const ThisType& rhs) = delete; @@ -293,20 +312,21 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateAndZero(size_t sizeInBytes) assert(sizeInBytes > 0); // Align with the minimum alignment const size_t alignMask = kMinAlignment - 1; - // Implement without calling ::allocate, because in most common case we don't need to test for null. + // Implement without calling ::allocate, because in most common case we don't need to test for + // null. uint8_t* mem = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); uint8_t* end = mem + sizeInBytes; - if ( end <= m_end) + if (end <= m_end) { ::memset(mem, 0, sizeInBytes); - m_current = end; + m_current = end; return mem; } else { return _allocateAlignedFromNewBlockAndZero(sizeInBytes, kMinAlignment); } -} +} // -------------------------------------------------------------------------- SLANG_FORCE_INLINE void* MemoryArena::allocateAligned(size_t sizeInBytes, size_t alignment) @@ -356,25 +376,29 @@ inline const char* MemoryArena::allocateString(const char* chars, size_t numChar // Add null-terminating zero dst[numChars] = 0; return dst; -} +} // -------------------------------------------------------------------------- -template <typename T> +template<typename T> SLANG_FORCE_INLINE T* MemoryArena::allocate() { - void* mem = (SLANG_ALIGN_OF(T) <= kMinAlignment) ? allocate(sizeof(T)) : allocateAligned(sizeof(T), SLANG_ALIGN_OF(T)); + void* mem = (SLANG_ALIGN_OF(T) <= kMinAlignment) + ? allocate(sizeof(T)) + : allocateAligned(sizeof(T), SLANG_ALIGN_OF(T)); return reinterpret_cast<T*>(mem); } // -------------------------------------------------------------------------- -template <typename T> +template<typename T> SLANG_FORCE_INLINE T* MemoryArena::allocateArray(size_t numElems) { - return (numElems > 0) ? reinterpret_cast<T*>(allocateAligned(sizeof(T) * numElems, SLANG_ALIGN_OF(T))) : nullptr; + return (numElems > 0) + ? reinterpret_cast<T*>(allocateAligned(sizeof(T) * numElems, SLANG_ALIGN_OF(T))) + : nullptr; } // -------------------------------------------------------------------------- -template <typename T> +template<typename T> SLANG_FORCE_INLINE T* MemoryArena::allocateAndCopyArray(const T* arr, size_t numElems) { static_assert(std::is_trivially_copyable_v<T>); @@ -389,7 +413,7 @@ SLANG_FORCE_INLINE T* MemoryArena::allocateAndCopyArray(const T* arr, size_t num } // --------------------------------------------------------------------------- -template <typename T> +template<typename T> SLANG_FORCE_INLINE T* MemoryArena::allocateAndZeroArray(size_t numElems) { if (numElems > 0) @@ -409,12 +433,13 @@ inline void MemoryArena::adjustToBlockAlignment() uint8_t* ptr = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); // Alignment might push beyond end of block... if so allocate a new block - // This test could be avoided if we aligned m_end, but depending on block alignment that might waste some space + // This test could be avoided if we aligned m_end, but depending on block alignment that might + // waste some space if (ptr > m_end) { // We'll need a new block to make this alignment. Allocate a byte, and then rewind it. _allocateAlignedFromNewBlock(1, 1); - m_current = m_usedBlocks->m_start; + m_current = m_usedBlocks->m_start; } else { diff --git a/source/core/slang-memory-file-system.cpp b/source/core/slang-memory-file-system.cpp index b24abc20b..2bca497e2 100644 --- a/source/core/slang-memory-file-system.cpp +++ b/source/core/slang-memory-file-system.cpp @@ -1,10 +1,9 @@ #include "slang-memory-file-system.h" // For Path:: -#include "slang-io.h" #include "slang-blob.h" - #include "slang-implicit-directory-collector.h" +#include "slang-io.h" namespace Slang { @@ -16,11 +15,9 @@ MemoryFileSystem::MemoryFileSystem() void* MemoryFileSystem::getInterface(const Guid& guid) { - if ( guid == ISlangUnknown::getTypeGuid() || - guid == ISlangCastable::getTypeGuid() || - guid == ISlangFileSystem::getTypeGuid() || - guid == ISlangFileSystemExt::getTypeGuid() || - guid == ISlangMutableFileSystem::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangCastable::getTypeGuid() || + guid == ISlangFileSystem::getTypeGuid() || guid == ISlangFileSystemExt::getTypeGuid() || + guid == ISlangMutableFileSystem::getTypeGuid()) { return static_cast<ISlangMutableFileSystem*>(this); } @@ -42,9 +39,9 @@ void* MemoryFileSystem::castAs(const Guid& guid) return getObject(guid); } -void MemoryFileSystem::_clear() -{ - m_entries = Dictionary<String, Entry>(); +void MemoryFileSystem::_clear() +{ + m_entries = Dictionary<String, Entry>(); } MemoryFileSystem::Entry* MemoryFileSystem::_getEntryFromCanonicalPath(const String& canonicalPath) @@ -90,7 +87,7 @@ SlangResult MemoryFileSystem::loadFile(char const* path, ISlangBlob** outBlob) { Entry* entry; SLANG_RETURN_ON_FAIL(_loadFile(path, &entry)); - + ISlangBlob* contents = entry->m_contents; contents->addRef(); *outBlob = contents; @@ -98,22 +95,28 @@ SlangResult MemoryFileSystem::loadFile(char const* path, ISlangBlob** outBlob) return SLANG_OK; } -SlangResult MemoryFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) +SlangResult MemoryFileSystem::getFileUniqueIdentity( + const char* path, + ISlangBlob** outUniqueIdentity) { return getPath(PathKind::Canonical, path, outUniqueIdentity); } -SlangResult MemoryFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +SlangResult MemoryFileSystem::calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) { String combinedPath; switch (fromPathType) { - case SLANG_PATH_TYPE_FILE: + case SLANG_PATH_TYPE_FILE: { combinedPath = Path::combine(Path::getParentDirectory(fromPath), path); break; } - case SLANG_PATH_TYPE_DIRECTORY: + case SLANG_PATH_TYPE_DIRECTORY: { combinedPath = Path::combine(fromPath, path); break; @@ -139,26 +142,29 @@ SlangResult MemoryFileSystem::getPath(PathKind kind, const char* path, ISlangBlo { switch (kind) { - case PathKind::Simplified: + case PathKind::Simplified: { String simplifiedPath = Path::simplify(path); *outPath = StringBlob::moveCreate(simplifiedPath).detach(); return SLANG_OK; } - case PathKind::Display: - case PathKind::Canonical: + case PathKind::Display: + case PathKind::Canonical: { StringBuilder buffer; SLANG_RETURN_ON_FAIL(_getCanonical(path, buffer)); *outPath = StringBlob::moveCreate(buffer).detach(); return SLANG_OK; } - default: break; + default: break; } return SLANG_E_NOT_AVAILABLE; } -SlangResult MemoryFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) +SlangResult MemoryFileSystem::enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) { String canonicalPath; Entry* entry = _getEntryFromPath(path, &canonicalPath); @@ -204,11 +210,16 @@ SlangResult MemoryFileSystem::saveFileBlob(const char* path, ISlangBlob* dataBlo SlangResult MemoryFileSystem::_getCanonical(const char* path, StringBuilder& outCanonicalPath) { StringBuilder canonicalPath; - SLANG_RETURN_ON_FAIL(Path::simplify(UnownedStringSlice(path), Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, outCanonicalPath)); + SLANG_RETURN_ON_FAIL(Path::simplify( + UnownedStringSlice(path), + Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, + outCanonicalPath)); return SLANG_OK; } -SlangResult MemoryFileSystem::_getCanonicalWithExistingParent(const char* path, StringBuilder& outCanonicalPath) +SlangResult MemoryFileSystem::_getCanonicalWithExistingParent( + const char* path, + StringBuilder& outCanonicalPath) { SLANG_RETURN_ON_FAIL(_getCanonical(path, outCanonicalPath)); @@ -224,7 +235,7 @@ SlangResult MemoryFileSystem::_getCanonicalWithExistingParent(const char* path, return SLANG_E_NOT_FOUND; } } - + return SLANG_OK; } @@ -255,7 +266,9 @@ SlangResult MemoryFileSystem::_requireFile(const char* path, Entry** outEntry) } // It must be found and be a file - SLANG_ASSERT(foundEntry && foundEntry->m_type == SLANG_PATH_TYPE_FILE && foundEntry->m_canonicalPath == canonicalPath); + SLANG_ASSERT( + foundEntry && foundEntry->m_type == SLANG_PATH_TYPE_FILE && + foundEntry->m_canonicalPath == canonicalPath); *outEntry = foundEntry; return SLANG_OK; diff --git a/source/core/slang-memory-file-system.h b/source/core/slang-memory-file-system.h index 321f7fe74..ebf6e239a 100644 --- a/source/core/slang-memory-file-system.h +++ b/source/core/slang-memory-file-system.h @@ -2,66 +2,81 @@ #define SLANG_CORE_MEMORY_FILE_SYSTEM_H #include "slang-basic.h" - -#include "slang-com-ptr.h" #include "slang-com-object.h" +#include "slang-com-ptr.h" namespace Slang { -/* MemoryFileSystem is an implementation of ISlangMutableFileSystem that stores file contents in 'blobs' (typically) in memory. +/* MemoryFileSystem is an implementation of ISlangMutableFileSystem that stores file contents in +'blobs' (typically) in memory. -A derived class can change how the contents of the contents blob is interpretted (so for example the RiffFileSystem is implemented -such that the Entry.m_contents is the files contents compressed). +A derived class can change how the contents of the contents blob is interpretted (so for example the +RiffFileSystem is implemented such that the Entry.m_contents is the files contents compressed). -The implementation uses a map to store the file/directory based on their canonical path. This makes access relatively fast and simple - -an access only requires a path being converted into a canonical path, and then a lookup. Whilst this makes typical access fast, it means -doing an enumeration of a directory slower as it requires traversing all entries to find which are in the path. +The implementation uses a map to store the file/directory based on their canonical path. This makes +access relatively fast and simple - an access only requires a path being converted into a canonical +path, and then a lookup. Whilst this makes typical access fast, it means doing an enumeration of a +directory slower as it requires traversing all entries to find which are in the path. -This is in contrast with an implementation that held items in directories 'objects'. In that scenario the path through the hierarchy -would need to be traversed to find the item. Finding all of the items in a directory is very fast - it's all the items held -in the the directory 'object'. +This is in contrast with an implementation that held items in directories 'objects'. In that +scenario the path through the hierarchy would need to be traversed to find the item. Finding all of +the items in a directory is very fast - it's all the items held in the the directory 'object'. TODO(JS): -* We may want to make saveFile take a blob, or have a version that does. Doing so would allow the application to handle memory management -around the blob. +* We may want to make saveFile take a blob, or have a version that does. Doing so would allow the +application to handle memory management around the blob. */ class MemoryFileSystem : public ISlangMutableFileSystem, public ComBaseObject { public: - - // ISlangUnknown + // ISlangUnknown SLANG_COM_BASE_IUNKNOWN_ALL // ISlangCastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // ISlangFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) + SLANG_OVERRIDE; // ISlangFileSystemExt - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE {} - virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE; - virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE { return OSPathKind::None; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) SLANG_OVERRIDE; + virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE + { + return OSPathKind::None; + } // ISlangModifyableFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE; - /// Ctor + /// Ctor MemoryFileSystem(); protected: - struct Entry { - void reset() + void reset() { m_type = SLANG_PATH_TYPE_FILE; m_canonicalPath = String(); @@ -100,10 +115,10 @@ protected: SlangPathType m_type; String m_canonicalPath; - /// The size as seen on the file system. Might be different from the size of m_contents + /// The size as seen on the file system. Might be different from the size of m_contents /// if it's actually being stored in some other representation (such as compressed) - size_t m_uncompressedSizeInBytes; - ComPtr<ISlangBlob> m_contents; ///< Can be compressed or not + size_t m_uncompressedSizeInBytes; + ComPtr<ISlangBlob> m_contents; ///< Can be compressed or not }; void* getInterface(const Guid& guid); @@ -111,28 +126,28 @@ protected: Entry* _getEntryFromPath(const char* path, String* outPath = nullptr); Entry* _getEntryFromCanonicalPath(const String& canonicalPath); - /// Creates or returns a file entry for the given path. - /// If created the entry is empty. + /// Creates or returns a file entry for the given path. + /// If created the entry is empty. SlangResult _requireFile(const char* path, Entry** outEntry); - /// Given the path returns the entry if it's a file, or returns an error + /// Given the path returns the entry if it's a file, or returns an error SlangResult _loadFile(const char* path, Entry** outEntry); - /// Given a path returns a canonical path. - /// The canonical path must have *existing* parent paths. + /// Given a path returns a canonical path. + /// The canonical path must have *existing* parent paths. SlangResult _getCanonicalWithExistingParent(const char* path, StringBuilder& canonicalPath); - /// Given a path returns a canonical path. + /// Given a path returns a canonical path. SlangResult _getCanonical(const char* path, StringBuilder& canonicalPath); - /// Clear, ensures any backing memory is also freed + /// Clear, ensures any backing memory is also freed void _clear(); // Maps canonical paths to an entries (which could be files or directories) Dictionary<String, Entry> m_entries; - Entry m_rootEntry; + Entry m_rootEntry; }; -} +} // namespace Slang #endif diff --git a/source/core/slang-name-value.cpp b/source/core/slang-name-value.cpp index 5418043f5..9e1bf9ce1 100644 --- a/source/core/slang-name-value.cpp +++ b/source/core/slang-name-value.cpp @@ -2,12 +2,16 @@ #include "slang-name-value.h" -#include "slang-string-util.h" #include "slang-char-util.h" +#include "slang-string-util.h" -namespace Slang { +namespace Slang +{ -/* static */ValueInt NameValueUtil::findValue(const ConstArrayView<NameValue>& opts, const UnownedStringSlice& slice, ValueInt defaultValue) +/* static */ ValueInt NameValueUtil::findValue( + const ConstArrayView<NameValue>& opts, + const UnownedStringSlice& slice, + ValueInt defaultValue) { for (const auto& opt : opts) { @@ -19,7 +23,10 @@ namespace Slang { return defaultValue; } -/* static */ValueInt NameValueUtil::findValue(const ConstArrayView<NamesValue>& opts, const UnownedStringSlice& slice, ValueInt defaultValue) +/* static */ ValueInt NameValueUtil::findValue( + const ConstArrayView<NamesValue>& opts, + const UnownedStringSlice& slice, + ValueInt defaultValue) { for (const auto& opt : opts) { @@ -33,7 +40,10 @@ namespace Slang { return defaultValue; } -/* static */ValueInt NameValueUtil::findValue(const ConstArrayView<NamesDescriptionValue>& opts, const UnownedStringSlice& slice, ValueInt defaultValue) +/* static */ ValueInt NameValueUtil::findValue( + const ConstArrayView<NamesDescriptionValue>& opts, + const UnownedStringSlice& slice, + ValueInt defaultValue) { for (const auto& opt : opts) { @@ -46,7 +56,10 @@ namespace Slang { return defaultValue; } -/* static */ UnownedStringSlice NameValueUtil::findName(const ConstArrayView<NameValue>& opts, ValueInt value, const UnownedStringSlice& defaultName) +/* static */ UnownedStringSlice NameValueUtil::findName( + const ConstArrayView<NameValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultName) { for (const auto& opt : opts) { @@ -58,7 +71,10 @@ namespace Slang { return defaultName; } -/* static */ UnownedStringSlice NameValueUtil::findName(const ConstArrayView<NamesValue>& opts, ValueInt value, const UnownedStringSlice& defaultName) +/* static */ UnownedStringSlice NameValueUtil::findName( + const ConstArrayView<NamesValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultName) { for (const auto& opt : opts) { @@ -72,7 +88,10 @@ namespace Slang { return defaultName; } -/* static */ UnownedStringSlice NameValueUtil::findName(const ConstArrayView<NamesDescriptionValue>& opts, ValueInt value, const UnownedStringSlice& defaultName) +/* static */ UnownedStringSlice NameValueUtil::findName( + const ConstArrayView<NamesDescriptionValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultName) { for (const auto& opt : opts) { @@ -87,7 +106,10 @@ namespace Slang { } -/* static */UnownedStringSlice NameValueUtil::findDescription(const ConstArrayView<NamesDescriptionValue>& opts, ValueInt value, const UnownedStringSlice& defaultDescription) +/* static */ UnownedStringSlice NameValueUtil::findDescription( + const ConstArrayView<NamesDescriptionValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultDescription) { for (const auto& opt : opts) { @@ -100,7 +122,10 @@ namespace Slang { return defaultDescription; } -/* static */ void NameValueUtil::appendNames(NameKind kind, const ConstArrayView<NameValue>& opts, List<UnownedStringSlice>& out) +/* static */ void NameValueUtil::appendNames( + NameKind kind, + const ConstArrayView<NameValue>& opts, + List<UnownedStringSlice>& out) { SLANG_UNUSED(kind); for (auto& opt : opts) @@ -109,7 +134,10 @@ namespace Slang { } } -static void _appendNames(NameValueUtil::NameKind kind, const char* names, List<UnownedStringSlice>& out) +static void _appendNames( + NameValueUtil::NameKind kind, + const char* names, + List<UnownedStringSlice>& out) { if (kind == NameValueUtil::NameKind::All) { @@ -121,7 +149,10 @@ static void _appendNames(NameValueUtil::NameKind kind, const char* names, List<U } } -/* static */ void NameValueUtil::appendNames(NameKind kind, const ConstArrayView<NamesValue>& opts, List<UnownedStringSlice>& out) +/* static */ void NameValueUtil::appendNames( + NameKind kind, + const ConstArrayView<NamesValue>& opts, + List<UnownedStringSlice>& out) { for (auto& opt : opts) { @@ -129,7 +160,10 @@ static void _appendNames(NameValueUtil::NameKind kind, const char* names, List<U } } -/* static */ void NameValueUtil::appendNames(NameKind kind, const ConstArrayView<NamesDescriptionValue>& opts, List<UnownedStringSlice>& out) +/* static */ void NameValueUtil::appendNames( + NameKind kind, + const ConstArrayView<NamesDescriptionValue>& opts, + List<UnownedStringSlice>& out) { for (auto& opt : opts) { @@ -137,21 +171,27 @@ static void _appendNames(NameValueUtil::NameKind kind, const char* names, List<U } } -/* static */ List<UnownedStringSlice> NameValueUtil::getNames(NameKind kind, const ConstArrayView<NameValue>& opts) +/* static */ List<UnownedStringSlice> NameValueUtil::getNames( + NameKind kind, + const ConstArrayView<NameValue>& opts) { List<UnownedStringSlice> names; appendNames(kind, opts, names); return names; } -/* static */ List<UnownedStringSlice> NameValueUtil::getNames(NameKind kind, const ConstArrayView<NamesValue>& opts) +/* static */ List<UnownedStringSlice> NameValueUtil::getNames( + NameKind kind, + const ConstArrayView<NamesValue>& opts) { List<UnownedStringSlice> names; appendNames(kind, opts, names); return names; } -/* static */ List<UnownedStringSlice> NameValueUtil::getNames(NameKind kind, const ConstArrayView<NamesDescriptionValue>& opts) +/* static */ List<UnownedStringSlice> NameValueUtil::getNames( + NameKind kind, + const ConstArrayView<NamesDescriptionValue>& opts) { List<UnownedStringSlice> names; appendNames(kind, opts, names); @@ -159,5 +199,3 @@ static void _appendNames(NameValueUtil::NameKind kind, const char* names, List<U } } // namespace Slang - - diff --git a/source/core/slang-name-value.h b/source/core/slang-name-value.h index a50e149a8..5062f2c45 100644 --- a/source/core/slang-name-value.h +++ b/source/core/slang-name-value.h @@ -1,9 +1,8 @@ #ifndef SLANG_CORE_NAME_VALUE_H #define SLANG_CORE_NAME_VALUE_H -#include "slang-basic.h" - #include "slang-array-view.h" +#include "slang-basic.h" namespace Slang { @@ -20,57 +19,107 @@ struct NameValue struct NamesValue { ValueInt value; - const char* names; ///< Can hold comma delimited list of names - + const char* names; ///< Can hold comma delimited list of names }; struct NamesDescriptionValue { ValueInt value; - const char* names; ///< Can hold comma delimited list of names - const char* description; ///< Optional description, can hold null ptr or empty string if not defined + const char* names; ///< Can hold comma delimited list of names + const char* + description; ///< Optional description, can hold null ptr or empty string if not defined }; struct NameValueUtil { enum class NameKind { - First, ///< Only the first name if there is more than one - All, ///< All valid associated names + First, ///< Only the first name if there is more than one + All, ///< All valid associated names }; - /// Use the default type to infer the actual type desired - template <typename T> - static T findValue(const ConstArrayView<NameValue>& opts, const UnownedStringSlice& slice, T defaultValue) { return (T)findValue(opts, slice, ValueInt(defaultValue)); } - template <typename T> - static T findValue(const ConstArrayView<NamesValue>& opts, const UnownedStringSlice& slice, T defaultValue) { return (T)findValue(opts, slice, ValueInt(defaultValue)); } - template <typename T> - static T findValue(const ConstArrayView<NamesDescriptionValue>& opts, const UnownedStringSlice& slice, T defaultValue) { return (T)findValue(opts, slice, ValueInt(defaultValue)); } + /// Use the default type to infer the actual type desired + template<typename T> + static T findValue( + const ConstArrayView<NameValue>& opts, + const UnownedStringSlice& slice, + T defaultValue) + { + return (T)findValue(opts, slice, ValueInt(defaultValue)); + } + template<typename T> + static T findValue( + const ConstArrayView<NamesValue>& opts, + const UnownedStringSlice& slice, + T defaultValue) + { + return (T)findValue(opts, slice, ValueInt(defaultValue)); + } + template<typename T> + static T findValue( + const ConstArrayView<NamesDescriptionValue>& opts, + const UnownedStringSlice& slice, + T defaultValue) + { + return (T)findValue(opts, slice, ValueInt(defaultValue)); + } - /// Given a slice finds the associated value. If no entry is found, defaultValue is returned - static ValueInt findValue(const ConstArrayView<NameValue>& opts, const UnownedStringSlice& slice, ValueInt defaultValue = -1); - static ValueInt findValue(const ConstArrayView<NamesValue>& opts, const UnownedStringSlice& slice, ValueInt defaultValue = -1); - static ValueInt findValue(const ConstArrayView<NamesDescriptionValue>& opts, const UnownedStringSlice& slice, ValueInt defaultValue = -1); + /// Given a slice finds the associated value. If no entry is found, defaultValue is returned + static ValueInt findValue( + const ConstArrayView<NameValue>& opts, + const UnownedStringSlice& slice, + ValueInt defaultValue = -1); + static ValueInt findValue( + const ConstArrayView<NamesValue>& opts, + const UnownedStringSlice& slice, + ValueInt defaultValue = -1); + static ValueInt findValue( + const ConstArrayView<NamesDescriptionValue>& opts, + const UnownedStringSlice& slice, + ValueInt defaultValue = -1); - /// Given a value find the name. If there are multiple names, returns the first name - static UnownedStringSlice findName(const ConstArrayView<NameValue>& opts, ValueInt value, const UnownedStringSlice& defaultName = UnownedStringSlice()); - static UnownedStringSlice findName(const ConstArrayView<NamesValue>& opts, ValueInt value, const UnownedStringSlice& defaultName = UnownedStringSlice()); - static UnownedStringSlice findName(const ConstArrayView<NamesDescriptionValue>& opts, ValueInt value, const UnownedStringSlice& defaultName = UnownedStringSlice()); + /// Given a value find the name. If there are multiple names, returns the first name + static UnownedStringSlice findName( + const ConstArrayView<NameValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultName = UnownedStringSlice()); + static UnownedStringSlice findName( + const ConstArrayView<NamesValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultName = UnownedStringSlice()); + static UnownedStringSlice findName( + const ConstArrayView<NamesDescriptionValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultName = UnownedStringSlice()); - /// Append all the names from opts to out - static void appendNames(NameKind kind, const ConstArrayView<NameValue>& opts, List<UnownedStringSlice>& out); - static void appendNames(NameKind kind, const ConstArrayView<NamesValue>& opts, List<UnownedStringSlice>& out); - static void appendNames(NameKind kind, const ConstArrayView<NamesDescriptionValue>& opts, List<UnownedStringSlice>& out); + /// Append all the names from opts to out + static void appendNames( + NameKind kind, + const ConstArrayView<NameValue>& opts, + List<UnownedStringSlice>& out); + static void appendNames( + NameKind kind, + const ConstArrayView<NamesValue>& opts, + List<UnownedStringSlice>& out); + static void appendNames( + NameKind kind, + const ConstArrayView<NamesDescriptionValue>& opts, + List<UnownedStringSlice>& out); - /// Return the list of all valid names + /// Return the list of all valid names static List<UnownedStringSlice> getNames(NameKind kind, const ConstArrayView<NameValue>& opts); static List<UnownedStringSlice> getNames(NameKind kind, const ConstArrayView<NamesValue>& opts); - static List<UnownedStringSlice> getNames(NameKind kind, const ConstArrayView<NamesDescriptionValue>& opts); - - /// Get the description - static UnownedStringSlice findDescription(const ConstArrayView<NamesDescriptionValue>& opts, ValueInt value, const UnownedStringSlice& defaultDescription = UnownedStringSlice()); + static List<UnownedStringSlice> getNames( + NameKind kind, + const ConstArrayView<NamesDescriptionValue>& opts); + + /// Get the description + static UnownedStringSlice findDescription( + const ConstArrayView<NamesDescriptionValue>& opts, + ValueInt value, + const UnownedStringSlice& defaultDescription = UnownedStringSlice()); }; } // namespace Slang -#endif +#endif diff --git a/source/core/slang-offset-container.cpp b/source/core/slang-offset-container.cpp index 75852c990..c216b704d 100644 --- a/source/core/slang-offset-container.cpp +++ b/source/core/slang-offset-container.cpp @@ -1,7 +1,8 @@ // slang-offset-container.cpp #include "slang-offset-container.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OffsetString !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -22,14 +23,14 @@ size_t OffsetString::calcEncodedSize(size_t size, uint8_t encode[kMaxSizeEncodeS num++; } - // It might be one byte past the front, if its < 0x100 but greater than kSizeBase + // It might be one byte past the front, if its < 0x100 but greater than kSizeBase SLANG_ASSERT(num >= 1); encode[0] = uint8_t(kSizeBase + num); return num + 1; } -/* static */const char* OffsetString::decodeSize(const char* in, size_t& outSize) +/* static */ const char* OffsetString::decodeSize(const char* in, size_t& outSize) { const uint8_t* cur = (const uint8_t*)in; if (*cur <= kSizeBase) @@ -41,27 +42,28 @@ size_t OffsetString::calcEncodedSize(size_t size, uint8_t encode[kMaxSizeEncodeS int numBytes = *cur - kSizeBase; switch (numBytes) { - case 1: + case 1: { outSize = cur[1]; return in + 2; } - case 2: + case 2: { outSize = cur[1] | (uint32_t(cur[2]) << 8); return in + 3; } - case 3: + case 3: { outSize = cur[1] | (uint32_t(cur[2]) << 8) | (uint32_t(cur[3]) << 16); return in + 4; } - case 4: + case 4: { - outSize = cur[1] | (uint32_t(cur[2]) << 8) | (uint32_t(cur[3]) << 16) | (uint32_t(cur[4]) << 24); + outSize = cur[1] | (uint32_t(cur[2]) << 8) | (uint32_t(cur[3]) << 16) | + (uint32_t(cur[4]) << 24); return in + 5; } - default: + default: { outSize = 0; return nullptr; @@ -69,7 +71,7 @@ size_t OffsetString::calcEncodedSize(size_t size, uint8_t encode[kMaxSizeEncodeS } } -/* static */size_t OffsetString::calcAllocationSize(size_t stringSize) +/* static */ size_t OffsetString::calcAllocationSize(size_t stringSize) { uint8_t encode[kMaxSizeEncodeSize]; size_t encodeSize = calcEncodedSize(stringSize, encode); @@ -77,7 +79,7 @@ size_t OffsetString::calcEncodedSize(size_t size, uint8_t encode[kMaxSizeEncodeS return encodeSize + stringSize + 1; } -/* static */size_t OffsetString::calcAllocationSize(const UnownedStringSlice& slice) +/* static */ size_t OffsetString::calcAllocationSize(const UnownedStringSlice& slice) { return calcAllocationSize(slice.getLength()); } @@ -95,14 +97,15 @@ const char* OffsetString::getCstr() const return getSlice().begin(); } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OffsetContainer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OffsetContainer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ OffsetContainer::OffsetContainer() { m_capacity = 0; m_data = nullptr; - // We need to allocate some of the first bytes 0 can be used for nullptr. + // We need to allocate some of the first bytes 0 can be used for nullptr. allocateAndZero(kStartOffset, 1); } @@ -174,7 +177,7 @@ Offset32Ptr<OffsetString> OffsetContainer::newString(const UnownedStringSlice& s size_t allocSize = headSize + stringSize + 1; uint8_t* bytes = (uint8_t*)allocate(allocSize); - ::memcpy(bytes, head, headSize); + ::memcpy(bytes, head, headSize); ::memcpy(bytes + headSize, slice.begin(), stringSize); // 0 terminate diff --git a/source/core/slang-offset-container.h b/source/core/slang-offset-container.h index 95c3a6589..4e6920bed 100644 --- a/source/core/slang-offset-container.h +++ b/source/core/slang-offset-container.h @@ -4,54 +4,62 @@ #include "slang-basic.h" -namespace Slang { +namespace Slang +{ /* -The purpose of OffsetContainer and related types is to provide a mechanism to easily serialize offset structures. +The purpose of OffsetContainer and related types is to provide a mechanism to easily serialize +offset structures. -The root idea here is the "offset pointer". A typical pointer in a language like C/C++ holds the absolute address -in the current address space of the thing that is being pointed to. This introduces a problem, as when data is -serialized in the contents will very likely be be placed at different addresses - meaning any absolute pointer -will point to the wrong place. There is also a related issue around pointer sizes - on some targets they are 32 bits -and on others 64 bits. +The root idea here is the "offset pointer". A typical pointer in a language like C/C++ holds the +absolute address in the current address space of the thing that is being pointed to. This introduces +a problem, as when data is serialized in the contents will very likely be be placed at different +addresses - meaning any absolute pointer will point to the wrong place. There is also a related +issue around pointer sizes - on some targets they are 32 bits and on others 64 bits. -An offset pointer means a pointer that points to something 'offset' to some base address. The OffsetPtr uses a 32 bit -offset from the pointers location in memory. This means such a pointer can address a 4Gb address space. +An offset pointer means a pointer that points to something 'offset' to some base address. The +OffsetPtr uses a 32 bit offset from the pointers location in memory. This means such a pointer can +address a 4Gb address space. -Special care is needed when using offset pointers - both when constructing structures that contain them, reading -them and in general usage. +Special care is needed when using offset pointers - both when constructing structures that contain +them, reading them and in general usage. -For simplicity here we store all offset pointers within a single contiguous allocation. This allocation is -typically managed by the OffsetContainer for writing. When reading a MemoryOffsetBase can be used. +For simplicity here we store all offset pointers within a single contiguous allocation. This +allocation is typically managed by the OffsetContainer for writing. When reading a MemoryOffsetBase +can be used. -An issue around using offset pointers, is that we cannot directly access it's contents, because it's just an -offset to some base address. Thus to access the thing being pointed to we need to turn the offset pointer back into -a 'raw' pointer. This is achieved via using the asRaw methods on the OffsetBase. For a convenience operator[] can also -be used, and this is typically the preferred mechanism. +An issue around using offset pointers, is that we cannot directly access it's contents, because it's +just an offset to some base address. Thus to access the thing being pointed to we need to turn the +offset pointer back into a 'raw' pointer. This is achieved via using the asRaw methods on the +OffsetBase. For a convenience operator[] can also be used, and this is typically the preferred +mechanism. -NOTE! That the evaluation order of a function calls parameters is undefined in C++. That whilst it might appear doing +NOTE! That the evaluation order of a function calls parameters is undefined in C++. That whilst it +might appear doing ``` base[thing] = container.newObject<Thing>(); ``` -will evaluate the construction of newObject *before* the assignment, if you look at the assignment as being a function call -(as it is when it is overloaded), then base[thing] might be evaluated *before* newObject, and if it is then the result -could be wrong if the newObject needed to reallocate. Therefore when allocation is involved, a new (or any allocation backed -function call from the OffsetContainer) should always place a result in a local variable. Then assign as in +will evaluate the construction of newObject *before* the assignment, if you look at the assignment +as being a function call (as it is when it is overloaded), then base[thing] might be evaluated +*before* newObject, and if it is then the result could be wrong if the newObject needed to +reallocate. Therefore when allocation is involved, a new (or any allocation backed function call +from the OffsetContainer) should always place a result in a local variable. Then assign as in ``` auto anotherThing = container.newObject<Thing>(); -base[thing] = anotherThing; +base[thing] = anotherThing; ``` -When creating structures - unless you know the allocated space (in the OffsetContainer or some other piece of memory) -is larger than required, then special care is needed, because when a new larger piece of memory is allocated to hold -everything, raw pointers pointers will likely be invalidated. When reading there is typically no need to move -the base address, so raw pointers remain valid through out. When doing writing if a call is made to something that -allocates memory on the OffsetContainer - any raw pointer should be assumed invalid. +When creating structures - unless you know the allocated space (in the OffsetContainer or some other +piece of memory) is larger than required, then special care is needed, because when a new larger +piece of memory is allocated to hold everything, raw pointers pointers will likely be invalidated. +When reading there is typically no need to move the base address, so raw pointers remain valid +through out. When doing writing if a call is made to something that allocates memory on the +OffsetContainer - any raw pointer should be assumed invalid. -For example +For example ``` @@ -83,7 +91,7 @@ void func() // Or more perhaps slightly more conveniently [] auto rawThing = base[thing]; - + // We can write and read things via the Safe32Ptr rawThing->value = 10; const int value = rawThing->value; @@ -93,18 +101,18 @@ void func() // Now lets write to it { - // We can have raw pointer (or reference) to a thing but we need to be *careful* if we allocate - Thing* rawThing = base[thing]; - // We are okay here, nothing between getting the raw pointer and the write allocated/newed anything on the OffsetContainer - rawThing->value = 20; + // We can have raw pointer (or reference) to a thing but we need to be *careful* if we +allocate Thing* rawThing = base[thing]; + // We are okay here, nothing between getting the raw pointer and the write allocated/newed +anything on the OffsetContainer rawThing->value = 20; - // Lets set up name + // Lets set up name Offset32Ptr<OffsetString> text = offsetContainer.newString("Hello World!"); - // BAD! The rawThing point could now be invalid because the call to newString may have had to allocate more memory - rawThing->text = text; + // BAD! The rawThing point could now be invalid because the call to newString may have had +to allocate more memory rawThing->text = text; - // This is okay + // This is okay base[thing]->text = text; // Or we can update rawThing such that is up to date @@ -112,10 +120,12 @@ void func() // So now this is okay again rawThing->text = text; - // BAD! we don't know the evaluation order here, if the lhs is evaluate before the rhs, then it could write to the wrong area of memory. - base[thing]->text = offsetContainer.newString("Hello World again!"); + // BAD! we don't know the evaluation order here, if the lhs is evaluate before the rhs, then +it could write to the wrong area of memory. base[thing]->text = offsetContainer.newString("Hello +World again!"); - // So where there is allocation, and assignment to something that in held in offset ptr use a local for the allocation as in + // So where there is allocation, and assignment to something that in held in offset ptr use +a local for the allocation as in { auto text = offsetContainer.newString("Hello World again!"); base[thing]->text = text; @@ -128,23 +138,27 @@ void func() enum { - kNull32Offset = 0, - kStartOffset = uint32_t(sizeof(uint64_t)), ///< The offset to the first contained thing + kNull32Offset = 0, + kStartOffset = uint32_t(sizeof(uint64_t)), ///< The offset to the first contained thing }; -template <typename T> +template<typename T> class Offset32Ref; /* A pointer to items held in OffsetContainer (or OffsetBase relative) that remains correct even if the memory inside OffsetContainer moves. */ -template <typename T> +template<typename T> class Offset32Ptr { public: typedef Offset32Ptr ThisType; - const ThisType& operator=(const ThisType& rhs) { m_offset = rhs.m_offset; return *this; } + const ThisType& operator=(const ThisType& rhs) + { + m_offset = rhs.m_offset; + return *this; + } bool operator==(const ThisType& rhs) const { return m_offset == rhs.m_offset; } bool operator!=(const ThisType& rhs) const { return m_offset != rhs.m_offset; } @@ -157,55 +171,99 @@ public: Offset32Ref<T> operator*(); - ThisType& operator++() { m_offset += uint32_t(sizeof(T)); return *this; } - ThisType operator++(int) { const auto offset = m_offset; m_offset += uint32_t(sizeof(T)); return ThisType(offset); } + ThisType& operator++() + { + m_offset += uint32_t(sizeof(T)); + return *this; + } + ThisType operator++(int) + { + const auto offset = m_offset; + m_offset += uint32_t(sizeof(T)); + return ThisType(offset); + } - ThisType& operator--() { m_offset -= sizeof(T); return *this; } - ThisType operator--(int) { const auto offset = m_offset; m_offset -= uint32_t(sizeof(T)); return ThisType(offset); } + ThisType& operator--() + { + m_offset -= sizeof(T); + return *this; + } + ThisType operator--(int) + { + const auto offset = m_offset; + m_offset -= uint32_t(sizeof(T)); + return ThisType(offset); + } - friend ThisType operator+(const ThisType& a, Index b) { return ThisType(a.m_offset + uint32_t(sizeof(T) * b)); } - friend ThisType operator+(Index a, const ThisType& b) { return ThisType(b.m_offset + uint32_t(sizeof(T) * a)); } + friend ThisType operator+(const ThisType& a, Index b) + { + return ThisType(a.m_offset + uint32_t(sizeof(T) * b)); + } + friend ThisType operator+(Index a, const ThisType& b) + { + return ThisType(b.m_offset + uint32_t(sizeof(T) * a)); + } bool isNull() const { return m_offset == kNull32Offset; } void setNull() { m_offset = kNull32Offset; } - Offset32Ptr():m_offset(kNull32Offset) {} - Offset32Ptr(const ThisType& rhs): m_offset(rhs.m_offset) {} - explicit Offset32Ptr(uint32_t offset): m_offset(offset) {} + Offset32Ptr() + : m_offset(kNull32Offset) + { + } + Offset32Ptr(const ThisType& rhs) + : m_offset(rhs.m_offset) + { + } + explicit Offset32Ptr(uint32_t offset) + : m_offset(offset) + { + } uint32_t m_offset; }; -/* A reference to items held in OffsetContainer (or OffsetBase relative) that remains correct even if -the memory inside OffsetContainer moves. +/* A reference to items held in OffsetContainer (or OffsetBase relative) that remains correct even +if the memory inside OffsetContainer moves. */ -template <typename T> +template<typename T> class Offset32Ref { public: typedef Offset32Ref ThisType; - const ThisType& operator=(const ThisType& rhs) { m_offset = rhs.m_offset; return *this; } + const ThisType& operator=(const ThisType& rhs) + { + m_offset = rhs.m_offset; + return *this; + } Offset32Ptr<T> operator&() { return Offset32Ptr<T>(m_offset); } - Offset32Ref(const ThisType& rhs) : m_offset(rhs.m_offset) {} - explicit Offset32Ref(uint32_t offset) : m_offset(offset) { SLANG_ASSERT(offset != kNull32Offset); } + Offset32Ref(const ThisType& rhs) + : m_offset(rhs.m_offset) + { + } + explicit Offset32Ref(uint32_t offset) + : m_offset(offset) + { + SLANG_ASSERT(offset != kNull32Offset); + } uint32_t m_offset; }; // --------------------------------------------------------------------------- -template <typename T> +template<typename T> SLANG_FORCE_INLINE Offset32Ref<T> Offset32Ptr<T>::operator*() { return Offset32Ref<T>(m_offset); } -/* Much like Offset32Ptr this is an array but whose memory is stored inside the OffsetContainer. This means elements types -must be 'offset types'. */ -template <typename T> +/* Much like Offset32Ptr this is an array but whose memory is stored inside the OffsetContainer. +This means elements types must be 'offset types'. */ +template<typename T> class Offset32Array { public: @@ -217,20 +275,34 @@ public: Index getCount() const { return Index(m_count); } - Offset32Ref<const T> operator[](Index i) const { SLANG_ASSERT(i >= 0 && uint32_t(i) < m_count); return Offset32Ref<const T>((m_data + i).m_offset); } - Offset32Ref<T> operator[](Index i) { SLANG_ASSERT(i >= 0 && uint32_t(i) < m_count); return Offset32Ref<T>((m_data + i).m_offset); } + Offset32Ref<const T> operator[](Index i) const + { + SLANG_ASSERT(i >= 0 && uint32_t(i) < m_count); + return Offset32Ref<const T>((m_data + i).m_offset); + } + Offset32Ref<T> operator[](Index i) + { + SLANG_ASSERT(i >= 0 && uint32_t(i) < m_count); + return Offset32Ref<T>((m_data + i).m_offset); + } - Offset32Array(Offset32Ptr<T> data, uint32_t count) :m_data(data), m_count(count) {} + Offset32Array(Offset32Ptr<T> data, uint32_t count) + : m_data(data), m_count(count) + { + } - Offset32Array() :m_count(0) {} + Offset32Array() + : m_count(0) + { + } Offset32Ptr<T> m_data; uint32_t m_count; }; -/** OffsetString is used for storing strings within a OffsetContainer. Strings are stored with the initial byte indicating the size -of the string. Note that all offset strings are stored with a terminating zero, and that the terminating zero is *NOT* included in -the encoded size. */ +/** OffsetString is used for storing strings within a OffsetContainer. Strings are stored with the +initial byte indicating the size of the string. Note that all offset strings are stored with a +terminating zero, and that the terminating zero is *NOT* included in the encoded size. */ struct OffsetString { enum @@ -239,51 +311,75 @@ struct OffsetString kMaxSizeEncodeSize = 5, }; - /// Get contents as a slice + /// Get contents as a slice UnownedStringSlice getSlice() const; - /// Get null terminated string + /// Get null terminated string const char* getCstr() const; - /// Decode the size. Returns the start of the string text, and outSize holds the size (NOT including terminating 0) + /// Decode the size. Returns the start of the string text, and outSize holds the size (NOT + /// including terminating 0) static const char* decodeSize(const char* in, size_t& outSize); - /// Returns the amount of bytes used, end encoding in 'encode' + /// Returns the amount of bytes used, end encoding in 'encode' static size_t calcEncodedSize(size_t size, uint8_t encode[kMaxSizeEncodeSize]); - /// Calculate the total size needed to store the string *including* terminating 0 + /// Calculate the total size needed to store the string *including* terminating 0 static size_t calcAllocationSize(const UnownedStringSlice& slice); - /// Calculate the total size needed to store string. Size should be passed *without* terminating 0 + /// Calculate the total size needed to store string. Size should be passed *without* terminating + /// 0 static size_t calcAllocationSize(size_t size); char m_sizeThenContents[1]; }; -/* A type that is used to hold the base address of the contiguous memory that holds either Offset32Ptr and related types> -*/ +/* A type that is used to hold the base address of the contiguous memory that holds either + * Offset32Ptr and related types> + */ class OffsetBase { public: typedef OffsetBase ThisType; - /// Turn an offset into a raw regular pointer or reference - template <typename T> - T* asRaw(const Offset32Ptr<T>& ptr) { return (T*)_getRaw(ptr.m_offset); } - template <typename T> - T& asRaw(const Offset32Ref<T>& ref) { return *(T*)_getRaw(ref.m_offset); } - - /// A more terse way to get a raw pointer/reference. Using the [] operator can be seen as 'indexing' to access the - /// object the offset relates to. Unlike 'indices' that are typically used with [] offsets are generally not contiguous. - template <typename T> - T* operator[](const Offset32Ptr<T>& ptr) { return (T*)_getRaw(ptr.m_offset); } - template <typename T> - T& operator[](const Offset32Ref<T>& ref) { return *(T*)_getRaw(ref.m_offset); } - - template <typename T> - Offset32Ptr<T> asPtr(T* ptr) { return Offset32Ptr<T>(getOffset(ptr)); } - /// Note the use of ptr when setting up a reference here - it's needed because a ref does not have to be backed by a pointer. - /// And commonly is not when the const& and the thing referenced can be held in a word. - template <typename T> - Offset32Ref<T> asRef(T* ptr) { SLANG_ASSERT(ptr); return Offset32Ref<T>(getOffset(ptr)); } + /// Turn an offset into a raw regular pointer or reference + template<typename T> + T* asRaw(const Offset32Ptr<T>& ptr) + { + return (T*)_getRaw(ptr.m_offset); + } + template<typename T> + T& asRaw(const Offset32Ref<T>& ref) + { + return *(T*)_getRaw(ref.m_offset); + } + + /// A more terse way to get a raw pointer/reference. Using the [] operator can be seen as + /// 'indexing' to access the object the offset relates to. Unlike 'indices' that are typically + /// used with [] offsets are generally not contiguous. + template<typename T> + T* operator[](const Offset32Ptr<T>& ptr) + { + return (T*)_getRaw(ptr.m_offset); + } + template<typename T> + T& operator[](const Offset32Ref<T>& ref) + { + return *(T*)_getRaw(ref.m_offset); + } + + template<typename T> + Offset32Ptr<T> asPtr(T* ptr) + { + return Offset32Ptr<T>(getOffset(ptr)); + } + /// Note the use of ptr when setting up a reference here - it's needed because a ref does not + /// have to be backed by a pointer. And commonly is not when the const& and the thing referenced + /// can be held in a word. + template<typename T> + Offset32Ref<T> asRef(T* ptr) + { + SLANG_ASSERT(ptr); + return Offset32Ref<T>(getOffset(ptr)); + } uint32_t getOffset(const void* ptr) { @@ -296,30 +392,31 @@ public: return uint32_t(diff); } - /// Get the contained data + /// Get the contained data SLANG_FORCE_INLINE uint8_t* getData() { return m_data; } - /// Return the last used byte of the data + /// Return the last used byte of the data SLANG_FORCE_INLINE size_t getDataCount() const { return m_dataSize; } - /// Get the first allocated thing. Typically the root of the structure contained - void* getFirst() { return (m_dataSize < kStartOffset) ? nullptr : (m_data + kStartOffset); } - - /// Get a raw pointer from the offset - uint8_t* _getRaw(uint32_t offset) { return (offset == kNull32Offset) ? nullptr : (m_data + offset); } + /// Get the first allocated thing. Typically the root of the structure contained + void* getFirst() { return (m_dataSize < kStartOffset) ? nullptr : (m_data + kStartOffset); } - OffsetBase(): - m_data(nullptr), - m_dataSize(0) + /// Get a raw pointer from the offset + uint8_t* _getRaw(uint32_t offset) { + return (offset == kNull32Offset) ? nullptr : (m_data + offset); } + OffsetBase() + : m_data(nullptr), m_dataSize(0) + { + } uint8_t* m_data; size_t m_dataSize; protected: - /// We want protected, because we don't want copies to be made of OffsetBase by default! + /// We want protected, because we don't want copies to be made of OffsetBase by default! OffsetBase(const ThisType& rhs) = default; ThisType& operator=(const ThisType& rhs) = default; }; @@ -334,17 +431,18 @@ public: } }; -/* OffsetContainer is a type designed to manage the construction structures around 'offset types'. In particular it allows -for construction of offset structures where their total encoded size is not known at the outset. +/* OffsetContainer is a type designed to manage the construction structures around 'offset types'. +In particular it allows for construction of offset structures where their total encoded size is not +known at the outset. -The main mechanism to make this work is via the use of OffsetXXX types, which when constructed from the OffsetContainer will -maintain valid values, even if the underlying backing memories location is changed. +The main mechanism to make this work is via the use of OffsetXXX types, which when constructed from +the OffsetContainer will maintain valid values, even if the underlying backing memories location is +changed. */ class OffsetContainer : public OffsetBase { public: - - template <typename T> + template<typename T> Offset32Ptr<T> newObject() { void* data = allocate(sizeof(T), SLANG_ALIGN_OF(T)); @@ -352,7 +450,7 @@ public: return Offset32Ptr<T>(getOffset(data)); } - template <typename T> + template<typename T> Offset32Array<T> newArray(size_t size) { if (size == 0) @@ -367,7 +465,7 @@ public: return Offset32Array<T>(Offset32Ptr<T>(getOffset(data)), uint32_t(size)); } - /// Get the base - which is needed for turning offsets into things + /// Get the base - which is needed for turning offsets into things OffsetBase& asBase() { return *this; } /// Allocate without alignment (effectively 1) @@ -380,7 +478,7 @@ public: Offset32Ptr<OffsetString> newString(const UnownedStringSlice& slice); Offset32Ptr<OffsetString> newString(const char* contents); - /// Ctor + /// Ctor OffsetContainer(); ~OffsetContainer(); diff --git a/source/core/slang-performance-profiler.cpp b/source/core/slang-performance-profiler.cpp index b272c9e17..9bc532680 100644 --- a/source/core/slang-performance-profiler.cpp +++ b/source/core/slang-performance-profiler.cpp @@ -1,122 +1,120 @@ #include "slang-performance-profiler.h" + #include "slang-dictionary.h" namespace Slang { - class PerformanceProfilerImpl : public PerformanceProfiler - { - public: - OrderedDictionary<const char*, FuncProfileInfo> data; +class PerformanceProfilerImpl : public PerformanceProfiler +{ +public: + OrderedDictionary<const char*, FuncProfileInfo> data; - virtual FuncProfileContext enterFunction(const char* funcName) override - { - auto entry = data.tryGetValue(funcName); - if (!entry) - { - data.add(funcName, FuncProfileInfo()); - entry = data.tryGetValue(funcName); - } - entry->invocationCount++; - FuncProfileContext ctx; - ctx.funcName = funcName; - ctx.startTime = std::chrono::high_resolution_clock::now(); - return ctx; - } - virtual void exitFunction(FuncProfileContext ctx) override - { - auto endTime = std::chrono::high_resolution_clock::now(); - auto duration = endTime - ctx.startTime; - auto entry = data.tryGetValue(ctx.funcName); - entry->duration += duration; - } - virtual void getResult(StringBuilder& out) override - { - char buffer[512]; - for (const auto& func : data) - { - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, sizeof(buffer), "[*] %30s", func.key); - out << buffer << " \t"; - auto milliseconds = std::chrono::duration_cast< std::chrono::milliseconds >(func.value.duration); - out << func.value.invocationCount << " \t" << static_cast<uint64_t>(milliseconds.count()) << "ms\n"; - } - } - virtual void clear() override + virtual FuncProfileContext enterFunction(const char* funcName) override + { + auto entry = data.tryGetValue(funcName); + if (!entry) { - data.clear(); + data.add(funcName, FuncProfileInfo()); + entry = data.tryGetValue(funcName); } - virtual void dispose() override + entry->invocationCount++; + FuncProfileContext ctx; + ctx.funcName = funcName; + ctx.startTime = std::chrono::high_resolution_clock::now(); + return ctx; + } + virtual void exitFunction(FuncProfileContext ctx) override + { + auto endTime = std::chrono::high_resolution_clock::now(); + auto duration = endTime - ctx.startTime; + auto entry = data.tryGetValue(ctx.funcName); + entry->duration += duration; + } + virtual void getResult(StringBuilder& out) override + { + char buffer[512]; + for (const auto& func : data) { - data = decltype(data)(); + memset(buffer, 0, sizeof(buffer)); + snprintf(buffer, sizeof(buffer), "[*] %30s", func.key); + out << buffer << " \t"; + auto milliseconds = + std::chrono::duration_cast<std::chrono::milliseconds>(func.value.duration); + out << func.value.invocationCount << " \t" + << static_cast<uint64_t>(milliseconds.count()) << "ms\n"; } - }; - - PerformanceProfiler* Slang::PerformanceProfiler::getProfiler() - { - thread_local static PerformanceProfilerImpl profiler = PerformanceProfilerImpl(); - return &profiler; } + virtual void clear() override { data.clear(); } + virtual void dispose() override { data = decltype(data)(); } +}; - SlangProfiler::SlangProfiler(PerformanceProfiler* profiler) - { - PerformanceProfilerImpl* profilerImpl = static_cast<PerformanceProfilerImpl*>(profiler); - size_t entryCount = profilerImpl->data.getCount(); +PerformanceProfiler* Slang::PerformanceProfiler::getProfiler() +{ + thread_local static PerformanceProfilerImpl profiler = PerformanceProfilerImpl(); + return &profiler; +} + +SlangProfiler::SlangProfiler(PerformanceProfiler* profiler) +{ + PerformanceProfilerImpl* profilerImpl = static_cast<PerformanceProfilerImpl*>(profiler); + size_t entryCount = profilerImpl->data.getCount(); + + m_profilEntries.reserve(entryCount); - m_profilEntries.reserve(entryCount); + int index = 0; + for (auto func : profilerImpl->data) + { + ProfileInfo profileEntry{}; + size_t strSize = std::min(sizeof(profileEntry.funcName) - 1, strlen(func.key)); - int index = 0; - for (auto func : profilerImpl->data) + if (strSize > 0) { - ProfileInfo profileEntry {}; - size_t strSize = std::min(sizeof(profileEntry.funcName) - 1, strlen(func.key)); - - if (strSize > 0) - { - memcpy(profileEntry.funcName, func.key, strSize); - } - profileEntry.invocationCount = func.value.invocationCount; - profileEntry.duration = func.value.duration; - - m_profilEntries.insert(index, profileEntry); - index++; + memcpy(profileEntry.funcName, func.key, strSize); } - } + profileEntry.invocationCount = func.value.invocationCount; + profileEntry.duration = func.value.duration; - ISlangUnknown* SlangProfiler::getInterface(const Guid& guid) - { - if(guid == SlangProfiler::getTypeGuid()) - return static_cast<ISlangUnknown*>(this); - else - return nullptr; + m_profilEntries.insert(index, profileEntry); + index++; } +} - size_t SlangProfiler::getEntryCount() - { - return m_profilEntries.getCount(); - } +ISlangUnknown* SlangProfiler::getInterface(const Guid& guid) +{ + if (guid == SlangProfiler::getTypeGuid()) + return static_cast<ISlangUnknown*>(this); + else + return nullptr; +} - const char* SlangProfiler::getEntryName(uint32_t index) - { - if (index >= (uint32_t)m_profilEntries.getCount()) - return nullptr; +size_t SlangProfiler::getEntryCount() +{ + return m_profilEntries.getCount(); +} - return m_profilEntries[index].funcName; - } +const char* SlangProfiler::getEntryName(uint32_t index) +{ + if (index >= (uint32_t)m_profilEntries.getCount()) + return nullptr; - long SlangProfiler::getEntryTimeMS(uint32_t index) - { - if (index >= (uint32_t)m_profilEntries.getCount()) - return 0; + return m_profilEntries[index].funcName; +} - auto milliseconds = std::chrono::duration_cast< std::chrono::milliseconds >(m_profilEntries[index].duration); - return (long)milliseconds.count(); - } +long SlangProfiler::getEntryTimeMS(uint32_t index) +{ + if (index >= (uint32_t)m_profilEntries.getCount()) + return 0; - uint32_t SlangProfiler::getEntryInvocationTimes(uint32_t index) - { - if (index >= (uint32_t)m_profilEntries.getCount()) - return 0; + auto milliseconds = + std::chrono::duration_cast<std::chrono::milliseconds>(m_profilEntries[index].duration); + return (long)milliseconds.count(); +} - return m_profilEntries[index].invocationCount; - } +uint32_t SlangProfiler::getEntryInvocationTimes(uint32_t index) +{ + if (index >= (uint32_t)m_profilEntries.getCount()) + return 0; + + return m_profilEntries[index].invocationCount; } +} // namespace Slang diff --git a/source/core/slang-performance-profiler.h b/source/core/slang-performance-profiler.h index 9895793c4..40ace4e6d 100644 --- a/source/core/slang-performance-profiler.h +++ b/source/core/slang-performance-profiler.h @@ -1,11 +1,12 @@ #ifndef SLANG_CORE_PERFORMANCE_PROFILER_H #define SLANG_CORE_PERFORMANCE_PROFILER_H +#include "../core/slang-list.h" +#include "slang-com-helper.h" #include "slang-string.h" + #include <chrono> #include <vector> -#include "slang-com-helper.h" -#include "../core/slang-list.h" namespace Slang { @@ -30,6 +31,7 @@ public: virtual void getResult(StringBuilder& out) = 0; virtual void clear() = 0; virtual void dispose() = 0; + public: static PerformanceProfiler* getProfiler(); }; @@ -47,7 +49,7 @@ struct PerformanceProfilerFuncRAIIContext } }; -struct SlangProfiler: public ISlangProfiler, public RefObject +struct SlangProfiler : public ISlangProfiler, public RefObject { public: SLANG_REF_OBJECT_IUNKNOWN_ALL @@ -57,20 +59,21 @@ public: int invocationCount = 0; std::chrono::nanoseconds duration = std::chrono::nanoseconds::zero(); }; - SlangProfiler(PerformanceProfiler * profiler); + SlangProfiler(PerformanceProfiler* profiler); ISlangUnknown* getInterface(const Guid& guid); virtual SLANG_NO_THROW size_t SLANG_MCALL getEntryCount() override; virtual SLANG_NO_THROW const char* SLANG_MCALL getEntryName(uint32_t index) override; virtual SLANG_NO_THROW long SLANG_MCALL getEntryTimeMS(uint32_t index) override; virtual SLANG_NO_THROW uint32_t SLANG_MCALL getEntryInvocationTimes(uint32_t index) override; + private: List<ProfileInfo> m_profilEntries; }; -#define SLANG_PROFILE PerformanceProfilerFuncRAIIContext _profileContext(__func__) +#define SLANG_PROFILE PerformanceProfilerFuncRAIIContext _profileContext(__func__) #define SLANG_PROFILE_SECTION(s) PerformanceProfilerFuncRAIIContext _profileContext##s(#s) -} +} // namespace Slang #endif diff --git a/source/core/slang-persistent-cache.cpp b/source/core/slang-persistent-cache.cpp index 2b4113e16..ca3400231 100644 --- a/source/core/slang-persistent-cache.cpp +++ b/source/core/slang-persistent-cache.cpp @@ -1,9 +1,9 @@ #include "slang-persistent-cache.h" +#include "../core/slang-blob.h" #include "../core/slang-io.h" #include "../core/slang-stream.h" #include "../core/slang-string-util.h" -#include "../core/slang-blob.h" namespace Slang { @@ -25,9 +25,7 @@ PersistentCache::PersistentCache(const Desc& desc) initialize(); } -PersistentCache::~PersistentCache() -{ -} +PersistentCache::~PersistentCache() {} SlangResult PersistentCache::clear() { @@ -46,13 +44,14 @@ SlangResult PersistentCache::clear() const String& lockFileName; Visitor(const String& directory, const String& lockFileName) - : directory(directory) - , lockFileName(lockFileName) - {} + : directory(directory), lockFileName(lockFileName) + { + } void accept(Path::Type type, const UnownedStringSlice& fileName) SLANG_OVERRIDE { - String fullPath = Path::simplify(directory + "/" + fileName);; + String fullPath = Path::simplify(directory + "/" + fileName); + ; if (type == Path::Type::File && lockFileName != fullPath) { Path::remove(fullPath); @@ -106,7 +105,8 @@ SlangResult PersistentCache::readEntry(const Key& key, ISlangBlob** outData) } // Find the entry. - Index entryIndex = cacheIndex.findFirstIndex([&key] (const CacheEntry& entry) { return entry.key == key; }); + Index entryIndex = + cacheIndex.findFirstIndex([&key](const CacheEntry& entry) { return entry.key == key; }); if (entryIndex == -1) { return SLANG_E_NOT_FOUND; @@ -171,7 +171,8 @@ SlangResult PersistentCache::writeEntry(const Key& key, ISlangBlob* data) // Write the cache entry. String entryFileName = getEntryFileName(key); - SLANG_RETURN_ON_FAIL(File::writeAllBytes(entryFileName, data->getBufferPointer(), data->getBufferSize())); + SLANG_RETURN_ON_FAIL( + File::writeAllBytes(entryFileName, data->getBufferPointer(), data->getBufferSize())); // Update the index. if (m_maxEntryCount > 0 && cacheIndex.getCount() >= m_maxEntryCount) @@ -179,12 +180,12 @@ SlangResult PersistentCache::writeEntry(const Key& key, ISlangBlob* data) // Replace oldest entry. SLANG_ASSERT(oldestEntryIndex >= 0); File::remove(getEntryFileName(cacheIndex[oldestEntryIndex].key)); - cacheIndex[oldestEntryIndex] = CacheEntry{ key, 0 }; + cacheIndex[oldestEntryIndex] = CacheEntry{key, 0}; } else { // Add new entry. - cacheIndex.add(CacheEntry{ key, 0 }); + cacheIndex.add(CacheEntry{key, 0}); } // Write the cache index. @@ -265,7 +266,7 @@ SlangResult PersistentCache::readIndex(const String& fileName, CacheIndex& outIn outIndex.setCount(header.count); SLANG_RETURN_ON_FAIL(fs.readExactly(outIndex.getBuffer(), header.count * sizeof(CacheEntry))); - + return SLANG_OK; } @@ -286,4 +287,4 @@ SlangResult PersistentCache::writeIndex(const String& fileName, const CacheIndex return SLANG_OK; } -} +} // namespace Slang diff --git a/source/core/slang-persistent-cache.h b/source/core/slang-persistent-cache.h index e7d02b861..9425bf7a2 100644 --- a/source/core/slang-persistent-cache.h +++ b/source/core/slang-persistent-cache.h @@ -18,7 +18,7 @@ class PersistentCache : public RefObject { public: struct Desc - { + { // The root directory for the cache. const char* directory = nullptr; // The maximum number of entries stored in the cache. By default, there is no limit. @@ -49,7 +49,7 @@ public: /// Read an entry from the cache. /// Returns SLANG_OK if successful, SLANG_E_NOT_FOUND if the entry is not in the cache. SlangResult readEntry(const Key& key, ISlangBlob** outData); - + /// Write an entry to the cache. /// Returns SLANG_OK if successful. SlangResult writeEntry(const Key& key, ISlangBlob* data); @@ -88,4 +88,4 @@ private: friend struct PersistentCacheTest; }; -} +} // namespace Slang diff --git a/source/core/slang-platform.cpp b/source/core/slang-platform.cpp index e84f9095f..ea8a2f4a5 100644 --- a/source/core/slang-platform.cpp +++ b/source/core/slang-platform.cpp @@ -8,24 +8,27 @@ #include "slang-io.h" #ifdef _WIN32 - #include <windows.h> +#include <windows.h> #else - #include "slang-string.h" - #include <dlfcn.h> +#include "slang-string.h" + +#include <dlfcn.h> #endif namespace Slang { - // SharedLibrary +// SharedLibrary -/* static */SlangResult SharedLibrary::load(const char* path, SharedLibrary::Handle& handleOut) +/* static */ SlangResult SharedLibrary::load(const char* path, SharedLibrary::Handle& handleOut) { StringBuilder builder; calcPlatformPath(UnownedStringSlice(path), builder); return loadWithPlatformPath(builder.begin(), handleOut); } -/* static */void SharedLibrary::calcPlatformPath(const UnownedStringSlice& path, StringBuilder& outPath) +/* static */ void SharedLibrary::calcPlatformPath( + const UnownedStringSlice& path, + StringBuilder& outPath) { // Work out the shared library name String parent = Path::getParentDirectory(path); @@ -37,15 +40,18 @@ namespace Slang StringBuilder platformFileNameBuilder; SharedLibrary::appendPlatformFileName(filename.getUnownedSlice(), platformFileNameBuilder); - Path::combineIntoBuilder(parent.getUnownedSlice(), platformFileNameBuilder.getUnownedSlice(), outPath); + Path::combineIntoBuilder( + parent.getUnownedSlice(), + platformFileNameBuilder.getUnownedSlice(), + outPath); } else if (filename.getLength() > 0) - { + { appendPlatformFileName(filename.getUnownedSlice(), outPath); } } -/* static */String SharedLibrary::calcPlatformPath(const UnownedStringSlice& path) +/* static */ String SharedLibrary::calcPlatformPath(const UnownedStringSlice& path) { StringBuilder builder; calcPlatformPath(path, builder); @@ -62,7 +68,7 @@ SLANG_COMPILE_TIME_ASSERT(E_NOTIMPL == SLANG_E_NOT_IMPLEMENTED); SLANG_COMPILE_TIME_ASSERT(E_INVALIDARG == SLANG_E_INVALID_ARG); SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); -/* static */SlangResult PlatformUtil::getInstancePath(StringBuilder& out) +/* static */ SlangResult PlatformUtil::getInstancePath(StringBuilder& out) { wchar_t path[_MAX_PATH]; ::GetModuleFileName(::GetModuleHandle(NULL), path, SLANG_COUNT_OF(path)); @@ -75,12 +81,13 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); return out.getLength() > 0 ? SLANG_OK : SLANG_FAIL; } -/* static */SlangResult PlatformUtil::appendResult(SlangResult res, StringBuilder& builderOut) +/* static */ SlangResult PlatformUtil::appendResult(SlangResult res, StringBuilder& builderOut) { if (SLANG_FAILED(res) && res != SLANG_FAIL) { LPWSTR buffer = nullptr; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language @@ -100,7 +107,9 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); return SLANG_FAIL; } -/* static */SlangResult SharedLibrary::loadWithPlatformPath(char const* platformFileName, SharedLibrary::Handle& handleOut) +/* static */ SlangResult SharedLibrary::loadWithPlatformPath( + char const* platformFileName, + SharedLibrary::Handle& handleOut) { handleOut = nullptr; if (!platformFileName || strlen(platformFileName) == 0) @@ -117,19 +126,19 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); const DWORD lastError = GetLastError(); switch (lastError) { - case ERROR_MOD_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - case ERROR_FILE_NOT_FOUND: + case ERROR_MOD_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_FILE_NOT_FOUND: { return SLANG_E_NOT_FOUND; } - case ERROR_INVALID_ACCESS: - case ERROR_ACCESS_DENIED: - case ERROR_INVALID_DATA: + case ERROR_INVALID_ACCESS: + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_DATA: { return SLANG_E_CANNOT_OPEN; } - default: break; + default: break; } // Turn to Result, if not one of the well known errors return HRESULT_FROM_WIN32(lastError); @@ -138,7 +147,7 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); return SLANG_OK; } -/* static */void SharedLibrary::unload(Handle handle) +/* static */ void SharedLibrary::unload(Handle handle) { SLANG_ASSERT(handle); ::FreeLibrary((HMODULE)handle); @@ -150,7 +159,9 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); return GetProcAddress((HMODULE)handle, name); } -/* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) +/* static */ void SharedLibrary::appendPlatformFileName( + const UnownedStringSlice& name, + StringBuilder& dst) { dst.append(name); dst.append(".dll"); @@ -158,19 +169,23 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); #else // _WIN32 -/* static */SlangResult PlatformUtil::getInstancePath([[maybe_unused]] StringBuilder& out) +/* static */ SlangResult PlatformUtil::getInstancePath([[maybe_unused]] StringBuilder& out) { // On non Windows it's typically hard to get the instance path, so we'll say not implemented. // The meaning is also somewhat more ambiguous - is it the exe or the shared library path? return SLANG_E_NOT_IMPLEMENTED; } -/* static */SlangResult PlatformUtil::appendResult([[maybe_unused]] SlangResult res, [[maybe_unused]] StringBuilder& builderOut) +/* static */ SlangResult PlatformUtil::appendResult( + [[maybe_unused]] SlangResult res, + [[maybe_unused]] StringBuilder& builderOut) { return SLANG_E_NOT_IMPLEMENTED; } -/* static */SlangResult SharedLibrary::loadWithPlatformPath(char const* platformFileName, Handle& handleOut) +/* static */ SlangResult SharedLibrary::loadWithPlatformPath( + char const* platformFileName, + Handle& handleOut) { handleOut = nullptr; // Work around @@ -180,9 +195,9 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); // closed const auto unclosableLibNames = {"libdxcompiler", "libdxvk_d3d11", "libdxvk_dxgi"}; bool isUnclosable = false; - for(auto n : unclosableLibNames) + for (auto n : unclosableLibNames) { - if(strncmp(platformFileName, n, strlen(n)) == 0) + if (strncmp(platformFileName, n, strlen(n)) == 0) { isUnclosable = true; break; @@ -191,7 +206,7 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); if (strlen(platformFileName) == 0) platformFileName = nullptr; const auto mode = RTLD_NOW | RTLD_GLOBAL | (isUnclosable ? RTLD_NODELETE : 0); - void *h = dlopen(platformFileName, mode); + void* h = dlopen(platformFileName, mode); if (!h) { #if 0 @@ -202,23 +217,25 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); } #endif return SLANG_FAIL; - } + } handleOut = (Handle)h; return SLANG_OK; } -/* static */void SharedLibrary::unload(Handle handle) -{ +/* static */ void SharedLibrary::unload(Handle handle) +{ SLANG_ASSERT(handle); - dlclose(handle); + dlclose(handle); } -/* static */void* SharedLibrary::findSymbolAddressByName(Handle handle, char const* name) +/* static */ void* SharedLibrary::findSymbolAddressByName(Handle handle, char const* name) { - return dlsym((void*)handle, name); + return dlsym((void*)handle, name); } -/* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) +/* static */ void SharedLibrary::appendPlatformFileName( + const UnownedStringSlice& name, + StringBuilder& dst) { #if __CYGWIN__ dst.append(name); @@ -242,7 +259,9 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); #endif // _WIN32 -/* static */SlangResult PlatformUtil::getEnvironmentVariable(const UnownedStringSlice& name, StringBuilder& out) +/* static */ SlangResult PlatformUtil::getEnvironmentVariable( + const UnownedStringSlice& name, + StringBuilder& out) { const char* value = getenv(String(name).getBuffer()); if (value) @@ -253,7 +272,7 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); return SLANG_E_NOT_FOUND; } -/* static */PlatformKind PlatformUtil::getPlatformKind() +/* static */ PlatformKind PlatformUtil::getPlatformKind() { #if SLANG_WINRT return PlatformKind::WinRT; @@ -286,22 +305,22 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY); #endif } -static const PlatformFlags s_familyFlags[int(PlatformFamily::CountOf)] = -{ - 0, // Unknown - PlatformFlag::WinRT | PlatformFlag::Win32 | PlatformFlag::Win64, // Windows - PlatformFlag::WinRT | PlatformFlag::Win32 | PlatformFlag::Win64 | PlatformFlag::X360 | PlatformFlag::XBoxOne, // Microsoft - PlatformFlag::Linux | PlatformFlag::Android, // Linux - PlatformFlag::IOS | PlatformFlag::OSX, // Apple - PlatformFlag::Linux | PlatformFlag::Android | PlatformFlag::IOS | PlatformFlag::OSX, // Unix +static const PlatformFlags s_familyFlags[int(PlatformFamily::CountOf)] = { + 0, // Unknown + PlatformFlag::WinRT | PlatformFlag::Win32 | PlatformFlag::Win64, // Windows + PlatformFlag::WinRT | PlatformFlag::Win32 | PlatformFlag::Win64 | PlatformFlag::X360 | + PlatformFlag::XBoxOne, // Microsoft + PlatformFlag::Linux | PlatformFlag::Android, // Linux + PlatformFlag::IOS | PlatformFlag::OSX, // Apple + PlatformFlag::Linux | PlatformFlag::Android | PlatformFlag::IOS | PlatformFlag::OSX, // Unix }; -/* static */PlatformFlags PlatformUtil::getPlatformFlags(PlatformFamily family) +/* static */ PlatformFlags PlatformUtil::getPlatformFlags(PlatformFamily family) { return s_familyFlags[int(family)]; } -/* static */SlangResult PlatformUtil::outputDebugMessage([[maybe_unused]] const char* text) +/* static */ SlangResult PlatformUtil::outputDebugMessage([[maybe_unused]] const char* text) { #ifdef _WIN32 OutputDebugStringA(text); @@ -311,4 +330,4 @@ static const PlatformFlags s_familyFlags[int(PlatformFamily::CountOf)] = #endif } -} +} // namespace Slang diff --git a/source/core/slang-platform.h b/source/core/slang-platform.h index 81bae88d6..0b97aca6d 100644 --- a/source/core/slang-platform.h +++ b/source/core/slang-platform.h @@ -7,150 +7,157 @@ namespace Slang { - enum class PlatformKind : uint8_t +enum class PlatformKind : uint8_t +{ + Unknown, + WinRT, + XBoxOne, + Win64, + Win32, + X360, + Android, + Linux, + IOS, + OSX, + PS3, + PS4, + PSP2, + WIIU, + CountOf, +}; + +typedef uint32_t PlatformFlags; +struct PlatformFlag +{ + enum Enum { - Unknown, - WinRT, - XBoxOne, - Win64, - Win32, - X360, - Android, - Linux, - IOS, - OSX, - PS3, - PS4, - PSP2, - WIIU, - CountOf, + Unknown = 1 << int(PlatformKind::Unknown), + WinRT = 1 << int(PlatformKind::WinRT), + XBoxOne = 1 << int(PlatformKind::XBoxOne), + Win64 = 1 << int(PlatformKind::Win64), + Win32 = 1 << int(PlatformKind::Win32), + X360 = 1 << int(PlatformKind::X360), + Android = 1 << int(PlatformKind::Android), + Linux = 1 << int(PlatformKind::Linux), + IOS = 1 << int(PlatformKind::IOS), + OSX = 1 << int(PlatformKind::OSX), + PS3 = 1 << int(PlatformKind::PS3), + PS4 = 1 << int(PlatformKind::PS4), + PSP2 = 1 << int(PlatformKind::PSP2), + WIIU = 1 << int(PlatformKind::WIIU), }; +}; - typedef uint32_t PlatformFlags; - struct PlatformFlag - { - enum Enum - { - Unknown = 1 << int(PlatformKind::Unknown), - WinRT = 1 << int(PlatformKind::WinRT), - XBoxOne = 1 << int(PlatformKind::XBoxOne), - Win64 = 1 << int(PlatformKind::Win64), - Win32 = 1 << int(PlatformKind::Win32), - X360 = 1 << int(PlatformKind::X360), - Android = 1 << int(PlatformKind::Android), - Linux = 1 << int(PlatformKind::Linux), - IOS = 1 << int(PlatformKind::IOS), - OSX = 1 << int(PlatformKind::OSX), - PS3 = 1 << int(PlatformKind::PS3), - PS4 = 1 << int(PlatformKind::PS4), - PSP2 = 1 << int(PlatformKind::PSP2), - WIIU = 1 << int(PlatformKind::WIIU), - }; - }; +enum class PlatformFamily : uint8_t +{ + Unknown, + Windows, + Microsoft, + Linux, + Apple, + Unix, + CountOf, +}; + +// Interface for working with shared libraries +// in a platform-independent fashion. +struct SharedLibrary +{ + typedef struct SharedLibraryImpl* Handle; + + typedef void (*FuncPtr)(void); + + /// Load via an unadorned path/filename. + /// + /// The unadorned path here means without a path without any platform specific filename + /// elements. This typically means no extension and no prefix. On windows this means without the + /// '.dll' extension. On linux this means without the 'lib' prefix and '.so' extension. To load + /// with a platform specific filename use the 'loadWithPlatformFilename' API Most platforms have + /// a built in mechanism to search for shared libraries, such that shared libraries are often + /// just passed by filename. + /// + /// @param the unadorned filename/path + /// @return Returns a non null handle for the shared library on success. nullptr indicated + /// failure + static SlangResult load(const char* path, Handle& handleOut); + + /// Attempt to load a shared library for + /// the current platform. Returns null handle on failure + /// The platform specific filename can be generated from a call to appendPlatformFileName + /// + /// @param platform the platform specific file name/ or path + /// @return Returns a non null handle for the shared library on success. nullptr indicated + /// failure + static SlangResult loadWithPlatformPath(char const* platformPath, Handle& handleOut); + + /// Unload the library that was returned from load as handle + /// @param The valid handle returned from load + static void unload(Handle handle); + + /// Given a shared library handle and a name, return the associated object + /// Return nullptr if object is not found + /// @param The shared library handle as returned by loadPlatformLibrary + static void* findSymbolAddressByName(Handle handle, char const* name); + + /// Append to the end of dst, the name, with any platform specific additions + /// The input name should be unadorned with any 'lib' prefix or extension + static void appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst); + + /// Given a path, calculate that path with the filename replaced with the platform filename + /// (using appendPlatformFilename) + static String calcPlatformPath(const UnownedStringSlice& path); + static void calcPlatformPath(const UnownedStringSlice& path, StringBuilder& outBuilder); + + +private: + /// Not constructible! + SharedLibrary(); +}; + +struct PlatformUtil +{ + /// Appends a text interpretation of a result (as defined by supporting OS) + /// @param res Result to produce a string for + /// @param builderOut Append the string produced to builderOut + /// @return SLANG_OK if string is found and appended. Fail otherwise. SLANG_E_NOT_IMPLEMENTED if + /// there is no impl for this platform. + static SlangResult appendResult(SlangResult res, StringBuilder& builderOut); - enum class PlatformFamily : uint8_t - { - Unknown, - Windows, - Microsoft, - Linux, - Apple, - Unix, - CountOf, - }; + /// Get the platform kind as determined at compile time + static PlatformKind getPlatformKind(); - // Interface for working with shared libraries - // in a platform-independent fashion. - struct SharedLibrary - { - typedef struct SharedLibraryImpl* Handle; - - typedef void(*FuncPtr)(void); - - /// Load via an unadorned path/filename. - /// - /// The unadorned path here means without a path without any platform specific filename elements. - /// This typically means no extension and no prefix. - /// On windows this means without the '.dll' extension. - /// On linux this means without the 'lib' prefix and '.so' extension. - /// To load with a platform specific filename use the 'loadWithPlatformFilename' API - /// Most platforms have a built in mechanism to search for shared libraries, such that - /// shared libraries are often just passed by filename. - /// - /// @param the unadorned filename/path - /// @return Returns a non null handle for the shared library on success. nullptr indicated failure - static SlangResult load(const char* path, Handle& handleOut); - - /// Attempt to load a shared library for - /// the current platform. Returns null handle on failure - /// The platform specific filename can be generated from a call to appendPlatformFileName - /// - /// @param platform the platform specific file name/ or path - /// @return Returns a non null handle for the shared library on success. nullptr indicated failure - static SlangResult loadWithPlatformPath(char const* platformPath, Handle& handleOut); - - /// Unload the library that was returned from load as handle - /// @param The valid handle returned from load - static void unload(Handle handle); - - /// Given a shared library handle and a name, return the associated object - /// Return nullptr if object is not found - /// @param The shared library handle as returned by loadPlatformLibrary - static void* findSymbolAddressByName(Handle handle, char const* name); - - /// Append to the end of dst, the name, with any platform specific additions - /// The input name should be unadorned with any 'lib' prefix or extension - static void appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst); - - /// Given a path, calculate that path with the filename replaced with the platform filename (using appendPlatformFilename) - static String calcPlatformPath(const UnownedStringSlice& path); - static void calcPlatformPath(const UnownedStringSlice& path, StringBuilder& outBuilder); - - - private: - /// Not constructible! - SharedLibrary(); - }; + /// Get the platforms that make up a family + static PlatformFlags getPlatformFlags(PlatformFamily family); - struct PlatformUtil + /// True if the kind is part of the family + static bool isFamily(PlatformFamily family, PlatformKind kind) { - /// Appends a text interpretation of a result (as defined by supporting OS) - /// @param res Result to produce a string for - /// @param builderOut Append the string produced to builderOut - /// @return SLANG_OK if string is found and appended. Fail otherwise. SLANG_E_NOT_IMPLEMENTED if there is no impl for this platform. - static SlangResult appendResult(SlangResult res, StringBuilder& builderOut); - - /// Get the platform kind as determined at compile time - static PlatformKind getPlatformKind(); - - /// Get the platforms that make up a family - static PlatformFlags getPlatformFlags(PlatformFamily family); - - /// True if the kind is part of the family - static bool isFamily(PlatformFamily family, PlatformKind kind) { return (getPlatformFlags(family) & (PlatformFlags(1) << int(kind))) != 0; } - - /// Given an environment name returns the set system variable. - /// Will return SLANG_E_NOT_FOUND if the variable is not set - static SlangResult getEnvironmentVariable(const UnownedStringSlice& name, StringBuilder& out); - - /// Get the path to this instance (the path to the dll/executable/shared library the call is in) - /// NOTE! This is not supported on all platforms, and will return SLANG_E_NOT_IMPLEMENTED in that scenario - static SlangResult getInstancePath(StringBuilder& out); - - /// Outputs message to a debug stream. Not all platforms support - /// this feature. - /// - /// @param text Text to be displayed in 'debugger output' - /// @return SLANG_E_NOT_AVAILABLE if not on this platform, and potentially other errors - static SlangResult outputDebugMessage(const char* text); - }; + return (getPlatformFlags(family) & (PlatformFlags(1) << int(kind))) != 0; + } + + /// Given an environment name returns the set system variable. + /// Will return SLANG_E_NOT_FOUND if the variable is not set + static SlangResult getEnvironmentVariable(const UnownedStringSlice& name, StringBuilder& out); + + /// Get the path to this instance (the path to the dll/executable/shared library the call is in) + /// NOTE! This is not supported on all platforms, and will return SLANG_E_NOT_IMPLEMENTED in + /// that scenario + static SlangResult getInstancePath(StringBuilder& out); + + /// Outputs message to a debug stream. Not all platforms support + /// this feature. + /// + /// @param text Text to be displayed in 'debugger output' + /// @return SLANG_E_NOT_AVAILABLE if not on this platform, and potentially other errors + static SlangResult outputDebugMessage(const char* text); +}; #ifndef _MSC_VER - #define _fileno fileno - #define _isatty isatty - #define _setmode setmode - #define _O_BINARY O_BINARY +#define _fileno fileno +#define _isatty isatty +#define _setmode setmode +#define _O_BINARY O_BINARY #endif -} +} // namespace Slang #endif diff --git a/source/core/slang-process-util.cpp b/source/core/slang-process-util.cpp index 47484156d..62cc4b1dc 100644 --- a/source/core/slang-process-util.cpp +++ b/source/core/slang-process-util.cpp @@ -2,15 +2,17 @@ #include "slang-process-util.h" -#include "slang-string.h" +#include "slang-com-helper.h" #include "slang-string-escape-util.h" #include "slang-string-util.h" +#include "slang-string.h" -#include "slang-com-helper.h" - -namespace Slang { +namespace Slang +{ -/* static */SlangResult ProcessUtil::execute(const CommandLine& commandLine, ExecuteResult& outExecuteResult) +/* static */ SlangResult ProcessUtil::execute( + const CommandLine& commandLine, + ExecuteResult& outExecuteResult) { RefPtr<Process> process; SLANG_RETURN_ON_FAIL(Process::create(commandLine, 0, process)); @@ -27,11 +29,15 @@ static Index _getCount(List<Byte>* buf) static String _getText(const ConstArrayView<Byte>& bytes) { StringBuilder buf; - StringUtil::appendStandardLines(UnownedStringSlice((const char*)bytes.begin(), (const char*)bytes.end()), buf); + StringUtil::appendStandardLines( + UnownedStringSlice((const char*)bytes.begin(), (const char*)bytes.end()), + buf); return buf.produceString(); } -/* static */SlangResult ProcessUtil::readUntilTermination(Process* process, ExecuteResult& outExecuteResult) +/* static */ SlangResult ProcessUtil::readUntilTermination( + Process* process, + ExecuteResult& outExecuteResult) { List<Byte> stdOut; List<Byte> stdError; @@ -47,7 +53,10 @@ static String _getText(const ConstArrayView<Byte>& bytes) return SLANG_OK; } -/* static */SlangResult ProcessUtil::readUntilTermination(Process* process, List<Byte>* outStdOut, List<Byte>* outStdError) +/* static */ SlangResult ProcessUtil::readUntilTermination( + Process* process, + List<Byte>* outStdOut, + List<Byte>* outStdError) { Stream* stdOutStream = process->getStream(StdStreamType::Out); Stream* stdErrorStream = process->getStream(StdStreamType::ErrorOut); @@ -70,7 +79,7 @@ static String _getText(const ConstArrayView<Byte>& bytes) } // Read anything remaining - for(;;) + for (;;) { const auto preCount = _getCount(outStdOut) + _getCount(outStdError); StreamUtil::readOrDiscard(stdOutStream, 0, outStdOut); diff --git a/source/core/slang-process-util.h b/source/core/slang-process-util.h index 14ca208f8..25cf0aca3 100644 --- a/source/core/slang-process-util.h +++ b/source/core/slang-process-util.h @@ -4,7 +4,8 @@ #include "slang-process.h" -namespace Slang { +namespace Slang +{ struct ExecuteResult { @@ -24,17 +25,20 @@ struct ExecuteResult struct ProcessUtil { - /// Execute the command line + /// Execute the command line static SlangResult execute(const CommandLine& commandLine, ExecuteResult& outExecuteResult); - /// Read from read from streams until process terminates. - /// Passing nullptr for a stream, will just discard what's in the stream - static SlangResult readUntilTermination(Process* process, List<Byte>* outStdOut, List<Byte>* stdError); + /// Read from read from streams until process terminates. + /// Passing nullptr for a stream, will just discard what's in the stream + static SlangResult readUntilTermination( + Process* process, + List<Byte>* outStdOut, + List<Byte>* stdError); - /// Read streams from process. + /// Read streams from process. static SlangResult readUntilTermination(Process* process, ExecuteResult& outExecuteResult); }; -} +} // namespace Slang #endif // SLANG_PROCESS_UTIL_H diff --git a/source/core/slang-process.h b/source/core/slang-process.h index c36064ac3..002e2d5e1 100644 --- a/source/core/slang-process.h +++ b/source/core/slang-process.h @@ -2,16 +2,15 @@ #ifndef SLANG_PROCESS_H #define SLANG_PROCESS_H -#include "slang-string.h" +#include "slang-command-line.h" +#include "slang-io.h" #include "slang-list.h" #include "slang-stream.h" -#include "slang-io.h" - #include "slang-string-escape-util.h" +#include "slang-string.h" -#include "slang-command-line.h" - -namespace Slang { +namespace Slang +{ class Process : public RefObject { @@ -27,59 +26,64 @@ public: }; }; - /// Get the stream for the type + /// Get the stream for the type Stream* getStream(StdStreamType type) const { return m_streams[Index(type)]; } - /// Get the value returned from the process when it exited/returned. - int32_t getReturnValue() const { return m_returnValue; } + /// Get the value returned from the process when it exited/returned. + int32_t getReturnValue() const { return m_returnValue; } - /// True if the process has terminated + /// True if the process has terminated virtual bool isTerminated() = 0; - /// Blocks until the process has terminated or the timeout completes - /// Can optionally supply a timeout time. -1 means 'infinite' and is the default. - /// Note that the timeOut is only used approximately. - /// Returns true if has terminated. + /// Blocks until the process has terminated or the timeout completes + /// Can optionally supply a timeout time. -1 means 'infinite' and is the default. + /// Note that the timeOut is only used approximately. + /// Returns true if has terminated. virtual bool waitForTermination(Int timeOutInMs = -1) = 0; - /// Terminate the process gracefully. - /// After calling it may take time before the process actually terminates - /// Ie calling isTerminated directly after `terminate` may return false. - /// The return code depending on implementation/termination style, may not be set. + /// Terminate the process gracefully. + /// After calling it may take time before the process actually terminates + /// Ie calling isTerminated directly after `terminate` may return false. + /// The return code depending on implementation/termination style, may not be set. virtual void terminate(int32_t returnCode) = 0; - /// Kill the process - attempt to terminate immediately. + /// Kill the process - attempt to terminate immediately. virtual void kill(int32_t returnCode) = 0; - /// The quoting style used for the command line on this target. Currently just uses Space, - /// but in future may take into account platform sec + /// The quoting style used for the command line on this target. Currently just uses Space, + /// but in future may take into account platform sec static StringEscapeHandler* getEscapeHandler(); - /// Get the suffix used on this platform + /// Get the suffix used on this platform static UnownedStringSlice getExecutableSuffix(); - /// Create a process using the executable/args defined from the commandLine - static SlangResult create(const CommandLine& commandLine, Process::Flags flags, RefPtr<Process>& outProcess); + /// Create a process using the executable/args defined from the commandLine + static SlangResult create( + const CommandLine& commandLine, + Process::Flags flags, + RefPtr<Process>& outProcess); - /// Sleep the current thread for time specified in milliseconds. 0 indicates to OS ok to yield this thread. + /// Sleep the current thread for time specified in milliseconds. 0 indicates to OS ok to yield + /// this thread. static void sleepCurrentThread(Int timeInMs); - /// Get a standard stream + /// Get a standard stream static SlangResult getStdStream(StdStreamType type, RefPtr<Stream>& out); - /// Get the clock frequency + /// Get the clock frequency static uint64_t getClockFrequency(); - /// Get the clock tick. + /// Get the clock tick. static uint64_t getClockTick(); static uint32_t getId(); protected: - int32_t m_returnValue = 0; ///< Value returned if process terminated - RefPtr<Stream> m_streams[Index(StdStreamType::CountOf)]; ///< Streams to communicate with the process + int32_t m_returnValue = 0; ///< Value returned if process terminated + RefPtr<Stream> + m_streams[Index(StdStreamType::CountOf)]; ///< Streams to communicate with the process }; -} +} // namespace Slang #endif // SLANG_PROCESS_H diff --git a/source/core/slang-random-generator.cpp b/source/core/slang-random-generator.cpp index 315678f0a..26781b582 100644 --- a/source/core/slang-random-generator.cpp +++ b/source/core/slang-random-generator.cpp @@ -1,7 +1,8 @@ #include "slang-random-generator.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!! RandomGenerator !!!!!!!!!!!!!!!!!!!!!!!! */ @@ -20,8 +21,8 @@ bool RandomGenerator::nextBool() bits = ((bits & 0x44444444) >> 2) ^ (bits & 0x11111111); bits = ((bits & 0x10101010) >> 4) ^ (bits & 0x01010101); - // In effect is the xor of all the bits of the original last byte - return ( bits & 1) != 0; + // In effect is the xor of all the bits of the original last byte + return (bits & 1) != 0; } int64_t RandomGenerator::nextInt64() @@ -34,7 +35,7 @@ int64_t RandomGenerator::nextInt64() uint32_t RandomGenerator::nextUInt32InRange(uint32_t min, uint32_t max) { - // Make sure max is at least in + // Make sure max is at least in max = (max >= min) ? max : min; // Make 64 bit so can be lazier than having to take care of 32 bit overflow/underflow issues @@ -49,7 +50,7 @@ uint32_t RandomGenerator::nextUInt32InRange(uint32_t min, uint32_t max) int32_t RandomGenerator::nextInt32InRange(int32_t min, int32_t max) { - // Make sure max is at least in + // Make sure max is at least in max = (max >= min) ? max : min; // Make 64 bit so can be lazier than having to take care of 32 bit overflow/underflow issues @@ -90,7 +91,7 @@ static uint8_t* _nextData(RandomGenerator* rand, uint8_t* out, size_t size) void RandomGenerator::nextData(void* out, size_t size) { uint8_t* dst = (uint8_t*)out; - uint8_t*const end = dst + size; + uint8_t* const end = dst + size; // For short runs just output if (size <= 4) @@ -98,7 +99,7 @@ void RandomGenerator::nextData(void* out, size_t size) _nextData(this, dst, size); return; } - + { const size_t preAlign = size_t(((size_t(dst) + 3) & ~size_t(3)) - size_t(dst)); dst = _nextData(this, dst, preAlign); @@ -122,7 +123,7 @@ void RandomGenerator::nextData(void* out, size_t size) _nextData(this, dst, size_t(end - dst)); } -/* static */RandomGenerator* RandomGenerator::create(int32_t seed) +/* static */ RandomGenerator* RandomGenerator::create(int32_t seed) { return new DefaultRandomGenerator(seed); } @@ -149,7 +150,7 @@ void Mt19937RandomGenerator::_generate() const uint32_t xorValue = 2567483615u; for (int i = 0; i < kNumEntries - 1; ++i) { - const uint32_t y = (m_mt[i] & 0x80000000) + (m_mt[i + 1] & 0x7fffffff); + const uint32_t y = (m_mt[i] & 0x80000000) + (m_mt[i + 1] & 0x7fffffff); // o = (i + 397) % kNumEntries int32_t o = i + 397; @@ -200,7 +201,7 @@ int32_t Mt19937RandomGenerator::nextInt32() uint32_t y = m_mt[m_index++]; y = y ^ (y >> 11); y = y ^ ((y << 7) & uint32_t(0x9d2c5680u)); - y = y ^ ((y << 15) & uint32_t(0xefc6000u)); + y = y ^ ((y << 15) & uint32_t(0xefc6000u)); y = y ^ (y >> 18); return int32_t(y); diff --git a/source/core/slang-random-generator.h b/source/core/slang-random-generator.h index fa83fec3b..02bf18af2 100644 --- a/source/core/slang-random-generator.h +++ b/source/core/slang-random-generator.h @@ -1,78 +1,86 @@ #ifndef SLANG_CORE_RANDOM_GENERATOR_H #define SLANG_CORE_RANDOM_GENERATOR_H +#include "slang-smart-pointer.h" #include "slang.h" #include <stdlib.h> #include <string.h> -#include "slang-smart-pointer.h" - -namespace Slang { - -class RandomGenerator: public RefObject +namespace Slang { - public: - /// Make a copy of the generator in the same state +class RandomGenerator : public RefObject +{ +public: + /// Make a copy of the generator in the same state virtual RandomGenerator* clone() = 0; - /// Reset with a seed + /// Reset with a seed virtual void reset(int32_t seed) = 0; - /// Next int32_t random number + /// Next int32_t random number virtual int32_t nextInt32() = 0; - /// Next int64_t random number + /// Next int64_t random number virtual int64_t nextInt64(); - /// Get a 0-1 range floating point + /// Get a 0-1 range floating point virtual float nextUnitFloat32(); - - /// Get the next bool + + /// Get the next bool virtual bool nextBool(); - /// Get multiple int32s + /// Get multiple int32s virtual void nextInt32s(int32_t* dst, size_t count) = 0; - /// Next uint32_t + /// Next uint32_t uint32_t nextUInt32() { return uint32_t(nextInt32()); } - /// Next Int32 which can only be positive + /// Next Int32 which can only be positive int32_t nextPositiveInt32() { return nextInt32() & 0x7fffffff; } - /// Next Int64 which can only be positive + /// Next Int64 which can only be positive int64_t nextPositiveInt64() { return nextInt64() & SLANG_INT64(0x7fffffffffffffff); } - /// Returns value up to BUT NOT INCLUDING maxValue. - int32_t nextInt32UpTo(int32_t maxValue) { assert(maxValue > 0); return (maxValue <= 1) ? 0 : (nextPositiveInt32() % maxValue); } + /// Returns value up to BUT NOT INCLUDING maxValue. + int32_t nextInt32UpTo(int32_t maxValue) + { + assert(maxValue > 0); + return (maxValue <= 1) ? 0 : (nextPositiveInt32() % maxValue); + } - /// Returns value from min up to BUT NOT INCLUDING max. + /// Returns value from min up to BUT NOT INCLUDING max. int32_t nextInt32InRange(int32_t min, int32_t max); /// Returns value from min up to BUT NOT INCLUDING max uint32_t nextUInt32InRange(uint32_t min, uint32_t max); - /// Returns value up to BUT NOT INCLUDING maxValue - int64_t nextInt64UpTo(int64_t maxValue) { assert(maxValue > 0); return (maxValue <= 1) ? 0 : (nextPositiveInt64() % maxValue); } + /// Returns value up to BUT NOT INCLUDING maxValue + int64_t nextInt64UpTo(int64_t maxValue) + { + assert(maxValue > 0); + return (maxValue <= 1) ? 0 : (nextPositiveInt64() % maxValue); + } - /// Returns value from min up to BUT NOT INCLUDING max + /// Returns value from min up to BUT NOT INCLUDING max int64_t nextInt64InRange(int64_t min, int64_t max); - /// Fill with random data. - /// NOTE! Output is only identical bytes if generator in same state *and* size_t(dst) & 3 is the same on calls. + /// Fill with random data. + /// NOTE! Output is only identical bytes if generator in same state *and* size_t(dst) & 3 is the + /// same on calls. void nextData(void* dst, size_t size); - /// Create a RandomGenerator with specified seed using default generator type + /// Create a RandomGenerator with specified seed using default generator type static RandomGenerator* create(int32_t seed); }; -/* Mersenne Twister random number generator +/* Mersenne Twister random number generator https://en.wikipedia.org/wiki/Mersenne_Twister */ -class Mt19937RandomGenerator: public RandomGenerator +class Mt19937RandomGenerator : public RandomGenerator { - public: +public: typedef Mt19937RandomGenerator ThisType; - enum + enum { kNumEntries = 624 }; @@ -82,24 +90,23 @@ class Mt19937RandomGenerator: public RandomGenerator int32_t nextInt32() SLANG_OVERRIDE; void nextInt32s(int32_t* dst, size_t count) SLANG_OVERRIDE; - /// Ctor + /// Ctor Mt19937RandomGenerator(); Mt19937RandomGenerator(const ThisType& rhs); explicit Mt19937RandomGenerator(int32_t seed); - /// Assignment + /// Assignment void operator=(const ThisType& rhs) { m_index = rhs.m_index; ::memcpy(m_mt, rhs.m_mt, sizeof(m_mt)); } - - protected: - void _generate(); - uint32_t m_mt[kNumEntries]; ///< The random state vector - int m_index; ///< If set to >= kMaxEntries it means reset +protected: + void _generate(); + uint32_t m_mt[kNumEntries]; ///< The random state vector + int m_index; ///< If set to >= kMaxEntries it means reset }; typedef Mt19937RandomGenerator DefaultRandomGenerator; diff --git a/source/core/slang-range.h b/source/core/slang-range.h index 6e4419ce0..e85ce6a9d 100644 --- a/source/core/slang-range.h +++ b/source/core/slang-range.h @@ -3,27 +3,24 @@ namespace Slang { - template<typename T> - struct Range - { - T begin = 0; - T end = 0; - - bool inRange(T val) const - { - return val >= begin && val < end; - } - }; +template<typename T> +struct Range +{ + T begin = 0; + T end = 0; - template <typename T> - Range<T> makeRange(T begin, T end) - { - Range<T> result; - result.begin = begin; - result.end = end; - return result; - } + bool inRange(T val) const { return val >= begin && val < end; } +}; +template<typename T> +Range<T> makeRange(T begin, T end) +{ + Range<T> result; + result.begin = begin; + result.end = end; + return result; } -#endif //SLANG_CORE_RANGE_H +} // namespace Slang + +#endif // SLANG_CORE_RANGE_H diff --git a/source/core/slang-render-api-util.cpp b/source/core/slang-render-api-util.cpp index 797d82cd7..476188abd 100644 --- a/source/core/slang-render-api-util.cpp +++ b/source/core/slang-render-api-util.cpp @@ -1,25 +1,23 @@ #include "slang-render-api-util.h" -#include "slang.h" - #include "slang-list.h" -#include "slang-string-util.h" - #include "slang-platform.h" +#include "slang-string-util.h" +#include "slang.h" -namespace Slang { +namespace Slang +{ // NOTE! Must keep in same order as RenderApiType and have same amount of entries -/* static */const RenderApiUtil::Info RenderApiUtil::s_infos[] = -{ - { RenderApiType::Vulkan, "vk,vulkan", ""}, - { RenderApiType::D3D12, "dx12,d3d12", ""}, - { RenderApiType::D3D11, "dx11,d3d11", "hlsl,hlsl-rewrite,slang"}, - { RenderApiType::Metal, "mtl,metal", ""}, - { RenderApiType::CPU, "cpu", ""}, - { RenderApiType::CUDA, "cuda", "cuda,ptx"}, - { RenderApiType::WebGPU, "wgpu,webgpu", "wgsl"}, +/* static */ const RenderApiUtil::Info RenderApiUtil::s_infos[] = { + {RenderApiType::Vulkan, "vk,vulkan", ""}, + {RenderApiType::D3D12, "dx12,d3d12", ""}, + {RenderApiType::D3D11, "dx11,d3d11", "hlsl,hlsl-rewrite,slang"}, + {RenderApiType::Metal, "mtl,metal", ""}, + {RenderApiType::CPU, "cpu", ""}, + {RenderApiType::CUDA, "cuda", "cuda,ptx"}, + {RenderApiType::WebGPU, "wgpu,webgpu", "wgsl"}, }; static int _calcAvailableApis() @@ -36,7 +34,7 @@ static int _calcAvailableApis() return flags; } -/* static */int RenderApiUtil::getAvailableApis() +/* static */ int RenderApiUtil::getAvailableApis() { static int s_availableApis = _calcAvailableApis(); return s_availableApis; @@ -53,7 +51,7 @@ UnownedStringSlice RenderApiUtil::getApiName(RenderApiType type) return StringUtil::getAtInSplit(UnownedStringSlice(s_infos[index].names), ',', 0); } -/* static */RenderApiType RenderApiUtil::findApiTypeByName(const Slang::UnownedStringSlice& name) +/* static */ RenderApiType RenderApiUtil::findApiTypeByName(const Slang::UnownedStringSlice& name) { using namespace Slang; List<UnownedStringSlice> namesList; @@ -78,7 +76,9 @@ UnownedStringSlice RenderApiUtil::getApiName(RenderApiType type) return RenderApiType::Unknown; } -/* static */ Slang::Result RenderApiUtil::findApiFlagsByName(const Slang::UnownedStringSlice& name, RenderApiFlags* flagsOut) +/* static */ Slang::Result RenderApiUtil::findApiFlagsByName( + const Slang::UnownedStringSlice& name, + RenderApiFlags* flagsOut) { // Special case 'all' if (name == "all") @@ -102,7 +102,7 @@ UnownedStringSlice RenderApiUtil::getApiName(RenderApiType type) static bool isNameStartChar(char c) { - return (c >= 'a' && c <='z') || (c >= 'A' && c <= 'Z') || (c == '_'); + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_'); } static bool isNameNextChar(char c) @@ -110,15 +110,16 @@ static bool isNameNextChar(char c) return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9'); } -namespace { // anonymous -enum class Token +namespace +{ // anonymous +enum class Token { eError, eOp, eId, eEnd, }; -} +} // namespace static Token nextToken(Slang::UnownedStringSlice& textInOut, Slang::UnownedStringSlice& lexemeOut) { @@ -154,18 +155,21 @@ static Token nextToken(Slang::UnownedStringSlice& textInOut, Slang::UnownedStrin return Token::eId; } -/* static */Slang::Result RenderApiUtil::parseApiFlags(const Slang::UnownedStringSlice& textIn, RenderApiFlags initialFlags, RenderApiFlags* apiFlagsOut) +/* static */ Slang::Result RenderApiUtil::parseApiFlags( + const Slang::UnownedStringSlice& textIn, + RenderApiFlags initialFlags, + RenderApiFlags* apiFlagsOut) { using namespace Slang; UnownedStringSlice text(textIn); UnownedStringSlice lexeme; - RenderApiFlags apiFlags = 0; - + RenderApiFlags apiFlags = 0; + switch (nextToken(text, lexeme)) { - case Token::eOp: + case Token::eOp: { // If we start with an op - we use the passed in values as the default // Rewind back to the start @@ -173,27 +177,27 @@ static Token nextToken(Slang::UnownedStringSlice& textInOut, Slang::UnownedStrin apiFlags = initialFlags; break; } - case Token::eId: + case Token::eId: { // If we start with an Id - we use that as the starting state SLANG_RETURN_ON_FAIL(findApiFlagsByName(lexeme, &apiFlags)); break; } - default: return SLANG_FAIL; + default: return SLANG_FAIL; } - + while (true) { // Must have an op followed by an id unless we are at the end switch (nextToken(text, lexeme)) { - case Token::eEnd: + case Token::eEnd: { *apiFlagsOut = apiFlags; return SLANG_OK; } - case Token::eOp: break; - default: return SLANG_FAIL; + case Token::eOp: break; + default: return SLANG_FAIL; } const char op = lexeme[0]; @@ -216,7 +220,7 @@ static Token nextToken(Slang::UnownedStringSlice& textInOut, Slang::UnownedStrin } } -/* static */RenderApiType RenderApiUtil::findRenderApiType(const Slang::UnownedStringSlice& text) +/* static */ RenderApiType RenderApiUtil::findRenderApiType(const Slang::UnownedStringSlice& text) { using namespace Slang; for (Index j = 0; j < SLANG_COUNT_OF(RenderApiUtil::s_infos); j++) @@ -231,7 +235,8 @@ static Token nextToken(Slang::UnownedStringSlice& textInOut, Slang::UnownedStrin return RenderApiType::Unknown; } -/* static */RenderApiType RenderApiUtil::findImplicitLanguageRenderApiType(const Slang::UnownedStringSlice& text) +/* static */ RenderApiType RenderApiUtil::findImplicitLanguageRenderApiType( + const Slang::UnownedStringSlice& text) { using namespace Slang; for (Index j = 0; j < SLANG_COUNT_OF(RenderApiUtil::s_infos); j++) @@ -260,32 +265,34 @@ static bool _canLoadSharedLibrary(const char* libName) } #endif -/* static */bool RenderApiUtil::calcHasApi(RenderApiType type) +/* static */ bool RenderApiUtil::calcHasApi(RenderApiType type) { switch (type) { #if SLANG_WINDOWS_FAMILY - case RenderApiType::Vulkan: return _canLoadSharedLibrary("vulkan-1") || _canLoadSharedLibrary("vk_swiftshader"); - case RenderApiType::WebGPU: - return _canLoadSharedLibrary("webgpu_dawn") && - _canLoadSharedLibrary("dxcompiler") && - _canLoadSharedLibrary("dxil"); + case RenderApiType::Vulkan: + return _canLoadSharedLibrary("vulkan-1") || _canLoadSharedLibrary("vk_swiftshader"); + case RenderApiType::WebGPU: + return _canLoadSharedLibrary("webgpu_dawn") && _canLoadSharedLibrary("dxcompiler") && + _canLoadSharedLibrary("dxil"); #elif SLANG_APPLE_FAMILY - case RenderApiType::Vulkan: return true; - case RenderApiType::Metal: return true; + case RenderApiType::Vulkan: return true; + case RenderApiType::Metal: return true; #elif SLANG_UNIX_FAMILY - case RenderApiType::Vulkan: return true; + case RenderApiType::Vulkan: return true; #endif #if SLANG_ENABLE_DIRECTX - case RenderApiType::D3D11: return _canLoadSharedLibrary(SLANG_ENABLE_DXVK ? "dxvk_d3d11" : "d3d11"); - case RenderApiType::D3D12: return _canLoadSharedLibrary(SLANG_ENABLE_VKD3D ? "vkd3d-proton-d3d12" : "d3d12"); + case RenderApiType::D3D11: + return _canLoadSharedLibrary(SLANG_ENABLE_DXVK ? "dxvk_d3d11" : "d3d11"); + case RenderApiType::D3D12: + return _canLoadSharedLibrary(SLANG_ENABLE_VKD3D ? "vkd3d-proton-d3d12" : "d3d12"); #endif - case RenderApiType::CPU: return true; - // We'll assume CUDA is available, and if not, trying to create it will detect it - case RenderApiType::CUDA: return true; - default: break; + case RenderApiType::CPU: return true; + // We'll assume CUDA is available, and if not, trying to create it will detect it + case RenderApiType::CUDA: return true; + default: break; } return false; } diff --git a/source/core/slang-render-api-util.h b/source/core/slang-render-api-util.h index f1be930cc..b1fae8c37 100644 --- a/source/core/slang-render-api-util.h +++ b/source/core/slang-render-api-util.h @@ -2,7 +2,6 @@ #define SLANG_CORE_RENDER_API_UTIL_H #include "../../source/core/slang-string.h" - #include "slang-com-helper.h" namespace Slang @@ -21,7 +20,8 @@ enum class RenderApiType CountOf, }; -// Use a struct wrapped Enum instead of enum class, cos we want to be able to manipulate as integrals +// Use a struct wrapped Enum instead of enum class, cos we want to be able to manipulate as +// integrals struct RenderApiFlag { enum Enum @@ -30,10 +30,10 @@ struct RenderApiFlag D3D12 = 1 << int(RenderApiType::D3D12), D3D11 = 1 << int(RenderApiType::D3D11), Metal = 1 << int(RenderApiType::Metal), - CPU = 1 << int(RenderApiType::CPU), - CUDA = 1 << int(RenderApiType::CUDA), + CPU = 1 << int(RenderApiType::CPU), + CUDA = 1 << int(RenderApiType::CUDA), WebGPU = 1 << int(RenderApiType::WebGPU), - AllOf = (1 << int(RenderApiType::CountOf)) - 1 ///< All bits set + AllOf = (1 << int(RenderApiType::CountOf)) - 1 ///< All bits set }; }; typedef uint32_t RenderApiFlags; @@ -42,40 +42,47 @@ struct RenderApiUtil { struct Info { - RenderApiType type; ///< The type - const char* names; ///< Comma separated list of names associated with the type - const char* languageNames; ///< Comma separated list of target language names associated with the type + RenderApiType type; ///< The type + const char* names; ///< Comma separated list of names associated with the type + const char* languageNames; ///< Comma separated list of target language names associated + ///< with the type }; - /// Returns true if the API is available. + /// Returns true if the API is available. static bool calcHasApi(RenderApiType type); - /// Returns a combination of RenderApiFlag bits which if set indicates that the API is available. + /// Returns a combination of RenderApiFlag bits which if set indicates that the API is + /// available. static int getAvailableApis(); - /// Get the name + /// Get the name static UnownedStringSlice getApiName(RenderApiType type); - /// Returns RenderApiType::Unknown if not found + /// Returns RenderApiType::Unknown if not found static RenderApiType findApiTypeByName(const Slang::UnownedStringSlice& name); - /// FlagsOut will have flag/flags specified by a name if returns with successful result code. - static Slang::Result findApiFlagsByName(const Slang::UnownedStringSlice& name, RenderApiFlags* flagsOut); - - /// Parse api flags string, returning SLANG_OK on success. - /// If first character is + or - the flags will be applied to initialFlags, else initialFlags is ignored. - /// For example "all-dx12" would be all apis, except dx12 - /// -vk would be whatever is in initial flags, but not vulkan. - static Slang::Result parseApiFlags(const Slang::UnownedStringSlice& text, RenderApiFlags initialFlags, RenderApiFlags* apiBitsOut); - - /// Gets the API type from a string, or returns RenderApiType::Unknown if not found + /// FlagsOut will have flag/flags specified by a name if returns with successful result code. + static Slang::Result findApiFlagsByName( + const Slang::UnownedStringSlice& name, + RenderApiFlags* flagsOut); + + /// Parse api flags string, returning SLANG_OK on success. + /// If first character is + or - the flags will be applied to initialFlags, else initialFlags is + /// ignored. For example "all-dx12" would be all apis, except dx12 -vk would be whatever is in + /// initial flags, but not vulkan. + static Slang::Result parseApiFlags( + const Slang::UnownedStringSlice& text, + RenderApiFlags initialFlags, + RenderApiFlags* apiBitsOut); + + /// Gets the API type from a string, or returns RenderApiType::Unknown if not found static RenderApiType findRenderApiType(const Slang::UnownedStringSlice& text); static RenderApiType findImplicitLanguageRenderApiType(const Slang::UnownedStringSlice& text); - /// Get information about a render API + /// Get information about a render API static const Info& getInfo(RenderApiType type) { return s_infos[int(type)]; } - /// Static information about each render api + /// Static information about each render api static const Info s_infos[int(RenderApiType::CountOf)]; }; diff --git a/source/core/slang-riff-file-system.cpp b/source/core/slang-riff-file-system.cpp index 1072db186..b290ee5e5 100644 --- a/source/core/slang-riff-file-system.cpp +++ b/source/core/slang-riff-file-system.cpp @@ -1,10 +1,9 @@ #include "slang-riff-file-system.h" +#include "slang-blob.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" -#include "slang-blob.h" - // Compression systems #include "slang-deflate-compression-system.h" #include "slang-lz4-compression-system.h" @@ -12,8 +11,8 @@ namespace Slang { -RiffFileSystem::RiffFileSystem(ICompressionSystem* compressionSystem): - m_compressionSystem(compressionSystem) +RiffFileSystem::RiffFileSystem(ICompressionSystem* compressionSystem) + : m_compressionSystem(compressionSystem) { } @@ -57,7 +56,11 @@ SlangResult RiffFileSystem::loadFile(char const* path, ISlangBlob** outBlob) // Okay lets decompress into a blob ScopedAllocation alloc; void* dst = alloc.allocateTerminated(entry->m_uncompressedSizeInBytes); - SLANG_RETURN_ON_FAIL(m_compressionSystem->decompress(contents->getBufferPointer(), contents->getBufferSize(), entry->m_uncompressedSizeInBytes, dst)); + SLANG_RETURN_ON_FAIL(m_compressionSystem->decompress( + contents->getBufferPointer(), + contents->getBufferSize(), + entry->m_uncompressedSizeInBytes, + dst)); auto blob = RawBlob::moveCreate(alloc); @@ -74,7 +77,7 @@ SlangResult RiffFileSystem::loadFile(char const* path, ISlangBlob** outBlob) } SlangResult RiffFileSystem::saveFile(const char* path, const void* data, size_t size) -{ +{ Entry* entry; SLANG_RETURN_ON_FAIL(_requireFile(path, &entry)); @@ -82,7 +85,8 @@ SlangResult RiffFileSystem::saveFile(const char* path, const void* data, size_t if (m_compressionSystem) { // Lets try compressing the input - SLANG_RETURN_ON_FAIL(m_compressionSystem->compress(&m_compressionStyle, data, size, contents.writeRef())); + SLANG_RETURN_ON_FAIL( + m_compressionSystem->compress(&m_compressionStyle, data, size, contents.writeRef())); } else { @@ -129,28 +133,29 @@ SlangResult RiffFileSystem::loadArchive(const void* archive, size_t archiveSizeI _clear(); // Find the header - const auto header = rootList->findContainedData<RiffFileSystemBinary::Header>(RiffFileSystemBinary::kHeaderFourCC); + const auto header = rootList->findContainedData<RiffFileSystemBinary::Header>( + RiffFileSystemBinary::kHeaderFourCC); CompressionSystemType compressionType = CompressionSystemType(header->compressionSystemType); switch (compressionType) { - case CompressionSystemType::None: + case CompressionSystemType::None: { // Null m_compressionSystem means no compression m_compressionSystem.setNull(); break; } - case CompressionSystemType::Deflate: + case CompressionSystemType::Deflate: { m_compressionSystem = DeflateCompressionSystem::getSingleton(); break; } - case CompressionSystemType::LZ4: + case CompressionSystemType::LZ4: { m_compressionSystem = LZ4CompressionSystem::getSingleton(); break; } - default: return SLANG_FAIL; + default: return SLANG_FAIL; } // Read all of the contained data @@ -175,7 +180,9 @@ SlangResult RiffFileSystem::loadArchive(const void* archive, size_t archiveSizeI srcData += sizeof(*srcEntry); // Check if seems plausible - if (sizeof(RiffFileSystemBinary::Entry) + srcEntry->compressedSize + srcEntry->pathSize != dataSize) + if (sizeof(RiffFileSystemBinary::Entry) + srcEntry->compressedSize + + srcEntry->pathSize != + dataSize) { return SLANG_FAIL; } @@ -188,10 +195,10 @@ SlangResult RiffFileSystem::loadArchive(const void* archive, size_t archiveSizeI dstEntry.m_canonicalPath = UnownedStringSlice(path, srcEntry->pathSize - 1); dstEntry.m_type = (SlangPathType)srcEntry->pathType; dstEntry.m_uncompressedSizeInBytes = srcEntry->uncompressedSize; - + switch (dstEntry.m_type) { - case SLANG_PATH_TYPE_FILE: + case SLANG_PATH_TYPE_FILE: { if (srcData + srcEntry->compressedSize != data->getPayloadEnd()) { @@ -202,8 +209,8 @@ SlangResult RiffFileSystem::loadArchive(const void* archive, size_t archiveSizeI dstEntry.m_contents = RawBlob::create(srcData, srcEntry->compressedSize); break; } - case SLANG_PATH_TYPE_DIRECTORY: break; - default: return SLANG_FAIL; + case SLANG_PATH_TYPE_DIRECTORY: break; + default: return SLANG_FAIL; } // If it's the root entry we can ignore (as already added) @@ -226,11 +233,16 @@ SlangResult RiffFileSystem::storeArchive(bool blobOwnsContent, ISlangBlob** outB SLANG_UNUSED(blobOwnsContent) RiffContainer container; - RiffContainer::ScopeChunk scopeContainer(&container, RiffContainer::Chunk::Kind::List, RiffFileSystemBinary::kContainerFourCC); + RiffContainer::ScopeChunk scopeContainer( + &container, + RiffContainer::Chunk::Kind::List, + RiffFileSystemBinary::kContainerFourCC); { RiffFileSystemBinary::Header header; - CompressionSystemType compressionSystemType = m_compressionSystem ? m_compressionSystem->getSystemType() : CompressionSystemType::None; + CompressionSystemType compressionSystemType = m_compressionSystem + ? m_compressionSystem->getSystemType() + : CompressionSystemType::None; header.compressionSystemType = uint32_t(compressionSystemType); container.addDataChunk(RiffFileSystemBinary::kHeaderFourCC, &header, sizeof(header)); } @@ -243,7 +255,10 @@ SlangResult RiffFileSystem::storeArchive(bool blobOwnsContent, ISlangBlob** outB continue; } - RiffContainer::ScopeChunk scopeData(&container, RiffContainer::Chunk::Kind::Data, RiffFileSystemBinary::kEntryFourCC); + RiffContainer::ScopeChunk scopeData( + &container, + RiffContainer::Chunk::Kind::Data, + RiffFileSystemBinary::kEntryFourCC); RiffFileSystemBinary::Entry dstEntry; dstEntry.uncompressedSize = 0; @@ -263,13 +278,18 @@ SlangResult RiffFileSystem::storeArchive(bool blobOwnsContent, ISlangBlob** outB container.write(&dstEntry, sizeof(dstEntry)); // Path - container.write(srcEntry.m_canonicalPath.getBuffer(), srcEntry.m_canonicalPath.getLength() + 1); + container.write( + srcEntry.m_canonicalPath.getBuffer(), + srcEntry.m_canonicalPath.getLength() + 1); // Add the contained data without copying if (blob) { RiffContainer::Data* data = container.addData(); - container.setUnowned(data, const_cast<void*>(blob->getBufferPointer()), blob->getBufferSize()); + container.setUnowned( + data, + const_cast<void*>(blob->getBufferPointer()), + blob->getBufferSize()); } } @@ -284,11 +304,12 @@ SlangResult RiffFileSystem::storeArchive(bool blobOwnsContent, ISlangBlob** outB return SLANG_OK; } -/* static */bool RiffFileSystem::isArchive(const void* data, size_t sizeInBytes) +/* static */ bool RiffFileSystem::isArchive(const void* data, size_t sizeInBytes) { MemoryStreamBase stream(FileAccess::Read, data, sizeInBytes); RiffListHeader header; - return SLANG_SUCCEEDED(RiffUtil::readHeader(&stream, header)) && header.subType == RiffFileSystemBinary::kContainerFourCC; + return SLANG_SUCCEEDED(RiffUtil::readHeader(&stream, header)) && + header.subType == RiffFileSystemBinary::kContainerFourCC; } } // namespace Slang diff --git a/source/core/slang-riff-file-system.h b/source/core/slang-riff-file-system.h index 60e5a7ae2..6eda1a371 100644 --- a/source/core/slang-riff-file-system.h +++ b/source/core/slang-riff-file-system.h @@ -3,7 +3,6 @@ #include "slang-archive-file-system.h" #include "slang-memory-file-system.h" - #include "slang-riff.h" namespace Slang @@ -18,33 +17,37 @@ struct RiffFileSystemBinary struct Header { - uint32_t compressionSystemType; /// One of CompressionSystemType + uint32_t compressionSystemType; /// One of CompressionSystemType }; struct Entry { uint32_t compressedSize; uint32_t uncompressedSize; - uint32_t pathSize; ///< The size of the path in bytes, including terminating 0 - uint32_t pathType; ///< One of SlangPathType + uint32_t pathSize; ///< The size of the path in bytes, including terminating 0 + uint32_t pathType; ///< One of SlangPathType // Followed by the path (including terminating 0) // Followed by the compressed data }; }; -/* RiffFileSystem implements ISlangMutableFileSystem and can be used to save and load the whole of it's contents as an 'archive' blob. +/* RiffFileSystem implements ISlangMutableFileSystem and can be used to save and load the whole of +it's contents as an 'archive' blob. -The 'RIFF' part provides the structure to store out the contents. The data is only accessed in the RIFF format when being -read/written to an archive. Normal operations on the file system act in memory. +The 'RIFF' part provides the structure to store out the contents. The data is only accessed in the +RIFF format when being read/written to an archive. Normal operations on the file system act in +memory. -A RiffFileSystem allows for compression to be used on files. To use compression pass in a suitable ICompressionSystem -implementation on construction. If constructed without an ICompressionSystem, data is stored uncompressed. When compression is -used, files 'contents' blob is actually the *compressed* version of the contents. Calling loadFile/saveFile will -uncompress/compress as need. If there is no compression contents is identical to the file contents. +A RiffFileSystem allows for compression to be used on files. To use compression pass in a suitable +ICompressionSystem implementation on construction. If constructed without an ICompressionSystem, +data is stored uncompressed. When compression is used, files 'contents' blob is actually the +*compressed* version of the contents. Calling loadFile/saveFile will uncompress/compress as need. If +there is no compression contents is identical to the file contents. NOTE: -* The RIFF chunk IDs are *slang specific*. It conforms to RIFF but is unlikely to be usable with other tooling. +* The RIFF chunk IDs are *slang specific*. It conforms to RIFF but is unlikely to be usable with +other tooling. * The RIFF chunk IDs are in RiffFileSystemBinary struct */ class RiffFileSystem : public MemoryFileSystem, public IArchiveFileSystem @@ -52,28 +55,37 @@ class RiffFileSystem : public MemoryFileSystem, public IArchiveFileSystem public: typedef MemoryFileSystem Super; - // ISlangUnknown + // ISlangUnknown SLANG_COM_BASE_IUNKNOWN_ALL // ISlangCastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // ISlangFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) + SLANG_OVERRIDE; // ISlangModifyableFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; // IArchiveFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadArchive(const void* archive, size_t archiveSizeInBytes) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) SLANG_OVERRIDE; - virtual SLANG_NO_THROW void SLANG_MCALL setCompressionStyle(const CompressionStyle& style) SLANG_OVERRIDE { m_compressionStyle = style; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadArchive(const void* archive, size_t archiveSizeInBytes) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL setCompressionStyle(const CompressionStyle& style) + SLANG_OVERRIDE + { + m_compressionStyle = style; + } - /// Pass in nullptr, if no compression is wanted. + /// Pass in nullptr, if no compression is wanted. explicit RiffFileSystem(ICompressionSystem* compressionSystem); - /// True if this appears to be Riff archive + /// True if this appears to be Riff archive static bool isArchive(const void* data, size_t sizeInBytes); protected: @@ -85,6 +97,6 @@ protected: CompressionStyle m_compressionStyle; }; -} +} // namespace Slang #endif diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp index 83693433e..94cd2038e 100644 --- a/source/core/slang-riff.cpp +++ b/source/core/slang-riff.cpp @@ -1,19 +1,21 @@ #include "slang-riff.h" #include "slang-com-helper.h" - #include "slang-hex-dump-util.h" namespace Slang { -/* static */int64_t RiffUtil::calcChunkTotalSize(const RiffHeader& chunk) +/* static */ int64_t RiffUtil::calcChunkTotalSize(const RiffHeader& chunk) { size_t size = chunk.size + sizeof(RiffHeader); return getPadSize(size); } -/* static */SlangResult RiffUtil::skip(const RiffHeader& chunk, Stream* stream, int64_t* remainingBytesInOut) +/* static */ SlangResult RiffUtil::skip( + const RiffHeader& chunk, + Stream* stream, + int64_t* remainingBytesInOut) { int64_t chunkSize = calcChunkTotalSize(chunk); if (remainingBytesInOut) @@ -26,7 +28,7 @@ namespace Slang return SLANG_OK; } -/* static */SlangResult RiffUtil::readChunk(Stream* stream, RiffHeader& outChunk) +/* static */ SlangResult RiffUtil::readChunk(Stream* stream, RiffHeader& outChunk) { size_t readBytes; SLANG_RETURN_ON_FAIL(stream->read(&outChunk, sizeof(RiffHeader), readBytes)); @@ -34,7 +36,12 @@ namespace Slang return (readBytes == sizeof(RiffHeader)) ? SLANG_OK : SLANG_FAIL; } -/* static */SlangResult RiffUtil::writeData(const RiffHeader* header, size_t headerSize, const void* payload, size_t payloadSize, Stream* out) +/* static */ SlangResult RiffUtil::writeData( + const RiffHeader* header, + size_t headerSize, + const void* payload, + size_t payloadSize, + Stream* out) { SLANG_ASSERT(uint64_t(payloadSize) <= uint64_t(0xfffffffff)); SLANG_ASSERT(headerSize >= sizeof(RiffHeader)); @@ -62,14 +69,18 @@ namespace Slang size_t padSize = getPadSize(payloadSize); if (padSize - payloadSize) { - uint8_t end[kRiffPadSize] = { 0 }; + uint8_t end[kRiffPadSize] = {0}; SLANG_RETURN_ON_FAIL(out->write(end, padSize - payloadSize)); } - + return SLANG_OK; } -/* static */SlangResult RiffUtil::readPayload(Stream* stream, size_t size, void* outData, size_t& outReadSize) +/* static */ SlangResult RiffUtil::readPayload( + Stream* stream, + size_t size, + void* outData, + size_t& outReadSize) { outReadSize = 0; @@ -85,7 +96,11 @@ namespace Slang return SLANG_OK; } -/* static */SlangResult RiffUtil::readData(Stream* stream, RiffHeader* outHeader, size_t headerSize, List<uint8_t>& data) +/* static */ SlangResult RiffUtil::readData( + Stream* stream, + RiffHeader* outHeader, + size_t headerSize, + List<uint8_t>& data) { RiffHeader chunk; SLANG_RETURN_ON_FAIL(readChunk(stream, chunk)); @@ -101,14 +116,14 @@ namespace Slang { SLANG_RETURN_ON_FAIL(stream->readExactly(outHeader + 1, headerSize - sizeof(RiffHeader))); } - + const size_t payloadSize = chunk.size - (headerSize - sizeof(RiffHeader)); size_t readSize; data.setCount(payloadSize); return readPayload(stream, payloadSize, data.getBuffer(), readSize); } -/* static */SlangResult RiffUtil::readHeader(Stream* stream, RiffListHeader& outHeader) +/* static */ SlangResult RiffUtil::readHeader(Stream* stream, RiffListHeader& outHeader) { // Need to read the chunk header SLANG_RETURN_ON_FAIL(readChunk(stream, outHeader.chunk)); @@ -117,13 +132,15 @@ namespace Slang if (isListType(outHeader.chunk.type)) { // Read the sub type - SLANG_RETURN_ON_FAIL(stream->readExactly(&outHeader.subType, sizeof(RiffListHeader) - sizeof(RiffHeader))); + SLANG_RETURN_ON_FAIL( + stream->readExactly(&outHeader.subType, sizeof(RiffListHeader) - sizeof(RiffHeader))); } return SLANG_OK; } -namespace { // anonymous +namespace +{ // anonymous struct DumpVisitor : public RiffContainer::Visitor { @@ -167,10 +184,8 @@ struct DumpVisitor : public RiffContainer::Visitor return SLANG_OK; } - DumpVisitor(WriterHelper writer, Chunk* rootChunk) : - m_writer(writer), - m_indent(0), - m_rootChunk(rootChunk) + DumpVisitor(WriterHelper writer, Chunk* rootChunk) + : m_writer(writer), m_indent(0), m_rootChunk(rootChunk) { } @@ -199,15 +214,18 @@ struct DumpVisitor : public RiffContainer::Visitor WriterHelper m_writer; }; -} +} // namespace -/* static */void RiffUtil::dump(RiffContainer::Chunk* chunk, WriterHelper writer) +/* static */ void RiffUtil::dump(RiffContainer::Chunk* chunk, WriterHelper writer) { DumpVisitor visitor(writer, chunk); chunk->visit(&visitor); } -/* static */SlangResult RiffUtil::write(RiffContainer::ListChunk* list, bool isRoot, Stream* stream) +/* static */ SlangResult RiffUtil::write( + RiffContainer::ListChunk* list, + bool isRoot, + Stream* stream) { RiffListHeader listHeader; @@ -218,20 +236,20 @@ struct DumpVisitor : public RiffContainer::Visitor // Write the header SLANG_RETURN_ON_FAIL(stream->write(&listHeader, sizeof(listHeader))); - // Write the contained chunks + // Write the contained chunks Chunk* chunk = list->m_containedChunks; while (chunk) { switch (chunk->m_kind) { - case Chunk::Kind::List: + case Chunk::Kind::List: { auto listChunk = static_cast<ListChunk*>(chunk); // It's a container SLANG_RETURN_ON_FAIL(write(listChunk, false, stream)); break; } - case Chunk::Kind::Data: + case Chunk::Kind::Data: { auto dataChunk = static_cast<DataChunk*>(chunk); @@ -252,30 +270,31 @@ struct DumpVisitor : public RiffContainer::Visitor } // Need to write for alignment - const size_t remainingSize = getPadSize(dataChunk->m_payloadSize) - dataChunk->m_payloadSize; + const size_t remainingSize = + getPadSize(dataChunk->m_payloadSize) - dataChunk->m_payloadSize; if (remainingSize) { - static const uint8_t trailing[kRiffPadSize] = { 0 }; + static const uint8_t trailing[kRiffPadSize] = {0}; SLANG_RETURN_ON_FAIL(stream->write(trailing, remainingSize)); } } - default: break; + default: break; } // Next chunk = chunk->m_next; } - + return SLANG_OK; } -/* static */SlangResult RiffUtil::write(RiffContainer* container, Stream* stream) +/* static */ SlangResult RiffUtil::write(RiffContainer* container, Stream* stream) { return write(container->getRoot(), true, stream); } -/* static */SlangResult RiffUtil::read(Stream* stream, RiffContainer& outContainer) +/* static */ SlangResult RiffUtil::read(Stream* stream, RiffContainer& outContainer) { typedef RiffContainer::ScopeChunk ScopeChunk; outContainer.reset(); @@ -333,7 +352,7 @@ struct DumpVisitor : public RiffContainer::Visitor const size_t padSize = getPadSize(header.chunk.size); // Subtract the size of this chunk from remaining of the current chunk - remaining -= sizeof(RiffHeader) + padSize; + remaining -= sizeof(RiffHeader) + padSize; // Push it, for when we hit the end remainingStack.add(remaining); @@ -347,11 +366,12 @@ struct DumpVisitor : public RiffContainer::Visitor { ScopeChunk scopeChunk(&outContainer, Chunk::Kind::Data, header.chunk.type); RiffContainer::Data* data = outContainer.addData(); - + outContainer.setPayload(data, nullptr, header.chunk.size); size_t readSize; - SLANG_RETURN_ON_FAIL(readPayload(stream, header.chunk.size, data->getPayload(), readSize)); + SLANG_RETURN_ON_FAIL( + readPayload(stream, header.chunk.size, data->getPayload(), readSize)); // All read sizes must end up aligned SLANG_ASSERT((readSize & kRiffPadMask) == 0); @@ -371,11 +391,11 @@ SlangResult RiffContainer::Chunk::visit(Visitor* visitor) { switch (m_kind) { - case Kind::Data: + case Kind::Data: { return visitor->handleData(static_cast<DataChunk*>(this)); } - case Kind::List: + case Kind::List: { auto list = static_cast<ListChunk*>(this); SLANG_RETURN_ON_FAIL(visitor->enterList(list)); @@ -391,7 +411,7 @@ SlangResult RiffContainer::Chunk::visit(Visitor* visitor) SLANG_RETURN_ON_FAIL(visitor->leaveList(list)); return SLANG_OK; } - default: return SLANG_FAIL; + default: return SLANG_FAIL; } } @@ -399,11 +419,11 @@ SlangResult RiffContainer::Chunk::visitPreOrder(VisitorCallback callback, void* { switch (m_kind) { - case Kind::Data: + case Kind::Data: { return callback(this, data); } - case Kind::List: + case Kind::List: { auto list = static_cast<ListChunk*>(this); // Do this containing node first @@ -418,7 +438,7 @@ SlangResult RiffContainer::Chunk::visitPreOrder(VisitorCallback callback, void* } return SLANG_OK; } - default: return SLANG_FAIL; + default: return SLANG_FAIL; } } @@ -426,11 +446,11 @@ SlangResult RiffContainer::Chunk::visitPostOrder(VisitorCallback callback, void* { switch (m_kind) { - case Kind::Data: + case Kind::Data: { return callback(this, data); } - case Kind::List: + case Kind::List: { auto list = static_cast<ListChunk*>(this); @@ -445,7 +465,7 @@ SlangResult RiffContainer::Chunk::visitPostOrder(VisitorCallback callback, void* SLANG_RETURN_ON_FAIL(callback(this, data)); return SLANG_OK; } - default: return SLANG_FAIL; + default: return SLANG_FAIL; } } @@ -453,15 +473,15 @@ size_t RiffContainer::Chunk::calcPayloadSize() { switch (m_kind) { - case Kind::Data: return static_cast<DataChunk*>(this)->calcPayloadSize(); - case Kind::List: return static_cast<ListChunk*>(this)->calcPayloadSize(); - default: return 0; + case Kind::Data: return static_cast<DataChunk*>(this)->calcPayloadSize(); + case Kind::List: return static_cast<ListChunk*>(this)->calcPayloadSize(); + default: return 0; } } RiffContainer::Data* RiffContainer::Chunk::getSingleData() const { - return (m_kind == Kind::Data) ? static_cast<const DataChunk*>(this)->getSingleData(): nullptr; + return (m_kind == Kind::Data) ? static_cast<const DataChunk*>(this)->getSingleData() : nullptr; } // !!!!!!!!!!!!!!!!!!!!!!!!!!! RiffContainer::ListChunk !!!!!!!!!!!!!!!!!!!!!! @@ -582,7 +602,7 @@ static RiffContainer::ListChunk* _findListRec(RiffContainer::ListChunk* list, Fo return nullptr; } -/* static */RiffContainer::ListChunk* RiffContainer::ListChunk::findListRec(FourCC subType) +/* static */ RiffContainer::ListChunk* RiffContainer::ListChunk::findListRec(FourCC subType) { return (getSubType() == subType) ? this : _findListRec(this, subType); } @@ -683,8 +703,8 @@ bool RiffContainer::DataChunk::isEqual(const void* inData, size_t count) const // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RiffContainer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -RiffContainer::RiffContainer() : - m_arena(4096) +RiffContainer::RiffContainer() + : m_arena(4096) { m_rootList = nullptr; m_listChunk = nullptr; @@ -723,7 +743,8 @@ void RiffContainer::_addChunk(Chunk* chunk) if (m_listChunk) { chunk->m_parent = m_listChunk; - Chunk*& next = m_listChunk->m_endChunk ? m_listChunk->m_endChunk->m_next : m_listChunk->m_containedChunks; + Chunk*& next = m_listChunk->m_endChunk ? m_listChunk->m_endChunk->m_next + : m_listChunk->m_containedChunks; SLANG_ASSERT(next == nullptr); next = chunk; m_listChunk->m_endChunk = chunk; @@ -736,9 +757,10 @@ void RiffContainer::startChunk(Chunk::Kind kind, FourCC fourCC) switch (kind) { - case Chunk::Kind::Data: + case Chunk::Kind::Data: { - // We can only start a data chunk if we are in a container, and we can't already be in data chunk + // We can only start a data chunk if we are in a container, and we can't already be in + // data chunk SLANG_ASSERT(m_listChunk && m_dataChunk == nullptr); DataChunk* chunk = _newDataChunk(fourCC); @@ -746,7 +768,7 @@ void RiffContainer::startChunk(Chunk::Kind kind, FourCC fourCC) m_dataChunk = chunk; break; } - case Chunk::Kind::List: + case Chunk::Kind::List: { // We can't be in a data chunk SLANG_ASSERT(m_dataChunk == nullptr); @@ -771,7 +793,7 @@ void RiffContainer::endChunk() { size_t chunkPayloadSize; - // The chunk we are popping + // The chunk we are popping // Only keep track of this in debug builds [[maybe_unused]] Chunk* chunk = nullptr; @@ -782,7 +804,7 @@ void RiffContainer::endChunk() parent = m_dataChunk->m_parent; chunkPayloadSize = m_dataChunk->m_payloadSize; - + m_dataChunk = nullptr; } else @@ -824,7 +846,7 @@ void RiffContainer::setPayload(Data* data, const void* payload, size_t size) // Add current chunks data m_dataChunk->m_payloadSize += size; - + data->m_ownership = Ownership::Arena; data->m_size = size; @@ -901,7 +923,7 @@ RiffContainer::Data* RiffContainer::makeSingleData(DataChunk* dataChunk) { Data* data = dataChunk->m_dataList; - + // Okay lets combine all into one block const size_t payloadSize = dataChunk->calcPayloadSize(); @@ -932,7 +954,7 @@ void RiffContainer::write(const void* inData, size_t size) { uint8_t* end = ((uint8_t*)endData->m_payload) + endData->m_size; // See if can just add to end of current data - if ( end == m_arena.getCursor() && m_arena.allocateCurrentUnaligned(size)) + if (end == m_arena.getCursor() && m_arena.allocateCurrentUnaligned(size)) { ::memcpy(end, inData, size); endData->m_size += size; @@ -953,7 +975,7 @@ static SlangResult _isChunkOk(RiffContainer::Chunk* chunk, void* data) return chunk->calcPayloadSize() == chunk->m_payloadSize ? SLANG_OK : SLANG_FAIL; } -/* static */bool RiffContainer::isChunkOk(Chunk* chunk) +/* static */ bool RiffContainer::isChunkOk(Chunk* chunk) { return SLANG_SUCCEEDED(chunk->visitPostOrder(&_isChunkOk, nullptr)); } @@ -965,11 +987,10 @@ static SlangResult _calcAndSetSize(RiffContainer::Chunk* chunk, void* data) return SLANG_OK; } -/* static */void RiffContainer::calcAndSetSize(Chunk* chunk) +/* static */ void RiffContainer::calcAndSetSize(Chunk* chunk) { chunk->visitPostOrder(&_calcAndSetSize, nullptr); } - -} +} // namespace Slang diff --git a/source/core/slang-riff.h b/source/core/slang-riff.h index 3a964df2d..1e2c883b9 100644 --- a/source/core/slang-riff.h +++ b/source/core/slang-riff.h @@ -2,10 +2,10 @@ #define SLANG_RIFF_H #include "slang-basic.h" -#include "slang-stream.h" #include "slang-memory-arena.h" -#include "slang-writer.h" #include "slang-semantic-version.h" +#include "slang-stream.h" +#include "slang-writer.h" namespace Slang { @@ -16,27 +16,30 @@ namespace Slang typedef uint32_t FourCC; -/* Use of macros to construct and extract from FourCC means the FourCC ordering can be fixed for endian differences. */ +/* Use of macros to construct and extract from FourCC means the FourCC ordering can be fixed for + * endian differences. */ -#if SLANG_LITTLE_ENDIAN +#if SLANG_LITTLE_ENDIAN -#define SLANG_FOUR_CC(c0, c1, c2, c3) ((FourCC(c0) << 0) | (FourCC(c1) << 8) | (FourCC(c2) << 16) | (FourCC(c3) << 24)) +#define SLANG_FOUR_CC(c0, c1, c2, c3) \ + ((FourCC(c0) << 0) | (FourCC(c1) << 8) | (FourCC(c2) << 16) | (FourCC(c3) << 24)) #define SLANG_FOUR_CC_GET_FIRST_CHAR(x) char((x) & 0xff) #define SLANG_FOUR_CC_REPLACE_FIRST_CHAR(x, c) (((x) & 0xffffff00) | FourCC(c)) #else -#define SLANG_FOUR_CC(c0, c1, c2, c3) ((FourCC(c0) << 24) | (FourCC(c1) << 16) | (FourCC(c2) << 8) | (FourCC(c3) << 0)) +#define SLANG_FOUR_CC(c0, c1, c2, c3) \ + ((FourCC(c0) << 24) | (FourCC(c1) << 16) | (FourCC(c2) << 8) | (FourCC(c3) << 0)) #define SLANG_FOUR_CC_GET_FIRST_CHAR(x) char((x) >> 24) #define SLANG_FOUR_CC_REPLACE_FIRST_CHAR(x, c) (((x) & 0x00ffffff) | (FourCC(c) << 24)) #endif -enum +enum { - kRiffPadSize = 2, ///< We only align to 2 bytes + kRiffPadSize = 2, ///< We only align to 2 bytes kRiffPadMask = kRiffPadSize - 1, }; @@ -45,8 +48,9 @@ typedef int RiffHashCode; struct RiffHeader { - FourCC type; ///< The FourCC code that identifies this chunk - uint32_t size; ///< Size does *NOT* include the riff chunk size. The size can be byte sized, but on storage it will always be treated as aligned up by 4. + FourCC type; ///< The FourCC code that identifies this chunk + uint32_t size; ///< Size does *NOT* include the riff chunk size. The size can be byte sized, but + ///< on storage it will always be treated as aligned up by 4. }; struct RiffListHeader @@ -58,35 +62,39 @@ struct RiffListHeader struct RiffFourCC { - /// A 'riff' is the high level file container. It is followed by a subtype and then the contained chunks. - static const FourCC kRiff = SLANG_FOUR_CC('R', 'I', 'F', 'F'); - /// A list is the same as a 'riff' except can be placed anywhere in hierarchy. - static const FourCC kList = SLANG_FOUR_CC('L', 'I', 'S', 'T'); + /// A 'riff' is the high level file container. It is followed by a subtype and then the + /// contained chunks. + static const FourCC kRiff = SLANG_FOUR_CC('R', 'I', 'F', 'F'); + /// A list is the same as a 'riff' except can be placed anywhere in hierarchy. + static const FourCC kList = SLANG_FOUR_CC('L', 'I', 'S', 'T'); + private: RiffFourCC() = delete; }; // Follows semantic version rules // https://semver.org/ -// +// // major.minor.patch -// Patch versions indicate a change. -// Minor means a change that is backwards compatible with previous minor versions. A step in minor and/or major zeros patch. -// Major means a non compatible change. A step in major, zeros minor and patch. +// Patch versions indicate a change. +// Minor means a change that is backwards compatible with previous minor versions. A step in minor +// and/or major zeros patch. Major means a non compatible change. A step in major, zeros minor and +// patch. struct RiffSemanticVersion { typedef RiffSemanticVersion ThisType; typedef uint32_t RawType; - /// == + /// == bool operator==(const ThisType& rhs) const { return m_raw == rhs.m_raw; } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - - /// A patch change indices a different version but does not change the compatibility of the format + + /// A patch change indices a different version but does not change the compatibility of the + /// format int getPatch() const { return m_raw & 0xff; } - /// A minor change implies a format change that is backwards compatible + /// A minor change implies a format change that is backwards compatible int getMinor() const { return (m_raw >> 8) & 0xff; } - /// A major change is binary incompatible by default + /// A major change is binary incompatible by default int getMajor() const { return (m_raw >> 16); } SemanticVersion asSemanticVersion() const @@ -108,18 +116,25 @@ struct RiffSemanticVersion return version; } - static RiffSemanticVersion make(int major, int minor, int patch) { return makeFromRaw(makeRaw(major, minor, patch)); } - static RiffSemanticVersion make(const SemanticVersion& in) { return makeFromRaw(makeRaw(in.m_major, in.m_minor, in.m_patch)); } + static RiffSemanticVersion make(int major, int minor, int patch) + { + return makeFromRaw(makeRaw(major, minor, patch)); + } + static RiffSemanticVersion make(const SemanticVersion& in) + { + return makeFromRaw(makeRaw(in.m_major, in.m_minor, in.m_patch)); + } - /// True if the read version is compatible with the current version, based on semantic rules. + /// True if the read version is compatible with the current version, based on semantic rules. static bool areCompatible(const ThisType& currentVersion, const ThisType& readVersion) { const RawType currentRaw = currentVersion.m_raw; const RawType readRaw = readVersion.m_raw; // Must have same major version. - // For minor version, the read version must be less than or equal. - return ((currentRaw & 0xffff0000) == (readRaw & 0xffff0000)) && ((currentRaw & 0xff00) >= (readRaw & 0xff00)); + // For minor version, the read version must be less than or equal. + return ((currentRaw & 0xffff0000) == (readRaw & 0xffff0000)) && + ((currentRaw & 0xff00) >= (readRaw & 0xff00)); } RawType m_raw; @@ -129,7 +144,7 @@ struct RiffSemanticVersion class RiffReadHelper { public: - template <typename T> + template<typename T> SlangResult read(T& out) { if (m_cur + sizeof(T) > m_end) @@ -143,15 +158,13 @@ public: return SLANG_OK; } - /// Get the data + /// Get the data const uint8_t* getData() const { return m_cur; } - /// Get the remaining size + /// Get the remaining size size_t getRemainingSize() const { return size_t(m_end - m_cur); } - RiffReadHelper(const uint8_t* data, size_t size): - m_start(data), - m_end(data + size), - m_cur(data) + RiffReadHelper(const uint8_t* data, size_t size) + : m_start(data), m_end(data + size), m_cur(data) { } @@ -176,37 +189,38 @@ protected: With the data held in memory allows for adding or removing chunks at will. A future implementation does not necessarily have to be backed by memory when construction, -as data could be written to stream, and the chunk sizes written by seeking back over the file and setting the value. +as data could be written to stream, and the chunk sizes written by seeking back over the file and +setting the value. -In normal usage the chunk sizes are calculated during construction. If the structure is changed, the sizes may -need to be recalculated, before serialization. +In normal usage the chunk sizes are calculated during construction. If the structure is changed, the +sizes may need to be recalculated, before serialization. */ class RiffContainer { public: - // This alignment is only made for arena based allocations. - // For external blocks it's client code to have appropriate alignment. - // This is needed because when reading a RiffContainer, all allocation is arena based, and - // if the payload contains 8 byte aligned data, the overall payload needs to be 8 byte aligned. + // This alignment is only made for arena based allocations. + // For external blocks it's client code to have appropriate alignment. + // This is needed because when reading a RiffContainer, all allocation is arena based, and + // if the payload contains 8 byte aligned data, the overall payload needs to be 8 byte aligned. static const size_t kPayloadMinAlignment = 8; enum class Ownership { - Uninitialized, ///< Doesn't contain anything - NotOwned, ///< It's not owned by the container - Arena, ///< It's owned and allocated on the arena - Owned, ///< It's owned, but wasn't allocated on the arena + Uninitialized, ///< Doesn't contain anything + NotOwned, ///< It's not owned by the container + Arena, ///< It's owned and allocated on the arena + Owned, ///< It's owned, but wasn't allocated on the arena }; struct Data { - /// Get the payload + /// Get the payload void* getPayload() { return m_payload; } - /// Get the end pointer + /// Get the end pointer void* getPayloadEnd() { return (void*)((uint8_t*)m_payload + m_size); } - /// Get the size of the payload + /// Get the size of the payload size_t getSize() const { return m_size; } - /// Get the ownership of the data held in the payload + /// Get the ownership of the data held in the payload Ownership getOwnership() const { return m_ownership; } void init() @@ -217,24 +231,25 @@ public: m_payload = nullptr; } - Ownership m_ownership; ///< Stores the ownership of the payload - size_t m_size; ///< The size of the payload - void* m_payload; ///< The payload - Data* m_next; ///< The next Data block in the list + Ownership m_ownership; ///< Stores the ownership of the payload + size_t m_size; ///< The size of the payload + void* m_payload; ///< The payload + Data* m_next; ///< The next Data block in the list }; struct Chunk; struct ListChunk; struct DataChunk; - typedef SlangResult(*VisitorCallback)(Chunk* chunk, void* data); - + typedef SlangResult (*VisitorCallback)(Chunk* chunk, void* data); + class Visitor; struct Chunk { enum class Kind { - List, ///< Strictly speaking this can be a 'LIST' or a 'RIFF' as they have the same structure + List, ///< Strictly speaking this can be a 'LIST' or a 'RIFF' as they have the same + ///< structure Data, }; @@ -251,23 +266,26 @@ public: SlangResult visitPostOrder(VisitorCallback callback, void* data); SlangResult visitPreOrder(VisitorCallback callback, void* data); - /// Returns a single data chunk + /// Returns a single data chunk Data* getSingleData() const; - /// Calculate the payload size + /// Calculate the payload size size_t calcPayloadSize(); - Kind m_kind; ///< Kind of chunk - FourCC m_fourCC; ///< The chunk type for data, or the sub type for a List (riff/list) - size_t m_payloadSize; ///< The payload size (ie does NOT include RiffChunk header). - Chunk* m_next; ///< Next chunk in this list - ListChunk* m_parent; ///< The chunk this belongs to + Kind m_kind; ///< Kind of chunk + FourCC m_fourCC; ///< The chunk type for data, or the sub type for a List (riff/list) + size_t m_payloadSize; ///< The payload size (ie does NOT include RiffChunk header). + Chunk* m_next; ///< Next chunk in this list + ListChunk* m_parent; ///< The chunk this belongs to }; struct ListChunk : public Chunk { typedef Chunk Super; - SLANG_FORCE_INLINE static bool isType(const Chunk* chunk) { return chunk->m_kind == Kind::List; } + SLANG_FORCE_INLINE static bool isType(const Chunk* chunk) + { + return chunk->m_kind == Kind::List; + } void init(FourCC subType) { @@ -278,61 +296,68 @@ public: m_payloadSize = uint32_t(sizeof(RiffListHeader) - sizeof(RiffHeader)); } - /// Finds chunk (list or data) that matches type. For List/Riff, type is the subtype + /// Finds chunk (list or data) that matches type. For List/Riff, type is the subtype Chunk* findContained(FourCC type) const; void* findContainedData(FourCC type, size_t minSize) const; ListChunk* findContainedList(FourCC type); - /// Finds the contained data. NOTE! Assumes that there is only as single data block, and will return nullptr if there is not + /// Finds the contained data. NOTE! Assumes that there is only as single data block, and + /// will return nullptr if there is not Data* findContainedData(FourCC type) const; - template <typename T> - T* findContainedData(FourCC type) const { return (T*)findContainedData(type, sizeof(T)); } + template<typename T> + T* findContainedData(FourCC type) const + { + return (T*)findContainedData(type, sizeof(T)); + } - /// Find all contained that match the type + /// Find all contained that match the type void findContained(FourCC type, List<ListChunk*>& out); - /// Find all contained that match the type + /// Find all contained that match the type void findContained(FourCC type, List<DataChunk*>& out); - /// Find the list (including self) that matches subtype recursively + /// Find the list (including self) that matches subtype recursively ListChunk* findListRec(FourCC subType); - /// NOTE! Assumes all contained chunks have correct payload sizes + /// NOTE! Assumes all contained chunks have correct payload sizes size_t calcPayloadSize(); - /// Get the sub type + /// Get the sub type FourCC getSubType() const { return m_fourCC; } - /// A singly linked list of contained chunks directly contained in this chunk + /// A singly linked list of contained chunks directly contained in this chunk Chunk* getFirstContainedChunk() const { return m_containedChunks; } - Chunk* m_containedChunks; ///< The contained chunks - Chunk* m_endChunk; ///< The last chunk (only set when pushed, and used when popped) + Chunk* m_containedChunks; ///< The contained chunks + Chunk* m_endChunk; ///< The last chunk (only set when pushed, and used when popped) }; struct DataChunk : public Chunk { typedef Chunk Super; - SLANG_FORCE_INLINE static bool isType(const Chunk* chunk) { return chunk->m_kind == Kind::Data; } + SLANG_FORCE_INLINE static bool isType(const Chunk* chunk) + { + return chunk->m_kind == Kind::Data; + } - /// Calculate a hash (not necessarily very fast) + /// Calculate a hash (not necessarily very fast) RiffHashCode calcHash() const; - /// Calculate the payload size + /// Calculate the payload size size_t calcPayloadSize() const; - /// Copy the payload to dst. Dst must be at least the payload size. + /// Copy the payload to dst. Dst must be at least the payload size. void getPayload(void* dst) const; - /// True if payloads contents is equal to data + /// True if payloads contents is equal to data bool isEqual(const void* data, size_t count) const; - /// Get single data payload. + /// Get single data payload. Data* getSingleData() const; - /// Return as read helper + /// Return as read helper RiffReadHelper asReadHelper() const; void init(FourCC fourCC) @@ -342,22 +367,20 @@ public: m_endData = nullptr; } - Data* m_dataList; ///< List of 0 or more data items - Data* m_endData; ///< The last data point + Data* m_dataList; ///< List of 0 or more data items + Data* m_endData; ///< The last data point }; class ScopeChunk { public: - ScopeChunk(RiffContainer* container, Chunk::Kind kind, FourCC fourCC) : - m_container(container) + ScopeChunk(RiffContainer* container, Chunk::Kind kind, FourCC fourCC) + : m_container(container) { container->startChunk(kind, fourCC); } - ~ScopeChunk() - { - m_container->endChunk(); - } + ~ScopeChunk() { m_container->endChunk(); } + private: RiffContainer* m_container; }; @@ -371,54 +394,61 @@ public: }; - /// Add a complete data chunk + /// Add a complete data chunk void addDataChunk(FourCC dataFourCC, const void* data, size_t dataSizeInBytes); - /// Start a chunk + /// Start a chunk void startChunk(Chunk::Kind kind, FourCC type); - /// Write data into a chunk (can only be inside a Kind::Data) + /// Write data into a chunk (can only be inside a Kind::Data) void write(const void* data, size_t size); - /// Adds an empty data block + /// Adds an empty data block Data* addData(); - /// Set the payload on a data. Payload can be passed as nullptr, if it is no memory will be copied. + /// Set the payload on a data. Payload can be passed as nullptr, if it is no memory will be + /// copied. void setPayload(Data* data, const void* payload, size_t size); - /// Move ownership to. - /// NOTE! The payload *must* be deallocatable via 'free' + /// Move ownership to. + /// NOTE! The payload *must* be deallocatable via 'free' void moveOwned(Data* data, void* payload, size_t size); - /// Move unowned. The payload scope must last longer than the RiffContainer + /// Move unowned. The payload scope must last longer than the RiffContainer void setUnowned(Data* data, void* payload, size_t size); - /// End a chunk + /// End a chunk void endChunk(); - /// Get the root + /// Get the root ListChunk* getRoot() const { return m_rootList; } - /// Get the current chunk - Chunk* getCurrentChunk() { return m_dataChunk ? static_cast<Chunk*>(m_dataChunk) : static_cast<Chunk*>(m_listChunk); } + /// Get the current chunk + Chunk* getCurrentChunk() + { + return m_dataChunk ? static_cast<Chunk*>(m_dataChunk) : static_cast<Chunk*>(m_listChunk); + } - /// Reset the container + /// Reset the container void reset(); - /// true if has a root container, and nothing remains open - bool isFullyConstructed() { return m_rootList && m_listChunk == nullptr && m_dataChunk == nullptr; } + /// true if has a root container, and nothing remains open + bool isFullyConstructed() + { + return m_rootList && m_listChunk == nullptr && m_dataChunk == nullptr; + } - /// Makes a data chunk contain a single contiguous data block + /// Makes a data chunk contain a single contiguous data block Data* makeSingleData(DataChunk* dataChunk); - /// Get the memory arena that is backing the storage of data + /// Get the memory arena that is backing the storage of data MemoryArena& getMemoryArena() { return m_arena; } - /// The if the list and sublists appear correct + /// The if the list and sublists appear correct static bool isChunkOk(Chunk* chunk); - /// Traverses over chunk hierarchy and sets the sizes + /// Traverses over chunk hierarchy and sets the sizes static void calcAndSetSize(Chunk* chunk); - /// Ctor + /// Ctor RiffContainer(); protected: @@ -426,25 +456,26 @@ protected: ListChunk* _newListChunk(FourCC subType); DataChunk* _newDataChunk(FourCC type); - ListChunk* m_rootList; ///< Root list + ListChunk* m_rootList; ///< Root list ListChunk* m_listChunk; DataChunk* m_dataChunk; - MemoryArena m_arena; ///< Can be used to use other owned blocks + MemoryArena m_arena; ///< Can be used to use other owned blocks }; // ----------------------------------------------------------------------------- -template <typename T> +template<typename T> T* as(RiffContainer::Chunk* chunk) { return chunk && T::isType(chunk) ? static_cast<T*>(chunk) : nullptr; } // ----------------------------------------------------------------------------- -template <typename T> +template<typename T> T* as(RiffContainer::Chunk* chunk, FourCC fourCC) { - return chunk && chunk->m_fourCC == fourCC && T::isType(chunk) ? static_cast<T*>(chunk) : nullptr; + return chunk && chunk->m_fourCC == fourCC && T::isType(chunk) ? static_cast<T*>(chunk) + : nullptr; } struct RiffUtil @@ -459,32 +490,44 @@ struct RiffUtil static SlangResult readChunk(Stream* stream, RiffHeader& outChunk); - static SlangResult writeData(const RiffHeader* header, size_t headerSize, const void* payload, size_t payloadSize, Stream* out); - static SlangResult readData(Stream* stream, RiffHeader* outHeader, size_t headerSize, List<uint8_t>& data); + static SlangResult writeData( + const RiffHeader* header, + size_t headerSize, + const void* payload, + size_t payloadSize, + Stream* out); + static SlangResult readData( + Stream* stream, + RiffHeader* outHeader, + size_t headerSize, + List<uint8_t>& data); static SlangResult readPayload(Stream* stream, size_t size, void* outData, size_t& outReadSize); - /// Read a header. Handles special case of list/riff types + /// Read a header. Handles special case of list/riff types static SlangResult readHeader(Stream* stream, RiffListHeader& outHeader); - /// True if the type is a container type - static bool isListType(FourCC type) { return type == RiffFourCC::kRiff || type == RiffFourCC::kList; } + /// True if the type is a container type + static bool isListType(FourCC type) + { + return type == RiffFourCC::kRiff || type == RiffFourCC::kList; + } - /// Dump the chunk structure + /// Dump the chunk structure static void dump(Chunk* chunk, WriterHelper writer); - /// Get the size taking into account padding + /// Get the size taking into account padding static size_t getPadSize(size_t in) { return (in + kRiffPadMask) & ~size_t(kRiffPadMask); } - /// Write a chunk list and contents to a stream + /// Write a chunk list and contents to a stream static SlangResult write(ListChunk* listChunk, bool isRoot, Stream* stream); - /// Write a container to the stream + /// Write a container to the stream static SlangResult write(RiffContainer* container, Stream* stream); - /// Read the stream into the container + /// Read the stream into the container static SlangResult read(Stream* stream, RiffContainer& outContainer); }; -} +} // namespace Slang #endif diff --git a/source/core/slang-rtti-info.cpp b/source/core/slang-rtti-info.cpp index de0460082..9ca1c19b6 100644 --- a/source/core/slang-rtti-info.cpp +++ b/source/core/slang-rtti-info.cpp @@ -1,19 +1,26 @@ #include "slang-rtti-info.h" #include "slang-com-helper.h" - #include "slang-rtti-util.h" #include <mutex> -namespace Slang { +namespace Slang +{ -#define SLANG_RTTI_INFO_INVALID(name) RttiInfo{RttiInfo::Kind::Invalid, 0, 0} -#define SLANG_RTTI_INFO_BASIC(name, type) \ - RttiInfo{RttiInfo::Kind::name, RttiInfo::AlignmentType(SLANG_ALIGN_OF(type)), RttiInfo::SizeType(sizeof(type))} +#define SLANG_RTTI_INFO_INVALID(name) \ + RttiInfo \ + { \ + RttiInfo::Kind::Invalid, 0, 0 \ + } +#define SLANG_RTTI_INFO_BASIC(name, type) \ + RttiInfo \ + { \ + RttiInfo::Kind::name, RttiInfo::AlignmentType(SLANG_ALIGN_OF(type)), \ + RttiInfo::SizeType(sizeof(type)) \ + } -/* static */const RttiInfo RttiInfo::g_basicTypes[Index(Kind::CountOf)] = -{ +/* static */ const RttiInfo RttiInfo::g_basicTypes[Index(Kind::CountOf)] = { SLANG_RTTI_INFO_INVALID(Invalid), SLANG_RTTI_INFO_BASIC(I32, int32_t), SLANG_RTTI_INFO_BASIC(U32, uint32_t), @@ -54,26 +61,27 @@ struct RttiInfoManager } protected: - RttiInfoManager() : - m_arena(1024) + RttiInfoManager() + : m_arena(1024) { } - std::recursive_mutex m_mutex; ///< We need a mutex to guard access to m_arena + std::recursive_mutex m_mutex; ///< We need a mutex to guard access to m_arena MemoryArena m_arena; }; -/* static */void* RttiInfo::allocate(size_t size) +/* static */ void* RttiInfo::allocate(size_t size) { return RttiInfoManager::getSingleton().allocate(size); } -/* static */void RttiInfo::deallocateAll() +/* static */ void RttiInfo::deallocateAll() { return RttiInfoManager::getSingleton().deallocateAll(); } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuilder& out) { @@ -97,27 +105,27 @@ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuil } } -/* static */void RttiInfo::append(const RttiInfo* info, StringBuilder& out) +/* static */ void RttiInfo::append(const RttiInfo* info, StringBuilder& out) { switch (info->m_kind) { - case RttiInfo::Kind::I32: out << "int32_t"; break; - case RttiInfo::Kind::U32: out << "uint32_t"; break; - case RttiInfo::Kind::I64: out << "int64_t"; break; - case RttiInfo::Kind::U64: out << "uint64_t"; break; - case RttiInfo::Kind::F32: out << "float"; break; - case RttiInfo::Kind::F64: out << "double"; break; - case RttiInfo::Kind::Bool: out << "bool"; break; - case RttiInfo::Kind::String: out << "String"; break; - case RttiInfo::Kind::UnownedStringSlice: out << "UnownedStringSlice"; break; - case RttiInfo::Kind::Ptr: + case RttiInfo::Kind::I32: out << "int32_t"; break; + case RttiInfo::Kind::U32: out << "uint32_t"; break; + case RttiInfo::Kind::I64: out << "int64_t"; break; + case RttiInfo::Kind::U64: out << "uint64_t"; break; + case RttiInfo::Kind::F32: out << "float"; break; + case RttiInfo::Kind::F64: out << "double"; break; + case RttiInfo::Kind::Bool: out << "bool"; break; + case RttiInfo::Kind::String: out << "String"; break; + case RttiInfo::Kind::UnownedStringSlice: out << "UnownedStringSlice"; break; + case RttiInfo::Kind::Ptr: { const PtrRttiInfo* ptrRttiInfo = static_cast<const PtrRttiInfo*>(info); append(ptrRttiInfo->m_targetType, out); out << "*"; break; } - case RttiInfo::Kind::RefPtr: + case RttiInfo::Kind::RefPtr: { const RefPtrRttiInfo* ptrRttiInfo = static_cast<const RefPtrRttiInfo*>(info); out << "RefPtr<"; @@ -125,13 +133,13 @@ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuil out << ">"; break; } - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* arrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(info); _appendFixedArray(arrayRttiInfo, out); break; } - case RttiInfo::Kind::List: + case RttiInfo::Kind::List: { const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(info); out << "List<"; @@ -139,9 +147,10 @@ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuil out << ">"; break; } - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Dictionary: { - const DictionaryRttiInfo* dictionaryRttiInfo = static_cast<const DictionaryRttiInfo*>(info); + const DictionaryRttiInfo* dictionaryRttiInfo = + static_cast<const DictionaryRttiInfo*>(info); out << "Dictionary<"; append(dictionaryRttiInfo->m_keyType, out); @@ -150,7 +159,7 @@ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuil out << ">"; break; } - default: + default: { if (info->isNamed()) { @@ -165,7 +174,8 @@ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuil } } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ void StructRttiBuilder::_init(const char* name, const StructRttiInfo* super, const Byte* base) { @@ -183,7 +193,8 @@ StructRttiInfo StructRttiBuilder::make() if (fieldCount) { - StructRttiInfo::Field* dstFields = (StructRttiInfo::Field*)RttiInfo::allocate(sizeof(StructRttiInfo::Field) * fieldCount); + StructRttiInfo::Field* dstFields = + (StructRttiInfo::Field*)RttiInfo::allocate(sizeof(StructRttiInfo::Field) * fieldCount); ::memcpy(dstFields, m_fields.getBuffer(), sizeof(StructRttiInfo::Field) * fieldCount); m_rttiInfo.m_fields = dstFields; @@ -193,7 +204,8 @@ StructRttiInfo StructRttiBuilder::make() return m_rttiInfo; } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncsMap !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncsMap !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ RttiTypeFuncs RttiTypeFuncsMap::getFuncsForType(const RttiInfo* rttiInfo) { @@ -215,7 +227,7 @@ void RttiTypeFuncsMap::add(const RttiInfo* rttiInfo, const RttiTypeFuncs& funcs) { if (auto funcsPtr = m_map.tryGetValueOrAdd(rttiInfo, funcs)) { - // If there are funcs set, they aren't valid otherwise this would be + // If there are funcs set, they aren't valid otherwise this would be // replacing, so assert on that scenario. SLANG_ASSERT(!funcsPtr->isValid()); diff --git a/source/core/slang-rtti-info.h b/source/core/slang-rtti-info.h index a7262e50f..01c042511 100644 --- a/source/core/slang-rtti-info.h +++ b/source/core/slang-rtti-info.h @@ -2,25 +2,32 @@ #define SLANG_CORE_RTTI_INFO_H #include "slang-basic.h" -#include "slang-memory-arena.h" - -#include "slang-list.h" #include "slang-dictionary.h" +#include "slang-list.h" +#include "slang-memory-arena.h" -namespace Slang { +namespace Slang +{ struct RttiInfo; struct RttiTypeFuncsMap; struct RttiTypeFuncs { - typedef void (*CtorArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count); - typedef void (*DtorArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count); - typedef void (*CopyArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, const void* src, Index count); + typedef void ( + *CtorArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count); + typedef void ( + *DtorArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count); + typedef void (*CopyArray)( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* dst, + const void* src, + Index count); - bool isValid() const { return ctorArray && dtorArray && copyArray; } + bool isValid() const { return ctorArray && dtorArray && copyArray; } - static RttiTypeFuncs makeEmpty() { return RttiTypeFuncs{ nullptr, nullptr, nullptr }; } + static RttiTypeFuncs makeEmpty() { return RttiTypeFuncs{nullptr, nullptr, nullptr}; } CtorArray ctorArray; DtorArray dtorArray; @@ -30,11 +37,11 @@ struct RttiTypeFuncs /* Provides a mechanism to map a type to it's RttiFuncs */ struct RttiTypeFuncsMap { - /// For a given type returns the funcs. - /// If not found returns funcs that return 'isValid' as false. + /// For a given type returns the funcs. + /// If not found returns funcs that return 'isValid' as false. RttiTypeFuncs getFuncsForType(const RttiInfo* rttiInfo); - /// Add funcs for a type + /// Add funcs for a type void add(const RttiInfo* rttiInfo, const RttiTypeFuncs& funcs); protected: @@ -42,10 +49,14 @@ protected: }; /* Template to get funcs for any arbitrary type */ -template <typename T> +template<typename T> struct GetRttiTypeFuncs { - static void ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* in, Index count) + static void ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* in, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); @@ -55,7 +66,11 @@ struct GetRttiTypeFuncs new (dst + i) T; } } - static void dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* in, Index count) + static void dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* in, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); @@ -65,7 +80,12 @@ struct GetRttiTypeFuncs (dst + i)->~T(); } } - static void copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) + static void copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + const void* inSrc, + Index count) { SLANG_UNUSED(rttiInfo); SLANG_UNUSED(typeMap); @@ -90,23 +110,36 @@ struct GetRttiTypeFuncs /* An implementation of funcs, for a type that is POD *and* can be zero initialized. Built in types generally fall into this catagory, but so do raw pointers and other types, such as structs that only contain "ZeroPod" types */ -template <typename T> +template<typename T> struct GetRttiTypeFuncsForZeroPod { - static void ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count) + static void ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* dst, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); ::memset(dst, 0, sizeof(T) * count); } - static void dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count) + static void dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* dst, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); SLANG_UNUSED(dst); SLANG_UNUSED(count); } - static void copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, const void* src, Index count) + static void copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* dst, + const void* src, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); @@ -148,7 +181,7 @@ struct RttiInfo Enum, List, Dictionary, - + CountOf, }; @@ -156,25 +189,47 @@ struct RttiInfo AlignmentType m_alignment; SizeType m_size; - void init(Kind kind, size_t alignment, size_t size) { m_kind = kind; m_alignment = AlignmentType(alignment); m_size = SizeType(size); } + void init(Kind kind, size_t alignment, size_t size) + { + m_kind = kind; + m_alignment = AlignmentType(alignment); + m_size = SizeType(size); + } + + template<typename T> + void init(Kind kind) + { + init(kind, SLANG_ALIGN_OF(T), sizeof(T)); + } - template <typename T> - void init(Kind kind) { init(kind, SLANG_ALIGN_OF(T), sizeof(T)); } - - /// Allocate memory for RttiInfo types. - /// Is thread safe, and doesn't require the memory to be freed explicitly - /// Will be freed at shutdown (via global dtor) + /// Allocate memory for RttiInfo types. + /// Is thread safe, and doesn't require the memory to be freed explicitly + /// Will be freed at shutdown (via global dtor) static void* allocate(size_t size); - /// Will free up any allocations. Can only be called at shutdown, and there are guarenteed no uses of - /// RttiInfo - otherwise contents may be undefined. - /// NOTE! Memory *will* be freed with final dtors, but if memory check functions are used they can report - /// this memory. + /// Will free up any allocations. Can only be called at shutdown, and there are guarenteed no + /// uses of RttiInfo - otherwise contents may be undefined. NOTE! Memory *will* be freed with + /// final dtors, but if memory check functions are used they can report this memory. static void deallocateAll(); - static bool isIntegral(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::I32) && Index(kind) <= Index(RttiInfo::Kind::U64); } - static bool isFloat(RttiInfo::Kind kind) { return kind == RttiInfo::Kind::F32 || kind == RttiInfo::Kind::F64; } - static bool isBuiltIn(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::I32) && Index(kind) <= Index(RttiInfo::Kind::Bool); } - static bool isNamed(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::Struct) && Index(kind) <= Index(RttiInfo::Kind::Enum); } + static bool isIntegral(RttiInfo::Kind kind) + { + return Index(kind) >= Index(RttiInfo::Kind::I32) && + Index(kind) <= Index(RttiInfo::Kind::U64); + } + static bool isFloat(RttiInfo::Kind kind) + { + return kind == RttiInfo::Kind::F32 || kind == RttiInfo::Kind::F64; + } + static bool isBuiltIn(RttiInfo::Kind kind) + { + return Index(kind) >= Index(RttiInfo::Kind::I32) && + Index(kind) <= Index(RttiInfo::Kind::Bool); + } + static bool isNamed(RttiInfo::Kind kind) + { + return Index(kind) >= Index(RttiInfo::Kind::Struct) && + Index(kind) <= Index(RttiInfo::Kind::Enum); + } bool isIntegral() const { return isIntegral(m_kind); } bool isFloat() const { return isFloat(m_kind); } @@ -190,7 +245,7 @@ struct RttiInfo // but this works fine for most purposes enum class RttiDefaultValue : uint8_t { - Normal, ///< Zero for integral/float types/false for bool + Normal, ///< Zero for integral/float types/false for bool One, MinusOne, @@ -199,7 +254,7 @@ enum class RttiDefaultValue : uint8_t struct NamedRttiInfo : public RttiInfo { - const char* m_name; ///< Name + const char* m_name; ///< Name }; struct StructRttiInfo : public NamedRttiInfo @@ -216,16 +271,16 @@ struct StructRttiInfo : public NamedRttiInfo struct Field { - const char* m_name; ///< Name of this field - const RttiInfo* m_type; ///< The type of this field - uint32_t m_offset; ///< Offset from object type in bytes - Flags m_flags; ///< Field flags + const char* m_name; ///< Name of this field + const RttiInfo* m_type; ///< The type of this field + uint32_t m_offset; ///< Offset from object type in bytes + Flags m_flags; ///< Field flags }; - const StructRttiInfo* m_super; ///< Super class or nullptr if not defined + const StructRttiInfo* m_super; ///< Super class or nullptr if not defined - Index m_fieldCount; ///< Amount of fields - const Field* m_fields; ///< Fields + Index m_fieldCount; ///< Amount of fields + const Field* m_fields; ///< Fields bool m_ignoreUnknownFieldsInJson = false; }; @@ -234,7 +289,9 @@ struct EnumRttiInfo : public NamedRttiInfo // TODO(JS): }; -SLANG_FORCE_INLINE StructRttiInfo::Flags combine(StructRttiInfo::Flags flags, RttiDefaultValue defaultValue) +SLANG_FORCE_INLINE StructRttiInfo::Flags combine( + StructRttiInfo::Flags flags, + RttiDefaultValue defaultValue) { return StructRttiInfo::Flags(defaultValue) | flags; } @@ -274,23 +331,62 @@ struct OtherRttiInfo : public NamedRttiInfo }; // The default is to just get the info from a global held inside the type. -template <typename T> +template<typename T> struct GetRttiInfo { SLANG_FORCE_INLINE static const RttiInfo* get() { return &T::g_rttiInfo; } }; -template <> struct GetRttiInfo<bool> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::Bool)];} }; -template <> struct GetRttiInfo<int32_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I32)]; } }; -template <> struct GetRttiInfo<int64_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I64)]; } }; -template <> struct GetRttiInfo<uint32_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U32)]; } }; -template <> struct GetRttiInfo<uint64_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U64)]; } }; -template <> struct GetRttiInfo<float> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F32)]; } }; -template <> struct GetRttiInfo<double> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F64)]; } }; -template <> struct GetRttiInfo<String> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::String)]; } }; -template <> struct GetRttiInfo<UnownedStringSlice> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::UnownedStringSlice)]; } }; +template<> +struct GetRttiInfo<bool> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::Bool)]; } +}; +template<> +struct GetRttiInfo<int32_t> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I32)]; } +}; +template<> +struct GetRttiInfo<int64_t> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I64)]; } +}; +template<> +struct GetRttiInfo<uint32_t> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U32)]; } +}; +template<> +struct GetRttiInfo<uint64_t> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U64)]; } +}; +template<> +struct GetRttiInfo<float> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F32)]; } +}; +template<> +struct GetRttiInfo<double> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F64)]; } +}; +template<> +struct GetRttiInfo<String> +{ + static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::String)]; } +}; +template<> +struct GetRttiInfo<UnownedStringSlice> +{ + static const RttiInfo* get() + { + return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::UnownedStringSlice)]; + } +}; -template <typename T> +template<typename T> struct GetRttiInfo<List<T>> { static const ListRttiInfo _make() @@ -300,17 +396,21 @@ struct GetRttiInfo<List<T>> info.m_elementType = GetRttiInfo<T>::get(); return info; } - static const RttiInfo* get() { static const ListRttiInfo g_info = _make(); return &g_info; } + static const RttiInfo* get() + { + static const ListRttiInfo g_info = _make(); + return &g_info; + } }; // Strip const -template <typename T> +template<typename T> struct GetRttiInfo<const T> { static const RttiInfo* get() { return GetRttiInfo<T>::get(); } }; -template <typename K, typename V> +template<typename K, typename V> struct GetRttiInfo<Dictionary<K, V>> { static const DictionaryRttiInfo _make() @@ -321,10 +421,14 @@ struct GetRttiInfo<Dictionary<K, V>> info.m_valueType = GetRttiInfo<V>::get(); return info; } - static const RttiInfo* get() { static const DictionaryRttiInfo g_info = _make(); return &g_info; } + static const RttiInfo* get() + { + static const DictionaryRttiInfo g_info = _make(); + return &g_info; + } }; -template <typename TARGET> +template<typename TARGET> struct GetRttiInfo<TARGET*> { static const PtrRttiInfo _make() @@ -334,10 +438,14 @@ struct GetRttiInfo<TARGET*> info.m_targetType = GetRttiInfo<TARGET>::get(); return info; } - static const RttiInfo* get() { static const PtrRttiInfo g_info = _make(); return &g_info; } + static const RttiInfo* get() + { + static const PtrRttiInfo g_info = _make(); + return &g_info; + } }; -template <typename TARGET> +template<typename TARGET> struct GetRttiInfo<RefPtr<TARGET>> { static const RefPtrRttiInfo _make() @@ -347,10 +455,14 @@ struct GetRttiInfo<RefPtr<TARGET>> info.m_targetType = GetRttiInfo<TARGET>::get(); return info; } - static const RttiInfo* get() { static const RefPtrRttiInfo g_info = _make(); return &g_info; } + static const RttiInfo* get() + { + static const RefPtrRttiInfo g_info = _make(); + return &g_info; + } }; -template <typename T, size_t COUNT> +template<typename T, size_t COUNT> struct GetRttiInfo<T[COUNT]> { static const FixedArrayRttiInfo _make() @@ -363,19 +475,23 @@ struct GetRttiInfo<T[COUNT]> info.m_elementCount = COUNT; return info; } - static const RttiInfo* get() { static const FixedArrayRttiInfo g_info = _make(); return &g_info; } + static const RttiInfo* get() + { + static const FixedArrayRttiInfo g_info = _make(); + return &g_info; + } }; struct StructRttiBuilder { - template <typename T> - StructRttiBuilder(T* obj, const char* name, const StructRttiInfo* super) + template<typename T> + StructRttiBuilder(T* obj, const char* name, const StructRttiInfo* super) { m_rttiInfo.init<T>(RttiInfo::Kind::Struct); _init(name, super, (const Byte*)obj); } - template <typename T> + template<typename T> void addField(const char* name, const T* fieldPtr, StructRttiInfo::Flags flags = 0) { StructRttiInfo::Field field; diff --git a/source/core/slang-rtti-util.cpp b/source/core/slang-rtti-util.cpp index 65ddf8554..701c90e2f 100644 --- a/source/core/slang-rtti-util.cpp +++ b/source/core/slang-rtti-util.cpp @@ -1,19 +1,25 @@ #include "slang-rtti-util.h" -namespace Slang { +namespace Slang +{ -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncs Impls !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncs Impls + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ struct ListFuncs { - static void ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) + static void ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); // We don't care about the element type, as we can just initialize them all as List<Byte> - //const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); + // const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); typedef List<Byte> Type; Type* dst = (Type*)inDst; @@ -24,7 +30,12 @@ struct ListFuncs } } - static void copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) + static void copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + const void* inSrc, + Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); @@ -34,7 +45,8 @@ struct ListFuncs auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); - // We need a type that we can get information from the list from - List<Byte> gives us the functions we need. + // We need a type that we can get information from the list from - List<Byte> gives us the + // functions we need. typedef List<Byte> Type; Type* dst = (Type*)inDst; @@ -71,13 +83,22 @@ struct ListFuncs } else { - typeFuncs.copyArray(typeMap, elementType, dstList.getBuffer(), srcList.getBuffer(), srcCount); + typeFuncs.copyArray( + typeMap, + elementType, + dstList.getBuffer(), + srcList.getBuffer(), + srcCount); dstList.unsafeShrinkToCount(srcCount); } } } - static void dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) + static void dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); @@ -118,14 +139,18 @@ struct ListFuncs struct StructFuncs { - static void ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) + static void ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); // We don't care about the element type, as we can just initialize them all as List<Byte> - //const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); + // const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); typedef List<Byte> Type; Type* dst = (Type*)inDst; @@ -135,7 +160,12 @@ struct StructFuncs new (dst + i) Type; } } - static void copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) + static void copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + const void* inSrc, + Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); @@ -145,7 +175,8 @@ struct StructFuncs auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); - // We need a type that we can get information from the list from - List<Byte> gives us the functions we need. + // We need a type that we can get information from the list from - List<Byte> gives us the + // functions we need. typedef List<Byte> Type; Type* dst = (Type*)inDst; @@ -182,13 +213,22 @@ struct StructFuncs } else { - typeFuncs.copyArray(typeMap, elementType, dstList.getBuffer(), srcList.getBuffer(), srcCount); + typeFuncs.copyArray( + typeMap, + elementType, + dstList.getBuffer(), + srcList.getBuffer(), + srcCount); dstList.unsafeShrinkToCount(srcCount); } } } - static void dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) + static void dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo); @@ -229,17 +269,30 @@ struct StructFuncs struct StructArrayFuncs { - static void ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) + static void ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + Index count) { return RttiUtil::ctorArray(typeMap, rttiInfo, inDst, rttiInfo->m_size, count); } - static void copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) + static void copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + const void* inSrc, + Index count) { return RttiUtil::copyArray(typeMap, rttiInfo, inDst, inSrc, rttiInfo->m_size, count); } - static void dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) + static void dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + Index count) { return RttiUtil::dtorArray(typeMap, rttiInfo, inDst, rttiInfo->m_size, count); } @@ -256,33 +309,34 @@ struct StructArrayFuncs /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) +RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) { if (rttiInfo->isBuiltIn()) { switch (rttiInfo->m_size) { - case 1: return GetRttiTypeFuncsForZeroPod<uint8_t>::getFuncs(); - case 2: return GetRttiTypeFuncsForZeroPod<uint16_t>::getFuncs(); - case 4: return GetRttiTypeFuncsForZeroPod<uint32_t>::getFuncs(); - case 8: return GetRttiTypeFuncsForZeroPod<uint64_t>::getFuncs(); + case 1: return GetRttiTypeFuncsForZeroPod<uint8_t>::getFuncs(); + case 2: return GetRttiTypeFuncsForZeroPod<uint16_t>::getFuncs(); + case 4: return GetRttiTypeFuncsForZeroPod<uint32_t>::getFuncs(); + case 8: return GetRttiTypeFuncsForZeroPod<uint64_t>::getFuncs(); } return RttiTypeFuncs::makeEmpty(); } switch (rttiInfo->m_kind) { - case RttiInfo::Kind::String: return GetRttiTypeFuncs<String>::getFuncs(); - case RttiInfo::Kind::UnownedStringSlice: return GetRttiTypeFuncs<UnownedStringSlice>::getFuncs(); - case RttiInfo::Kind::List: return ListFuncs::getFuncs(); - case RttiInfo::Kind::Struct: return StructArrayFuncs::getFuncs(); - default: break; + case RttiInfo::Kind::String: return GetRttiTypeFuncs<String>::getFuncs(); + case RttiInfo::Kind::UnownedStringSlice: + return GetRttiTypeFuncs<UnownedStringSlice>::getFuncs(); + case RttiInfo::Kind::List: return ListFuncs::getFuncs(); + case RttiInfo::Kind::Struct: return StructArrayFuncs::getFuncs(); + default: break; } return RttiTypeFuncs::makeEmpty(); } -/* static */SlangResult RttiUtil::setInt(int64_t value, const RttiInfo* rttiInfo, void* dst) +/* static */ SlangResult RttiUtil::setInt(int64_t value, const RttiInfo* rttiInfo, void* dst) { SLANG_ASSERT(rttiInfo->isIntegral()); @@ -290,33 +344,33 @@ RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) // Passing in rttiInfo allows for other more complex types to be econverted switch (rttiInfo->m_kind) { - case RttiInfo::Kind::I32: *(int32_t*)dst = int32_t(value); break; - case RttiInfo::Kind::U32: *(uint32_t*)dst = uint32_t(value); break; - case RttiInfo::Kind::I64: *(int64_t*)dst = int64_t(value); break; - case RttiInfo::Kind::U64: *(uint64_t*)dst = uint64_t(value); break; - default: return SLANG_FAIL; + case RttiInfo::Kind::I32: *(int32_t*)dst = int32_t(value); break; + case RttiInfo::Kind::U32: *(uint32_t*)dst = uint32_t(value); break; + case RttiInfo::Kind::I64: *(int64_t*)dst = int64_t(value); break; + case RttiInfo::Kind::U64: *(uint64_t*)dst = uint64_t(value); break; + default: return SLANG_FAIL; } return SLANG_OK; } -/* static */int64_t RttiUtil::getInt64(const RttiInfo* rttiInfo, const void* src) +/* static */ int64_t RttiUtil::getInt64(const RttiInfo* rttiInfo, const void* src) { SLANG_ASSERT(rttiInfo->isIntegral()); switch (rttiInfo->m_kind) { - case RttiInfo::Kind::I32: return *(const int32_t*)src; - case RttiInfo::Kind::U32: return *(const uint32_t*)src; - case RttiInfo::Kind::I64: return *(const int64_t*)src; - case RttiInfo::Kind::U64: return *(const uint64_t*)src; - default: break; + case RttiInfo::Kind::I32: return *(const int32_t*)src; + case RttiInfo::Kind::U32: return *(const uint32_t*)src; + case RttiInfo::Kind::I64: return *(const int64_t*)src; + case RttiInfo::Kind::U64: return *(const uint64_t*)src; + default: break; } SLANG_ASSERT(!"Not integral!"); return -1; } -/* static */double RttiUtil::asDouble(const RttiInfo* rttiInfo, const void* src) +/* static */ double RttiUtil::asDouble(const RttiInfo* rttiInfo, const void* src) { if (rttiInfo->isIntegral()) { @@ -326,9 +380,9 @@ RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) { switch (rttiInfo->m_kind) { - case RttiInfo::Kind::F32: return *(const float*)src; - case RttiInfo::Kind::F64: return *(const double*)src; - default: break; + case RttiInfo::Kind::F32: return *(const float*)src; + case RttiInfo::Kind::F64: return *(const double*)src; + default: break; } } @@ -336,7 +390,7 @@ RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) return 0.0; } -/* static */SlangResult RttiUtil::setFromDouble(double v, const RttiInfo* rttiInfo, void* dst) +/* static */ SlangResult RttiUtil::setFromDouble(double v, const RttiInfo* rttiInfo, void* dst) { if (rttiInfo->isIntegral()) { @@ -346,16 +400,16 @@ RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) { switch (rttiInfo->m_kind) { - case RttiInfo::Kind::F32: *(float*)dst = float(v); return SLANG_OK; - case RttiInfo::Kind::F64: *(double*)dst = v; return SLANG_OK; - default: break; + case RttiInfo::Kind::F32: *(float*)dst = float(v); return SLANG_OK; + case RttiInfo::Kind::F64: *(double*)dst = v; return SLANG_OK; + default: break; } } return SLANG_FAIL; } -/* static */bool RttiUtil::asBool(const RttiInfo* rttiInfo, const void* src) +/* static */ bool RttiUtil::asBool(const RttiInfo* rttiInfo, const void* src) { if (rttiInfo->m_kind == RttiInfo::Kind::Bool) { @@ -379,10 +433,10 @@ static int64_t _getIntDefaultValue(RttiDefaultValue value) { switch (value) { - default: - case RttiDefaultValue::Normal: return 0; - case RttiDefaultValue::One: return 1; - case RttiDefaultValue::MinusOne: return -1; + default: + case RttiDefaultValue::Normal: return 0; + case RttiDefaultValue::One: return 1; + case RttiDefaultValue::MinusOne: return -1; } } @@ -403,7 +457,8 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) { const auto& field = type->m_fields[i]; - const RttiDefaultValue defaultValue = RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask)); + const RttiDefaultValue defaultValue = + RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask)); if (!RttiUtil::isDefault(defaultValue, field.m_type, base + field.m_offset)) { @@ -414,7 +469,10 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) return true; } -/* static */bool RttiUtil::isDefault(RttiDefaultValue defaultValue, const RttiInfo* rttiInfo, const void* src) +/* static */ bool RttiUtil::isDefault( + RttiDefaultValue defaultValue, + const RttiInfo* rttiInfo, + const void* src) { if (rttiInfo->isIntegral()) { @@ -429,52 +487,56 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) switch (rttiInfo->m_kind) { - case RttiInfo::Kind::Invalid: return true; - case RttiInfo::Kind::Bool: return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0); - case RttiInfo::Kind::String: + case RttiInfo::Kind::Invalid: return true; + case RttiInfo::Kind::Bool: return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0); + case RttiInfo::Kind::String: { return ((const String*)src)->getLength() == 0; } - case RttiInfo::Kind::UnownedStringSlice: + case RttiInfo::Kind::UnownedStringSlice: { return ((const UnownedStringSlice*)src)->getLength() == 0; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { return _isStructDefault(static_cast<const StructRttiInfo*>(rttiInfo), src); } - case RttiInfo::Kind::Enum: + case RttiInfo::Kind::Enum: { SLANG_ASSERT(!"Not implemented yet"); return false; } - case RttiInfo::Kind::List: + case RttiInfo::Kind::List: { const auto& v = *(const List<Byte>*)src; return v.getCount() == 0; } - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Dictionary: { const auto& v = *(const Dictionary<Byte, Byte>*)src; return v.getCount() == 0; } - case RttiInfo::Kind::Other: + case RttiInfo::Kind::Other: { const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo); return otherRttiInfo->m_isDefaultFunc && otherRttiInfo->m_isDefaultFunc(rttiInfo, src); } - default: + default: { return false; } } } -/* static */SlangResult RttiUtil::setListCount(RttiTypeFuncsMap* typeMap, const RttiInfo* elementType, void* dst, Index count) +/* static */ SlangResult RttiUtil::setListCount( + RttiTypeFuncsMap* typeMap, + const RttiInfo* elementType, + void* dst, + Index count) { // NOTE! The following only works because List<T> has capacity initialized members, and // setting the count if it is <= capacity just sets the count (ie things aren't released(!)). - + List<Byte>& dstList = *(List<Byte>*)dst; const Index oldCount = dstList.getCount(); if (oldCount == count) @@ -512,34 +574,35 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) return SLANG_OK; } -/* static */bool RttiUtil::canMemCpy(const RttiInfo* type) +/* static */ bool RttiUtil::canMemCpy(const RttiInfo* type) { switch (type->m_kind) { - case RttiInfo::Kind::RefPtr: - case RttiInfo::Kind::String: - case RttiInfo::Kind::Invalid: + case RttiInfo::Kind::RefPtr: + case RttiInfo::Kind::String: + case RttiInfo::Kind::Invalid: { return false; } - case RttiInfo::Kind::UnownedStringSlice: - case RttiInfo::Kind::Ptr: - case RttiInfo::Kind::Enum: + case RttiInfo::Kind::UnownedStringSlice: + case RttiInfo::Kind::Ptr: + case RttiInfo::Kind::Enum: { return true; } - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(type); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast<const FixedArrayRttiInfo*>(type); return canMemCpy(fixedArrayRttiInfo->m_elementType); } - case RttiInfo::Kind::Other: - case RttiInfo::Kind::List: - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Other: + case RttiInfo::Kind::List: + case RttiInfo::Kind::Dictionary: { return false; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(type); @@ -558,51 +621,51 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } } structRttiInfo = structRttiInfo->m_super; - } - while (structRttiInfo); + } while (structRttiInfo); return true; } - default: + default: { return type->isBuiltIn(); } } } -/* static */bool RttiUtil::canZeroInit(const RttiInfo* type) +/* static */ bool RttiUtil::canZeroInit(const RttiInfo* type) { switch (type->m_kind) { - case RttiInfo::Kind::Invalid: + case RttiInfo::Kind::Invalid: { return true; } - case RttiInfo::Kind::String: + case RttiInfo::Kind::String: { // As it stands we can zero init String, but if impl changes that might not // be true return true; } - case RttiInfo::Kind::UnownedStringSlice: - case RttiInfo::Kind::Ptr: - case RttiInfo::Kind::RefPtr: - case RttiInfo::Kind::Enum: + case RttiInfo::Kind::UnownedStringSlice: + case RttiInfo::Kind::Ptr: + case RttiInfo::Kind::RefPtr: + case RttiInfo::Kind::Enum: { return true; } - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(type); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast<const FixedArrayRttiInfo*>(type); return canZeroInit(fixedArrayRttiInfo->m_elementType); } - case RttiInfo::Kind::Other: - case RttiInfo::Kind::List: - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Other: + case RttiInfo::Kind::List: + case RttiInfo::Kind::Dictionary: { return false; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(type); @@ -621,49 +684,49 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } } structRttiInfo = structRttiInfo->m_super; - } - while (structRttiInfo); + } while (structRttiInfo); return true; } - default: + default: { return type->isBuiltIn(); } } } -/* static */bool RttiUtil::hasDtor(const RttiInfo* type) +/* static */ bool RttiUtil::hasDtor(const RttiInfo* type) { switch (type->m_kind) { - case RttiInfo::Kind::Invalid: + case RttiInfo::Kind::Invalid: { return false; } - case RttiInfo::Kind::String: - case RttiInfo::Kind::RefPtr: + case RttiInfo::Kind::String: + case RttiInfo::Kind::RefPtr: { return true; } - case RttiInfo::Kind::UnownedStringSlice: - case RttiInfo::Kind::Ptr: - case RttiInfo::Kind::Enum: + case RttiInfo::Kind::UnownedStringSlice: + case RttiInfo::Kind::Ptr: + case RttiInfo::Kind::Enum: { return false; } - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(type); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast<const FixedArrayRttiInfo*>(type); return hasDtor(fixedArrayRttiInfo->m_elementType); } - case RttiInfo::Kind::Other: - case RttiInfo::Kind::List: - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Other: + case RttiInfo::Kind::List: + case RttiInfo::Kind::Dictionary: { return true; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(type); @@ -682,18 +745,22 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } } structRttiInfo = structRttiInfo->m_super; - } - while (structRttiInfo); + } while (structRttiInfo); return false; } - default: + default: { return !type->isBuiltIn(); } } } -/* static */void RttiUtil::ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count) +/* static */ void RttiUtil::ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + ptrdiff_t stride, + Index count) { if (count <= 0) { @@ -720,28 +787,39 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) switch (rttiInfo->m_kind) { - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(rttiInfo); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast<const FixedArrayRttiInfo*>(rttiInfo); if (fixedArrayRttiInfo->m_size == stride) { // It's contiguous do in one go - ctorArray(typeMap, fixedArrayRttiInfo->m_elementType, dst, fixedArrayRttiInfo->m_elementType->m_size, fixedArrayRttiInfo->m_elementCount * count); + ctorArray( + typeMap, + fixedArrayRttiInfo->m_elementType, + dst, + fixedArrayRttiInfo->m_elementType->m_size, + fixedArrayRttiInfo->m_elementCount * count); } else { // Do it in array runs for (Index i = 0; i < count; ++i, dst += stride) { - ctorArray(typeMap, fixedArrayRttiInfo->m_elementType, dst, fixedArrayRttiInfo->m_elementType->m_size, fixedArrayRttiInfo->m_elementCount); + ctorArray( + typeMap, + fixedArrayRttiInfo->m_elementType, + dst, + fixedArrayRttiInfo->m_elementType->m_size, + fixedArrayRttiInfo->m_elementCount); } } return; } - case RttiInfo::Kind::List: - case RttiInfo::Kind::Dictionary: - case RttiInfo::Kind::Other: + case RttiInfo::Kind::List: + case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Other: { auto funcs = typeMap->getFuncsForType(rttiInfo); SLANG_ASSERT(funcs.isValid()); @@ -761,7 +839,7 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } return; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(rttiInfo); @@ -777,17 +855,22 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) ctorArray(typeMap, field.m_type, dst + field.m_offset, stride, count); } structRttiInfo = structRttiInfo->m_super; - } - while(structRttiInfo); + } while (structRttiInfo); return; } } - + SLANG_ASSERT(!"Unexpected"); } -/* static */void RttiUtil::copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, ptrdiff_t stride, Index count) +/* static */ void RttiUtil::copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + const void* inSrc, + ptrdiff_t stride, + Index count) { if (count <= 0) { @@ -806,7 +889,7 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } else { - + for (Index i = 0; i < count; ++i, dst += stride, src += stride) { ::memcpy(dst, src, size); @@ -817,9 +900,10 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) switch (rttiInfo->m_kind) { - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(rttiInfo); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast<const FixedArrayRttiInfo*>(rttiInfo); const auto elementType = fixedArrayRttiInfo->m_elementType; const auto elementSize = elementType->m_size; const auto elementCount = fixedArrayRttiInfo->m_elementCount; @@ -839,9 +923,9 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } return; } - case RttiInfo::Kind::List: - case RttiInfo::Kind::Dictionary: - case RttiInfo::Kind::Other: + case RttiInfo::Kind::List: + case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Other: { auto funcs = typeMap->getFuncsForType(rttiInfo); SLANG_ASSERT(funcs.isValid()); @@ -860,7 +944,7 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } return; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(rttiInfo); @@ -873,11 +957,16 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; - copyArray(typeMap, field.m_type, dst + field.m_offset, src + field.m_offset, stride, count); + copyArray( + typeMap, + field.m_type, + dst + field.m_offset, + src + field.m_offset, + stride, + count); } structRttiInfo = structRttiInfo->m_super; - } - while (structRttiInfo); + } while (structRttiInfo); return; } @@ -886,7 +975,12 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) SLANG_ASSERT(!"Unexpected"); } -/* static */void RttiUtil::dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count) +/* static */ void RttiUtil::dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + ptrdiff_t stride, + Index count) { if (count <= 0 || !hasDtor(rttiInfo)) { @@ -898,9 +992,10 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) switch (rttiInfo->m_kind) { - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(rttiInfo); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast<const FixedArrayRttiInfo*>(rttiInfo); const auto elementType = fixedArrayRttiInfo->m_elementType; const auto elementSize = elementType->m_size; const auto elementCount = fixedArrayRttiInfo->m_elementCount; @@ -920,9 +1015,9 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } return; } - case RttiInfo::Kind::List: - case RttiInfo::Kind::Dictionary: - case RttiInfo::Kind::Other: + case RttiInfo::Kind::List: + case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Other: { auto funcs = typeMap->getFuncsForType(rttiInfo); SLANG_ASSERT(funcs.isValid()); @@ -941,7 +1036,7 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) } return; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(rttiInfo); @@ -957,8 +1052,7 @@ static bool _isStructDefault(const StructRttiInfo* type, const void* src) dtorArray(typeMap, field.m_type, dst + field.m_offset, stride, count); } structRttiInfo = structRttiInfo->m_super; - } - while (structRttiInfo); + } while (structRttiInfo); return; } diff --git a/source/core/slang-rtti-util.h b/source/core/slang-rtti-util.h index 4807c5ea2..0058eaddf 100644 --- a/source/core/slang-rtti-util.h +++ b/source/core/slang-rtti-util.h @@ -25,31 +25,33 @@ // // Convert from such JSON objects using JSONToNativeConverter::convert -#define SLANG_MAKE_STRUCT_RTTI_INFO(S, ...) \ - template<> \ - struct GetRttiInfo<S> \ - { \ - static const RttiInfo* get() \ - { \ - using S_ = S; \ - const static StructRttiInfo::Field fs[] = {__VA_ARGS__}; \ - const auto ignoreUnknownFields = true; \ - const static auto ret = StructRttiInfo{ \ +#define SLANG_MAKE_STRUCT_RTTI_INFO(S, ...) \ + template<> \ + struct GetRttiInfo<S> \ + { \ + static const RttiInfo* get() \ + { \ + using S_ = S; \ + const static StructRttiInfo::Field fs[] = {__VA_ARGS__}; \ + const auto ignoreUnknownFields = true; \ + const static auto ret = StructRttiInfo{ \ {{RttiInfo::Kind::Struct, alignof(S), sizeof(S)}, #S}, \ - nullptr, \ - SLANG_COUNT_OF(fs), \ - fs, \ - ignoreUnknownFields \ - }; \ - return &ret; \ - } \ + nullptr, \ + SLANG_COUNT_OF(fs), \ + fs, \ + ignoreUnknownFields}; \ + return &ret; \ + } \ }; -#define SLANG_RTTI_FIELD_IMPL(m, name, flags) \ - {name, GetRttiInfo<decltype(S_::m)>::get(), offsetof(S_, m), flags} +#define SLANG_RTTI_FIELD_IMPL(m, name, flags) \ + { \ + name, GetRttiInfo<decltype(S_::m)>::get(), offsetof(S_, m), flags \ + } #define SLANG_RTTI_FIELD(m) SLANG_RTTI_FIELD_IMPL(m, #m, 0) #define SLANG_OPTIONAL_RTTI_FIELD(m) SLANG_RTTI_FIELD_IMPL(m, #m, StructRttiInfo::Flag::Optional) -namespace Slang { +namespace Slang +{ struct RttiUtil { @@ -64,22 +66,42 @@ struct RttiUtil static bool isDefault(RttiDefaultValue defaultValue, const RttiInfo* rttiInfo, const void* src); - /// Gets funcs for default scenarios + /// Gets funcs for default scenarios static RttiTypeFuncs getDefaultTypeFuncs(const RttiInfo* rttiInfo); - /// Set a list count - static SlangResult setListCount(RttiTypeFuncsMap* typeMap, const RttiInfo* elementType, void* dst, Index count); + /// Set a list count + static SlangResult setListCount( + RttiTypeFuncsMap* typeMap, + const RttiInfo* elementType, + void* dst, + Index count); - /// Returns if the type can be zero initialized + /// Returns if the type can be zero initialized static bool canZeroInit(const RttiInfo* type); - /// Returns true if the type needs dtor + /// Returns true if the type needs dtor static bool hasDtor(const RttiInfo* type); - /// Returns true if we can memcpy to copy + /// Returns true if we can memcpy to copy static bool canMemCpy(const RttiInfo* type); - static void ctorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count); - static void copyArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, ptrdiff_t stride, Index count); - static void dtorArray(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count); + static void ctorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + ptrdiff_t stride, + Index count); + static void copyArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + const void* inSrc, + ptrdiff_t stride, + Index count); + static void dtorArray( + RttiTypeFuncsMap* typeMap, + const RttiInfo* rttiInfo, + void* inDst, + ptrdiff_t stride, + Index count); }; } // namespace Slang diff --git a/source/core/slang-secure-crt.h b/source/core/slang-secure-crt.h index 46552914a..57e38f0dd 100644 --- a/source/core/slang-secure-crt.h +++ b/source/core/slang-secure-crt.h @@ -1,16 +1,15 @@ #ifndef _MSC_VER #ifndef SLANG_CORE_SECURE_CRT_H #define SLANG_CORE_SECURE_CRT_H +#include <assert.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> -#include <assert.h> - #include <wchar.h> -inline void memcpy_s(void *dest, [[maybe_unused]] size_t destSize, const void * src, size_t count) +inline void memcpy_s(void* dest, [[maybe_unused]] size_t destSize, const void* src, size_t count) { assert(destSize >= count); memcpy(dest, src, count); @@ -19,75 +18,92 @@ inline void memcpy_s(void *dest, [[maybe_unused]] size_t destSize, const void * #define _TRUNCATE ((size_t)-1) #define _stricmp strcasecmp -inline void fopen_s(FILE**f, const char * fileName, const char * mode) +inline void fopen_s(FILE** f, const char* fileName, const char* mode) { - *f = fopen(fileName, mode); + *f = fopen(fileName, mode); } -inline size_t fread_s(void * buffer, [[maybe_unused]] size_t bufferSize, size_t elementSize, size_t count, FILE * stream) +inline size_t fread_s( + void* buffer, + [[maybe_unused]] size_t bufferSize, + size_t elementSize, + size_t count, + FILE* stream) { assert(bufferSize >= elementSize * count); return fread(buffer, elementSize, count, stream); } -inline size_t wcsnlen_s(const wchar_t * str, size_t /*numberofElements*/) +inline size_t wcsnlen_s(const wchar_t* str, size_t /*numberofElements*/) { - return wcslen(str); + return wcslen(str); } -inline size_t strnlen_s(const char * str, size_t numberOfElements) +inline size_t strnlen_s(const char* str, size_t numberOfElements) { -#if defined( __CYGWIN__ ) +#if defined(__CYGWIN__) const char* cur = str; if (str) { - const char*const end = str + numberOfElements; - while (*cur && cur < end) cur++; + const char* const end = str + numberOfElements; + while (*cur && cur < end) + cur++; } return size_t(cur - str); #else - return strnlen(str, numberOfElements); + return strnlen(str, numberOfElements); #endif } -__attribute__((format(printf, 3, 4))) -inline int sprintf_s(char * buffer, size_t sizeOfBuffer, const char * format, ...) +__attribute__((format(printf, 3, 4))) inline int sprintf_s( + char* buffer, + size_t sizeOfBuffer, + const char* format, + ...) { - va_list argptr; - va_start(argptr, format); - int rs = vsnprintf(buffer, sizeOfBuffer, format, argptr); - va_end(argptr); - return rs; + va_list argptr; + va_start(argptr, format); + int rs = vsnprintf(buffer, sizeOfBuffer, format, argptr); + va_end(argptr); + return rs; } // A patch was submitted to GCC wchar_t support in 2001, so I'm sure we can // enable this any day now... // __attribute__((format(wprintf, 3, 4))) -inline int swprintf_s(wchar_t * buffer, size_t sizeOfBuffer, const wchar_t * format, ...) +inline int swprintf_s(wchar_t* buffer, size_t sizeOfBuffer, const wchar_t* format, ...) { - va_list argptr; - va_start(argptr, format); - int rs = vswprintf(buffer, sizeOfBuffer, format, argptr); - va_end(argptr); - return rs; + va_list argptr; + va_start(argptr, format); + int rs = vswprintf(buffer, sizeOfBuffer, format, argptr); + va_end(argptr); + return rs; } -inline void wcscpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource) +inline void wcscpy_s(wchar_t* strDestination, size_t /*numberOfElements*/, const wchar_t* strSource) { - wcscpy(strDestination, strSource); + wcscpy(strDestination, strSource); } -inline void strcpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource) +inline void strcpy_s(char* strDestination, size_t /*numberOfElements*/, const char* strSource) { - strcpy(strDestination, strSource); + strcpy(strDestination, strSource); } -inline void wcsncpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource, size_t count) +inline void wcsncpy_s( + wchar_t* strDestination, + size_t /*numberOfElements*/, + const wchar_t* strSource, + size_t count) { - wcsncpy(strDestination, strSource, count); + wcsncpy(strDestination, strSource, count); } -inline void strncpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource, size_t count) +inline void strncpy_s( + char* strDestination, + size_t /*numberOfElements*/, + const char* strSource, + size_t count) { - strncpy(strDestination, strSource, count); + strncpy(strDestination, strSource, count); } #endif #endif diff --git a/source/core/slang-semantic-version.cpp b/source/core/slang-semantic-version.cpp index 9e68de746..ab7b5007b 100644 --- a/source/core/slang-semantic-version.cpp +++ b/source/core/slang-semantic-version.cpp @@ -1,15 +1,18 @@ // slang-semantic-version.cpp #include "slang-semantic-version.h" -#include "slang-com-helper.h" - #include "../core/slang-string-util.h" +#include "slang-com-helper.h" -namespace Slang { +namespace Slang +{ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SemanticVersion !!!!!!!!!!!!!!!!!!!!!!!!!!!!! -SlangResult SemanticVersion::parse(const UnownedStringSlice& value, char separatorChar, SemanticVersion& outVersion) +SlangResult SemanticVersion::parse( + const UnownedStringSlice& value, + char separatorChar, + SemanticVersion& outVersion) { outVersion.reset(); @@ -21,7 +24,7 @@ SlangResult SemanticVersion::parse(const UnownedStringSlice& value, char separat return SLANG_FAIL; } - Int ints[3] = { 0, 0, 0 }; + Int ints[3] = {0, 0, 0}; for (Index i = 0; i < splitCount; i++) { SLANG_RETURN_ON_FAIL(StringUtil::parseInt(slices[i], ints[i])); @@ -40,7 +43,7 @@ SlangResult SemanticVersion::parse(const UnownedStringSlice& value, char separat return SLANG_OK; } -SlangResult SemanticVersion::parse(const UnownedStringSlice& value, SemanticVersion& outVersion) +SlangResult SemanticVersion::parse(const UnownedStringSlice& value, SemanticVersion& outVersion) { return parse(value, '.', outVersion); } @@ -54,7 +57,7 @@ void SemanticVersion::append(StringBuilder& buf) const } } -/* static */SemanticVersion SemanticVersion::getEarliest(const ThisType* versions, Count count) +/* static */ SemanticVersion SemanticVersion::getEarliest(const ThisType* versions, Count count) { if (count <= 0) { @@ -72,7 +75,7 @@ void SemanticVersion::append(StringBuilder& buf) const return bestVersion; } -/* static */SemanticVersion SemanticVersion::getLatest(const ThisType* versions, Count count) +/* static */ SemanticVersion SemanticVersion::getLatest(const ThisType* versions, Count count) { if (count <= 0) { @@ -92,7 +95,10 @@ void SemanticVersion::append(StringBuilder& buf) const // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MatchSemanticVersion !!!!!!!!!!!!!!!!!!!!!!!!!!!!! -/* static */SemanticVersion MatchSemanticVersion::findAnyBest(const SemanticVersion* versions, Count count, const ThisType& matchVersion) +/* static */ SemanticVersion MatchSemanticVersion::findAnyBest( + const SemanticVersion* versions, + Count count, + const ThisType& matchVersion) { // If there aren't any we are done if (count <= 0) @@ -111,48 +117,58 @@ void SemanticVersion::append(StringBuilder& buf) const switch (matchVersion.m_kind) { - case Kind::Past: + case Kind::Past: { return SemanticVersion::getEarliest(versions, count); } - case Kind::Unknown: - case Kind::Future: + case Kind::Unknown: + case Kind::Future: { // If it's unknown, we just get the latest return SemanticVersion::getLatest(versions, count); } - case Kind::Major: + case Kind::Major: { start = SemanticVersion(matchVersion.m_version.m_major, 0, 0); end = SemanticVersion(matchVersion.m_version.m_major + 1, 0, 0); break; } - case Kind::MajorMinor: + case Kind::MajorMinor: { - start = SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor, 0); - end = SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor + 1, 0); + start = + SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor, 0); + end = SemanticVersion( + matchVersion.m_version.m_major, + matchVersion.m_version.m_minor + 1, + 0); break; } - case Kind::MajorMinorPatch: + case Kind::MajorMinorPatch: { start = SemanticVersion(matchVersion.m_version); - end = SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor, matchVersion.m_version.m_patch + 1); + end = SemanticVersion( + matchVersion.m_version.m_major, + matchVersion.m_version.m_minor, + matchVersion.m_version.m_patch + 1); break; } - default: break; + default: break; } List<SemanticVersion> sortedVersions; sortedVersions.addRange(versions, count); // Sort into increasing values - sortedVersions.sort([&](const SemanticVersion& a, const SemanticVersion& b) -> bool { return a < b; }); + sortedVersions.sort( + [&](const SemanticVersion& a, const SemanticVersion& b) -> bool { return a < b; }); Index startIndex = 0; - for (; startIndex < count && sortedVersions[startIndex] < start; ++startIndex); + for (; startIndex < count && sortedVersions[startIndex] < start; ++startIndex) + ; Index endIndex = startIndex; - for (; endIndex < count && sortedVersions[endIndex] < end; ++endIndex); + for (; endIndex < count && sortedVersions[endIndex] < end; ++endIndex) + ; // If we have a span of versions, get the last in the span if (startIndex < endIndex) @@ -173,7 +189,7 @@ void SemanticVersion::append(StringBuilder& buf) const return sortedVersions[startIndex - 1]; } - // All cases should be covered, but return the last one + // All cases should be covered, but return the last one return sortedVersions[count - 1]; } @@ -181,21 +197,21 @@ void MatchSemanticVersion::append(StringBuilder& buf) const { switch (m_kind) { - default: - case Kind::Unknown: buf << "unknown"; break; - case Kind::Past: buf << "past"; break; - case Kind::Future: buf << "future"; break; - case Kind::Major: + default: + case Kind::Unknown: buf << "unknown"; break; + case Kind::Past: buf << "past"; break; + case Kind::Future: buf << "future"; break; + case Kind::Major: { buf << m_version.m_major; break; } - case Kind::MajorMinor: + case Kind::MajorMinor: { buf << m_version.m_major << "." << m_version.m_minor; break; } - case Kind::MajorMinorPatch: + case Kind::MajorMinorPatch: { m_version.append(buf); break; diff --git a/source/core/slang-semantic-version.h b/source/core/slang-semantic-version.h index e7f10eeed..0bb467ab7 100644 --- a/source/core/slang-semantic-version.h +++ b/source/core/slang-semantic-version.h @@ -14,13 +14,15 @@ struct SemanticVersion typedef uint64_t IntegerType; - SemanticVersion():m_major(0), m_minor(0), m_patch(0) {} + SemanticVersion() + : m_major(0), m_minor(0), m_patch(0) + { + } - SemanticVersion(int inMajor, int inMinor = 0, int inPatch = 0): - m_major(uint16_t(inMajor)), - m_minor(uint16_t(inMinor)), - m_patch(uint32_t(inPatch)) - {} + SemanticVersion(int inMajor, int inMinor = 0, int inPatch = 0) + : m_major(uint16_t(inMajor)), m_minor(uint16_t(inMinor)), m_patch(uint32_t(inPatch)) + { + } void reset() { @@ -29,28 +31,34 @@ struct SemanticVersion m_patch = 0; } - /// All zeros means nothing is set + /// All zeros means nothing is set bool isSet() const { return m_major || m_minor || m_patch; } - IntegerType toInteger() const { return (IntegerType(m_major) << 48) | (IntegerType(m_minor) << 32) | m_patch; } + IntegerType toInteger() const + { + return (IntegerType(m_major) << 48) | (IntegerType(m_minor) << 32) | m_patch; + } void setFromInteger(IntegerType v) { set(int(v >> 48), int((v >> 32) & 0xffff), int(v & 0xffffffff)); } void set(int major, int minor, int patch = 0) { - SLANG_ASSERT(major >= 0 && minor >=0 && patch >= 0); + SLANG_ASSERT(major >= 0 && minor >= 0 && patch >= 0); m_major = uint16_t(major); m_minor = uint16_t(minor); m_patch = uint32_t(patch); } - /// Get hash value + /// Get hash value HashCode getHashCode() const { return Slang::getHashCode(toInteger()); } static SlangResult parse(const UnownedStringSlice& value, SemanticVersion& outVersion); - static SlangResult parse(const UnownedStringSlice& value, char separatorChar, SemanticVersion& outVersion); + static SlangResult parse( + const UnownedStringSlice& value, + char separatorChar, + SemanticVersion& outVersion); static ThisType getEarliest(const ThisType* versions, Count count); static ThisType getLatest(const ThisType* versions, Count count); @@ -68,7 +76,7 @@ struct SemanticVersion uint16_t m_major; uint16_t m_minor; - uint32_t m_patch; ///< Patch number. Can actually be quite large for some code bases. + uint32_t m_patch; ///< Patch number. Can actually be quite large for some code bases. }; /* Adds to the semantic versioning information for an incomplete version that can be matched */ @@ -78,41 +86,64 @@ struct MatchSemanticVersion enum class Kind { - Unknown, ///< Not known - Past, ///< Some unknown past version - Future, ///< Some future unknown version - Major, ///< Major version is defined (minor is in effect undefined) - MajorMinor, ///< Major and minor version are defined - MajorMinorPatch, ///< All elements of semantic version are defined + Unknown, ///< Not known + Past, ///< Some unknown past version + Future, ///< Some future unknown version + Major, ///< Major version is defined (minor is in effect undefined) + MajorMinor, ///< Major and minor version are defined + MajorMinorPatch, ///< All elements of semantic version are defined }; - /// True if has a complete version + /// True if has a complete version bool hasCompleteVersion() const { return m_kind == Kind::MajorMinorPatch; } - /// True if has some version information + /// True if has some version information bool hasVersion() const { return Index(m_kind) >= Index(Kind::Major); } - void set(Index major) { m_kind = Kind::Major; m_version = SemanticVersion(int(major), 0, 0); } - void set(Index major, Index minor) { m_kind = Kind::MajorMinor; m_version = SemanticVersion(int(major), int(minor), 0); } - void set(Index major, Index minor, Index patch) { m_kind = Kind::MajorMinorPatch; m_version = SemanticVersion(int(major), int(minor), int(patch)); } + void set(Index major) + { + m_kind = Kind::Major; + m_version = SemanticVersion(int(major), 0, 0); + } + void set(Index major, Index minor) + { + m_kind = Kind::MajorMinor; + m_version = SemanticVersion(int(major), int(minor), 0); + } + void set(Index major, Index minor, Index patch) + { + m_kind = Kind::MajorMinorPatch; + m_version = SemanticVersion(int(major), int(minor), int(patch)); + } void append(StringBuilder& buf) const; - static MatchSemanticVersion makeFuture() { MatchSemanticVersion version; version.m_kind = Kind::Future; return version; } + static MatchSemanticVersion makeFuture() + { + MatchSemanticVersion version; + version.m_kind = Kind::Future; + return version; + } - /// Finds the 'best' version based on the versions passed. - /// Doesn't follow strict semantic rules as will attempt to return the closest 'any' in past or future - /// If none can be found, returns an empty semantic version - static SemanticVersion findAnyBest(const SemanticVersion* versions, Count count, const ThisType& matchVersion); + /// Finds the 'best' version based on the versions passed. + /// Doesn't follow strict semantic rules as will attempt to return the closest 'any' in past or + /// future If none can be found, returns an empty semantic version + static SemanticVersion findAnyBest( + const SemanticVersion* versions, + Count count, + const ThisType& matchVersion); - MatchSemanticVersion():m_kind(Kind::Unknown) {} - MatchSemanticVersion(Kind kind, const SemanticVersion& version): - m_kind(kind), - m_version(version) - {} + MatchSemanticVersion() + : m_kind(Kind::Unknown) + { + } + MatchSemanticVersion(Kind kind, const SemanticVersion& version) + : m_kind(kind), m_version(version) + { + } Kind m_kind; SemanticVersion m_version; }; -} +} // namespace Slang #endif diff --git a/source/core/slang-shared-library.cpp b/source/core/slang-shared-library.cpp index 34464597c..f62591af0 100644 --- a/source/core/slang-shared-library.cpp +++ b/source/core/slang-shared-library.cpp @@ -1,7 +1,6 @@ #include "slang-shared-library.h" #include "slang-com-ptr.h" - #include "slang-io.h" #include "slang-string-util.h" @@ -13,7 +12,7 @@ #include <sys/stat.h> #include <sys/types.h> #ifndef _WIN32 -# include <unistd.h> +#include <unistd.h> #endif namespace Slang @@ -21,14 +20,19 @@ namespace Slang /* !!!!!!!!!!!!!!!!!!!!!!!!!! DefaultSharedLibraryLoader !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ -/* static */DefaultSharedLibraryLoader DefaultSharedLibraryLoader::s_singleton; +/* static */ DefaultSharedLibraryLoader DefaultSharedLibraryLoader::s_singleton; ISlangUnknown* DefaultSharedLibraryLoader::getInterface(const Guid& guid) { - return (guid == ISlangUnknown::getTypeGuid() || guid == ISlangSharedLibraryLoader::getTypeGuid()) ? static_cast<ISlangSharedLibraryLoader*>(this) : nullptr; + return (guid == ISlangUnknown::getTypeGuid() || + guid == ISlangSharedLibraryLoader::getTypeGuid()) + ? static_cast<ISlangSharedLibraryLoader*>(this) + : nullptr; } -SlangResult DefaultSharedLibraryLoader::loadSharedLibrary(const char* path, ISlangSharedLibrary** outSharedLibrary) +SlangResult DefaultSharedLibraryLoader::loadSharedLibrary( + const char* path, + ISlangSharedLibrary** outSharedLibrary) { *outSharedLibrary = nullptr; // Try loading @@ -38,7 +42,9 @@ SlangResult DefaultSharedLibraryLoader::loadSharedLibrary(const char* path, ISla return SLANG_OK; } -SlangResult DefaultSharedLibraryLoader::loadPlatformSharedLibrary(const char* path, ISlangSharedLibrary** outSharedLibrary) +SlangResult DefaultSharedLibraryLoader::loadPlatformSharedLibrary( + const char* path, + ISlangSharedLibrary** outSharedLibrary) { *outSharedLibrary = nullptr; // Try loading @@ -48,7 +54,11 @@ SlangResult DefaultSharedLibraryLoader::loadPlatformSharedLibrary(const char* pa return SLANG_OK; } -/* static */SlangResult DefaultSharedLibraryLoader::load(ISlangSharedLibraryLoader* loader, const String& path, const String& name, ISlangSharedLibrary** outLibrary) +/* static */ SlangResult DefaultSharedLibraryLoader::load( + ISlangSharedLibraryLoader* loader, + const String& path, + const String& name, + ISlangSharedLibrary** outLibrary) { if (path.getLength()) { @@ -99,8 +109,7 @@ void* DefaultSharedLibrary::castAs(const SlangUUID& guid) void* DefaultSharedLibrary::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == ISlangSharedLibrary::getTypeGuid()) { return static_cast<ISlangSharedLibrary*>(this); @@ -164,4 +173,4 @@ uint64_t SharedLibraryUtils::getSharedLibraryTimestamp(void* symbolInLib) return 0; } -} +} // namespace Slang diff --git a/source/core/slang-shared-library.h b/source/core/slang-shared-library.h index d6c1618ec..fbc8a1d30 100644 --- a/source/core/slang-shared-library.h +++ b/source/core/slang-shared-library.h @@ -1,15 +1,14 @@ #ifndef SLANG_CORE_SHARED_LIBRARY_H #define SLANG_CORE_SHARED_LIBRARY_H -#include "slang.h" -#include "slang-com-helper.h" -#include "slang-com-ptr.h" - #include "../core/slang-com-object.h" -#include "../core/slang-io.h" -#include "../core/slang-platform.h" #include "../core/slang-common.h" #include "../core/slang-dictionary.h" +#include "../core/slang-io.h" +#include "../core/slang-platform.h" +#include "slang-com-helper.h" +#include "slang-com-ptr.h" +#include "slang.h" namespace Slang { @@ -17,27 +16,30 @@ namespace Slang class DefaultSharedLibraryLoader : public ISlangSharedLibraryLoader { public: - - // ISlangUnknown + // ISlangUnknown // override ref counting, as DefaultSharedLibraryLoader is singleton - SLANG_IUNKNOWN_QUERY_INTERFACE + SLANG_IUNKNOWN_QUERY_INTERFACE SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } // ISlangSharedLibraryLoader - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadSharedLibrary(const char* path, - ISlangSharedLibrary** outSharedLibrary) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadSharedLibrary(const char* path, ISlangSharedLibrary** outSharedLibrary) SLANG_OVERRIDE; SlangResult loadPlatformSharedLibrary(const char* path, ISlangSharedLibrary** outSharedLibrary); - /// Get the singleton + /// Get the singleton static DefaultSharedLibraryLoader* getSingleton() { return &s_singleton; } - static SlangResult load(ISlangSharedLibraryLoader* loader, const String& path, const String& name, ISlangSharedLibrary** outLibrary); + static SlangResult load( + ISlangSharedLibraryLoader* loader, + const String& path, + const String& name, + ISlangSharedLibrary** outLibrary); private: - /// Make so not constructible + /// Make so not constructible DefaultSharedLibraryLoader() {} virtual ~DefaultSharedLibraryLoader() {} @@ -48,28 +50,28 @@ private: class DefaultSharedLibrary : public ISlangSharedLibrary, public ComBaseObject { - public: - SLANG_CLASS_GUID(0xe7f2597b, 0xf803, 0x4b6e, { 0xaf, 0x8b, 0xcb, 0xe3, 0xa2, 0x21, 0xfd, 0x5a }) +public: + SLANG_CLASS_GUID(0xe7f2597b, 0xf803, 0x4b6e, {0xaf, 0x8b, 0xcb, 0xe3, 0xa2, 0x21, 0xfd, 0x5a}) // ISlangUnknown SLANG_COM_BASE_IUNKNOWN_ALL // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangSharedLibrary - virtual SLANG_NO_THROW void* SLANG_MCALL findSymbolAddressByName(char const* name) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void* SLANG_MCALL findSymbolAddressByName(char const* name) + SLANG_OVERRIDE; - /// Ctor. - DefaultSharedLibrary(const SharedLibrary::Handle sharedLibraryHandle): - m_sharedLibraryHandle(sharedLibraryHandle) + /// Ctor. + DefaultSharedLibrary(const SharedLibrary::Handle sharedLibraryHandle) + : m_sharedLibraryHandle(sharedLibraryHandle) { SLANG_ASSERT(sharedLibraryHandle); } - /// Need virtual dtor to keep delete this happy + /// Need virtual dtor to keep delete this happy virtual ~DefaultSharedLibrary(); - protected: - +protected: void* getInterface(const Guid& guid); void* getObject(const Guid& guid); @@ -78,18 +80,19 @@ class DefaultSharedLibrary : public ISlangSharedLibrary, public ComBaseObject class ScopeSharedLibrary : public DefaultSharedLibrary { -public: +public: typedef DefaultSharedLibrary Super; - static ComPtr<ISlangSharedLibrary> create(const SharedLibrary::Handle sharedLibraryHandle, ISlangUnknown* scope) + static ComPtr<ISlangSharedLibrary> create( + const SharedLibrary::Handle sharedLibraryHandle, + ISlangUnknown* scope) { - return ComPtr< ISlangSharedLibrary>(new ScopeSharedLibrary(sharedLibraryHandle, scope)); + return ComPtr<ISlangSharedLibrary>(new ScopeSharedLibrary(sharedLibraryHandle, scope)); } /// Ctor - ScopeSharedLibrary(const SharedLibrary::Handle sharedLibraryHandle, ISlangUnknown* scope) : - Super(sharedLibraryHandle), - m_scope(scope) + ScopeSharedLibrary(const SharedLibrary::Handle sharedLibraryHandle, ISlangUnknown* scope) + : Super(sharedLibraryHandle), m_scope(scope) { } @@ -106,6 +109,6 @@ public: static uint64_t getSharedLibraryTimestamp(void* symbolInLib); }; -} +} // namespace Slang #endif // SLANG_SHARED_LIBRARY_H_INCLUDED diff --git a/source/core/slang-short-list.h b/source/core/slang-short-list.h index 66165fc72..87d52c8d7 100644 --- a/source/core/slang-short-list.h +++ b/source/core/slang-short-list.h @@ -1,497 +1,493 @@ #ifndef SLANG_CORE_SHORT_LIST_H #define SLANG_CORE_SHORT_LIST_H -#include "slang.h" - #include "slang-allocator.h" -#include "slang-math.h" #include "slang-array-view.h" +#include "slang-math.h" +#include "slang.h" namespace Slang { - template<typename T, int shortListSize = 16, typename TAllocator = StandardAllocator> - class ShortList - { - private: - static const Index kInitialCount = 16; - typedef ShortList<T, shortListSize, TAllocator> ThisType; - public: - ShortList() - : m_buffer(nullptr), m_count(0), m_capacity(0) +template<typename T, int shortListSize = 16, typename TAllocator = StandardAllocator> +class ShortList +{ +private: + static const Index kInitialCount = 16; + typedef ShortList<T, shortListSize, TAllocator> ThisType; + +public: + ShortList() + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + } + template<typename... Args> + ShortList(const T& val, Args... args) + { + _init(val, args...); + } + ShortList(const ThisType& list) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + this->operator=(list); + } + ShortList(ThisType&& list) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + this->operator=(static_cast<ThisType&&>(list)); + } + ~ShortList() { _deallocateBuffer(); } + template<int _otherShortListSize, typename TOtherAllocator> + ThisType& operator=(const ShortList<T, _otherShortListSize, TOtherAllocator>& list) + { + clearAndDeallocate(); + addRange(list); + return *this; + } + + ThisType& operator=(const ThisType& other) + { + clearAndDeallocate(); + addRange(other); + return *this; + } + + ThisType& operator=(ThisType&& list) + { + // Could just do a swap here, and memory would be freed on rhs dtor + _deallocateBuffer(); + m_count = list.m_count; + m_capacity = list.m_capacity; + m_buffer = list.m_buffer; + + list.m_buffer = nullptr; + list.m_count = 0; + list.m_capacity = 0; + + for (Index i = 0; i < Math::Min((Index)shortListSize, m_count); i++) + m_shortBuffer[i] = _Move(list.m_shortBuffer[i]); + return *this; + } + + struct Iterator + { + ThisType* container = nullptr; + Index index = -1; + Iterator& operator++() { + ++index; + return *this; } - template<typename... Args> - ShortList(const T& val, Args... args) + Iterator operator++(int) { - _init(val, args...); + Iterator rs = *this; + ++index; + return rs; } - ShortList(const ThisType& list) - : m_buffer(nullptr), m_count(0), m_capacity(0) + Iterator& operator--() { - this->operator=(list); + --index; + return *this; } - ShortList(ThisType&& list) - : m_buffer(nullptr), m_count(0), m_capacity(0) + Iterator operator--(int) { - this->operator=(static_cast<ThisType&&>(list)); + Iterator rs = *this; + --index; + return rs; } - ~ShortList() + T* operator->() { - _deallocateBuffer(); + SLANG_ASSERT(container); + return &(*container)[index]; } - template<int _otherShortListSize, typename TOtherAllocator> - ThisType& operator=(const ShortList<T, _otherShortListSize, TOtherAllocator>& list) + T& operator*() { - clearAndDeallocate(); - addRange(list); - return *this; + SLANG_ASSERT(container); + return (*container)[index]; } - - ThisType& operator=(const ThisType& other) + bool operator==(Iterator other) { - clearAndDeallocate(); - addRange(other); - return *this; + return container == other.container && index == other.index; } - - ThisType& operator=(ThisType&& list) + bool operator!=(Iterator other) { - // Could just do a swap here, and memory would be freed on rhs dtor - _deallocateBuffer(); - m_count = list.m_count; - m_capacity = list.m_capacity; - m_buffer = list.m_buffer; + return index != other.index || container != other.container; + } + }; - list.m_buffer = nullptr; - list.m_count = 0; - list.m_capacity = 0; + Iterator begin() const + { + Iterator rs; + rs.container = const_cast<ThisType*>(this); + rs.index = 0; + return rs; + } + Iterator end() const + { + Iterator rs; + rs.container = const_cast<ThisType*>(this); + rs.index = m_count; + return rs; + } - for (Index i = 0; i < Math::Min((Index)shortListSize, m_count); i++) - m_shortBuffer[i] = _Move(list.m_shortBuffer[i]); - return *this; - } + const T& getFirst() const + { + SLANG_ASSERT(m_count > 0); + return m_shortBuffer[0]; + } - struct Iterator - { - ThisType* container = nullptr; - Index index = -1; - Iterator& operator++() - { - ++index; - return *this; - } - Iterator operator++(int) - { - Iterator rs = *this; - ++index; - return rs; - } - Iterator& operator--() - { - --index; - return *this; - } - Iterator operator--(int) - { - Iterator rs = *this; - --index; - return rs; - } - T* operator->() - { - SLANG_ASSERT(container); - return &(*container)[index]; - } - T& operator*() - { - SLANG_ASSERT(container); - return (*container)[index]; - } - bool operator==(Iterator other) - { - return container == other.container && index == other.index; - } - bool operator!=(Iterator other) - { - return index != other.index || container != other.container; - } - }; + T& getFirst() + { + SLANG_ASSERT(m_count > 0); + return m_shortBuffer[0]; + } - Iterator begin() const - { - Iterator rs; - rs.container = const_cast<ThisType*>(this); - rs.index = 0; - return rs; - } - Iterator end() const - { - Iterator rs; - rs.container = const_cast<ThisType*>(this); - rs.index = m_count; - return rs; - } + const T& getLast() const + { + SLANG_ASSERT(m_count > 0); + if (m_count <= shortListSize) + return m_shortBuffer[m_count - 1]; + return m_buffer[m_count - shortListSize - 1]; + } - const T& getFirst() const - { - SLANG_ASSERT(m_count > 0); - return m_shortBuffer[0]; - } + T& getLast() + { + SLANG_ASSERT(m_count > 0); + if (m_count <= shortListSize) + return m_shortBuffer[m_count - 1]; + return m_buffer[m_count - shortListSize - 1]; + } - T& getFirst() - { - SLANG_ASSERT(m_count > 0); - return m_shortBuffer[0]; - } + void removeLast() + { + SLANG_ASSERT(m_count > 0); + m_count--; + } + + struct GetArrayViewResult + { + ArrayView<T> arrayView; + bool ownsStorage = false; - const T& getLast() const + GetArrayViewResult() = default; + GetArrayViewResult(const GetArrayViewResult&) = delete; + GetArrayViewResult(GetArrayViewResult&& other) { - SLANG_ASSERT(m_count > 0); - if (m_count <= shortListSize) - return m_shortBuffer[m_count - 1]; - return m_buffer[m_count - shortListSize - 1]; + ownsStorage = other.ownsStorage; + arrayView = other.arrayView; + other.ownsStorage = false; } - - T& getLast() + ~GetArrayViewResult() { - SLANG_ASSERT(m_count > 0); - if (m_count <= shortListSize) - return m_shortBuffer[m_count - 1]; - return m_buffer[m_count - shortListSize - 1]; + if (ownsStorage) + { + ThisType::_free(arrayView.m_buffer, arrayView.m_count); + } } - - void removeLast() + T* getBuffer() { return arrayView.getBuffer(); } + }; + inline GetArrayViewResult getArrayView() const + { + GetArrayViewResult result; + if (m_count > shortListSize) { - SLANG_ASSERT(m_count > 0); - m_count--; + result.arrayView.m_buffer = ThisType::_allocate(m_count); + result.arrayView.m_count = m_count; + for (Index i = 0; i < shortListSize; i++) + result.arrayView.m_buffer[i] = m_shortBuffer[i]; + for (Index i = shortListSize; i < m_count; i++) + result.arrayView.m_buffer[i] = m_buffer[i - shortListSize]; + result.ownsStorage = true; } - - struct GetArrayViewResult + else { - ArrayView<T> arrayView; - bool ownsStorage = false; + result.arrayView.m_buffer = const_cast<T*>(&m_shortBuffer[0]); + result.arrayView.m_count = m_count; + } + return result; + } - GetArrayViewResult() = default; - GetArrayViewResult(const GetArrayViewResult&) = delete; - GetArrayViewResult(GetArrayViewResult&& other) - { - ownsStorage = other.ownsStorage; - arrayView = other.arrayView; - other.ownsStorage = false; - } - ~GetArrayViewResult() - { - if (ownsStorage) - { - ThisType::_free(arrayView.m_buffer, arrayView.m_count); - } - } - T* getBuffer() { return arrayView.getBuffer(); } - }; - inline GetArrayViewResult getArrayView() const + inline GetArrayViewResult getArrayView(Index start, Index count) const + { + SLANG_ASSERT(start >= 0 && count >= 0 && start + count <= m_count); + GetArrayViewResult result; + if (start < shortListSize && start + count > shortListSize) + { + result.ownsStorage = true; + result.arrayView.m_count = count; + result.arrayView.m_buffer = ThisType::_allocate(count); + for (Index i = start; i < shortListSize; i++) + result.arrayView.m_buffer[i - start] = m_shortBuffer[i]; + for (Index i = shortListSize; i < start + count; i++) + result.arrayView.m_buffer[i - start] = m_buffer[i - shortListSize]; + return result; + } + else if (start + count <= shortListSize) { - GetArrayViewResult result; - if (m_count > shortListSize) - { - result.arrayView.m_buffer = ThisType::_allocate(m_count); - result.arrayView.m_count = m_count; - for (Index i = 0; i < shortListSize; i++) - result.arrayView.m_buffer[i] = m_shortBuffer[i]; - for (Index i = shortListSize; i < m_count; i++) - result.arrayView.m_buffer[i] = m_buffer[i - shortListSize]; - result.ownsStorage = true; - } - else - { - result.arrayView.m_buffer = const_cast<T*>(&m_shortBuffer[0]); - result.arrayView.m_count = m_count; - } + result.ownsStorage = false; + result.arrayView.m_count = count; + result.arrayView.m_buffer = const_cast<T*>(m_shortBuffer) + start; return result; } - - inline GetArrayViewResult getArrayView(Index start, Index count) const + else { - SLANG_ASSERT(start >= 0 && count >= 0 && start + count <= m_count); - GetArrayViewResult result; - if (start < shortListSize && start + count > shortListSize) - { - result.ownsStorage = true; - result.arrayView.m_count = count; - result.arrayView.m_buffer = ThisType::_allocate(count); - for (Index i = start; i < shortListSize; i++) - result.arrayView.m_buffer[i - start] = m_shortBuffer[i]; - for (Index i = shortListSize; i < start + count; i++) - result.arrayView.m_buffer[i - start] = m_buffer[i - shortListSize]; - return result; - } - else if (start + count <= shortListSize) - { - result.ownsStorage = false; - result.arrayView.m_count = count; - result.arrayView.m_buffer = const_cast<T*>(m_shortBuffer) + start; - return result; - } - else - { - result.ownsStorage = false; - result.arrayView.m_count = count; - result.arrayView.m_buffer = m_buffer + start - shortListSize; - return result; - } + result.ownsStorage = false; + result.arrayView.m_count = count; + result.arrayView.m_buffer = m_buffer + start - shortListSize; + return result; } + } - void _maybeReserveForAdd() + void _maybeReserveForAdd() + { + if (m_capacity <= m_count - shortListSize) { - if (m_capacity <= m_count - shortListSize) - { - Index newBufferSize = kInitialCount; - if (m_capacity) - newBufferSize = (m_capacity << 1); + Index newBufferSize = kInitialCount; + if (m_capacity) + newBufferSize = (m_capacity << 1); - reserveOverflowBuffer(newBufferSize); - } + reserveOverflowBuffer(newBufferSize); } + } - void add(T&& obj) + void add(T&& obj) + { + if (m_count < shortListSize) { - if (m_count < shortListSize) - { - m_shortBuffer[m_count] = static_cast<T&&>(obj); - m_count++; - return; - } - _maybeReserveForAdd(); - m_buffer[m_count - shortListSize] = static_cast<T&&>(obj); + m_shortBuffer[m_count] = static_cast<T&&>(obj); m_count++; + return; } + _maybeReserveForAdd(); + m_buffer[m_count - shortListSize] = static_cast<T&&>(obj); + m_count++; + } - void add(const T& obj) + void add(const T& obj) + { + if (m_count < shortListSize) { - if (m_count < shortListSize) - { - m_shortBuffer[m_count] = obj; - m_count++; - return; - } - _maybeReserveForAdd(); - m_buffer[m_count - shortListSize] = obj; + m_shortBuffer[m_count] = obj; m_count++; + return; } + _maybeReserveForAdd(); + m_buffer[m_count - shortListSize] = obj; + m_count++; + } - Index getCount() const { return m_count; } + Index getCount() const { return m_count; } - void addRange(const T* vals, Index n) - { - for (Index i = 0; i < n; i++) - add(vals[i]); - } + void addRange(const T* vals, Index n) + { + for (Index i = 0; i < n; i++) + add(vals[i]); + } - void addRange(ArrayView<T> list) { addRange(list.m_buffer, list.m_count); } + void addRange(ArrayView<T> list) { addRange(list.m_buffer, list.m_count); } - void addRange(ConstArrayView<T> list) { addRange(list.m_buffer, list.m_count); } + void addRange(ConstArrayView<T> list) { addRange(list.m_buffer, list.m_count); } - template<int _otherShortListSize, typename TOtherAllocator> - void addRange(const ShortList<T, _otherShortListSize, TOtherAllocator>& list) - { - for (Index i = 0; i < list.getCount(); i++) - add(list[i]); - } + template<int _otherShortListSize, typename TOtherAllocator> + void addRange(const ShortList<T, _otherShortListSize, TOtherAllocator>& list) + { + for (Index i = 0; i < list.getCount(); i++) + add(list[i]); + } - void fastRemove(const T& val) + void fastRemove(const T& val) + { + Index idx = indexOf(val); + if (idx >= 0) { - Index idx = indexOf(val); - if (idx >= 0) - { - fastRemoveAt(idx); - } + fastRemoveAt(idx); } + } - void fastRemoveAt(Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); + void fastRemoveAt(Index idx) + { + SLANG_ASSERT(idx >= 0 && idx < m_count); - if (idx != m_count - 1) - { - (*this)[idx] = _Move(getLast()); - } - m_count--; + if (idx != m_count - 1) + { + (*this)[idx] = _Move(getLast()); } + m_count--; + } - void clear() { m_count = 0; } + void clear() { m_count = 0; } - void clearAndDeallocate() - { - _deallocateBuffer(); - m_count = m_capacity = 0; - } + void clearAndDeallocate() + { + _deallocateBuffer(); + m_count = m_capacity = 0; + } - void reserveOverflowBuffer(Index size) + void reserveOverflowBuffer(Index size) + { + if (size > m_capacity) { - if (size > m_capacity) + T* newBuffer = _allocate(size); + if (m_capacity) { - T* newBuffer = _allocate(size); - if (m_capacity) + for (Index i = 0; i < m_count - shortListSize; i++) + newBuffer[i] = static_cast<T&&>(m_buffer[i]); + + // Default-initialize the remaining elements + for (Index i = m_count - shortListSize; i < size; i++) { - for (Index i = 0; i < m_count - shortListSize; i++) - newBuffer[i] = static_cast<T&&>(m_buffer[i]); - - // Default-initialize the remaining elements - for (Index i = m_count - shortListSize; i < size; i++) - { - new(newBuffer + i) T(); - } - _deallocateBuffer(); + new (newBuffer + i) T(); } - m_buffer = newBuffer; - m_capacity = size; + _deallocateBuffer(); } + m_buffer = newBuffer; + m_capacity = size; } + } - void setCount(Index count) - { - if (count > shortListSize) - reserveOverflowBuffer(count - shortListSize); - m_count = count; - } + void setCount(Index count) + { + if (count > shortListSize) + reserveOverflowBuffer(count - shortListSize); + m_count = count; + } - void unsafeShrinkToCount(Index count) { m_count = count; } + void unsafeShrinkToCount(Index count) { m_count = count; } - void compress() + void compress() + { + if (m_capacity > m_count - shortListSize && m_count > shortListSize) { - if (m_capacity > m_count - shortListSize && m_count > shortListSize) + T* newBuffer = nullptr; + if (m_count > shortListSize) { - T* newBuffer = nullptr; - if (m_count > shortListSize) - { - newBuffer = _allocate(m_count - shortListSize); - for (Index i = shortListSize; i < m_count; i++) - newBuffer[i - shortListSize] = static_cast<T&&>(m_buffer[i - shortListSize]); - } - _deallocateBuffer(); - m_buffer = newBuffer; - m_capacity = m_count - shortListSize; + newBuffer = _allocate(m_count - shortListSize); + for (Index i = shortListSize; i < m_count; i++) + newBuffer[i - shortListSize] = static_cast<T&&>(m_buffer[i - shortListSize]); } + _deallocateBuffer(); + m_buffer = newBuffer; + m_capacity = m_count - shortListSize; } + } - SLANG_FORCE_INLINE const T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return (idx < shortListSize) ? - m_shortBuffer[idx] : m_buffer[idx - shortListSize]; - } + SLANG_FORCE_INLINE const T& operator[](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return (idx < shortListSize) ? m_shortBuffer[idx] : m_buffer[idx - shortListSize]; + } - SLANG_FORCE_INLINE T& operator [](Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return (idx < shortListSize) ? - m_shortBuffer[idx] : m_buffer[idx - shortListSize]; - } + SLANG_FORCE_INLINE T& operator[](Index idx) + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return (idx < shortListSize) ? m_shortBuffer[idx] : m_buffer[idx - shortListSize]; + } - template<typename Func> - Index findFirstIndex(const Func& predicate) const + template<typename Func> + Index findFirstIndex(const Func& predicate) const + { + for (Index i = 0; i < Math::Min(m_count, (Index)shortListSize); i++) { - for (Index i = 0; i < Math::Min(m_count, (Index)shortListSize); i++) - { - if (predicate(m_shortBuffer[i])) - return i; - } - for (Index i = shortListSize; i < m_count; i++) - { - if (predicate(m_buffer[i - shortListSize])) - return i; - } - return -1; + if (predicate(m_shortBuffer[i])) + return i; } - - template<typename T2> - Index indexOf(const T2& val) const + for (Index i = shortListSize; i < m_count; i++) { - for (Index i = 0; i < Math::Min(m_count, (Index)shortListSize); i++) - { - if (m_shortBuffer[i] == val) - return i; - } - for (Index i = shortListSize; i < m_count; i++) - { - if (m_buffer[i - shortListSize] == val) - return i; - } - return -1; + if (predicate(m_buffer[i - shortListSize])) + return i; } + return -1; + } - template<typename Func> - Index findLastIndex(const Func& predicate) const + template<typename T2> + Index indexOf(const T2& val) const + { + for (Index i = 0; i < Math::Min(m_count, (Index)shortListSize); i++) { - for (Index i = m_count - 1; i >= shortListSize; i--) - { - if (predicate(m_buffer[i - shortListSize])) - return i; - } - for (Index i = Math::Min((Index)shortListSize, m_count) - 1; i >= 0; i--) - { - if (predicate(m_shortBuffer[i])) - return i; - } - return -1; + if (m_shortBuffer[i] == val) + return i; } - - template<typename T2> - Index lastIndexOf(const T2& val) const + for (Index i = shortListSize; i < m_count; i++) { - for (Index i = m_count - 1; i >= shortListSize; i--) - { - if (m_buffer[i - shortListSize] == val) - return i; - } - for (Index i = Math::Min((Index)shortListSize, m_count) - 1; i >= 0; i--) - { - if (m_shortBuffer[i] == val) - return i; - } - return -1; + if (m_buffer[i - shortListSize] == val) + return i; } + return -1; + } - bool contains(const T& val) const { return indexOf(val) != Index(-1); } - - template <typename IterateFunc> - void forEach(IterateFunc f) const + template<typename Func> + Index findLastIndex(const Func& predicate) const + { + for (Index i = m_count - 1; i >= shortListSize; i--) { - for (Index i = 0; i < m_count; i++) - f(m_buffer[i]); + if (predicate(m_buffer[i - shortListSize])) + return i; } - - private: - T* m_buffer = nullptr; ///< A new T[N] allocated buffer. NOTE! All elements up to capacity are in some valid form for T. - Index m_capacity = 0; ///< The total capacity of elements in m_buffer - Index m_count = 0; ///< The amount of elements - T m_shortBuffer[shortListSize]; - - void _deallocateBuffer() + for (Index i = Math::Min((Index)shortListSize, m_count) - 1; i >= 0; i--) { - if (m_buffer) - { - AllocateMethod<T, TAllocator>::deallocateArray(m_buffer, m_capacity); - m_buffer = nullptr; - } + if (predicate(m_shortBuffer[i])) + return i; } - static inline T* _allocate(Index count) + return -1; + } + + template<typename T2> + Index lastIndexOf(const T2& val) const + { + for (Index i = m_count - 1; i >= shortListSize; i--) { - return AllocateMethod<T, TAllocator>::allocateArray(count); + if (m_buffer[i - shortListSize] == val) + return i; } - static inline void _free(T* ptr, Index count) + for (Index i = Math::Min((Index)shortListSize, m_count) - 1; i >= 0; i--) { - return AllocateMethod<T, TAllocator>::deallocateArray(ptr, count); + if (m_shortBuffer[i] == val) + return i; } + return -1; + } - template<typename... Args> - void _init(const T& val, Args... args) + bool contains(const T& val) const { return indexOf(val) != Index(-1); } + + template<typename IterateFunc> + void forEach(IterateFunc f) const + { + for (Index i = 0; i < m_count; i++) + f(m_buffer[i]); + } + +private: + T* m_buffer = nullptr; ///< A new T[N] allocated buffer. NOTE! All elements up to capacity are + ///< in some valid form for T. + Index m_capacity = 0; ///< The total capacity of elements in m_buffer + Index m_count = 0; ///< The amount of elements + T m_shortBuffer[shortListSize]; + + void _deallocateBuffer() + { + if (m_buffer) { - add(val); - _init(args...); + AllocateMethod<T, TAllocator>::deallocateArray(m_buffer, m_capacity); + m_buffer = nullptr; } + } + static inline T* _allocate(Index count) + { + return AllocateMethod<T, TAllocator>::allocateArray(count); + } + static inline void _free(T* ptr, Index count) + { + return AllocateMethod<T, TAllocator>::deallocateArray(ptr, count); + } - void _init() {} - }; -} + template<typename... Args> + void _init(const T& val, Args... args) + { + add(val); + _init(args...); + } + + void _init() {} +}; +} // namespace Slang #endif diff --git a/source/core/slang-signal.cpp b/source/core/slang-signal.cpp index 5f53cba93..1600183e7 100644 --- a/source/core/slang-signal.cpp +++ b/source/core/slang-signal.cpp @@ -1,7 +1,6 @@ #include "slang-signal.h" #include "slang-exception.h" - #include "stdio.h" namespace Slang @@ -11,13 +10,13 @@ static const char* _getSignalTypeAsText(SignalType type) { switch (type) { - case SignalType::AssertFailure: return "assert failure"; - case SignalType::Unimplemented: return "unimplemented"; - case SignalType::Unreachable: return "hit unreachable code"; - case SignalType::Unexpected: return "unexpected"; - case SignalType::InvalidOperation: return "invalid operation"; - case SignalType::AbortCompilation: return "abort compilation"; - default: return "unhandled"; + case SignalType::AssertFailure: return "assert failure"; + case SignalType::Unimplemented: return "unimplemented"; + case SignalType::Unreachable: return "hit unreachable code"; + case SignalType::Unexpected: return "unexpected"; + case SignalType::InvalidOperation: return "invalid operation"; + case SignalType::AbortCompilation: return "abort compilation"; + default: return "unhandled"; } } @@ -30,7 +29,7 @@ String _getMessage(SignalType type, char const* message) { buf << ": " << message; } - + return buf.produceString(); } @@ -39,7 +38,7 @@ String _getMessage(SignalType type, char const* message) [[noreturn]] void handleSignal(SignalType type, char const* message) { StringBuilder buf; - const char*const typeText = _getSignalTypeAsText(type); + const char* const typeText = _getSignalTypeAsText(type); buf << typeText << ": " << message; // Can be useful to enable during debug when problem is on CI @@ -51,14 +50,14 @@ String _getMessage(SignalType type, char const* message) #if SLANG_HAS_EXCEPTIONS switch (type) { - case SignalType::InvalidOperation: throw InvalidOperationException(_getMessage(type, message)); - case SignalType::AbortCompilation: throw AbortCompilationException(_getMessage(type, message)); - default: throw InternalError(_getMessage(type, message)); + case SignalType::InvalidOperation: throw InvalidOperationException(_getMessage(type, message)); + case SignalType::AbortCompilation: throw AbortCompilationException(_getMessage(type, message)); + default: throw InternalError(_getMessage(type, message)); } #else - // Attempt to drop out into the debugger. If a debugger isn't attached this will likely crash - which is probably the best - // we can do. - + // Attempt to drop out into the debugger. If a debugger isn't attached this will likely crash - + // which is probably the best we can do. + SLANG_BREAKPOINT(0); // 'panic'. Exit with an error code as we can't throw or catch. @@ -66,4 +65,4 @@ String _getMessage(SignalType type, char const* message) #endif } -} +} // namespace Slang diff --git a/source/core/slang-signal.h b/source/core/slang-signal.h index 759581ee2..356ae42f6 100644 --- a/source/core/slang-signal.h +++ b/source/core/slang-signal.h @@ -20,17 +20,13 @@ enum class SignalType // Note that message can be passed as nullptr for no message. [[noreturn]] void handleSignal(SignalType type, char const* message); -#define SLANG_UNEXPECTED(reason) \ - ::Slang::handleSignal(::Slang::SignalType::Unexpected, reason) +#define SLANG_UNEXPECTED(reason) ::Slang::handleSignal(::Slang::SignalType::Unexpected, reason) -#define SLANG_UNIMPLEMENTED_X(what) \ - ::Slang::handleSignal(::Slang::SignalType::Unimplemented, what) +#define SLANG_UNIMPLEMENTED_X(what) ::Slang::handleSignal(::Slang::SignalType::Unimplemented, what) -#define SLANG_UNREACHABLE(msg) \ - ::Slang::handleSignal(::Slang::SignalType::Unreachable, msg) +#define SLANG_UNREACHABLE(msg) ::Slang::handleSignal(::Slang::SignalType::Unreachable, msg) -#define SLANG_ASSERT_FAILURE(msg) \ - ::Slang::handleSignal(::Slang::SignalType::AssertFailure, msg) +#define SLANG_ASSERT_FAILURE(msg) ::Slang::handleSignal(::Slang::SignalType::AssertFailure, msg) #define SLANG_INVALID_OPERATION(msg) \ ::Slang::handleSignal(::Slang::SignalType::InvalidOperation, msg) @@ -39,6 +35,6 @@ enum class SignalType ::Slang::handleSignal(::Slang::SignalType::AbortCompilation, msg) -} +} // namespace Slang #endif diff --git a/source/core/slang-smart-pointer.h b/source/core/slang-smart-pointer.h index a45f7a8ad..46070f0b8 100644 --- a/source/core/slang-smart-pointer.h +++ b/source/core/slang-smart-pointer.h @@ -6,118 +6,124 @@ #include "slang-type-traits.h" #include "slang.h" -#include "slang.h" - namespace Slang { - // Base class for all reference-counted objects - class SLANG_RT_API RefObject +// Base class for all reference-counted objects +class SLANG_RT_API RefObject +{ +private: + UInt referenceCount; + +public: + RefObject() + : referenceCount(0) { - private: - UInt referenceCount; + } - public: - RefObject() - : referenceCount(0) - {} + RefObject(const RefObject&) + : referenceCount(0) + { + } - RefObject(const RefObject &) - : referenceCount(0) - {} + RefObject& operator=(const RefObject&) { return *this; } - RefObject& operator=(const RefObject&) { return *this; } + virtual ~RefObject() {} - virtual ~RefObject() - {} + UInt addReference() { return ++referenceCount; } - UInt addReference() - { - return ++referenceCount; - } + UInt decreaseReference() { return --referenceCount; } - UInt decreaseReference() + UInt releaseReference() + { + SLANG_ASSERT(referenceCount != 0); + if (--referenceCount == 0) { - return --referenceCount; + delete this; + return 0; } + return referenceCount; + } - UInt releaseReference() - { - SLANG_ASSERT(referenceCount != 0); - if(--referenceCount == 0) - { - delete this; - return 0; - } - return referenceCount; - } + bool isUniquelyReferenced() + { + SLANG_ASSERT(referenceCount != 0); + return referenceCount == 1; + } - bool isUniquelyReferenced() - { - SLANG_ASSERT(referenceCount != 0); - return referenceCount == 1; - } + UInt debugGetReferenceCount() { return referenceCount; } +}; - UInt debugGetReferenceCount() - { - return referenceCount; - } - }; +SLANG_FORCE_INLINE void addReference(RefObject* obj) +{ + if (obj) + obj->addReference(); +} - SLANG_FORCE_INLINE void addReference(RefObject* obj) +SLANG_FORCE_INLINE void releaseReference(RefObject* obj) +{ + if (obj) + obj->releaseReference(); +} + +// For straight dynamic cast. +// Use instead of dynamic_cast as it allows for replacement without using Rtti in the future +template<typename T> +SLANG_FORCE_INLINE T* dynamicCast(RefObject* obj) +{ + return dynamic_cast<T*>(obj); +} +template<typename T> +SLANG_FORCE_INLINE const T* dynamicCast(const RefObject* obj) +{ + return dynamic_cast<const T*>(obj); +} + +// Like a dynamicCast, but allows a type to implement a specific implementation that is suitable for +// it +template<typename T> +SLANG_FORCE_INLINE T* as(RefObject* obj) +{ + return dynamicCast<T>(obj); +} +template<typename T> +SLANG_FORCE_INLINE const T* as(const RefObject* obj) +{ + return dynamicCast<T>(obj); +} + +// "Smart" pointer to a reference-counted object +template<typename T> +struct SLANG_RT_API RefPtr +{ + RefPtr() + : pointer(nullptr) { - if(obj) obj->addReference(); } - SLANG_FORCE_INLINE void releaseReference(RefObject* obj) + RefPtr(T* p) + : pointer(p) { - if(obj) obj->releaseReference(); + addReference(p); } - // For straight dynamic cast. - // Use instead of dynamic_cast as it allows for replacement without using Rtti in the future - template <typename T> - SLANG_FORCE_INLINE T* dynamicCast(RefObject* obj) { return dynamic_cast<T*>(obj); } - template <typename T> - SLANG_FORCE_INLINE const T* dynamicCast(const RefObject* obj) { return dynamic_cast<const T*>(obj); } - - // Like a dynamicCast, but allows a type to implement a specific implementation that is suitable for it - template <typename T> - SLANG_FORCE_INLINE T* as(RefObject* obj) { return dynamicCast<T>(obj); } - template <typename T> - SLANG_FORCE_INLINE const T* as(const RefObject* obj) { return dynamicCast<T>(obj); } - - // "Smart" pointer to a reference-counted object - template<typename T> struct SLANG_RT_API RefPtr + RefPtr(RefPtr<T> const& p) + : pointer(p.pointer) { - RefPtr() - : pointer(nullptr) - {} - - RefPtr(T* p) - : pointer(p) - { - addReference(p); - } - - RefPtr(RefPtr<T> const& p) - : pointer(p.pointer) - { - addReference(p.pointer); - } + addReference(p.pointer); + } - RefPtr(RefPtr<T>&& p) - : pointer(p.pointer) - { - p.pointer = nullptr; - } + RefPtr(RefPtr<T>&& p) + : pointer(p.pointer) + { + p.pointer = nullptr; + } - template <typename U> - RefPtr(RefPtr<U> const& p, - typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0) - : pointer(static_cast<U*>(p)) - { - addReference(static_cast<U*>(p)); - } + template<typename U> + RefPtr(RefPtr<U> const& p, typename EnableIf<IsConvertible<T*, U*>::Value, void>::type* = 0) + : pointer(static_cast<U*>(p)) + { + addReference(static_cast<U*>(p)); + } #if 0 void operator=(T* p) @@ -129,226 +135,202 @@ namespace Slang } #endif - void operator=(RefPtr<T> const& p) - { - T* old = pointer; - addReference(p.pointer); - pointer = p.pointer; - releaseReference(old); - } + void operator=(RefPtr<T> const& p) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } - void operator=(RefPtr<T>&& p) - { - T* old = pointer; - pointer = p.pointer; - p.pointer = old; - } + void operator=(RefPtr<T>&& p) + { + T* old = pointer; + pointer = p.pointer; + p.pointer = old; + } - template <typename U> - typename EnableIf<IsConvertible<T*, U*>::value, void>::type - operator=(RefPtr<U> const& p) - { - T* old = pointer; - addReference(p.pointer); - pointer = p.pointer; - releaseReference(old); - } + template<typename U> + typename EnableIf<IsConvertible<T*, U*>::value, void>::type operator=(RefPtr<U> const& p) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } - HashCode getHashCode() const - { - // Note: We need a `RefPtr<T>` to hash the same as a `T*`, - // so that a `T*` can be used as a key in a dictionary with - // `RefPtr<T>` keys, and vice versa. - // - return Slang::getHashCode(pointer); - } + HashCode getHashCode() const + { + // Note: We need a `RefPtr<T>` to hash the same as a `T*`, + // so that a `T*` can be used as a key in a dictionary with + // `RefPtr<T>` keys, and vice versa. + // + return Slang::getHashCode(pointer); + } - bool operator==(const T * ptr) const - { - return pointer == ptr; - } + bool operator==(const T* ptr) const { return pointer == ptr; } - bool operator!=(const T * ptr) const - { - return pointer != ptr; - } + bool operator!=(const T* ptr) const { return pointer != ptr; } - bool operator==(RefPtr<T> const& ptr) const - { - return pointer == ptr.pointer; - } + bool operator==(RefPtr<T> const& ptr) const { return pointer == ptr.pointer; } - bool operator!=(RefPtr<T> const& ptr) const - { - return pointer != ptr.pointer; - } + bool operator!=(RefPtr<T> const& ptr) const { return pointer != ptr.pointer; } - template<typename U> - RefPtr<U> dynamicCast() const - { - return RefPtr<U>(Slang::dynamicCast<U>(pointer)); - } + template<typename U> + RefPtr<U> dynamicCast() const + { + return RefPtr<U>(Slang::dynamicCast<U>(pointer)); + } - template<typename U> - RefPtr<U> as() const - { - return RefPtr<U>(Slang::as<U>(pointer)); - } + template<typename U> + RefPtr<U> as() const + { + return RefPtr<U>(Slang::as<U>(pointer)); + } - template <typename U> - bool is() const { return Slang::as<U>(pointer) != nullptr; } + template<typename U> + bool is() const + { + return Slang::as<U>(pointer) != nullptr; + } - ~RefPtr() - { - releaseReference(static_cast<Slang::RefObject*>(pointer)); - } + ~RefPtr() { releaseReference(static_cast<Slang::RefObject*>(pointer)); } - T& operator*() const - { - return *pointer; - } + T& operator*() const { return *pointer; } - T* operator->() const - { - return pointer; - } + T* operator->() const { return pointer; } - T * Ptr() const - { - return pointer; - } + T* Ptr() const { return pointer; } - T* get() const - { - return pointer; - } + T* get() const { return pointer; } - operator T*() const - { - return pointer; - } + operator T*() const { return pointer; } - void attach(T* p) - { - T* old = pointer; - pointer = p; - releaseReference(old); - } + void attach(T* p) + { + T* old = pointer; + pointer = p; + releaseReference(old); + } - T* detach() - { - auto rs = pointer; - pointer = nullptr; - return rs; - } + T* detach() + { + auto rs = pointer; + pointer = nullptr; + return rs; + } - void swapWith(RefPtr<T>& rhs) - { - auto rhsPtr = rhs.pointer; - rhs.pointer = pointer; - pointer = rhsPtr; - } + void swapWith(RefPtr<T>& rhs) + { + auto rhsPtr = rhs.pointer; + rhs.pointer = pointer; + pointer = rhsPtr; + } - SLANG_FORCE_INLINE void setNull() - { - releaseReference(pointer); - pointer = nullptr; - } + SLANG_FORCE_INLINE void setNull() + { + releaseReference(pointer); + pointer = nullptr; + } - /// Get ready for writing (nulls contents) - SLANG_FORCE_INLINE T** writeRef() { *this = nullptr; return &pointer; } + /// Get ready for writing (nulls contents) + SLANG_FORCE_INLINE T** writeRef() + { + *this = nullptr; + return &pointer; + } - /// Get for read access - SLANG_FORCE_INLINE T*const* readRef() const { return &pointer; } + /// Get for read access + SLANG_FORCE_INLINE T* const* readRef() const { return &pointer; } - private: - T* pointer; - }; +private: + T* pointer; +}; - // Helper type for implementing weak pointers. The object being pointed at weakly creates a WeakSink object - // that other objects can reference and share. When the object is destroyed it detaches the sink - // doing so will make other users call to 'get' return null. Thus any user of the WeakSink, must check if the weakly pointed to - // things pointer is nullptr before using. - template <typename T> - class WeakSink : public RefObject +// Helper type for implementing weak pointers. The object being pointed at weakly creates a WeakSink +// object that other objects can reference and share. When the object is destroyed it detaches the +// sink doing so will make other users call to 'get' return null. Thus any user of the WeakSink, +// must check if the weakly pointed to things pointer is nullptr before using. +template<typename T> +class WeakSink : public RefObject +{ +public: + WeakSink(T* ptr) + : m_ptr(ptr) { - public: - WeakSink(T* ptr): - m_ptr(ptr) - { - } + } - SLANG_FORCE_INLINE T* get() const { return m_ptr; } - SLANG_FORCE_INLINE void detach() { m_ptr = nullptr; } + SLANG_FORCE_INLINE T* get() const { return m_ptr; } + SLANG_FORCE_INLINE void detach() { m_ptr = nullptr; } - private: - T* m_ptr; - }; +private: + T* m_ptr; +}; - // A pointer that can be transformed to hold either a weak reference or a strong reference. - template<typename T> - class TransformablePtr - { - private: - T* m_weakPtr = nullptr; - RefPtr<T> m_strongPtr; +// A pointer that can be transformed to hold either a weak reference or a strong reference. +template<typename T> +class TransformablePtr +{ +private: + T* m_weakPtr = nullptr; + RefPtr<T> m_strongPtr; - public: - TransformablePtr() = default; - TransformablePtr(T* ptr) { *this = ptr; } - TransformablePtr(RefPtr<T> ptr) { *this = ptr; } - TransformablePtr(const TransformablePtr<T>& ptr) = default; - TransformablePtr<T>& operator=(const TransformablePtr<T>& ptr) = default; +public: + TransformablePtr() = default; + TransformablePtr(T* ptr) { *this = ptr; } + TransformablePtr(RefPtr<T> ptr) { *this = ptr; } + TransformablePtr(const TransformablePtr<T>& ptr) = default; + TransformablePtr<T>& operator=(const TransformablePtr<T>& ptr) = default; - void promoteToStrongReference() { m_strongPtr = m_weakPtr; } - void demoteToWeakReference() { m_strongPtr = nullptr; } - bool isStrongReference() const { return m_strongPtr != nullptr; } + void promoteToStrongReference() { m_strongPtr = m_weakPtr; } + void demoteToWeakReference() { m_strongPtr = nullptr; } + bool isStrongReference() const { return m_strongPtr != nullptr; } - T& operator*() const { return *m_weakPtr; } + T& operator*() const { return *m_weakPtr; } - T* operator->() const { return m_weakPtr; } + T* operator->() const { return m_weakPtr; } - T* Ptr() const { return m_weakPtr; } - T* get() const { return m_weakPtr; } + T* Ptr() const { return m_weakPtr; } + T* get() const { return m_weakPtr; } - operator T*() const { return m_weakPtr; } - operator RefPtr<T>() const { return m_weakPtr; } + operator T*() const { return m_weakPtr; } + operator RefPtr<T>() const { return m_weakPtr; } - TransformablePtr<T>& operator=(T* ptr) - { - m_weakPtr = ptr; - m_strongPtr = ptr; - return *this; - } - template<typename U> - TransformablePtr<T>& operator=(const RefPtr<U>& ptr) - { - m_weakPtr = ptr.Ptr(); - m_strongPtr = ptr; - return *this; - } - - HashCode getHashCode() const - { - // Note: We need a `RefPtr<T>` to hash the same as a `T*`, - // so that a `T*` can be used as a key in a dictionary with - // `RefPtr<T>` keys, and vice versa. - // - return Slang::getHashCode(m_weakPtr); - } + TransformablePtr<T>& operator=(T* ptr) + { + m_weakPtr = ptr; + m_strongPtr = ptr; + return *this; + } + template<typename U> + TransformablePtr<T>& operator=(const RefPtr<U>& ptr) + { + m_weakPtr = ptr.Ptr(); + m_strongPtr = ptr; + return *this; + } - bool operator==(const T* ptr) const { return m_weakPtr == ptr; } + HashCode getHashCode() const + { + // Note: We need a `RefPtr<T>` to hash the same as a `T*`, + // so that a `T*` can be used as a key in a dictionary with + // `RefPtr<T>` keys, and vice versa. + // + return Slang::getHashCode(m_weakPtr); + } - bool operator!=(const T* ptr) const { return m_weakPtr != ptr; } + bool operator==(const T* ptr) const { return m_weakPtr == ptr; } - bool operator==(RefPtr<T> const& ptr) const { return m_weakPtr == ptr.Ptr(); } + bool operator!=(const T* ptr) const { return m_weakPtr != ptr; } - bool operator!=(RefPtr<T> const& ptr) const { return m_weakPtr != ptr.Ptr(); } + bool operator==(RefPtr<T> const& ptr) const { return m_weakPtr == ptr.Ptr(); } - bool operator==(TransformablePtr<T> const& ptr) const { return m_weakPtr == ptr.m_weakPtr; } + bool operator!=(RefPtr<T> const& ptr) const { return m_weakPtr != ptr.Ptr(); } - bool operator!=(TransformablePtr<T> const& ptr) const { return m_weakPtr != ptr.m_weakPtr; } - }; -} + bool operator==(TransformablePtr<T> const& ptr) const { return m_weakPtr == ptr.m_weakPtr; } + + bool operator!=(TransformablePtr<T> const& ptr) const { return m_weakPtr != ptr.m_weakPtr; } +}; +} // namespace Slang #endif diff --git a/source/core/slang-stable-hash.h b/source/core/slang-stable-hash.h index 30a47121e..b804cc194 100644 --- a/source/core/slang-stable-hash.h +++ b/source/core/slang-stable-hash.h @@ -6,87 +6,87 @@ namespace Slang { - // - // Types - // +// +// Types +// - struct StableHashCode64 - { - uint64_t hash; - explicit operator uint64_t() const { return hash; } - bool operator==(StableHashCode64 other) const { return other.hash == hash; }; - bool operator!=(StableHashCode64 other) const { return other.hash != hash; }; - }; +struct StableHashCode64 +{ + uint64_t hash; + explicit operator uint64_t() const { return hash; } + bool operator==(StableHashCode64 other) const { return other.hash == hash; }; + bool operator!=(StableHashCode64 other) const { return other.hash != hash; }; +}; - struct StableHashCode32 - { - uint32_t hash; - explicit operator uint32_t() const { return hash; } - bool operator==(StableHashCode32 other) const { return other.hash == hash; }; - bool operator!=(StableHashCode32 other) const { return other.hash != hash; }; - }; +struct StableHashCode32 +{ + uint32_t hash; + explicit operator uint32_t() const { return hash; } + bool operator==(StableHashCode32 other) const { return other.hash == hash; }; + bool operator!=(StableHashCode32 other) const { return other.hash != hash; }; +}; - /* The 'Stable' hash code functions produce hashes that must be +/* The 'Stable' hash code functions produce hashes that must be - * The same result for the same inputs on all targets - * Rarely change - as their values can change the output of the Slang API/Serialization +* The same result for the same inputs on all targets +* Rarely change - as their values can change the output of the Slang API/Serialization - Hash value used from the 'Stable' functions can also be used as part of serialization - - so it is in effect part of the API. +Hash value used from the 'Stable' functions can also be used as part of serialization - +so it is in effect part of the API. - In effect this means changing a 'Stable' algorithm will typically require doing a new release. - */ - inline StableHashCode64 getStableHashCode64(const char* buffer, size_t numChars) +In effect this means changing a 'Stable' algorithm will typically require doing a new release. +*/ +inline StableHashCode64 getStableHashCode64(const char* buffer, size_t numChars) +{ + uint64_t hash = 0; + for (size_t i = 0; i < numChars; ++i) { - uint64_t hash = 0; - for (size_t i = 0; i < numChars; ++i) - { - hash = uint64_t(buffer[i]) + (hash << 6) + (hash << 16) - hash; - } - return StableHashCode64{hash}; + hash = uint64_t(buffer[i]) + (hash << 6) + (hash << 16) - hash; } + return StableHashCode64{hash}; +} - template<typename T> - inline StableHashCode64 getStableHashCode64(const T& t) - { - static_assert(std::has_unique_object_representations_v<T>); - return getStableHashCode64(reinterpret_cast<const char*>(&t), sizeof(T)); - } +template<typename T> +inline StableHashCode64 getStableHashCode64(const T& t) +{ + static_assert(std::has_unique_object_representations_v<T>); + return getStableHashCode64(reinterpret_cast<const char*>(&t), sizeof(T)); +} - inline StableHashCode32 getStableHashCode32(const char* buffer, size_t numChars) +inline StableHashCode32 getStableHashCode32(const char* buffer, size_t numChars) +{ + uint32_t hash = 0; + for (size_t i = 0; i < numChars; ++i) { - uint32_t hash = 0; - for (size_t i = 0; i < numChars; ++i) - { - hash = uint32_t(buffer[i]) + (hash << 6) + (hash << 16) - hash; - } - return StableHashCode32{hash}; + hash = uint32_t(buffer[i]) + (hash << 6) + (hash << 16) - hash; } + return StableHashCode32{hash}; +} - template<typename T> - inline StableHashCode32 getStableHashCode32(const T& t) - { - static_assert(std::has_unique_object_representations_v<T>); - return getStableHashCode32(reinterpret_cast<const char*>(&t), sizeof(T)); - } +template<typename T> +inline StableHashCode32 getStableHashCode32(const T& t) +{ + static_assert(std::has_unique_object_representations_v<T>); + return getStableHashCode32(reinterpret_cast<const char*>(&t), sizeof(T)); +} - inline StableHashCode64 combineStableHash(StableHashCode64 h) - { - return h; - } +inline StableHashCode64 combineStableHash(StableHashCode64 h) +{ + return h; +} - inline StableHashCode32 combineStableHash(StableHashCode32 h) - { - return h; - } +inline StableHashCode32 combineStableHash(StableHashCode32 h) +{ + return h; +} - // A left fold with a mixing operation - template<typename H, typename... Hs> - H combineStableHash(H n, H m, Hs... args) - { - return combineStableHash(H{(n.hash * 16777619) ^ m.hash}, args...); - } +// A left fold with a mixing operation +template<typename H, typename... Hs> +H combineStableHash(H n, H m, Hs... args) +{ + return combineStableHash(H{(n.hash * 16777619) ^ m.hash}, args...); } +} // namespace Slang // > Please draw a small horse in ASCII art: // diff --git a/source/core/slang-std-writers.cpp b/source/core/slang-std-writers.cpp index 264f37c98..c34f1a917 100644 --- a/source/core/slang-std-writers.cpp +++ b/source/core/slang-std-writers.cpp @@ -8,25 +8,27 @@ namespace Slang { -/* static */StdWriters* StdWriters::s_singleton = nullptr; +/* static */ StdWriters* StdWriters::s_singleton = nullptr; -/* static */RefPtr<StdWriters> StdWriters::createDefault() +/* static */ RefPtr<StdWriters> StdWriters::createDefault() { #if SLANG_WINDOWS_FAMILY SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); #endif RefPtr<StdWriters> stdWriters(new StdWriters); - RefPtr<FileWriter> stdError(new FileWriter(stderr, WriterFlag::AutoFlush | WriterFlag::IsUnowned)); - RefPtr<FileWriter> stdOut(new FileWriter(stdout, WriterFlag::AutoFlush | WriterFlag::IsUnowned)); + RefPtr<FileWriter> stdError( + new FileWriter(stderr, WriterFlag::AutoFlush | WriterFlag::IsUnowned)); + RefPtr<FileWriter> stdOut( + new FileWriter(stdout, WriterFlag::AutoFlush | WriterFlag::IsUnowned)); stdWriters->setWriter(SLANG_WRITER_CHANNEL_STD_ERROR, stdError); stdWriters->setWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT, stdOut); - + return stdWriters; } -/* static */RefPtr<StdWriters> StdWriters::initDefaultSingleton() +/* static */ RefPtr<StdWriters> StdWriters::initDefaultSingleton() { if (s_singleton) { @@ -37,5 +39,4 @@ namespace Slang return defaults; } -} - +} // namespace Slang diff --git a/source/core/slang-std-writers.h b/source/core/slang-std-writers.h index e99b386e3..bb67d9d9c 100644 --- a/source/core/slang-std-writers.h +++ b/source/core/slang-std-writers.h @@ -1,41 +1,48 @@ #ifndef SLANG_CORE_STD_WRITERS_H #define SLANG_CORE_STD_WRITERS_H -#include "slang-writer.h" #include "slang-com-ptr.h" +#include "slang-writer.h" namespace Slang { /* Holds standard writers for the channels */ -class StdWriters: public RefObject +class StdWriters : public RefObject { public: - ISlangWriter* getWriter(SlangWriterChannel chan) const { return m_writers[chan]; } void setWriter(SlangWriterChannel chan, ISlangWriter* writer) { m_writers[chan] = writer; } - /// Flush all the set writers + /// Flush all the set writers void flushWriters(); - /// Ctor + /// Ctor StdWriters() {} - /// Initialize a default context + /// Initialize a default context static RefPtr<StdWriters> createDefault(); static RefPtr<StdWriters> initDefaultSingleton(); static StdWriters* getSingleton() { return s_singleton; } - static void setSingleton(StdWriters* context) { s_singleton = context; } + static void setSingleton(StdWriters* context) { s_singleton = context; } - static WriterHelper getError() { return getSingleton()->getWriter(SLANG_WRITER_CHANNEL_STD_ERROR); } - static WriterHelper getOut() { return getSingleton()->getWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT); } - static WriterHelper getDiagnostic() { return getSingleton()->getWriter(SLANG_WRITER_CHANNEL_DIAGNOSTIC); } + static WriterHelper getError() + { + return getSingleton()->getWriter(SLANG_WRITER_CHANNEL_STD_ERROR); + } + static WriterHelper getOut() + { + return getSingleton()->getWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT); + } + static WriterHelper getDiagnostic() + { + return getSingleton()->getWriter(SLANG_WRITER_CHANNEL_DIAGNOSTIC); + } protected: + ComPtr<ISlangWriter> m_writers[SLANG_WRITER_CHANNEL_COUNT_OF]; - ComPtr<ISlangWriter> m_writers[SLANG_WRITER_CHANNEL_COUNT_OF]; - static StdWriters* s_singleton; }; @@ -52,6 +59,6 @@ inline void StdWriters::flushWriters() } } -} +} // namespace Slang #endif diff --git a/source/core/slang-stream.cpp b/source/core/slang-stream.cpp index 6507c2e56..ca7528f61 100644 --- a/source/core/slang-stream.cpp +++ b/source/core/slang-stream.cpp @@ -2,10 +2,11 @@ #ifdef _WIN32 #include <share.h> #endif -#include <thread> #include "slang-io.h" #include "slang-process.h" +#include <thread> + namespace Slang { @@ -20,10 +21,8 @@ SlangResult Stream::readExactly(void* buffer, size_t length) // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -FileStream::FileStream() : - m_handle(nullptr), - m_fileAccess(FileAccess::None), - m_endReached(false) +FileStream::FileStream() + : m_handle(nullptr), m_fileAccess(FileAccess::None), m_endReached(false) { } @@ -33,7 +32,11 @@ SlangResult FileStream::init(const String& fileName, FileMode fileMode) return _init(fileName, fileMode, access, FileShare::None); } -SlangResult FileStream::init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share) +SlangResult FileStream::init( + const String& fileName, + FileMode fileMode, + FileAccess access, + FileShare share) { return _init(fileName, fileMode, access, share); } @@ -120,46 +123,35 @@ SlangResult FileStream::_init( mode = "ab"; } break; - default: - break; + default: break; } #ifdef _WIN32 // NOTE! This works because we know all the characters in the mode // are encoded directly as the same value in a wchar_t. - // + // // Work out the length *including* terminating 0 const Index modeLength = Index(::strlen(mode)) + 1; wchar_t wideMode[8]; SLANG_ASSERT(modeLength <= SLANG_COUNT_OF(wideMode)); - // Copy to wchar_t - for (Index i = 0; i < modeLength ; ++i) + // Copy to wchar_t + for (Index i = 0; i < modeLength; ++i) { wideMode[i] = wchar_t(mode[i]); } - + int shFlag = _SH_DENYRW; switch (share) { - case FileShare::None: - shFlag = _SH_DENYRW; - break; - case FileShare::ReadOnly: - shFlag = _SH_DENYWR; - break; - case FileShare::WriteOnly: - shFlag = _SH_DENYRD; - break; - case FileShare::ReadWrite: - shFlag = _SH_DENYNO; - break; - default: - SLANG_ASSERT(!"Invalid file share mode."); - return SLANG_FAIL; + case FileShare::None: shFlag = _SH_DENYRW; break; + case FileShare::ReadOnly: shFlag = _SH_DENYWR; break; + case FileShare::WriteOnly: shFlag = _SH_DENYRD; break; + case FileShare::ReadWrite: shFlag = _SH_DENYNO; break; + default: SLANG_ASSERT(!"Invalid file share mode."); return SLANG_FAIL; } if (share == FileShare::None) -#pragma warning(suppress:4996) +#pragma warning(suppress : 4996) m_handle = _wfopen(fileName.toWString(), wideMode); else m_handle = _wfsopen(fileName.toWString(), wideMode, shFlag); @@ -189,7 +181,7 @@ Int64 FileStream::getPosition() return pos; #elif defined(__APPLE__) return ftell(m_handle); -#else +#else fpos64_t pos; fgetpos64(m_handle, &pos); return *(Int64*)(&pos); @@ -201,18 +193,10 @@ SlangResult FileStream::seek(SeekOrigin seekOrigin, Int64 offset) int fseekOrigin; switch (seekOrigin) { - case SeekOrigin::Start: - fseekOrigin = SEEK_SET; - break; - case SeekOrigin::End: - fseekOrigin = SEEK_END; - break; - case SeekOrigin::Current: - fseekOrigin = SEEK_CUR; - break; - default: - SLANG_ASSERT(!"Unsupported seek origin."); - return SLANG_FAIL; + case SeekOrigin::Start: fseekOrigin = SEEK_SET; break; + case SeekOrigin::End: fseekOrigin = SEEK_END; break; + case SeekOrigin::Current: fseekOrigin = SEEK_CUR; break; + default: SLANG_ASSERT(!"Unsupported seek origin."); return SLANG_FAIL; } // If endReached is intended to be like feof - then doing a seek will reset it @@ -301,18 +285,10 @@ SlangResult MemoryStreamBase::seek(SeekOrigin origin, Int64 offset) Int64 pos = 0; switch (origin) { - case SeekOrigin::Start: - pos = offset; - break; - case SeekOrigin::End: - pos = Int64(m_contentsSize) + offset; - break; - case SeekOrigin::Current: - pos = Int64(m_position) + offset; - break; - default: - SLANG_ASSERT(!"Unsupported seek origin."); - return SLANG_E_NOT_IMPLEMENTED; + case SeekOrigin::Start: pos = offset; break; + case SeekOrigin::End: pos = Int64(m_contentsSize) + offset; break; + case SeekOrigin::Current: pos = Int64(m_position) + offset; break; + default: SLANG_ASSERT(!"Unsupported seek origin."); return SLANG_E_NOT_IMPLEMENTED; } m_atEnd = false; @@ -338,7 +314,7 @@ SlangResult MemoryStreamBase::read(void* buffer, size_t length, size_t& outReadB if (maxRead == 0 && length > 0) { // At end of stream - m_atEnd = true; + m_atEnd = true; return SLANG_OK; } @@ -353,7 +329,7 @@ SlangResult MemoryStreamBase::read(void* buffer, size_t length, size_t& outReadB // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! OwnedMemoryStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -SlangResult OwnedMemoryStream::write(const void * buffer, size_t length) +SlangResult OwnedMemoryStream::write(const void* buffer, size_t length) { if (!canWrite()) { @@ -406,7 +382,8 @@ SlangResult BufferedReadStream::seek(SeekOrigin origin, Int64 offset) // So we could seek backwards up to -m_startIndex. // We don't worry about this here, for simplicity sake. - if (origin == SeekOrigin::End || origin == SeekOrigin::Start || offset < 0 || offset >= Int64(getCount())) + if (origin == SeekOrigin::End || origin == SeekOrigin::Start || offset < 0 || + offset >= Int64(getCount())) { // Empty the buffer _resetBuffer(); @@ -420,8 +397,9 @@ SlangResult BufferedReadStream::seek(SeekOrigin origin, Int64 offset) } SlangResult BufferedReadStream::read(void* inBuffer, size_t length, size_t& outReadBytes) -{ - // If the buffer has no data and the read size is larger than the default read size - may as well just read directly into the output buffer +{ + // If the buffer has no data and the read size is larger than the default read size - may as + // well just read directly into the output buffer if (getCount() == 0 && length > m_defaultReadSize) { return m_stream->read(inBuffer, length, outReadBytes); @@ -542,20 +520,21 @@ SlangResult BufferedReadStream::update() } else { - // Make sure we have the space + // Make sure we have the space const Index prevCount = m_buffer.getCount(); m_buffer.setCount(prevCount + m_defaultReadSize); m_buffer.setCount(prevCount); } } - + { const Index prevCount = m_buffer.getCount(); m_buffer.setCount(prevCount + m_defaultReadSize); size_t readBytes = 0; - const SlangResult res = m_stream->read(m_buffer.getBuffer() + prevCount, m_defaultReadSize, readBytes); + const SlangResult res = + m_stream->read(m_buffer.getBuffer() + prevCount, m_defaultReadSize, readBytes); m_buffer.setCount(prevCount + Index(readBytes)); @@ -591,41 +570,37 @@ SlangResult BufferedReadStream::readUntilContains(size_t size) SlangResult StreamUtil::readAndWrite( Stream* writeStream, ArrayView<Byte> bytesToWrite, - Stream* readStream, List<Byte>& outReadBytes, + Stream* readStream, + List<Byte>& outReadBytes, Stream* errStream, List<Byte>& outErrBytes) { - std::thread writeThread([&]() + std::thread writeThread( + [&]() { writeStream->write(bytesToWrite.getBuffer(), (size_t)bytesToWrite.getCount()); writeStream->close(); }); SlangResult readResult = SLANG_OK; - std::thread readThread([&]() - { - readResult = readAll(readStream, 1024, outReadBytes); - }); - std::thread readErrThread([&]() - { - readAll(errStream, 1024, outErrBytes); - }); + std::thread readThread([&]() { readResult = readAll(readStream, 1024, outReadBytes); }); + std::thread readErrThread([&]() { readAll(errStream, 1024, outErrBytes); }); writeThread.join(); readThread.join(); readErrThread.join(); return readResult; } -/* static */SlangResult StreamUtil::readAll(Stream* stream, size_t readSize, List<Byte>& ioBytes) +/* static */ SlangResult StreamUtil::readAll(Stream* stream, size_t readSize, List<Byte>& ioBytes) { while (!stream->isEnd()) { SLANG_RETURN_ON_FAIL(read(stream, readSize, ioBytes)); } - + return SLANG_OK; } -/* static */SlangResult StreamUtil::read(Stream* stream, size_t readSize, List<Byte>& ioBytes) +/* static */ SlangResult StreamUtil::read(Stream* stream, size_t readSize, List<Byte>& ioBytes) { readSize = (readSize <= 0) ? 1024 : readSize; @@ -635,7 +610,8 @@ SlangResult StreamUtil::readAndWrite( ioBytes.setCount(prevCount + readSize); size_t readBytesCount; - SLANG_RETURN_ON_FAIL(stream->read(ioBytes.getBuffer() + prevCount, readSize, readBytesCount)); + SLANG_RETURN_ON_FAIL( + stream->read(ioBytes.getBuffer() + prevCount, readSize, readBytesCount)); ioBytes.setCount(prevCount + Index(readBytesCount)); if (readBytesCount == 0) @@ -645,7 +621,7 @@ SlangResult StreamUtil::readAndWrite( } } -/* static */SlangResult StreamUtil::discard(Stream* stream) +/* static */ SlangResult StreamUtil::discard(Stream* stream) { Byte buf[1024]; const Index bufSize = SLANG_COUNT_OF(buf); @@ -654,7 +630,7 @@ SlangResult StreamUtil::readAndWrite( { size_t readBytesCount; SLANG_RETURN_ON_FAIL(stream->read(buf, bufSize, readBytesCount)); - + if (readBytesCount == 0) { return SLANG_OK; @@ -662,7 +638,7 @@ SlangResult StreamUtil::readAndWrite( } } -/* static */SlangResult StreamUtil::discardAll(Stream* stream) +/* static */ SlangResult StreamUtil::discardAll(Stream* stream) { while (!stream->isEnd()) { @@ -672,7 +648,10 @@ SlangResult StreamUtil::readAndWrite( } -/* static */SlangResult StreamUtil::readOrDiscard(Stream* stream, size_t readSize, List<Byte>* ioBytes) +/* static */ SlangResult StreamUtil::readOrDiscard( + Stream* stream, + size_t readSize, + List<Byte>* ioBytes) { if (ioBytes) { @@ -684,7 +663,10 @@ SlangResult StreamUtil::readAndWrite( } } -/* static */SlangResult StreamUtil::readOrDiscardAll(Stream* stream, size_t readSize, List<Byte>* ioBytes) +/* static */ SlangResult StreamUtil::readOrDiscardAll( + Stream* stream, + size_t readSize, + List<Byte>* ioBytes) { if (ioBytes) { @@ -700,10 +682,10 @@ static FILE* _getFileFromStdStreamType(StdStreamType stdStream) { switch (stdStream) { - case StdStreamType::ErrorOut: return stderr; - case StdStreamType::Out: return stdout; - case StdStreamType::In: return stdin; - default: return nullptr; + case StdStreamType::ErrorOut: return stderr; + case StdStreamType::Out: return stdout; + case StdStreamType::In: return stdin; + default: return nullptr; } } @@ -711,14 +693,16 @@ static int _getBufferOptions(StreamBufferStyle style) { switch (style) { - case StreamBufferStyle::None: return _IONBF; - case StreamBufferStyle::Line: return _IOLBF; - default: - case StreamBufferStyle::Full: return _IOFBF; + case StreamBufferStyle::None: return _IONBF; + case StreamBufferStyle::Line: return _IOLBF; + default: + case StreamBufferStyle::Full: return _IOFBF; } } -/* static */SlangResult StreamUtil::setStreamBufferStyle(StdStreamType stdStream, StreamBufferStyle style) +/* static */ SlangResult StreamUtil::setStreamBufferStyle( + StdStreamType stdStream, + StreamBufferStyle style) { FILE* file = _getFileFromStdStreamType(stdStream); diff --git a/source/core/slang-stream.h b/source/core/slang-stream.h index 8459d53d1..78664c17a 100644 --- a/source/core/slang-stream.h +++ b/source/core/slang-stream.h @@ -16,61 +16,74 @@ enum class StdStreamType enum class SeekOrigin { - Start, ///< Seek from the start of the stream - End, ///< Seek from the end of the stream - Current, ///< Seek from the current cursor position + Start, ///< Seek from the start of the stream + End, ///< Seek from the end of the stream + Current, ///< Seek from the current cursor position }; class Stream : public RefObject { public: virtual ~Stream() {} - /// Get the current 'cursor' position in the stream - virtual Int64 getPosition()=0; - /// Seek the cursor to a position. How the seek is performed is dependent on the 'origin' and the offset required. - /// NOTE that *any* seek will reset the 'end of stream' status. See 'read' for requirements for 'isEnd' to be reached. - virtual SlangResult seek(SeekOrigin origin, Int64 offset)=0; - /// Read from the current position into buffer. - /// If there are less bytes available than requested only the amount available will be read. outReadBytes holds the actual amount of bytes read. - /// It is valid (and not an error) for read to return 0 bytes read - even if the end of the stream. - /// - /// 'isEnd' only becomes true when a read is performed *past* the end of a stream. - /// If a non zero read is performed from the end then isEnd must be true. - /// - /// Will return an error if there is a reading failure. - virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) = 0; - /// Write to the stream from current position - virtual SlangResult write(const void* buffer, size_t length) = 0; - /// True if the of the stream has been hit. The 'read' method has more discussion as to when this can occur. - virtual bool isEnd() = 0; - /// Returns true if it's possible to read from the stream. - virtual bool canRead() = 0; - /// Returns true when it's possible to write to the stream. - virtual bool canWrite() = 0; - /// Close the stream. Once closed no more operations can be performed on the stream. - /// Implies any pending data is flushed. - virtual void close() = 0; - - /// Only applicable for write streams, flushes any buffers to underlying representation (such as pipe, or file) + /// Get the current 'cursor' position in the stream + virtual Int64 getPosition() = 0; + /// Seek the cursor to a position. How the seek is performed is dependent on the 'origin' and + /// the offset required. NOTE that *any* seek will reset the 'end of stream' status. See 'read' + /// for requirements for 'isEnd' to be reached. + virtual SlangResult seek(SeekOrigin origin, Int64 offset) = 0; + /// Read from the current position into buffer. + /// If there are less bytes available than requested only the amount available will be read. + /// outReadBytes holds the actual amount of bytes read. It is valid (and not an error) for read + /// to return 0 bytes read - even if the end of the stream. + /// + /// 'isEnd' only becomes true when a read is performed *past* the end of a stream. + /// If a non zero read is performed from the end then isEnd must be true. + /// + /// Will return an error if there is a reading failure. + virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) = 0; + /// Write to the stream from current position + virtual SlangResult write(const void* buffer, size_t length) = 0; + /// True if the of the stream has been hit. The 'read' method has more discussion as to when + /// this can occur. + virtual bool isEnd() = 0; + /// Returns true if it's possible to read from the stream. + virtual bool canRead() = 0; + /// Returns true when it's possible to write to the stream. + virtual bool canWrite() = 0; + /// Close the stream. Once closed no more operations can be performed on the stream. + /// Implies any pending data is flushed. + virtual void close() = 0; + + /// Only applicable for write streams, flushes any buffers to underlying representation (such as + /// pipe, or file) virtual SlangResult flush() = 0; - /// Helper function that will also *fail* if the specified amount of bytes aren't read. + /// Helper function that will also *fail* if the specified amount of bytes aren't read. SlangResult readExactly(void* buffer, size_t length); }; enum class FileMode { - Create, Open, CreateNew, Append + Create, + Open, + CreateNew, + Append }; enum class FileAccess { - None = 0, Read = 1, Write = 2, ReadWrite = 3 + None = 0, + Read = 1, + Write = 2, + ReadWrite = 3 }; enum class FileShare { - None, ReadOnly, WriteOnly, ReadWrite + None, + ReadOnly, + WriteOnly, + ReadWrite }; /// Base class for memory streams. Only supports reading and does NOT own contained data. @@ -81,47 +94,64 @@ public: virtual Int64 getPosition() SLANG_OVERRIDE { return m_position; } virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; - virtual SlangResult read(void * buffer, size_t length, size_t& outReadByts) SLANG_OVERRIDE; - virtual SlangResult write(const void * buffer, size_t length) SLANG_OVERRIDE { SLANG_UNUSED(buffer); SLANG_UNUSED(length); return SLANG_E_NOT_IMPLEMENTED; } + virtual SlangResult read(void* buffer, size_t length, size_t& outReadByts) SLANG_OVERRIDE; + virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE + { + SLANG_UNUSED(buffer); + SLANG_UNUSED(length); + return SLANG_E_NOT_IMPLEMENTED; + } virtual bool isEnd() SLANG_OVERRIDE { return m_atEnd; } virtual bool canRead() SLANG_OVERRIDE { return (int(m_access) & int(FileAccess::Read)) != 0; } virtual bool canWrite() SLANG_OVERRIDE { return (int(m_access) & int(FileAccess::Write)) != 0; } virtual void close() SLANG_OVERRIDE { m_access = FileAccess::None; } - virtual SlangResult flush() SLANG_OVERRIDE { return canWrite() ? SLANG_OK : SLANG_E_NOT_AVAILABLE; } + virtual SlangResult flush() SLANG_OVERRIDE + { + return canWrite() ? SLANG_OK : SLANG_E_NOT_AVAILABLE; + } - /// Get the contents - ConstArrayView<uint8_t> getContents() const { return ConstArrayView<uint8_t>(m_contents, m_contentsSize); } + /// Get the contents + ConstArrayView<uint8_t> getContents() const + { + return ConstArrayView<uint8_t>(m_contents, m_contentsSize); + } - MemoryStreamBase(FileAccess access = FileAccess::Read, const void* contents = nullptr, size_t contentsSize = 0): - m_access(access) + MemoryStreamBase( + FileAccess access = FileAccess::Read, + const void* contents = nullptr, + size_t contentsSize = 0) + : m_access(access) { _setContents(contents, contentsSize); } protected: - /// Set to replace wholly current content with specified content + /// Set to replace wholly current content with specified content void _setContents(const void* contents, size_t contentsSize) { m_contents = (const uint8_t*)contents; m_contentsSize = ptrdiff_t(contentsSize); m_position = 0; - m_atEnd = false; + m_atEnd = false; } - /// Update means that the content has changed, but position should be maintained + /// Update means that the content has changed, but position should be maintained void _updateContents(const void* contents, size_t contentsSize) { - const ptrdiff_t newPosition = (m_position > ptrdiff_t(contentsSize)) ? ptrdiff_t(contentsSize) : m_position; + const ptrdiff_t newPosition = + (m_position > ptrdiff_t(contentsSize)) ? ptrdiff_t(contentsSize) : m_position; _setContents(contents, contentsSize); m_position = newPosition; } - const uint8_t* m_contents; ///< The content held in the stream + const uint8_t* m_contents; ///< The content held in the stream // Using ptrdiff_t (as opposed to size_t) as makes maths simpler - ptrdiff_t m_contentsSize; ///< Total size of the content in bytes - ptrdiff_t m_position; ///< The current position within content (valid values can only be between 0 and m_contentSize) + ptrdiff_t m_contentsSize; ///< Total size of the content in bytes + ptrdiff_t m_position; ///< The current position within content (valid values can only be between + ///< 0 and m_contentSize) - bool m_atEnd; ///< Happens when a read is done and nothing can be returned because already at end + bool + m_atEnd; ///< Happens when a read is done and nothing can be returned because already at end FileAccess m_access; }; @@ -134,7 +164,7 @@ public: virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE; - /// Set the contents + /// Set the contents void setContent(const void* contents, size_t contentsSize) { m_ownedContents.setCount(contentsSize); @@ -151,12 +181,12 @@ public: _setContents(m_ownedContents.getBuffer(), m_ownedContents.getCount()); } - OwnedMemoryStream(FileAccess access) : - Super(access) - {} + OwnedMemoryStream(FileAccess access) + : Super(access) + { + } protected: - List<uint8_t> m_ownedContents; }; @@ -166,33 +196,38 @@ public: typedef Stream Super; // Stream interface - virtual Int64 getPosition() SLANG_OVERRIDE; - virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; - virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) SLANG_OVERRIDE; - virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE; - virtual bool canRead() SLANG_OVERRIDE; - virtual bool canWrite() SLANG_OVERRIDE; - virtual void close() SLANG_OVERRIDE; - virtual bool isEnd() SLANG_OVERRIDE; + virtual Int64 getPosition() SLANG_OVERRIDE; + virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; + virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) SLANG_OVERRIDE; + virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE; + virtual bool canRead() SLANG_OVERRIDE; + virtual bool canWrite() SLANG_OVERRIDE; + virtual void close() SLANG_OVERRIDE; + virtual bool isEnd() SLANG_OVERRIDE; virtual SlangResult flush() SLANG_OVERRIDE; FileStream(); - + SlangResult init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share); SlangResult init(const String& fileName, FileMode fileMode = FileMode::Open); ~FileStream(); private: - SlangResult _init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share); + SlangResult _init( + const String& fileName, + FileMode fileMode, + FileAccess access, + FileShare share); FILE* m_handle; - FileAccess m_fileAccess; + FileAccess m_fileAccess; bool m_endReached = false; }; /* A simple BufferedReader. The valid data is between m_startIndex and getCount(). -Can be used as a buffer to build up a result from a stream in memory using 'update' to read to the appropriate buffer size. +Can be used as a buffer to build up a result from a stream in memory using 'update' to read to the +appropriate buffer size. */ class BufferedReadStream : public Stream { @@ -209,10 +244,10 @@ public: virtual bool isEnd() SLANG_OVERRIDE; virtual SlangResult flush() SLANG_OVERRIDE; - /// Will read assuming backing stream is + /// Will read assuming backing stream is SlangResult update(); - /// Consume bytes in the buffer. + /// Consume bytes in the buffer. void consume(Index byteCount); Byte* getBuffer() { return m_buffer.getBuffer() + m_startIndex; } @@ -220,31 +255,31 @@ public: size_t getCount() const { return m_buffer.getCount() - m_startIndex; } - /// Read until the buffer contains the specified amount of bytes + /// Read until the buffer contains the specified amount of bytes SlangResult readUntilContains(size_t size); - ConstArrayView<Byte> getView() const { return ConstArrayView<Byte>(getBuffer(), Index(getCount())); } + ConstArrayView<Byte> getView() const + { + return ConstArrayView<Byte>(getBuffer(), Index(getCount())); + } ArrayView<Byte> getView() { return ArrayView<Byte>(getBuffer(), Index(getCount())); } - BufferedReadStream(Stream* stream) : - m_stream(stream), - m_startIndex(0) + BufferedReadStream(Stream* stream) + : m_stream(stream), m_startIndex(0) { - } protected: - void _resetBuffer() { m_startIndex = 0; m_buffer.setCount(0); } - size_t m_defaultReadSize = 1024; ///< When initiating a read the default read size - List<Byte> m_buffer; ///< Holds the characters - Index m_startIndex; ///< The start index - RefPtr<Stream> m_stream; ///< Stream that is being read from + size_t m_defaultReadSize = 1024; ///< When initiating a read the default read size + List<Byte> m_buffer; ///< Holds the characters + Index m_startIndex; ///< The start index + RefPtr<Stream> m_stream; ///< Stream that is being read from }; enum class StreamBufferStyle @@ -256,14 +291,20 @@ enum class StreamBufferStyle struct StreamUtil { - // Write inputs to writeStream while simultaneously read from readStream and errStream. - static SlangResult readAndWrite(Stream* writeStream, ArrayView<Byte> bytesToWrite, Stream* readStream, List<Byte>& outReadBytes, Stream* errStream, List<Byte>& outErrBytes); - - /// Appends all bytes that can be read from stream into bytes + // Write inputs to writeStream while simultaneously read from readStream and errStream. + static SlangResult readAndWrite( + Stream* writeStream, + ArrayView<Byte> bytesToWrite, + Stream* readStream, + List<Byte>& outReadBytes, + Stream* errStream, + List<Byte>& outErrBytes); + + /// Appends all bytes that can be read from stream into bytes static SlangResult readAll(Stream* stream, size_t readSize, List<Byte>& ioBytes); - /// Read as much as can be read until a 0 sized read, or an error and append onto ioBytes - /// Read size controls the size of each buffer read. Passing 0, will use the default read size. + /// Read as much as can be read until a 0 sized read, or an error and append onto ioBytes + /// Read size controls the size of each buffer read. Passing 0, will use the default read size. static SlangResult read(Stream* stream, size_t readSize, List<Byte>& ioBytes); static SlangResult discard(Stream* stream); diff --git a/source/core/slang-string-escape-util.cpp b/source/core/slang-string-escape-util.cpp index 77399552e..a6a70ce76 100644 --- a/source/core/slang-string-escape-util.cpp +++ b/source/core/slang-string-escape-util.cpp @@ -1,12 +1,12 @@ #include "slang-string-escape-util.h" #include "slang-char-util.h" -#include "slang-text-io.h" -#include "slang-memory-arena.h" - #include "slang-com-helper.h" +#include "slang-memory-arena.h" +#include "slang-text-io.h" -namespace Slang { +namespace Slang +{ // !!!!!!!!!!!!!!!!!!!!!!!!!! SpaceStringEscapeHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -15,16 +15,24 @@ class SpaceStringEscapeHandler : public StringEscapeHandler public: typedef StringEscapeHandler Super; - virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { return isEscapingNeeded(slice); } - + virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE + { + return isEscapingNeeded(slice); + } + virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE; virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE; - virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE; - virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE; + virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) + SLANG_OVERRIDE; + virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) + SLANG_OVERRIDE; virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE; - SpaceStringEscapeHandler() : Super('"') {} + SpaceStringEscapeHandler() + : Super('"') + { + } }; bool SpaceStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice) @@ -39,7 +47,9 @@ bool SpaceStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& sli return false; } -SlangResult SpaceStringEscapeHandler::appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) +SlangResult SpaceStringEscapeHandler::appendUnescaped( + const UnownedStringSlice& slice, + StringBuilder& out) { if (slice.indexOf('"') >= 0) { @@ -50,7 +60,9 @@ SlangResult SpaceStringEscapeHandler::appendUnescaped(const UnownedStringSlice& return SLANG_OK; } -SlangResult SpaceStringEscapeHandler::appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) +SlangResult SpaceStringEscapeHandler::appendEscaped( + const UnownedStringSlice& slice, + StringBuilder& out) { if (slice.indexOf('"') >= 0) { @@ -60,7 +72,9 @@ SlangResult SpaceStringEscapeHandler::appendEscaped(const UnownedStringSlice& sl return SLANG_OK; } -/* static */SlangResult SpaceStringEscapeHandler::lexQuoted(const char* cursor, const char** outCursor) +/* static */ SlangResult SpaceStringEscapeHandler::lexQuoted( + const char* cursor, + const char** outCursor) { *outCursor = cursor; @@ -80,14 +94,14 @@ SlangResult SpaceStringEscapeHandler::appendEscaped(const UnownedStringSlice& sl } switch (c) { - case 0: - case '\n': - case '\r': + case 0: + case '\n': + case '\r': { // Didn't hit closing quote! return SLANG_FAIL; } - default: + default: { ++cursor; break; @@ -97,7 +111,6 @@ SlangResult SpaceStringEscapeHandler::appendEscaped(const UnownedStringSlice& sl } - // !!!!!!!!!!!!!!!!!!!!!!!!!! CppStringEscapeHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! class CppStringEscapeHandler : public StringEscapeHandler @@ -105,31 +118,40 @@ class CppStringEscapeHandler : public StringEscapeHandler public: typedef StringEscapeHandler Super; - virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { SLANG_UNUSED(slice); return true; } + virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE + { + SLANG_UNUSED(slice); + return true; + } virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE; virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE; - virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE; - virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE; + virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) + SLANG_OVERRIDE; + virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) + SLANG_OVERRIDE; virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE; - CppStringEscapeHandler() : Super('"') {} + CppStringEscapeHandler() + : Super('"') + { + } }; static char _getCppEscapedChar(char c) { switch (c) { - case '\b': return 'b'; - case '\f': return 'f'; - case '\n': return 'n'; - case '\r': return 'r'; - case '\a': return 'a'; - case '\t': return 't'; - case '\v': return 'v'; - case '\'': return '\''; - case '\"': return '"'; - case '\\': return '\\'; - default: return 0; + case '\b': return 'b'; + case '\f': return 'f'; + case '\n': return 'n'; + case '\r': return 'r'; + case '\a': return 'a'; + case '\t': return 't'; + case '\v': return 'v'; + case '\'': return '\''; + case '\"': return '"'; + case '\\': return '\\'; + default: return 0; } } @@ -137,17 +159,17 @@ static char _getCppUnescapedChar(char c) { switch (c) { - case 'b': return '\b'; - case 'f': return '\f'; - case 'n': return '\n'; - case 'r': return '\r'; - case 'a': return '\a'; - case 't': return '\t'; - case 'v': return '\v'; - case '\'': return '\''; - case '\"': return '"'; - case '\\': return '\\'; - default: return 0; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 'a': return '\a'; + case 't': return '\t'; + case 'v': return '\v'; + case '\'': return '\''; + case '\"': return '"'; + case '\\': return '\\'; + default: return 0; } } @@ -156,10 +178,10 @@ bool CppStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice return slice.indexOf('\\') >= 0; } -/* static */bool CppStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice) +/* static */ bool CppStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice) { const char* cur = slice.begin(); - const char*const end = slice.end(); + const char* const end = slice.end(); for (; cur < end; ++cur) { @@ -167,14 +189,14 @@ bool CppStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice switch (c) { - case '\'': - case '\"': - case '\\': + case '\'': + case '\"': + case '\\': { - // Strictly speaking ' shouldn't need a quote if in a C style string. + // Strictly speaking ' shouldn't need a quote if in a C style string. return true; } - default: + default: { if (c < ' ' || c >= 0x7e) { @@ -187,11 +209,13 @@ bool CppStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice return false; } -SlangResult CppStringEscapeHandler::appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) +SlangResult CppStringEscapeHandler::appendEscaped( + const UnownedStringSlice& slice, + StringBuilder& out) { const char* start = slice.begin(); const char* cur = start; - const char*const end = slice.end(); + const char* const end = slice.end(); // TODO(JS): A cleverer implementation might support U and u prefixing for unicode characters. // For now we just stick with hex if it's not 'regular' ascii. @@ -222,12 +246,12 @@ SlangResult CppStringEscapeHandler::appendEscaped(const UnownedStringSlice& slic out.append(start, cur); } - // NOTE! There is a possible flaw around checking 'next' character (used for outputting oct and hex) - // If a string is constructed appended in parts, the next character is not available so the problem below can still - // occur. + // NOTE! There is a possible flaw around checking 'next' character (used for outputting + // oct and hex) If a string is constructed appended in parts, the next character is not + // available so the problem below can still occur. - // Another solution to this problem would be to output "", but that makes some other assumptions - // For example Slang doesn't support that style. + // Another solution to this problem would be to output "", but that makes some other + // assumptions For example Slang doesn't support that style. // C++ greedily consumes hex/octal digits. This is a problem if we have bytes // 0, '1' as by default this will output as @@ -240,10 +264,12 @@ SlangResult CppStringEscapeHandler::appendEscaped(const UnownedStringSlice& slic // On testing in Visual Studio hex can indeed be more than 3 digits - // There is a problem outputting values in hex, because C++ allows *any* amount of hex digits. - // We could work around with \u \U but they are later extensions (C++11) and have other issue + // There is a problem outputting values in hex, because C++ allows *any* amount of hex + // digits. We could work around with \u \U but they are later extensions (C++11) and + // have other issue - // The solution taken here is to always output as octal, because octal can be at most 3 digits. + // The solution taken here is to always output as octal, because octal can be at most 3 + // digits. // Special case handling of 0 if (c == 0 && !(cur + 1 < end && CharUtil::isOctalDigit(cur[1]))) @@ -253,8 +279,9 @@ SlangResult CppStringEscapeHandler::appendEscaped(const UnownedStringSlice& slic } else { - // A slightly more sophisticated implementation could output less digits if needed, if not followed by an octal - // digit, but for now we go simple and output all 3 digits + // A slightly more sophisticated implementation could output less digits if needed, + // if not followed by an octal digit, but for now we go simple and output all 3 + // digits const uint32_t v = uint32_t(c); @@ -279,11 +306,13 @@ SlangResult CppStringEscapeHandler::appendEscaped(const UnownedStringSlice& slic return SLANG_OK; } -SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) +SlangResult CppStringEscapeHandler::appendUnescaped( + const UnownedStringSlice& slice, + StringBuilder& out) { const char* start = slice.begin(); const char* cur = start; - const char*const end = slice.end(); + const char* const end = slice.end(); while (cur < end) { @@ -297,7 +326,7 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl out.append(start, cur); } - /// Next + /// Next cur++; if (cur >= end) @@ -311,17 +340,17 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl // Need to handle various escape sequence cases switch (nextC) { - case '\'': - case '\"': - case '\\': - case '?': - case 'a': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - case 'v': + case '\'': + case '\"': + case '\\': + case '?': + case 'a': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': { const char unescapedChar = _getCppUnescapedChar(nextC); if (unescapedChar == 0) @@ -334,13 +363,20 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl start = cur; break; } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { // Rewind back a character, as first digit is the 'nextC' --cur; - // Don't need to check for enough characters, because there must be 1 - the nextC + // Don't need to check for enough characters, because there must be 1 - the + // nextC // octal escape: up to 3 characters int value = 0; @@ -355,7 +391,7 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl { break; } - value = (value << 3) | digitValue; + value = (value << 3) | digitValue; } out.appendChar(char(value)); @@ -363,7 +399,7 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl start = cur; break; } - case 'x': + case 'x': { /// In the C++ standard we consume hex digits until we hit a non hex digit uint32_t value = 0; @@ -385,8 +421,8 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl } else { - // It's arguable what is appropriate. We only decode/encode 4, which the current spec has, - // but 6 are possible, so lets go large. + // It's arguable what is appropriate. We only decode/encode 4, which the + // current spec has, but 6 are possible, so lets go large. const Index maxUtf8EncodeCount = 6; char* chars = out.prepareForAppend(maxUtf8EncodeCount); @@ -398,8 +434,8 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl start = cur; break; } - case 'u': - case 'U': + case 'u': + case 'U': { // u implies 4 hex digits // U implies 6. @@ -433,8 +469,8 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl } else { - // It's arguable what is appropriate. We only decode/encode 4, which the current spec has, - // but 6 are possible, so lets go large. + // It's arguable what is appropriate. We only decode/encode 4, which the + // current spec has, but 6 are possible, so lets go large. const Index maxUtf8EncodeCount = 6; char* chars = out.prepareForAppend(maxUtf8EncodeCount); @@ -446,7 +482,7 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl start = cur; break; } - default: + default: { return SLANG_FAIL; } @@ -487,36 +523,42 @@ SlangResult CppStringEscapeHandler::lexQuoted(const char* cursor, const char** o } switch (c) { - case 0: - case '\n': - case '\r': + case 0: + case '\n': + case '\r': { // Didn't hit closing quote! return SLANG_FAIL; } - case '\\': + case '\\': { ++cursor; // Need to handle various escape sequence cases switch (*cursor) { - case '\'': - case '\"': - case '\\': - case '?': - case 'a': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - case 'v': + case '\'': + case '\"': + case '\\': + case '?': + case 'a': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': { ++cursor; break; } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { // octal escape: up to 3 characters ++cursor; @@ -535,11 +577,12 @@ SlangResult CppStringEscapeHandler::lexQuoted(const char* cursor, const char** o } break; } - case 'x': + case 'x': { // hexadecimal escape: any number of characters ++cursor; - for (; CharUtil::isHexDigit(*cursor); ++cursor); + for (; CharUtil::isHexDigit(*cursor); ++cursor) + ; // TODO: Unicode escape sequences break; @@ -547,7 +590,7 @@ SlangResult CppStringEscapeHandler::lexQuoted(const char* cursor, const char** o } break; } - default: + default: { ++cursor; break; @@ -563,14 +606,23 @@ class JSONStringEscapeHandler : public StringEscapeHandler public: typedef StringEscapeHandler Super; - virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { SLANG_UNUSED(slice); return true; } + virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE + { + SLANG_UNUSED(slice); + return true; + } virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE; virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE; - virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE; - virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE; + virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) + SLANG_OVERRIDE; + virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) + SLANG_OVERRIDE; virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE; - JSONStringEscapeHandler() : Super('"') {} + JSONStringEscapeHandler() + : Super('"') + { + } }; bool JSONStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slice) @@ -581,7 +633,7 @@ bool JSONStringEscapeHandler::isUnescapingNeeeded(const UnownedStringSlice& slic bool JSONStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice) { const char* cur = slice.begin(); - const char*const end = slice.end(); + const char* const end = slice.end(); for (; cur < end; ++cur) { @@ -589,13 +641,13 @@ bool JSONStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice) switch (c) { - case '\"': - case '\\': - case '/': + case '\"': + case '\\': + case '/': { return true; } - default: + default: { if (c < ' ' || c >= 0x7e) { @@ -617,30 +669,30 @@ SlangResult JSONStringEscapeHandler::lexQuoted(const char* cursor, const char** switch (c) { - case 0: return SLANG_FAIL; - case '"': + case 0: return SLANG_FAIL; + case '"': { *outCursor = cursor; return SLANG_OK; } - case '\\': + case '\\': { const char nextC = *cursor; switch (nextC) { - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': + case '"': + case '\\': + case '/': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': { ++cursor; break; } - case 'u': + case 'u': { cursor++; for (Index i = 0; i < 4; ++i) @@ -655,8 +707,8 @@ SlangResult JSONStringEscapeHandler::lexQuoted(const char* cursor, const char** } } } - // Somewhat surprisingly it appears it's valid to have \r\n inside of quotes. - default: break; + // Somewhat surprisingly it appears it's valid to have \r\n inside of quotes. + default: break; } } } @@ -665,15 +717,15 @@ static char _getJSONEscapedChar(char c) { switch (c) { - case '\b': return 'b'; - case '\f': return 'f'; - case '\n': return 'n'; - case '\r': return 'r'; - case '\t': return 't'; - case '\\': return '\\'; - case '/': return '/'; - case '"': return '"'; - default: return 0; + case '\b': return 'b'; + case '\f': return 'f'; + case '\n': return 'n'; + case '\r': return 'r'; + case '\t': return 't'; + case '\\': return '\\'; + case '/': return '/'; + case '"': return '"'; + default: return 0; } } @@ -681,15 +733,15 @@ static char _getJSONUnescapedChar(char c) { switch (c) { - case 'b': return '\b'; - case 'f': return '\f'; - case 'n': return '\n'; - case 'r': return '\r'; - case 't': return '\t'; - case '\\': return '\\'; - case '/': return '/'; - case '"': return '"'; - default: return 0; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case '\\': return '\\'; + case '/': return '/'; + case '"': return '"'; + default: return 0; } } @@ -745,16 +797,18 @@ static void _appendHex16(uint32_t value, StringBuilder& out) out.append(UnownedStringSlice(buf, 6)); } -SlangResult JSONStringEscapeHandler::appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) +SlangResult JSONStringEscapeHandler::appendEscaped( + const UnownedStringSlice& slice, + StringBuilder& out) { const char* start = slice.begin(); const char* cur = start; - const char*const end = slice.end(); + const char* const end = slice.end(); for (; cur < end; ++cur) { const char c = *cur; - + const char escapedChar = _getJSONEscapedChar(c); if (escapedChar) @@ -814,11 +868,13 @@ SlangResult JSONStringEscapeHandler::appendEscaped(const UnownedStringSlice& sli return SLANG_OK; } -SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) +SlangResult JSONStringEscapeHandler::appendUnescaped( + const UnownedStringSlice& slice, + StringBuilder& out) { const char* start = slice.begin(); const char* cur = start; - const char*const end = slice.end(); + const char* const end = slice.end(); for (; cur < end; ++cur) { @@ -832,7 +888,7 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s out.append(start, cur); } - /// Next + /// Next cur++; if (cur >= end) @@ -843,14 +899,14 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s // Need to handle various escape sequence cases switch (*cur) { - case '\"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': + case '\"': + case '\\': + case '/': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': { const char unescapedChar = _getJSONUnescapedChar(*cur); if (unescapedChar == 0) @@ -863,7 +919,7 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s start = cur + 1; break; } - case 'u': + case 'u': { uint32_t value = 0; cur++; @@ -884,9 +940,9 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s } else if (digitC >= 'a' && digitC <= 'f') { - digitValue = digitC -'a' + 10; + digitValue = digitC - 'a' + 10; } - else if(digitC >= 'A' && digitC <= 'F') + else if (digitC >= 'A' && digitC <= 'F') { digitValue = digitC - 'A' + 10; } @@ -899,9 +955,9 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s } cur += 4; - // NOTE! Strictly speaking we may want to combine 2 UTF16 surrogates to make a single - // UTF8 encoded char. - + // NOTE! Strictly speaking we may want to combine 2 UTF16 surrogates to make a + // single UTF8 encoded char. + // Need to encode in UTF8 to concat char buf[8]; @@ -913,7 +969,7 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s cur--; break; } - default: + default: { // Can't decode return SLANG_FAIL; @@ -941,17 +997,21 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) { switch (style) { - case Style::Cpp: return &g_cppHandler; - case Style::Space: return &g_spaceHandler; - case Style::JSON: return &g_jsonHandler; - // TODO(JS): For now we make Slang language string encoding/decoding the same as C++ - // That may not be desirable because C++ has a variety of surprising edge cases (for example around \x) - case Style::Slang: return &g_cppHandler; - default: return nullptr; + case Style::Cpp: return &g_cppHandler; + case Style::Space: return &g_spaceHandler; + case Style::JSON: return &g_jsonHandler; + // TODO(JS): For now we make Slang language string encoding/decoding the same as C++ + // That may not be desirable because C++ has a variety of surprising edge cases (for example + // around \x) + case Style::Slang: return &g_cppHandler; + default: return nullptr; } } -/* static */SlangResult StringEscapeUtil::appendQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out) +/* static */ SlangResult StringEscapeUtil::appendQuoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out) { const char quoteChar = handler->getQuoteChar(); out.appendChar(quoteChar); @@ -960,7 +1020,10 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) return res; } -/* static */SlangResult StringEscapeUtil::appendUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out) +/* static */ SlangResult StringEscapeUtil::appendUnquoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out) { const Index len = slice.getLength(); @@ -973,7 +1036,10 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) return handler->appendUnescaped(slice.subString(1, len - 2), out); } -/* static */SlangResult StringEscapeUtil::appendMaybeQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out) +/* static */ SlangResult StringEscapeUtil::appendMaybeQuoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out) { if (handler->isQuotingNeeded(slice)) { @@ -986,13 +1052,15 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) } } -/* static */bool StringEscapeUtil::isQuoted(char quoteChar, UnownedStringSlice& slice) +/* static */ bool StringEscapeUtil::isQuoted(char quoteChar, UnownedStringSlice& slice) { const Index len = slice.getLength(); return len >= 2 && slice[0] == quoteChar && slice[len - 1] == quoteChar; } -/* static */UnownedStringSlice StringEscapeUtil::unquote(char quoteChar, const UnownedStringSlice& slice) +/* static */ UnownedStringSlice StringEscapeUtil::unquote( + char quoteChar, + const UnownedStringSlice& slice) { const Index len = slice.getLength(); if (len >= 2 && slice[0] == quoteChar && slice[len - 1] == quoteChar) @@ -1003,7 +1071,10 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) return UnownedStringSlice(); } -/* static */SlangResult StringEscapeUtil::appendMaybeUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out) +/* static */ SlangResult StringEscapeUtil::appendMaybeUnquoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out) { const char quoteChar = handler->getQuoteChar(); @@ -1020,12 +1091,17 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) } } -/* static */SlangResult StringEscapeUtil::isUnescapeShellLikeNeeded(Handler* handler, const UnownedStringSlice& slice) +/* static */ SlangResult StringEscapeUtil::isUnescapeShellLikeNeeded( + Handler* handler, + const UnownedStringSlice& slice) { return slice.indexOf(handler->getQuoteChar()) >= 0; } -/* static */SlangResult StringEscapeUtil::unescapeShellLike(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out) +/* static */ SlangResult StringEscapeUtil::unescapeShellLike( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out) { StringBuilder buf; const char quoteChar = handler->getQuoteChar(); @@ -1051,7 +1127,8 @@ StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style) SLANG_RETURN_ON_FAIL(handler->lexQuoted(remaining.begin() + index, "edEnd)); // Unescape it - SLANG_RETURN_ON_FAIL(appendUnquoted(handler, UnownedStringSlice(remaining.begin() + index, quotedEnd), out)); + SLANG_RETURN_ON_FAIL( + appendUnquoted(handler, UnownedStringSlice(remaining.begin() + index, quotedEnd), out)); // Fix up remaining remaining = UnownedStringSlice(quotedEnd, remaining.end()); diff --git a/source/core/slang-string-escape-util.h b/source/core/slang-string-escape-util.h index c3a43b623..6e02d772d 100644 --- a/source/core/slang-string-escape-util.h +++ b/source/core/slang-string-escape-util.h @@ -1,39 +1,41 @@ #ifndef SLANG_CORE_STRING_ESCAPE_UTIL_H #define SLANG_CORE_STRING_ESCAPE_UTIL_H -#include "slang-string.h" #include "slang-list.h" +#include "slang-string.h" -namespace Slang { +namespace Slang +{ class StringEscapeHandler { public: - - /// True if quoting is needed + /// True if quoting is needed virtual bool isQuotingNeeded(const UnownedStringSlice& slice) = 0; - /// True if any escaping is needed. If not slice can be used (assuming appropriate quoting) as is + /// True if any escaping is needed. If not slice can be used (assuming appropriate quoting) as + /// is virtual bool isEscapingNeeded(const UnownedStringSlice& slice) = 0; - /// True if we need to unescape + /// True if we need to unescape virtual bool isUnescapingNeeeded(const UnownedStringSlice& slice) = 0; - /// Takes slice and adds any appropriate escaping (for example C++/C type escaping for special characters like '\', '"' and if not ascii will write out as hex sequence) - /// Does not append quotes + /// Takes slice and adds any appropriate escaping (for example C++/C type escaping for special + /// characters like '\', '"' and if not ascii will write out as hex sequence) Does not append + /// quotes virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) = 0; - /// Given a slice append it unescaped - /// Does not consume surrounding quotes + /// Given a slice append it unescaped + /// Does not consume surrounding quotes virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) = 0; - /// Lex quoted text. - /// The first character of cursor should be the quoteCharacter. - /// cursor points to the string to be lexed - must typically be 0 terminated. - /// outCursor on successful lex will be at the next character after was processed. + /// Lex quoted text. + /// The first character of cursor should be the quoteCharacter. + /// cursor points to the string to be lexed - must typically be 0 terminated. + /// outCursor on successful lex will be at the next character after was processed. virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) = 0; SLANG_FORCE_INLINE char getQuoteChar() const { return m_quoteChar; } - StringEscapeHandler(char quoteChar): - m_quoteChar(quoteChar) + StringEscapeHandler(char quoteChar) + : m_quoteChar(quoteChar) { } @@ -43,8 +45,8 @@ protected: /* A set of function that can be used for escaping/unescaping quoting/unquoting strings. -The distinction between 'escaping' and 'quoting' here, is just that escaping is the 'payload' of quotes. -In *principal* the Style can determine different styles of escaping that can be used. +The distinction between 'escaping' and 'quoting' here, is just that escaping is the 'payload' of +quotes. In *principal* the Style can determine different styles of escaping that can be used. */ struct StringEscapeUtil { @@ -52,43 +54,65 @@ struct StringEscapeUtil enum class Style { - Cpp, ///< Cpp style quoting and escape handling - Space, ///< Applies quotes if there are spaces. Does not escape. - JSON, ///< Json encoding - Slang, ///< Slang style string encoding (For now same as Cpp but that may change in the future) + Cpp, ///< Cpp style quoting and escape handling + Space, ///< Applies quotes if there are spaces. Does not escape. + JSON, ///< Json encoding + Slang, ///< Slang style string encoding (For now same as Cpp but that may change in the + ///< future) CountOf, }; - /// Given a style returns a handler + /// Given a style returns a handler static Handler* getHandler(Style style); - /// Get without quotes. Will assert if not correctly quoted + /// Get without quotes. Will assert if not correctly quoted static UnownedStringSlice unquote(char quoteChar, const UnownedStringSlice& slice); - static UnownedStringSlice unquote(Handler* handler, const UnownedStringSlice& slice) { return unquote(handler->getQuoteChar(), slice); } + static UnownedStringSlice unquote(Handler* handler, const UnownedStringSlice& slice) + { + return unquote(handler->getQuoteChar(), slice); + } /// True is slice is quoted static bool isQuoted(char quoteChar, UnownedStringSlice& slice); - static bool isQuoted(Handler* handler, UnownedStringSlice& slice) { return isQuoted(handler->getQuoteChar(), slice); } - - /// If quoting is needed appends to out quoted - static SlangResult appendMaybeQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out); - - /// If the slice appears to be quoted for the style, unquote it, else just append to out - static SlangResult appendMaybeUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out); - - /// Appends to out slice without quotes - static SlangResult appendUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out); - - /// Append with quotes (even if not needed) - static SlangResult appendQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out); - + static bool isQuoted(Handler* handler, UnownedStringSlice& slice) + { + return isQuoted(handler->getQuoteChar(), slice); + } - /// True if requires 'shell-like' unescape. With shell-like, quoting does *not* have to start at the start of the slice. - /// and there may be multiple quoted section + /// If quoting is needed appends to out quoted + static SlangResult appendMaybeQuoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out); + + /// If the slice appears to be quoted for the style, unquote it, else just append to out + static SlangResult appendMaybeUnquoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out); + + /// Appends to out slice without quotes + static SlangResult appendUnquoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out); + + /// Append with quotes (even if not needed) + static SlangResult appendQuoted( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out); + + + /// True if requires 'shell-like' unescape. With shell-like, quoting does *not* have to start at + /// the start of the slice. and there may be multiple quoted section static SlangResult isUnescapeShellLikeNeeded(Handler* handler, const UnownedStringSlice& slice); - /// Shells can have multiple quoted sections. This function makes a string with out quoting - static SlangResult unescapeShellLike(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out); + /// Shells can have multiple quoted sections. This function makes a string with out quoting + static SlangResult unescapeShellLike( + Handler* handler, + const UnownedStringSlice& slice, + StringBuilder& out); }; diff --git a/source/core/slang-string-slice-index-map.cpp b/source/core/slang-string-slice-index-map.cpp index d147556e4..dded10537 100644 --- a/source/core/slang-string-slice-index-map.cpp +++ b/source/core/slang-string-slice-index-map.cpp @@ -5,7 +5,9 @@ namespace Slang // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringSliceIndexMap !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -StringSliceIndexMap::CountIndex StringSliceIndexMap::add(const UnownedStringSlice& key, Index valueIndex) +StringSliceIndexMap::CountIndex StringSliceIndexMap::add( + const UnownedStringSlice& key, + Index valueIndex) { StringSlicePool::Handle handle; m_pool.findOrAdd(key, handle); @@ -22,7 +24,9 @@ StringSliceIndexMap::CountIndex StringSliceIndexMap::add(const UnownedStringSlic return countIndex; } -StringSliceIndexMap::CountIndex StringSliceIndexMap::findOrAdd(const UnownedStringSlice& key, Index defaultValueIndex) +StringSliceIndexMap::CountIndex StringSliceIndexMap::findOrAdd( + const UnownedStringSlice& key, + Index defaultValueIndex) { StringSlicePool::Handle handle; m_pool.findOrAdd(key, handle); diff --git a/source/core/slang-string-slice-index-map.h b/source/core/slang-string-slice-index-map.h index c57e0f570..b7c316c24 100644 --- a/source/core/slang-string-slice-index-map.h +++ b/source/core/slang-string-slice-index-map.h @@ -2,59 +2,61 @@ #define SLANG_CORE_STRING_SLICE_INDEX_MAP_H #include "slang-basic.h" - #include "slang-string-slice-pool.h" namespace Slang { -/* Maps an UnownedStringSlice to an index. All substrings are held internally in a StringSlicePool, and so -owned by the type. +/* Maps an UnownedStringSlice to an index. All substrings are held internally in a StringSlicePool, +and so owned by the type. */ class StringSliceIndexMap { public: - /// An index that identifies a key value pair. + /// An index that identifies a key value pair. typedef Index CountIndex; - /// Adds a key, value pair. Returns the CountIndex of the pair. - /// If there is already a value stored for the key it is replaced. + /// Adds a key, value pair. Returns the CountIndex of the pair. + /// If there is already a value stored for the key it is replaced. CountIndex add(const UnownedStringSlice& key, Index valueIndex); - /// Finds or adds the slice. If the slice is added the defaultValueIndex is set. - /// If not the index associated with the slice remains the same. - /// Returns the CountIndex where the key,value pair are stored + /// Finds or adds the slice. If the slice is added the defaultValueIndex is set. + /// If not the index associated with the slice remains the same. + /// Returns the CountIndex where the key,value pair are stored CountIndex findOrAdd(const UnownedStringSlice& key, Index defaultValueIndex); - /// Gets the index associated with the key. Returns -1 if there is no associated index. + /// Gets the index associated with the key. Returns -1 if there is no associated index. SLANG_FORCE_INLINE Index getValue(const UnownedStringSlice& key); - /// Get the amount of pairs in the map + /// Get the amount of pairs in the map Index getCount() const { return m_indexMap.getCount(); } - /// Get the slice and the index at the specified index + /// Get the slice and the index at the specified index SLANG_INLINE KeyValuePair<UnownedStringSlice, Index> getAt(CountIndex countIndex) const; - - /// Clear the contents of the map + + /// Clear the contents of the map void clear(); - /// Get the key at the specified index - UnownedStringSlice getKeyAt(CountIndex index) const { return m_pool.getSlice(StringSlicePool::Handle(index)); } - /// Get the value at the specified index + /// Get the key at the specified index + UnownedStringSlice getKeyAt(CountIndex index) const + { + return m_pool.getSlice(StringSlicePool::Handle(index)); + } + /// Get the value at the specified index Index& getValueAt(CountIndex index) { return m_indexMap[index]; } - /// Get the amount of key,value pairs + /// Get the amount of key,value pairs Index getCount() { return m_indexMap.getCount(); } - /// Ctor - StringSliceIndexMap() : - m_pool(StringSlicePool::Style::Empty) + /// Ctor + StringSliceIndexMap() + : m_pool(StringSlicePool::Style::Empty) { } protected: - StringSlicePool m_pool; ///< Pool holds the substrings - List<Index> m_indexMap; ///< Maps a pool index to the output index + StringSlicePool m_pool; ///< Pool holds the substrings + List<Index> m_indexMap; ///< Maps a pool index to the output index }; // --------------------------------------------------------------------------- @@ -73,6 +75,6 @@ KeyValuePair<UnownedStringSlice, Index> StringSliceIndexMap::getAt(CountIndex co return pair; } -} +} // namespace Slang #endif diff --git a/source/core/slang-string-slice-pool.cpp b/source/core/slang-string-slice-pool.cpp index 142952855..0c0ada09f 100644 --- a/source/core/slang-string-slice-pool.cpp +++ b/source/core/slang-string-slice-pool.cpp @@ -1,22 +1,21 @@ #include "slang-string-slice-pool.h" -namespace Slang { +namespace Slang +{ /* static */ const StringSlicePool::Handle StringSlicePool::kNullHandle; /* static */ const StringSlicePool::Handle StringSlicePool::kEmptyHandle; -/* static */const Index StringSlicePool::kDefaultHandlesCount; +/* static */ const Index StringSlicePool::kDefaultHandlesCount; -StringSlicePool::StringSlicePool(Style style) : - m_style(style), - m_arena(1024) +StringSlicePool::StringSlicePool(Style style) + : m_style(style), m_arena(1024) { clear(); } -StringSlicePool::StringSlicePool(const ThisType& rhs): - m_style(rhs.m_style), - m_arena(1024) +StringSlicePool::StringSlicePool(const ThisType& rhs) + : m_style(rhs.m_style), m_arena(1024) { // Set with rhs _set(rhs); @@ -42,7 +41,7 @@ void StringSlicePool::_set(const ThisType& rhs) if (count == 0) return; - + // We need the same amount of slices m_slices.setCount(count); @@ -117,19 +116,19 @@ void StringSlicePool::clear() switch (m_style) { - case Style::Default: + case Style::Default: { // Add the defaults m_slices.setCount(2); m_slices[0] = UnownedStringSlice((const char*)nullptr, (const char*)nullptr); m_slices[1] = UnownedStringSlice::fromLiteral(""); - + // Add the empty entry m_map.add(m_slices[1], kEmptyHandle); break; } - case Style::Empty: + case Style::Empty: { // There are no defaults m_slices.clear(); @@ -155,7 +154,9 @@ StringSlicePool::Handle StringSlicePool::add(const Slice& slice) } // Create a scoped copy - UnownedStringSlice scopePath(m_arena.allocateString(slice.begin(), slice.getLength()), slice.getLength()); + UnownedStringSlice scopePath( + m_arena.allocateString(slice.begin(), slice.getLength()), + slice.getLength()); const auto index = m_slices.getCount(); @@ -176,7 +177,9 @@ bool StringSlicePool::findOrAdd(const Slice& slice, Handle& outHandle) // Need to add. // Make a copy stored in the arena - UnownedStringSlice scopeSlice(m_arena.allocateString(slice.begin(), slice.getLength()), slice.getLength()); + UnownedStringSlice scopeSlice( + m_arena.allocateString(slice.begin(), slice.getLength()), + slice.getLength()); // Add using the arenas copy Handle newHandle = Handle(m_slices.getCount()); @@ -196,12 +199,12 @@ StringSlicePool::Handle StringSlicePool::add(StringRepresentation* stringRep) } return add(StringRepresentation::asSlice(stringRep)); } - + StringSlicePool::Handle StringSlicePool::add(const char* chars) { switch (m_style) { - case Style::Default: + case Style::Default: { if (!chars) { @@ -213,7 +216,7 @@ StringSlicePool::Handle StringSlicePool::add(const char* chars) } break; } - case Style::Empty: + case Style::Empty: { if (chars == nullptr) { @@ -223,7 +226,7 @@ StringSlicePool::Handle StringSlicePool::add(const char* chars) } } } - + return add(UnownedStringSlice(chars)); } diff --git a/source/core/slang-string-slice-pool.h b/source/core/slang-string-slice-pool.h index f50ac8dde..87ca18e16 100644 --- a/source/core/slang-string-slice-pool.h +++ b/source/core/slang-string-slice-pool.h @@ -1,14 +1,14 @@ #ifndef SLANG_CORE_STRING_SLICE_POOL_H #define SLANG_CORE_STRING_SLICE_POOL_H -#include "slang-string.h" - +#include "slang-array-view.h" +#include "slang-dictionary.h" #include "slang-list.h" #include "slang-memory-arena.h" -#include "slang-dictionary.h" -#include "slang-array-view.h" +#include "slang-string.h" -namespace Slang { +namespace Slang +{ /* Holds a unique set of slices. @@ -17,14 +17,14 @@ Note that all slices (except kNullHandle) are stored with terminating zeros. The default handles kNullHandle, kEmptyHandle can only be used on a StringSlicePool initialized with the Style::Default. Not doing so will return an undefined result. -TODO(JS): +TODO(JS): An argument could be made to make different classes, perhaps deriving from a base class that exhibited the two behaviors. That doing so would make the default handles defined for that class for example. This is a little awkward in practice, because behavior of some methods need to change (like adding a c string with nullptr, or clearing, as well as some other perhaps less necessary -optimizations). This could be achieved via virtual functions, but this all seems overkill. +optimizations). This could be achieved via virtual functions, but this all seems overkill. */ class StringSlicePool { @@ -34,57 +34,58 @@ public: enum class Style { - Default, ///< Default style - has default handles (like kNullHandle and kEmptyHandle) - Empty, ///< Empty style - has no handles by default. Using default handles will likely produce the wrong result. + Default, ///< Default style - has default handles (like kNullHandle and kEmptyHandle) + Empty, ///< Empty style - has no handles by default. Using default handles will likely + ///< produce the wrong result. }; enum class Handle : HandleIntegral; typedef UnownedStringSlice Slice; - /// The following default handles *only* apply if constructed with the Style::Default + /// The following default handles *only* apply if constructed with the Style::Default - /// Handle of 0 is null. If accessed will be returned as the empty string with nullptr the chars + /// Handle of 0 is null. If accessed will be returned as the empty string with nullptr the chars static const Handle kNullHandle = Handle(0); - /// Handle of 1 is the empty string. + /// Handle of 1 is the empty string. static const Handle kEmptyHandle = Handle(1); static const Index kDefaultHandlesCount = 2; - /// Returns the index of a slice, if contained, or -1 if not found + /// Returns the index of a slice, if contained, or -1 if not found Index findIndex(const Slice& slice) const; - /// True if has the slice + /// True if has the slice bool has(const Slice& slice) { return findIndex(slice) >= 0; } - /// Add a slice + /// Add a slice Handle add(const Slice& slice); - /// Add from a string + /// Add from a string Handle add(const char* chars); - /// Add a StringRepresentation + /// Add a StringRepresentation Handle add(StringRepresentation* string); - /// Add a string + /// Add a string Handle add(const String& string) { return add(string.getUnownedSlice()); } - /// Add and get the result as a slice + /// Add and get the result as a slice Slice addAndGetSlice(const Slice& slice) { return getSlice(add(slice)); } Slice addAndGetSlice(const char* chars) { return getSlice(add(chars)); } Slice addAndGetSlice(const String& string) { return getSlice(add(string)); } - /// Returns true if found + /// Returns true if found bool findOrAdd(const Slice& slice, Handle& outHandle); - /// Empty contents + /// Empty contents void clear(); - /// Get the slice from the handle + /// Get the slice from the handle const UnownedStringSlice& getSlice(Handle handle) const { return m_slices[UInt(handle)]; } - /// Get all the slices + /// Get all the slices const List<UnownedStringSlice>& getSlices() const { return m_slices; } - /// Get the number of slices + /// Get the number of slices Index getSlicesCount() const { return m_slices.getCount(); } - /// Returns true if the handle is a default one. Only meaningful on a Style::Default. + /// Returns true if the handle is a default one. Only meaningful on a Style::Default. bool isDefaultHandle(Handle handle) const { SLANG_ASSERT( @@ -94,30 +95,33 @@ public: return Index(handle) < kDefaultHandlesCount; } - /// Convert a handle to and index. (A handle is just an index!) + /// Convert a handle to and index. (A handle is just an index!) static Index asIndex(Handle handle) { return Index(handle); } - - /// Get the style of the pool + + /// Get the style of the pool Style getStyle() const { return m_style; } - /// Get all the added slices (does not have default slices, if there are any) - ConstArrayView<UnownedStringSlice> getAdded() const; + /// Get all the added slices (does not have default slices, if there are any) + ConstArrayView<UnownedStringSlice> getAdded() const; - /// Get the index of the first added handle - Index getFirstAddedIndex() const { return m_style == Style::Default ? kDefaultHandlesCount : 0; } + /// Get the index of the first added handle + Index getFirstAddedIndex() const + { + return m_style == Style::Default ? kDefaultHandlesCount : 0; + } - /// Swap this with rhs + /// Swap this with rhs void swapWith(ThisType& rhs); - /// True if the pools are identical. Same style, same slices in the same order. + /// True if the pools are identical. Same style, same slices in the same order. bool operator==(const ThisType& rhs) const; - /// Copy ctor + /// Copy ctor StringSlicePool(const ThisType& rhs); - /// Assignment + /// Assignment void operator=(const ThisType& rhs); - /// Ctor + /// Ctor explicit StringSlicePool(Style style); protected: diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp index 79f7307dc..1f67089a5 100644 --- a/source/core/slang-string-util.cpp +++ b/source/core/slang-string-util.cpp @@ -1,15 +1,18 @@ #include "slang-string-util.h" #include "slang-blob.h" - #include "slang-char-util.h" #include "slang-text-io.h" -namespace Slang { +namespace Slang +{ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! -/* static */bool StringUtil::areAllEqual(const List<UnownedStringSlice>& a, const List<UnownedStringSlice>& b, EqualFn equalFn) +/* static */ bool StringUtil::areAllEqual( + const List<UnownedStringSlice>& a, + const List<UnownedStringSlice>& b, + EqualFn equalFn) { if (a.getCount() != b.getCount()) { @@ -27,7 +30,11 @@ namespace Slang { return true; } -/* static */bool StringUtil::areAllEqualWithSplit(const UnownedStringSlice& a, const UnownedStringSlice& b, char splitChar, EqualFn equalFn) +/* static */ bool StringUtil::areAllEqualWithSplit( + const UnownedStringSlice& a, + const UnownedStringSlice& b, + char splitChar, + EqualFn equalFn) { List<UnownedStringSlice> slicesA, slicesB; StringUtil::split(a, splitChar, slicesA); @@ -35,14 +42,17 @@ namespace Slang { return areAllEqual(slicesA, slicesB, equalFn); } -/* static */void StringUtil::appendSplitOnWhitespace(const UnownedStringSlice& in, List<UnownedStringSlice>& outSlices) +/* static */ void StringUtil::appendSplitOnWhitespace( + const UnownedStringSlice& in, + List<UnownedStringSlice>& outSlices) { const char* start = in.begin(); const char* end = in.end(); // Skip any at the start - while (start < end && CharUtil::isWhitespace(*start)) start++; - + while (start < end && CharUtil::isWhitespace(*start)) + start++; + while (start < end) { // Find all the non white space in a run @@ -59,11 +69,15 @@ namespace Slang { start = cur + 1; // Skip the split - while (start < end && CharUtil::isWhitespace(*start)) start++; + while (start < end && CharUtil::isWhitespace(*start)) + start++; } } -/* static */void StringUtil::appendSplit(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& outSlices) +/* static */ void StringUtil::appendSplit( + const UnownedStringSlice& in, + char splitChar, + List<UnownedStringSlice>& outSlices) { const char* start = in.begin(); const char* end = in.end(); @@ -85,7 +99,10 @@ namespace Slang { } } -/* static */void StringUtil::appendSplit(const UnownedStringSlice& in, const UnownedStringSlice& splitSlice, List<UnownedStringSlice>& outSlices) +/* static */ void StringUtil::appendSplit( + const UnownedStringSlice& in, + const UnownedStringSlice& splitSlice, + List<UnownedStringSlice>& outSlices) { const Index splitLen = splitSlice.getLength(); @@ -129,25 +146,37 @@ namespace Slang { } } -/* static */void StringUtil::split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& outSlices) +/* static */ void StringUtil::split( + const UnownedStringSlice& in, + char splitChar, + List<UnownedStringSlice>& outSlices) { outSlices.clear(); appendSplit(in, splitChar, outSlices); } -/* static */void StringUtil::split(const UnownedStringSlice& in, const UnownedStringSlice& splitSlice, List<UnownedStringSlice>& outSlices) +/* static */ void StringUtil::split( + const UnownedStringSlice& in, + const UnownedStringSlice& splitSlice, + List<UnownedStringSlice>& outSlices) { outSlices.clear(); appendSplit(in, splitSlice, outSlices); } -/* static */void StringUtil::splitOnWhitespace(const UnownedStringSlice& in, List<UnownedStringSlice>& outSlices) +/* static */ void StringUtil::splitOnWhitespace( + const UnownedStringSlice& in, + List<UnownedStringSlice>& outSlices) { outSlices.clear(); appendSplitOnWhitespace(in, outSlices); } -/* static */Index StringUtil::split(const UnownedStringSlice& in, char splitChar, Index maxSlices, UnownedStringSlice* outSlices) +/* static */ Index StringUtil::split( + const UnownedStringSlice& in, + char splitChar, + Index maxSlices, + UnownedStringSlice* outSlices) { Index index = 0; @@ -173,7 +202,12 @@ namespace Slang { return index; } -/* static */SlangResult StringUtil::split(const UnownedStringSlice& in, char splitChar, Index maxSlices, UnownedStringSlice* outSlices, Index& outSlicesCount) +/* static */ SlangResult StringUtil::split( + const UnownedStringSlice& in, + char splitChar, + Index maxSlices, + UnownedStringSlice* outSlices, + Index& outSlicesCount) { const Index sliceCount = split(in, splitChar, maxSlices, outSlices); if (sliceCount == maxSlices && sliceCount > 0) @@ -188,12 +222,15 @@ namespace Slang { return SLANG_OK; } -/* static */void StringUtil::join(const List<String>& values, char separator, StringBuilder& out) +/* static */ void StringUtil::join(const List<String>& values, char separator, StringBuilder& out) { join(values, UnownedStringSlice(&separator, 1), out); } -/* static */void StringUtil::join(const List<String>& values, const UnownedStringSlice& separator, StringBuilder& out) +/* static */ void StringUtil::join( + const List<String>& values, + const UnownedStringSlice& separator, + StringBuilder& out) { const Index count = values.getCount(); if (count <= 0) @@ -208,12 +245,20 @@ namespace Slang { } } -/* static */void StringUtil::join(const UnownedStringSlice* values, Index valueCount, char separator, StringBuilder& out) +/* static */ void StringUtil::join( + const UnownedStringSlice* values, + Index valueCount, + char separator, + StringBuilder& out) { join(values, valueCount, UnownedStringSlice(&separator, 1), out); } -/* static */void StringUtil::join(const UnownedStringSlice* values, Index valueCount, const UnownedStringSlice& separator, StringBuilder& out) +/* static */ void StringUtil::join( + const UnownedStringSlice* values, + Index valueCount, + const UnownedStringSlice& separator, + StringBuilder& out) { if (valueCount <= 0) { @@ -227,7 +272,10 @@ namespace Slang { } } -/* static */Index StringUtil::indexOfInSplit(const UnownedStringSlice& in, char splitChar, const UnownedStringSlice& find) +/* static */ Index StringUtil::indexOfInSplit( + const UnownedStringSlice& in, + char splitChar, + const UnownedStringSlice& find) { const char* start = in.begin(); const char* end = in.end(); @@ -253,7 +301,10 @@ namespace Slang { return -1; } -UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char splitChar, Index index) +UnownedStringSlice StringUtil::getAtInSplit( + const UnownedStringSlice& in, + char splitChar, + Index index) { const char* start = in.begin(); const char* end = in.end(); @@ -279,16 +330,20 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s return UnownedStringSlice(); } -/* static */size_t StringUtil::calcFormattedSize(const char* format, va_list args) +/* static */ size_t StringUtil::calcFormattedSize(const char* format, va_list args) { #if SLANG_WINDOWS_FAMILY return _vscprintf(format, args); #else - return vsnprintf(nullptr, 0, format, args); + return vsnprintf(nullptr, 0, format, args); #endif } -/* static */void StringUtil::calcFormatted(const char* format, va_list args, size_t numChars, char* dst) +/* static */ void StringUtil::calcFormatted( + const char* format, + va_list args, + size_t numChars, + char* dst) { #if SLANG_WINDOWS_FAMILY vsnprintf_s(dst, numChars + 1, _TRUNCATE, format, args); @@ -297,7 +352,7 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s #endif } -/* static */void StringUtil::append(const char* format, va_list args, StringBuilder& buf) +/* static */ void StringUtil::append(const char* format, va_list args, StringBuilder& buf) { // Calculate the size required (not including terminating 0) size_t numChars; @@ -315,7 +370,7 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s buf.appendInPlace(dst, numChars); } -/* static */void StringUtil::appendFormat(StringBuilder& buf, const char* format, ...) +/* static */ void StringUtil::appendFormat(StringBuilder& buf, const char* format, ...) { va_list args; va_start(args, format); @@ -323,7 +378,7 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s va_end(args); } -/* static */String StringUtil::makeStringWithFormat(const char* format, ...) +/* static */ String StringUtil::makeStringWithFormat(const char* format, ...) { StringBuilder builder; @@ -335,7 +390,7 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s return builder; } -/* static */UnownedStringSlice StringUtil::getSlice(ISlangBlob* blob) +/* static */ UnownedStringSlice StringUtil::getSlice(ISlangBlob* blob) { if (blob) { @@ -343,7 +398,8 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s if (size > 0) { const char* contents = (const char*)blob->getBufferPointer(); - // Check it has terminating 0, if it has we skip it, because slices do not need zero termination + // Check it has terminating 0, if it has we skip it, because slices do not need zero + // termination if (contents[size - 1] == 0) { size--; @@ -354,7 +410,7 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s return UnownedStringSlice(); } -/* static */String StringUtil::getString(ISlangBlob* blob) +/* static */ String StringUtil::getString(ISlangBlob* blob) { return getSlice(blob); } @@ -364,7 +420,10 @@ ComPtr<ISlangBlob> StringUtil::createStringBlob(const String& string) return StringBlob::create(string); } -/* static */String StringUtil::calcCharReplaced(const UnownedStringSlice& slice, char fromChar, char toChar) +/* static */ String StringUtil::calcCharReplaced( + const UnownedStringSlice& slice, + char fromChar, + char toChar) { if (fromChar == toChar) { @@ -387,12 +446,17 @@ ComPtr<ISlangBlob> StringUtil::createStringBlob(const String& string) return builder; } -/* static */String StringUtil::calcCharReplaced(const String& string, char fromChar, char toChar) +/* static */ String StringUtil::calcCharReplaced(const String& string, char fromChar, char toChar) { - return (fromChar == toChar || string.indexOf(fromChar) == Index(-1)) ? string : calcCharReplaced(string.getUnownedSlice(), fromChar, toChar); + return (fromChar == toChar || string.indexOf(fromChar) == Index(-1)) + ? string + : calcCharReplaced(string.getUnownedSlice(), fromChar, toChar); } -String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr, UnownedStringSlice replacement) +String StringUtil::replaceAll( + UnownedStringSlice text, + UnownedStringSlice subStr, + UnownedStringSlice replacement) { StringBuilder builder; for (Index i = 0; i < text.getLength();) @@ -417,7 +481,9 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr } -/* static */void StringUtil::appendStandardLines(const UnownedStringSlice& text, StringBuilder& out) +/* static */ void StringUtil::appendStandardLines( + const UnownedStringSlice& text, + StringBuilder& out) { const char* cur = text.begin(); const char* start = cur; @@ -428,25 +494,25 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr const char c = *cur; switch (c) { - case '\n': + case '\n': { ++cur; if (cur < end && *cur == '\r') { // If we have following \r, we should append with \n - // Append (including \n) + // Append (including \n) out.append(start, cur); // Skip the \r start = ++cur; } else { - // If not, we don't need to append because just \n is 'standard', and everything remaining - // is appended at the end + // If not, we don't need to append because just \n is 'standard', and everything + // remaining is appended at the end } break; } - case '\r': + case '\r': { out.append(start, cur); out.appendChar('\n'); @@ -457,7 +523,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr start = cur; break; } - default: + default: { cur++; break; @@ -471,10 +537,10 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr } } -/* static */bool StringUtil::extractLine(UnownedStringSlice& ioText, UnownedStringSlice& outLine) +/* static */ bool StringUtil::extractLine(UnownedStringSlice& ioText, UnownedStringSlice& outLine) { - char const*const begin = ioText.begin(); - char const*const end = ioText.end(); + char const* const begin = ioText.begin(); + char const* const end = ioText.end(); // If we have hit the end then return the 'special' terminator if (begin == nullptr) @@ -489,10 +555,11 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr int c = *cursor++; switch (c) { - case '\r': case '\n': + case '\r': + case '\n': { // Remember the end of the line - const char*const lineEnd = cursor - 1; + const char* const lineEnd = cursor - 1; // When we see a line-break character we need // to record the line break, but we also need @@ -510,8 +577,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr outLine = UnownedStringSlice(begin, lineEnd); return true; } - default: - break; + default: break; } } @@ -525,7 +591,9 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr return true; } -/* static */void StringUtil::calcLines(const UnownedStringSlice& textIn, List<UnownedStringSlice>& outLines) +/* static */ void StringUtil::calcLines( + const UnownedStringSlice& textIn, + List<UnownedStringSlice>& outLines) { outLines.clear(); UnownedStringSlice text(textIn), line; @@ -535,7 +603,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr } } -/* static */UnownedStringSlice StringUtil::trimEndOfLine(const UnownedStringSlice& line) +/* static */ UnownedStringSlice StringUtil::trimEndOfLine(const UnownedStringSlice& line) { // Strip CR/LF from end of line if present @@ -557,10 +625,12 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr return line.head(Index(end - begin)); } -/* static */bool StringUtil::areLinesEqual(const UnownedStringSlice& inA, const UnownedStringSlice& inB) +/* static */ bool StringUtil::areLinesEqual( + const UnownedStringSlice& inA, + const UnownedStringSlice& inB) { UnownedStringSlice a(inA), b(inB), lineA, lineB; - + while (true) { const auto hasLineA = extractLine(a, lineA); @@ -579,7 +649,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr } } -/* static */SlangResult StringUtil::parseDouble(const UnownedStringSlice& text, double& out) +/* static */ SlangResult StringUtil::parseDouble(const UnownedStringSlice& text, double& out) { const Index bufSize = 32; @@ -606,7 +676,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr return SLANG_OK; } -/* static */SlangResult StringUtil::parseInt(const UnownedStringSlice& in, Int& outValue) +/* static */ SlangResult StringUtil::parseInt(const UnownedStringSlice& in, Int& outValue) { const char* cur = in.begin(); const char* end = in.end(); @@ -620,7 +690,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr int radix = 10; auto getDigit = CharUtil::getDecimalDigitValue; - if (cur+1 < end && *cur == '0' && (*(cur+1) == 'x' || *(cur+1) == 'X')) + if (cur + 1 < end && *cur == '0' && (*(cur + 1) == 'x' || *(cur + 1) == 'X')) { radix = 16; getDigit = CharUtil::getHexDigitValue; @@ -632,7 +702,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr { return SLANG_FAIL; } - + Int value = 0; // Do the digits for (; cur < end; ++cur) @@ -649,7 +719,7 @@ String StringUtil::replaceAll(UnownedStringSlice text, UnownedStringSlice subStr return SLANG_OK; } -/* static */SlangResult StringUtil::parseInt64(const UnownedStringSlice& text, int64_t& out) +/* static */ SlangResult StringUtil::parseInt64(const UnownedStringSlice& text, int64_t& out) { bool negate = false; diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h index c0a8f6973..9e7b2d65a 100644 --- a/source/core/slang-string-util.h +++ b/source/core/slang-string-util.h @@ -1,137 +1,202 @@ #ifndef SLANG_CORE_STRING_UTIL_H #define SLANG_CORE_STRING_UTIL_H -#include "slang-string.h" +#include "slang-com-helper.h" +#include "slang-com-ptr.h" #include "slang-list.h" +#include "slang-string.h" #include <stdarg.h> -#include "slang-com-helper.h" -#include "slang-com-ptr.h" - -namespace Slang { +namespace Slang +{ struct StringUtil { typedef bool (*EqualFn)(const UnownedStringSlice& a, const UnownedStringSlice& b); - /// True if the splits of a and b (via splitChar) are all equal as compared with the equalFn function - static bool areAllEqualWithSplit(const UnownedStringSlice& a, const UnownedStringSlice& b, char splitChar, EqualFn equalFn); - - /// True if all slices in match are all equal as compared with the equalFn function - static bool areAllEqual(const List<UnownedStringSlice>& a, const List<UnownedStringSlice>& b, EqualFn equalFn); - - /// Split in, by specified splitChar into slices out - /// Slices contents will directly address into in, so contents will only stay valid as long as in does. - static void split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut); - /// Split in by the specified splitSlice - /// Slices contents will directly address into in, so contents will only stay valid as long as in does. - static void split(const UnownedStringSlice& in, const UnownedStringSlice& splitSlice, List<UnownedStringSlice>& slicesOut); - - /// Splits in into outSlices, up to maxSlices. May not consume all of in (for example if it runs out of space). - static Index split(const UnownedStringSlice& in, char splitChar, Index maxSlices, UnownedStringSlice* outSlices); - /// Splits into outSlices up to maxSlices. Returns SLANG_OK if of 'in' consumed. - static SlangResult split(const UnownedStringSlice& in, char splitChar, Index maxSlices, UnownedStringSlice* outSlices, Index& outSlicesCount); - /// Splits on white space - static void splitOnWhitespace(const UnownedStringSlice& in, List<UnownedStringSlice>& slicesOut); - - /// Split in, by specified splitChar append into slices out - /// Slices contents will directly address into in, so contents will only stay valid as long as in does. - static void appendSplit(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut); - /// Split in by the specified splitSlice - /// Slices contents will directly address into in, so contents will only stay valid as long as in does. - static void appendSplit(const UnownedStringSlice& in, const UnownedStringSlice& splitSlice, List<UnownedStringSlice>& slicesOut); - - /// appends splits on white space - static void appendSplitOnWhitespace(const UnownedStringSlice& in, List<UnownedStringSlice>& slicesOut); - - /// Append the joining of in items, separated by 'separator' onto out + /// True if the splits of a and b (via splitChar) are all equal as compared with the equalFn + /// function + static bool areAllEqualWithSplit( + const UnownedStringSlice& a, + const UnownedStringSlice& b, + char splitChar, + EqualFn equalFn); + + /// True if all slices in match are all equal as compared with the equalFn function + static bool areAllEqual( + const List<UnownedStringSlice>& a, + const List<UnownedStringSlice>& b, + EqualFn equalFn); + + /// Split in, by specified splitChar into slices out + /// Slices contents will directly address into in, so contents will only stay valid as long as + /// in does. + static void split( + const UnownedStringSlice& in, + char splitChar, + List<UnownedStringSlice>& slicesOut); + /// Split in by the specified splitSlice + /// Slices contents will directly address into in, so contents will only stay valid as long as + /// in does. + static void split( + const UnownedStringSlice& in, + const UnownedStringSlice& splitSlice, + List<UnownedStringSlice>& slicesOut); + + /// Splits in into outSlices, up to maxSlices. May not consume all of in (for example if it runs + /// out of space). + static Index split( + const UnownedStringSlice& in, + char splitChar, + Index maxSlices, + UnownedStringSlice* outSlices); + /// Splits into outSlices up to maxSlices. Returns SLANG_OK if of 'in' consumed. + static SlangResult split( + const UnownedStringSlice& in, + char splitChar, + Index maxSlices, + UnownedStringSlice* outSlices, + Index& outSlicesCount); + /// Splits on white space + static void splitOnWhitespace( + const UnownedStringSlice& in, + List<UnownedStringSlice>& slicesOut); + + /// Split in, by specified splitChar append into slices out + /// Slices contents will directly address into in, so contents will only stay valid as long as + /// in does. + static void appendSplit( + const UnownedStringSlice& in, + char splitChar, + List<UnownedStringSlice>& slicesOut); + /// Split in by the specified splitSlice + /// Slices contents will directly address into in, so contents will only stay valid as long as + /// in does. + static void appendSplit( + const UnownedStringSlice& in, + const UnownedStringSlice& splitSlice, + List<UnownedStringSlice>& slicesOut); + + /// appends splits on white space + static void appendSplitOnWhitespace( + const UnownedStringSlice& in, + List<UnownedStringSlice>& slicesOut); + + /// Append the joining of in items, separated by 'separator' onto out static void join(const List<String>& in, char separator, StringBuilder& out); - static void join(const List<String>& in, const UnownedStringSlice& separator, StringBuilder& out); - - static void join(const UnownedStringSlice* values, Index valueCount, char separator, StringBuilder& out); - static void join(const UnownedStringSlice* values, Index valueCount, const UnownedStringSlice& separator, StringBuilder& out); - - /// Equivalent to doing a split and then finding the index of 'find' on the array - /// Returns -1 if not found - static Index indexOfInSplit(const UnownedStringSlice& in, char splitChar, const UnownedStringSlice& find); - - /// Given the entry at the split index specified. - /// Will return slice with begin() == nullptr if not found or input has begin() == nullptr) - static UnownedStringSlice getAtInSplit(const UnownedStringSlice& in, char splitChar, Index index); - - /// Returns the size in bytes needed to hold the formatted string using the specified args, NOT including a terminating 0 - /// NOTE! The caller *should* assume this will consume the va_list (use va_copy to make a copy to be consumed) + static void join( + const List<String>& in, + const UnownedStringSlice& separator, + StringBuilder& out); + + static void join( + const UnownedStringSlice* values, + Index valueCount, + char separator, + StringBuilder& out); + static void join( + const UnownedStringSlice* values, + Index valueCount, + const UnownedStringSlice& separator, + StringBuilder& out); + + /// Equivalent to doing a split and then finding the index of 'find' on the array + /// Returns -1 if not found + static Index indexOfInSplit( + const UnownedStringSlice& in, + char splitChar, + const UnownedStringSlice& find); + + /// Given the entry at the split index specified. + /// Will return slice with begin() == nullptr if not found or input has begin() == nullptr) + static UnownedStringSlice getAtInSplit( + const UnownedStringSlice& in, + char splitChar, + Index index); + + /// Returns the size in bytes needed to hold the formatted string using the specified args, NOT + /// including a terminating 0 NOTE! The caller *should* assume this will consume the va_list + /// (use va_copy to make a copy to be consumed) static size_t calcFormattedSize(const char* format, va_list args); - /// Calculate the formatted string using the specified args. - /// NOTE! The caller *should* assume this will consume the va_list - /// The buffer should be at least calcFormattedSize + 1 bytes. The +1 is needed because a terminating 0 is written. + /// Calculate the formatted string using the specified args. + /// NOTE! The caller *should* assume this will consume the va_list + /// The buffer should be at least calcFormattedSize + 1 bytes. The +1 is needed because a + /// terminating 0 is written. static void calcFormatted(const char* format, va_list args, size_t numChars, char* dst); - /// Appends formatted string with args into buf + /// Appends formatted string with args into buf static void append(const char* format, va_list args, StringBuilder& buf); - /// Appends the formatted string with specified trailing args + /// Appends the formatted string with specified trailing args static void appendFormat(StringBuilder& buf, const char* format, ...); - /// Create a string from the format string applying args (like sprintf) + /// Create a string from the format string applying args (like sprintf) static String makeStringWithFormat(const char* format, ...); - /// Given a string held in a blob, returns as a String - /// Returns an empty string if blob is nullptr + /// Given a string held in a blob, returns as a String + /// Returns an empty string if blob is nullptr static String getString(ISlangBlob* blob); static UnownedStringSlice getSlice(ISlangBlob* blob); - /// Given a string or slice, replaces all instances of fromChar with toChar + /// Given a string or slice, replaces all instances of fromChar with toChar static String calcCharReplaced(const UnownedStringSlice& slice, char fromChar, char toChar); static String calcCharReplaced(const String& string, char fromChar, char toChar); - - /// Replaces all occurrances of subStr with replacement. - static String replaceAll(UnownedStringSlice text, UnownedStringSlice subStr, UnownedStringSlice replacement); - /// Create a blob from a string + /// Replaces all occurrances of subStr with replacement. + static String replaceAll( + UnownedStringSlice text, + UnownedStringSlice subStr, + UnownedStringSlice replacement); + + /// Create a blob from a string static ComPtr<ISlangBlob> createStringBlob(const String& string); - /// Given input text outputs with standardized line endings. Ie \n\r -> \n + /// Given input text outputs with standardized line endings. Ie \n\r -> \n static void appendStandardLines(const UnownedStringSlice& text, StringBuilder& out); - /// Extracts a line and stores the remaining text in ioText, and the line in outLine. Returns true if has a line. - /// - /// As well as indicating end of text with the return value, at the end of all the text a 'special' null UnownedStringSlice with a null 'begin' - /// pointer is also returned as the outLine. - /// ioText will be modified to contain the remaining text, starting at the beginning of the next line. - /// As an empty final line is still a line, the special null UnownedStringSlice is the last value ioText after the last valid line is returned. - /// - /// NOTE! That behavior is as if line terminators (like \n) act as separators. Thus input of "\n" will return *two* lines - an empty line - /// before and then after the \n. + /// Extracts a line and stores the remaining text in ioText, and the line in outLine. Returns + /// true if has a line. + /// + /// As well as indicating end of text with the return value, at the end of all the text a + /// 'special' null UnownedStringSlice with a null 'begin' pointer is also returned as the + /// outLine. ioText will be modified to contain the remaining text, starting at the beginning of + /// the next line. As an empty final line is still a line, the special null UnownedStringSlice + /// is the last value ioText after the last valid line is returned. + /// + /// NOTE! That behavior is as if line terminators (like \n) act as separators. Thus input of + /// "\n" will return *two* lines - an empty line before and then after the \n. static bool extractLine(UnownedStringSlice& ioText, UnownedStringSlice& outLine); - - /// Given text, splits into lines stored in outLines. NOTE! That lines is only valid as long as textIn remains valid + + /// Given text, splits into lines stored in outLines. NOTE! That lines is only valid as long as + /// textIn remains valid static void calcLines(const UnownedStringSlice& textIn, List<UnownedStringSlice>& lines); - /// Given a line that may contain cr/lf, returns the the a slice that doesn't have trailing cr/lf + /// Given a line that may contain cr/lf, returns the the a slice that doesn't have trailing + /// cr/lf static UnownedStringSlice trimEndOfLine(const UnownedStringSlice& slice); - /// Equal if the lines are equal (in effect a way to ignore differences in line breaks) + /// Equal if the lines are equal (in effect a way to ignore differences in line breaks) static bool areLinesEqual(const UnownedStringSlice& a, const UnownedStringSlice& b); - /// Convert in to int. Returns SLANG_FAIL on error + /// Convert in to int. Returns SLANG_FAIL on error static SlangResult parseInt(const UnownedStringSlice& in, Int& outValue); - /// Convert ioText into double. Returns SLANG_OK on success. + /// Convert ioText into double. Returns SLANG_OK on success. static SlangResult parseDouble(const UnownedStringSlice& text, double& out); - /// Convert into int64_t. Returns SLANG_OK on success. + /// Convert into int64_t. Returns SLANG_OK on success. static SlangResult parseInt64(const UnownedStringSlice& text, int64_t& out); - /// Parse an integer from text starting at pos until the end or the first non-digit char. - /// Modifies pos to the position where parsing ends. - /// Returns parsed integer. + /// Parse an integer from text starting at pos until the end or the first non-digit char. + /// Modifies pos to the position where parsing ends. + /// Returns parsed integer. static int parseIntAndAdvancePos(UnownedStringSlice text, Index& pos); }; -/* A helper class that allows parsing of lines from text with iteration. Uses StringUtil::extractLine for the actual underlying implementation. */ +/* A helper class that allows parsing of lines from text with iteration. Uses + * StringUtil::extractLine for the actual underlying implementation. */ class LineParser { public: @@ -144,25 +209,46 @@ public: StringUtil::extractLine(m_remaining, m_line); return *this; } - Iterator operator++(int) { Iterator rs = *this; operator++(); return rs; } + Iterator operator++(int) + { + Iterator rs = *this; + operator++(); + return rs; + } - /// Equal if both are at the same m_line address exactly. Handles termination case correctly where line.begin() == nullptr. - bool operator==(const Iterator& rhs) const { return m_line.begin() == rhs.m_line.begin(); } - bool operator !=(const Iterator& rhs) const { return !(*this == rhs); } + /// Equal if both are at the same m_line address exactly. Handles termination case correctly + /// where line.begin() == nullptr. + bool operator==(const Iterator& rhs) const { return m_line.begin() == rhs.m_line.begin(); } + bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } - /// Ctor - Iterator(const UnownedStringSlice& line, const UnownedStringSlice& remaining) : m_line(line), m_remaining(remaining) {} + /// Ctor + Iterator(const UnownedStringSlice& line, const UnownedStringSlice& remaining) + : m_line(line), m_remaining(remaining) + { + } protected: UnownedStringSlice m_line; UnownedStringSlice m_remaining; }; - Iterator begin() const { UnownedStringSlice remaining(m_text), line; StringUtil::extractLine(remaining, line); return Iterator(line, remaining); } - Iterator end() const { UnownedStringSlice term(nullptr, nullptr); return Iterator(term, term); } + Iterator begin() const + { + UnownedStringSlice remaining(m_text), line; + StringUtil::extractLine(remaining, line); + return Iterator(line, remaining); + } + Iterator end() const + { + UnownedStringSlice term(nullptr, nullptr); + return Iterator(term, term); + } - /// Ctor - LineParser(const UnownedStringSlice& text) : m_text(text) {} + /// Ctor + LineParser(const UnownedStringSlice& text) + : m_text(text) + { + } protected: UnownedStringSlice m_text; diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index 182c6261e..b58d466fa 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -1,288 +1,292 @@ #include "slang-string.h" -#include "slang-text-io.h" #include "slang-char-util.h" +#include "slang-text-io.h" namespace Slang { - // HACK! - // JS: Many of the inlined functions of CharUtil just access a global map. That referencing this global is *NOT* enough to - // link correctly with CharUtil on linux for a shared library. The following call exists to try and force linkage of CharUtil - // for anything that uses core - static const auto s_charUtilLink = CharUtil::_ensureLink(); +// HACK! +// JS: Many of the inlined functions of CharUtil just access a global map. That referencing this +// global is *NOT* enough to link correctly with CharUtil on linux for a shared library. The +// following call exists to try and force linkage of CharUtil for anything that uses core +static const auto s_charUtilLink = CharUtil::_ensureLink(); - // StringRepresentation +// StringRepresentation - void StringRepresentation::setContents(const UnownedStringSlice& slice) - { - const auto sliceLength = slice.getLength(); - SLANG_ASSERT(sliceLength <= capacity); +void StringRepresentation::setContents(const UnownedStringSlice& slice) +{ + const auto sliceLength = slice.getLength(); + SLANG_ASSERT(sliceLength <= capacity); - char* chars = getData(); + char* chars = getData(); - // Use move (rather than memcpy), because the slice *could* be contained in the StringRepresentation - ::memmove(chars, slice.begin(), sliceLength * sizeof(char)); - // Zero terminate. - chars[sliceLength] = 0; - // Set the length - length = sliceLength; - } + // Use move (rather than memcpy), because the slice *could* be contained in the + // StringRepresentation + ::memmove(chars, slice.begin(), sliceLength * sizeof(char)); + // Zero terminate. + chars[sliceLength] = 0; + // Set the length + length = sliceLength; +} - /* static */StringRepresentation* StringRepresentation::create(const UnownedStringSlice& slice) +/* static */ StringRepresentation* StringRepresentation::create(const UnownedStringSlice& slice) +{ + const auto sliceLength = slice.getLength(); + + if (sliceLength) { - const auto sliceLength = slice.getLength(); + StringRepresentation* rep = StringRepresentation::createWithLength(sliceLength); - if (sliceLength) - { - StringRepresentation* rep = StringRepresentation::createWithLength(sliceLength); - - char* chars = rep->getData(); - ::memcpy(chars, slice.begin(), sizeof(char) * sliceLength); - chars[sliceLength] = 0; + char* chars = rep->getData(); + ::memcpy(chars, slice.begin(), sizeof(char) * sliceLength); + chars[sliceLength] = 0; - return rep; - } - else - { - return nullptr; - } + return rep; } - - /* static */StringRepresentation* StringRepresentation::createWithReference(const UnownedStringSlice& slice) + else { - const auto sliceLength = slice.getLength(); + return nullptr; + } +} - if (sliceLength) - { - StringRepresentation* rep = StringRepresentation::createWithLength(sliceLength); - rep->addReference(); +/* static */ StringRepresentation* StringRepresentation::createWithReference( + const UnownedStringSlice& slice) +{ + const auto sliceLength = slice.getLength(); - char* chars = rep->getData(); - ::memcpy(chars, slice.begin(), sizeof(char) * sliceLength); - chars[sliceLength] = 0; + if (sliceLength) + { + StringRepresentation* rep = StringRepresentation::createWithLength(sliceLength); + rep->addReference(); - return rep; - } - else - { - return nullptr; - } + char* chars = rep->getData(); + ::memcpy(chars, slice.begin(), sizeof(char) * sliceLength); + chars[sliceLength] = 0; + + return rep; } + else + { + return nullptr; + } +} - // OSString +// OSString - OSString::OSString() - : m_begin(nullptr) - , m_end(nullptr) - {} +OSString::OSString() + : m_begin(nullptr), m_end(nullptr) +{ +} - OSString::OSString(wchar_t* begin, wchar_t* end) - : m_begin(begin) - , m_end(end) - {} +OSString::OSString(wchar_t* begin, wchar_t* end) + : m_begin(begin), m_end(end) +{ +} - void OSString::_releaseBuffer() +void OSString::_releaseBuffer() +{ + if (m_begin) { - if (m_begin) - { - delete[] m_begin; - } + delete[] m_begin; } +} - void OSString::set(const wchar_t* begin, const wchar_t* end) +void OSString::set(const wchar_t* begin, const wchar_t* end) +{ + if (m_begin) { - if (m_begin) - { - delete[] m_begin; - m_begin = nullptr; - m_end = nullptr; - } - const size_t len = end - begin; - if (len > 0) - { - // TODO(JS): The allocation is only done this way to be compatible with the buffer being detached from an array - // This is unfortunate, because it means that the allocation stores the size (and alignment fix), which is a shame because we know the size - m_begin = new wchar_t[len + 1]; - memcpy(m_begin, begin, len * sizeof(wchar_t)); - // Zero terminate - m_begin[len] = 0; - m_end = m_begin + len; - } + delete[] m_begin; + m_begin = nullptr; + m_end = nullptr; } - - static const wchar_t kEmptyOSString[] = { 0 }; - - wchar_t const* OSString::begin() const + const size_t len = end - begin; + if (len > 0) { - return m_begin ? m_begin : kEmptyOSString; + // TODO(JS): The allocation is only done this way to be compatible with the buffer being + // detached from an array This is unfortunate, because it means that the allocation stores + // the size (and alignment fix), which is a shame because we know the size + m_begin = new wchar_t[len + 1]; + memcpy(m_begin, begin, len * sizeof(wchar_t)); + // Zero terminate + m_begin[len] = 0; + m_end = m_begin + len; } +} - wchar_t const* OSString::end() const - { - return m_end ? m_end : kEmptyOSString; - } +static const wchar_t kEmptyOSString[] = {0}; - // UnownedStringSlice +wchar_t const* OSString::begin() const +{ + return m_begin ? m_begin : kEmptyOSString; +} - bool UnownedStringSlice::startsWith(UnownedStringSlice const& other) const - { - UInt thisSize = getLength(); - UInt otherSize = other.getLength(); +wchar_t const* OSString::end() const +{ + return m_end ? m_end : kEmptyOSString; +} - if (otherSize > thisSize) - return false; +// UnownedStringSlice - return head(otherSize) == other; - } +bool UnownedStringSlice::startsWith(UnownedStringSlice const& other) const +{ + UInt thisSize = getLength(); + UInt otherSize = other.getLength(); - bool UnownedStringSlice::startsWith(char const* str) const - { - return startsWith(UnownedTerminatedStringSlice(str)); - } + if (otherSize > thisSize) + return false; - bool UnownedStringSlice::startsWithCaseInsensitive(UnownedStringSlice const& other) const - { - UInt thisSize = getLength(); - UInt otherSize = other.getLength(); + return head(otherSize) == other; +} - if (otherSize > thisSize) - return false; +bool UnownedStringSlice::startsWith(char const* str) const +{ + return startsWith(UnownedTerminatedStringSlice(str)); +} - return head(otherSize).caseInsensitiveEquals(other); - } +bool UnownedStringSlice::startsWithCaseInsensitive(UnownedStringSlice const& other) const +{ + UInt thisSize = getLength(); + UInt otherSize = other.getLength(); + if (otherSize > thisSize) + return false; - bool UnownedStringSlice::endsWith(UnownedStringSlice const& other) const - { - UInt thisSize = getLength(); - UInt otherSize = other.getLength(); + return head(otherSize).caseInsensitiveEquals(other); +} - if (otherSize > thisSize) - return false; - return UnownedStringSlice( - end() - otherSize, end()) == other; - } +bool UnownedStringSlice::endsWith(UnownedStringSlice const& other) const +{ + UInt thisSize = getLength(); + UInt otherSize = other.getLength(); - bool UnownedStringSlice::endsWithCaseInsensitive(UnownedStringSlice const& other) const - { - UInt thisSize = getLength(); - UInt otherSize = other.getLength(); + if (otherSize > thisSize) + return false; - if (otherSize > thisSize) - return false; + return UnownedStringSlice(end() - otherSize, end()) == other; +} - return UnownedStringSlice(end() - otherSize, end()).caseInsensitiveEquals(other); - } +bool UnownedStringSlice::endsWithCaseInsensitive(UnownedStringSlice const& other) const +{ + UInt thisSize = getLength(); + UInt otherSize = other.getLength(); - bool UnownedStringSlice::endsWith(char const* str) const - { - return endsWith(UnownedTerminatedStringSlice(str)); - } + if (otherSize > thisSize) + return false; - bool UnownedStringSlice::endsWithCaseInsensitive(char const* str) const - { - return endsWithCaseInsensitive(UnownedTerminatedStringSlice(str)); - } + return UnownedStringSlice(end() - otherSize, end()).caseInsensitiveEquals(other); +} - UnownedStringSlice UnownedStringSlice::trim() const - { - const char* start = m_begin; - const char* end = m_end; +bool UnownedStringSlice::endsWith(char const* str) const +{ + return endsWith(UnownedTerminatedStringSlice(str)); +} - while (start < end && CharUtil::isHorizontalWhitespace(*start)) start++; - while (end > start && CharUtil::isHorizontalWhitespace(end[-1])) end--; - return UnownedStringSlice(start, end); - } +bool UnownedStringSlice::endsWithCaseInsensitive(char const* str) const +{ + return endsWithCaseInsensitive(UnownedTerminatedStringSlice(str)); +} - UnownedStringSlice UnownedStringSlice::trimStart() const - { - const char* start = m_begin; +UnownedStringSlice UnownedStringSlice::trim() const +{ + const char* start = m_begin; + const char* end = m_end; + + while (start < end && CharUtil::isHorizontalWhitespace(*start)) + start++; + while (end > start && CharUtil::isHorizontalWhitespace(end[-1])) + end--; + return UnownedStringSlice(start, end); +} - while (start < m_end && CharUtil::isHorizontalWhitespace(*start)) start++; - return UnownedStringSlice(start, m_end); - } +UnownedStringSlice UnownedStringSlice::trimStart() const +{ + const char* start = m_begin; - UnownedStringSlice UnownedStringSlice::trim(char c) const - { - const char* start = m_begin; - const char* end = m_end; + while (start < m_end && CharUtil::isHorizontalWhitespace(*start)) + start++; + return UnownedStringSlice(start, m_end); +} - while (start < end && *start == c) start++; - while (end > start && end[-1] == c) end--; - return UnownedStringSlice(start, end); - } +UnownedStringSlice UnownedStringSlice::trim(char c) const +{ + const char* start = m_begin; + const char* end = m_end; + + while (start < end && *start == c) + start++; + while (end > start && end[-1] == c) + end--; + return UnownedStringSlice(start, end); +} - // StringSlice +// StringSlice - StringSlice::StringSlice() - : representation(0) - , beginIndex(0) - , endIndex(0) - {} +StringSlice::StringSlice() + : representation(0), beginIndex(0), endIndex(0) +{ +} - StringSlice::StringSlice(String const& str) - : representation(str.m_buffer) - , beginIndex(0) - , endIndex(str.getLength()) - {} +StringSlice::StringSlice(String const& str) + : representation(str.m_buffer), beginIndex(0), endIndex(str.getLength()) +{ +} - StringSlice::StringSlice(String const& str, UInt beginIndex, UInt endIndex) - : representation(str.m_buffer) - , beginIndex(beginIndex) - , endIndex(endIndex) - {} +StringSlice::StringSlice(String const& str, UInt beginIndex, UInt endIndex) + : representation(str.m_buffer), beginIndex(beginIndex), endIndex(endIndex) +{ +} - // +// - _EndLine EndLine; +_EndLine EndLine; - String operator+(const char * op1, const String & op2) - { - String result(op1); - result.append(op2); - return result; - } +String operator+(const char* op1, const String& op2) +{ + String result(op1); + result.append(op2); + return result; +} - String operator+(const String & op1, const char * op2) - { - String result(op1); - result.append(op2); - return result; - } +String operator+(const String& op1, const char* op2) +{ + String result(op1); + result.append(op2); + return result; +} - String operator+(const String & op1, const String & op2) - { - String result(op1); - result.append(op2); - return result; - } +String operator+(const String& op1, const String& op2) +{ + String result(op1); + result.append(op2); + return result; +} - int stringToInt(const String& str, int radix) - { - if (str.startsWith("0x")) - return (int)strtoll(str.getBuffer(), NULL, 16); - else - return (int)strtoll(str.getBuffer(), NULL, radix); - } - unsigned int stringToUInt(const String& str, int radix) - { - if (str.startsWith("0x")) - return (unsigned int)strtoull(str.getBuffer(), NULL, 16); - else - return (unsigned int)strtoull(str.getBuffer(), NULL, radix); - } - double stringToDouble(const String& str) - { - return (double)strtod(str.getBuffer(), NULL); - } - float stringToFloat(const String& str) - { - return strtof(str.getBuffer(), NULL); - } +int stringToInt(const String& str, int radix) +{ + if (str.startsWith("0x")) + return (int)strtoll(str.getBuffer(), NULL, 16); + else + return (int)strtoll(str.getBuffer(), NULL, radix); +} +unsigned int stringToUInt(const String& str, int radix) +{ + if (str.startsWith("0x")) + return (unsigned int)strtoull(str.getBuffer(), NULL, 16); + else + return (unsigned int)strtoull(str.getBuffer(), NULL, radix); +} +double stringToDouble(const String& str) +{ + return (double)strtod(str.getBuffer(), NULL); +} +float stringToFloat(const String& str) +{ + return strtof(str.getBuffer(), NULL); +} #if 0 String String::ReplaceAll(String src, String dst) const @@ -300,446 +304,473 @@ namespace Slang } #endif - String String::fromWString(const wchar_t* wstr) - { - List<char> buf; +String String::fromWString(const wchar_t* wstr) +{ + List<char> buf; #ifdef _WIN32 - Slang::CharEncoding::UTF16->decode((const Byte*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)), buf); + Slang::CharEncoding::UTF16->decode( + (const Byte*)wstr, + (int)(wcslen(wstr) * sizeof(wchar_t)), + buf); #else - Slang::CharEncoding::UTF32->decode((const Byte*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)), buf); + Slang::CharEncoding::UTF32->decode( + (const Byte*)wstr, + (int)(wcslen(wstr) * sizeof(wchar_t)), + buf); #endif - return String(buf.begin(), buf.end()); - } + return String(buf.begin(), buf.end()); +} - String String::fromWString(const wchar_t* wstr, const wchar_t* wend) - { - List<char> buf; +String String::fromWString(const wchar_t* wstr, const wchar_t* wend) +{ + List<char> buf; #ifdef _WIN32 - Slang::CharEncoding::UTF16->decode((const Byte*)wstr, (int)((wend - wstr) * sizeof(wchar_t)), buf); + Slang::CharEncoding::UTF16->decode( + (const Byte*)wstr, + (int)((wend - wstr) * sizeof(wchar_t)), + buf); #else - Slang::CharEncoding::UTF32->decode((const Byte*)wstr, (int)((wend - wstr) * sizeof(wchar_t)), buf); + Slang::CharEncoding::UTF32->decode( + (const Byte*)wstr, + (int)((wend - wstr) * sizeof(wchar_t)), + buf); #endif - return String(buf.begin(), buf.end()); - } + return String(buf.begin(), buf.end()); +} - String String::fromWChar(const wchar_t ch) - { - List<char> buf; +String String::fromWChar(const wchar_t ch) +{ + List<char> buf; #ifdef _WIN32 - Slang::CharEncoding::UTF16->decode((const Byte*)&ch, (int)(sizeof(wchar_t)), buf); + Slang::CharEncoding::UTF16->decode((const Byte*)&ch, (int)(sizeof(wchar_t)), buf); #else - Slang::CharEncoding::UTF32->decode((const Byte*)&ch, (int)(sizeof(wchar_t)), buf); + Slang::CharEncoding::UTF32->decode((const Byte*)&ch, (int)(sizeof(wchar_t)), buf); #endif - return String(buf.begin(), buf.end()); - } + return String(buf.begin(), buf.end()); +} + +/* static */ String String::fromUnicodePoint(Char32 codePoint) +{ + char buf[6]; + int len = Slang::encodeUnicodePointToUTF8(codePoint, buf); + return String(buf, buf + len); +} - /* static */String String::fromUnicodePoint(Char32 codePoint) +OSString String::toWString(Index* outLength) const +{ + if (!m_buffer) { - char buf[6]; - int len = Slang::encodeUnicodePointToUTF8(codePoint, buf); - return String(buf, buf + len); + return OSString(); } - - OSString String::toWString(Index* outLength) const + else { - if (!m_buffer) + List<Byte> buf; + switch (sizeof(wchar_t)) { - return OSString(); - } - else - { - List<Byte> buf; - switch(sizeof(wchar_t)) - { - case 2: - Slang::CharEncoding::UTF16->encode(getUnownedSlice(), buf); - break; + case 2: Slang::CharEncoding::UTF16->encode(getUnownedSlice(), buf); break; - case 4: - Slang::CharEncoding::UTF32->encode(getUnownedSlice(), buf); - break; + case 4: Slang::CharEncoding::UTF32->encode(getUnownedSlice(), buf); break; - default: - break; - } + default: break; + } - auto length = Index(buf.getCount() / sizeof(wchar_t)); - if (outLength) - *outLength = length; + auto length = Index(buf.getCount() / sizeof(wchar_t)); + if (outLength) + *outLength = length; - for(size_t ii = 0; ii < sizeof(wchar_t); ++ii) - buf.add(0); + for (size_t ii = 0; ii < sizeof(wchar_t); ++ii) + buf.add(0); - wchar_t* beginData = (wchar_t*)buf.getBuffer(); - wchar_t* endData = beginData + length; + wchar_t* beginData = (wchar_t*)buf.getBuffer(); + wchar_t* endData = beginData + length; - OSString ret; - ret.set(beginData, endData); - return ret; - } + OSString ret; + ret.set(beginData, endData); + return ret; } +} + +// - // +void String::ensureUniqueStorageWithCapacity(Index requiredCapacity) +{ + if (m_buffer && m_buffer->isUniquelyReferenced() && m_buffer->capacity >= requiredCapacity) + return; - void String::ensureUniqueStorageWithCapacity(Index requiredCapacity) + Index newCapacity = m_buffer ? 2 * m_buffer->capacity : 16; + if (newCapacity < requiredCapacity) { - if (m_buffer && m_buffer->isUniquelyReferenced() && m_buffer->capacity >= requiredCapacity) - return; + newCapacity = requiredCapacity; + } - Index newCapacity = m_buffer ? 2 * m_buffer->capacity : 16; - if (newCapacity < requiredCapacity) - { - newCapacity = requiredCapacity; - } + Index length = getLength(); + StringRepresentation* newRepresentation = + StringRepresentation::createWithCapacityAndLength(newCapacity, length); - Index length = getLength(); - StringRepresentation* newRepresentation = StringRepresentation::createWithCapacityAndLength(newCapacity, length); + if (m_buffer) + { + memcpy(newRepresentation->getData(), m_buffer->getData(), length + 1); + } - if (m_buffer) - { - memcpy(newRepresentation->getData(), m_buffer->getData(), length + 1); - } + m_buffer = newRepresentation; +} - m_buffer = newRepresentation; - } +char* String::prepareForAppend(Index count) +{ + auto oldLength = getLength(); + auto newLength = oldLength + count; + ensureUniqueStorageWithCapacity(newLength); + return getData() + oldLength; +} +void String::appendInPlace(const char* chars, Index count) +{ + SLANG_UNUSED(chars); - char* String::prepareForAppend(Index count) + if (count > 0) { + SLANG_ASSERT(m_buffer && m_buffer->isUniquelyReferenced()); + auto oldLength = getLength(); auto newLength = oldLength + count; - ensureUniqueStorageWithCapacity(newLength); - return getData() + oldLength; - } - void String::appendInPlace(const char* chars, Index count) - { - SLANG_UNUSED(chars); - - if (count > 0) - { - SLANG_ASSERT(m_buffer && m_buffer->isUniquelyReferenced()); - - auto oldLength = getLength(); - auto newLength = oldLength + count; - char* dst = m_buffer->getData(); + char* dst = m_buffer->getData(); - // Make sure the input buffer is the same one returned from prepareForAppend - SLANG_ASSERT(chars == dst + oldLength); - // It has to fit within the capacity - SLANG_ASSERT(newLength <= m_buffer->capacity); + // Make sure the input buffer is the same one returned from prepareForAppend + SLANG_ASSERT(chars == dst + oldLength); + // It has to fit within the capacity + SLANG_ASSERT(newLength <= m_buffer->capacity); - // We just need to modify the length - m_buffer->length = newLength; + // We just need to modify the length + m_buffer->length = newLength; - // And mark with a terminating 0 - dst[newLength] = 0; - } + // And mark with a terminating 0 + dst[newLength] = 0; } +} - void String::reduceLength(Index newLength) +void String::reduceLength(Index newLength) +{ + Index oldLength = getLength(); + SLANG_ASSERT(newLength <= oldLength); + if (oldLength == newLength) { - Index oldLength = getLength(); - SLANG_ASSERT(newLength <= oldLength); - if (oldLength == newLength) - { - return; - } + return; + } - // It must have a buffer, because only 0 length allows for nullptr - // and being 0 sized is already covered - SLANG_ASSERT(m_buffer); + // It must have a buffer, because only 0 length allows for nullptr + // and being 0 sized is already covered + SLANG_ASSERT(m_buffer); - if (m_buffer->isUniquelyReferenced()) + if (m_buffer->isUniquelyReferenced()) + { + m_buffer->length = newLength; + m_buffer->getData()[newLength] = 0; + } + else + { + // If 0 length is wanted we can just free + if (newLength == 0) { - m_buffer->length = newLength; - m_buffer->getData()[newLength] = 0; + m_buffer.setNull(); } else { - // If 0 length is wanted we can just free - if (newLength == 0) - { - m_buffer.setNull(); - } - else - { - // We need to make a new copy, that we will shrink + // We need to make a new copy, that we will shrink - // We'll just go with capacity enough for the new length - const Index newCapacity = newLength; - StringRepresentation* newRepresentation = StringRepresentation::createWithCapacityAndLength(newCapacity, newLength); + // We'll just go with capacity enough for the new length + const Index newCapacity = newLength; + StringRepresentation* newRepresentation = + StringRepresentation::createWithCapacityAndLength(newCapacity, newLength); - // Copy - char* dst = newRepresentation->getData(); - memcpy(dst, m_buffer->getData(), sizeof(char) * newLength); - // Zero terminate - dst[newLength] = 0; + // Copy + char* dst = newRepresentation->getData(); + memcpy(dst, m_buffer->getData(), sizeof(char) * newLength); + // Zero terminate + dst[newLength] = 0; - // Set the new rep - m_buffer = newRepresentation; - } + // Set the new rep + m_buffer = newRepresentation; } } +} - void String::append(char const* str, size_t len) - { - append(str, str + len); - } +void String::append(char const* str, size_t len) +{ + append(str, str + len); +} - void String::append(const char* textBegin, char const* textEnd) - { - auto oldLength = getLength(); - auto textLength = textEnd - textBegin; - if (textLength <= 0) - return; +void String::append(const char* textBegin, char const* textEnd) +{ + auto oldLength = getLength(); + auto textLength = textEnd - textBegin; + if (textLength <= 0) + return; - auto newLength = oldLength + textLength; + auto newLength = oldLength + textLength; - ensureUniqueStorageWithCapacity(newLength); + ensureUniqueStorageWithCapacity(newLength); - memcpy(getData() + oldLength, textBegin, textLength); - getData()[newLength] = 0; - m_buffer->length = newLength; - } + memcpy(getData() + oldLength, textBegin, textLength); + getData()[newLength] = 0; + m_buffer->length = newLength; +} - void String::append(char const* str) +void String::append(char const* str) +{ + if (str) { - if (str) - { - append(str, str + strlen(str)); - } + append(str, str + strlen(str)); } +} - void String::appendRepeatedChar(char chr, Index count) +void String::appendRepeatedChar(char chr, Index count) +{ + SLANG_ASSERT(count >= 0); + if (count > 0) { - SLANG_ASSERT(count >= 0); - if (count > 0) - { - char* chars = prepareForAppend(count); - // Set all space to repeated chr. - ::memset(chars, chr, sizeof(char) * count); - appendInPlace(chars, count); - } + char* chars = prepareForAppend(count); + // Set all space to repeated chr. + ::memset(chars, chr, sizeof(char) * count); + appendInPlace(chars, count); } +} - void String::appendChar(char c) - { - const auto oldLength = getLength(); - const auto newLength = oldLength + 1; +void String::appendChar(char c) +{ + const auto oldLength = getLength(); + const auto newLength = oldLength + 1; - ensureUniqueStorageWithCapacity(newLength); + ensureUniqueStorageWithCapacity(newLength); - // Since there must be space for at least one character, m_buffer cannot be nullptr - SLANG_ASSERT(m_buffer); - char* data = m_buffer->getData(); - data[oldLength] = c; - data[newLength] = 0; + // Since there must be space for at least one character, m_buffer cannot be nullptr + SLANG_ASSERT(m_buffer); + char* data = m_buffer->getData(); + data[oldLength] = c; + data[newLength] = 0; - m_buffer->length = newLength; - } + m_buffer->length = newLength; +} - void String::append(char chr) +void String::append(char chr) +{ + appendChar(chr); +} + +void String::append(String const& str) +{ + if (!m_buffer) { - appendChar(chr); + m_buffer = str.m_buffer; + return; } - void String::append(String const& str) - { - if (!m_buffer) - { - m_buffer = str.m_buffer; - return; - } + append(str.begin(), str.end()); +} - append(str.begin(), str.end()); - } +void String::append(StringSlice const& slice) +{ + append(slice.begin(), slice.end()); +} - void String::append(StringSlice const& slice) - { - append(slice.begin(), slice.end()); - } +void String::append(UnownedStringSlice const& slice) +{ + append(slice.begin(), slice.end()); +} - void String::append(UnownedStringSlice const& slice) +void String::append(int32_t value, int radix) +{ + enum { - append(slice.begin(), slice.end()); - } + kCount = 33 + }; + char* data = prepareForAppend(kCount); + const auto count = intToAscii(data, value, radix); + m_buffer->length += count; +} - void String::append(int32_t value, int radix) +void String::append(uint32_t value, int radix) +{ + enum { - enum { kCount = 33 }; - char* data = prepareForAppend(kCount); - const auto count = intToAscii(data, value, radix); - m_buffer->length += count; - } + kCount = 33 + }; + char* data = prepareForAppend(kCount); + const auto count = intToAscii(data, value, radix); + m_buffer->length += count; +} - void String::append(uint32_t value, int radix) +void String::append(int64_t value, int radix) +{ + enum { - enum { kCount = 33 }; - char* data = prepareForAppend(kCount); - const auto count = intToAscii(data, value, radix); - m_buffer->length += count; - } + kCount = 65 + }; + char* data = prepareForAppend(kCount); + auto count = intToAscii(data, value, radix); + m_buffer->length += count; +} - void String::append(int64_t value, int radix) +void String::append(uint64_t value, int radix) +{ + enum { - enum { kCount = 65 }; - char* data = prepareForAppend(kCount); - auto count = intToAscii(data, value, radix); - m_buffer->length += count; - } + kCount = 65 + }; + char* data = prepareForAppend(kCount); + auto count = intToAscii(data, value, radix); + m_buffer->length += count; +} - void String::append(uint64_t value, int radix) +void String::append(float val, const char* format) +{ + enum { - enum { kCount = 65 }; - char* data = prepareForAppend(kCount); - auto count = intToAscii(data, value, radix); - m_buffer->length += count; - } + kCount = 128 + }; + char* data = prepareForAppend(kCount); + sprintf_s(data, kCount, format, val); + m_buffer->length += strnlen_s(data, kCount); +} - void String::append(float val, const char* format) +void String::append(double val, const char* format) +{ + enum { - enum { kCount = 128 }; - char* data = prepareForAppend(kCount); - sprintf_s(data, kCount, format, val); - m_buffer->length += strnlen_s(data, kCount); - } + kCount = 128 + }; + char* data = prepareForAppend(kCount); + sprintf_s(data, kCount, format, val); + m_buffer->length += strnlen_s(data, kCount); +} + +void String::append(StableHashCode32 value) +{ + const Index digits = 8; + // + null terminator + char* data = prepareForAppend(digits + 1); + auto count = intToAscii(data, value.hash, 16, digits); + m_buffer->length += count; +} - void String::append(double val, const char* format) +void String::append(StableHashCode64 value) +{ + const Index digits = 16; + // + null terminator + char* data = prepareForAppend(digits + 1); + auto count = intToAscii(data, value.hash, 16, digits); + m_buffer->length += count; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnownedStringSlice !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Index UnownedStringSlice::indexOf(char c) const +{ + const Index size = Index(m_end - m_begin); + for (Index i = 0; i < size; ++i) { - enum { kCount = 128 }; - char* data = prepareForAppend(kCount); - sprintf_s(data, kCount, format, val); - m_buffer->length += strnlen_s(data, kCount); + if (m_begin[i] == c) + { + return i; + } } + return -1; +} - void String::append(StableHashCode32 value) +Index UnownedStringSlice::indexOf(const UnownedStringSlice& in) const +{ + const Index len = getLength(); + const Index inLen = in.getLength(); + if (inLen > len) { - const Index digits = 8; - // + null terminator - char* data = prepareForAppend(digits + 1); - auto count = intToAscii(data, value.hash, 16, digits); - m_buffer->length += count; + return -1; } - void String::append(StableHashCode64 value) + const char* inChars = in.m_begin; + switch (inLen) { - const Index digits = 16; - // + null terminator - char* data = prepareForAppend(digits + 1); - auto count = intToAscii(data, value.hash, 16, digits); - m_buffer->length += count; + case 0: return 0; + case 1: return indexOf(inChars[0]); + default: break; } - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnownedStringSlice !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + const char* chars = m_begin; + const char firstChar = inChars[0]; - Index UnownedStringSlice::indexOf(char c) const + for (Int i = 0; i <= len - inLen; ++i) { - const Index size = Index(m_end - m_begin); - for (Index i = 0; i < size; ++i) + if (chars[i] == firstChar && in == UnownedStringSlice(chars + i, inLen)) { - if (m_begin[i] == c) - { - return i; - } + return i; } - return -1; } - Index UnownedStringSlice::indexOf(const UnownedStringSlice& in) const - { - const Index len = getLength(); - const Index inLen = in.getLength(); - if (inLen > len) - { - return -1; - } + return -1; +} - const char* inChars = in.m_begin; - switch (inLen) - { - case 0: return 0; - case 1: return indexOf(inChars[0]); - default: break; - } +UnownedStringSlice UnownedStringSlice::subString(Index idx, Index len) const +{ + const Index totalLen = getLength(); + SLANG_ASSERT(idx >= 0 && len >= 0 && idx <= totalLen); - const char* chars = m_begin; - const char firstChar = inChars[0]; + // If too large, we truncate + len = (idx + len > totalLen) ? (totalLen - idx) : len; - for (Int i = 0; i <= len - inLen; ++i) - { - if (chars[i] == firstChar && in == UnownedStringSlice(chars + i, inLen)) - { - return i; - } - } + // Return the substring + return UnownedStringSlice(m_begin + idx, m_begin + idx + len); +} - return -1; - } +bool UnownedStringSlice::operator==(ThisType const& other) const +{ + // Note that memcmp is undefined when passed in null ptrs, so if we want to handle + // we need to cover that case. + // Can only be nullptr if size is 0. + auto thisSize = getLength(); + auto otherSize = other.getLength(); - UnownedStringSlice UnownedStringSlice::subString(Index idx, Index len) const + if (thisSize != otherSize) { - const Index totalLen = getLength(); - SLANG_ASSERT(idx >= 0 && len >= 0 && idx <= totalLen); - - // If too large, we truncate - len = (idx + len > totalLen) ? (totalLen - idx) : len; - - // Return the substring - return UnownedStringSlice(m_begin + idx, m_begin + idx + len); + return false; } - bool UnownedStringSlice::operator==(ThisType const& other) const + const char* const thisChars = begin(); + const char* const otherChars = other.begin(); + if (thisChars == otherChars || thisSize == 0) { - // Note that memcmp is undefined when passed in null ptrs, so if we want to handle - // we need to cover that case. - // Can only be nullptr if size is 0. - auto thisSize = getLength(); - auto otherSize = other.getLength(); - - if (thisSize != otherSize) - { - return false; - } - - const char*const thisChars = begin(); - const char*const otherChars = other.begin(); - if (thisChars == otherChars || thisSize == 0) - { - return true; - } - SLANG_ASSERT(thisChars && otherChars); - return memcmp(thisChars, otherChars, thisSize) == 0; + return true; } + SLANG_ASSERT(thisChars && otherChars); + return memcmp(thisChars, otherChars, thisSize) == 0; +} - bool UnownedStringSlice::caseInsensitiveEquals(const ThisType& rhs) const +bool UnownedStringSlice::caseInsensitiveEquals(const ThisType& rhs) const +{ + const auto length = getLength(); + if (length != rhs.getLength()) { - const auto length = getLength(); - if (length != rhs.getLength()) - { - return false; - } + return false; + } - const char* a = m_begin; - const char* b = rhs.m_begin; + const char* a = m_begin; + const char* b = rhs.m_begin; - // Assuming this is a faster test - if (memcmp(a, b, length) != 0) + // Assuming this is a faster test + if (memcmp(a, b, length) != 0) + { + // They aren't identical so compare character by character + for (Index i = 0; i < length; ++i) { - // They aren't identical so compare character by character - for (Index i = 0; i < length; ++i) + if (CharUtil::toLower(a[i]) != CharUtil::toLower(b[i])) { - if (CharUtil::toLower(a[i]) != CharUtil::toLower(b[i])) - { - return false; - } + return false; } } - - return true; } + + return true; } +} // namespace Slang -std::ostream& operator<< (std::ostream& stream, const Slang::String& s) +std::ostream& operator<<(std::ostream& stream, const Slang::String& s) { stream << s.getBuffer(); return stream; diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 6c0dec420..24b119383 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -1,989 +1,872 @@ #ifndef SLANG_CORE_STRING_H #define SLANG_CORE_STRING_H -#include <string.h> -#include <cstdlib> -#include <stdio.h> -#include <iostream> - -#include "slang-smart-pointer.h" #include "slang-common.h" #include "slang-hash.h" #include "slang-secure-crt.h" +#include "slang-smart-pointer.h" #include "slang-stable-hash.h" +#include <cstdlib> +#include <iostream> #include <new> +#include <stdio.h> +#include <string.h> #include <type_traits> namespace Slang { - class _EndLine - {}; - extern _EndLine EndLine; +class _EndLine +{ +}; +extern _EndLine EndLine; - // in-place reversion, works only for ascii string - inline void reverseInplaceAscii(char* buffer, int length) +// in-place reversion, works only for ascii string +inline void reverseInplaceAscii(char* buffer, int length) +{ + int i, j; + char c; + for (i = 0, j = length - 1; i < j; i++, j--) { - int i, j; - char c; - for (i = 0, j = length - 1; i<j; i++, j--) - { - c = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = c; - } + c = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = c; } - template<typename IntType> - inline int intToAscii(char* buffer, IntType val, int radix, int padTo = 0) +} +template<typename IntType> +inline int intToAscii(char* buffer, IntType val, int radix, int padTo = 0) +{ + static_assert(std::is_integral_v<IntType>); + + int i = 0; + IntType sign; + + sign = val; + if (sign < 0) { - static_assert(std::is_integral_v<IntType>); + val = (IntType)(0 - val); + } - int i = 0; - IntType sign; - - sign = val; - if (sign < 0) - { - val = (IntType)(0 - val); - } + do + { + int digit = (val % radix); + if (digit <= 9) + buffer[i++] = (char)(digit + '0'); + else + buffer[i++] = (char)(digit - 10 + 'A'); + } while ((val /= radix) > 0); - do - { - int digit = (val % radix); - if (digit <= 9) - buffer[i++] = (char)(digit + '0'); - else - buffer[i++] = (char)(digit - 10 + 'A'); - } while ((val /= radix) > 0); + SLANG_ASSERT(i >= 0); + while (i < padTo) + buffer[i++] = '0'; - SLANG_ASSERT(i >= 0); - while(i < padTo) - buffer[i++] = '0'; + if (sign < 0) + buffer[i++] = '-'; - if (sign < 0) - buffer[i++] = '-'; + // Put in normal character order + reverseInplaceAscii(buffer, i); - // Put in normal character order - reverseInplaceAscii(buffer, i); + buffer[i] = '\0'; + return i; +} - buffer[i] = '\0'; - return i; - } +SLANG_FORCE_INLINE bool isUtf8LeadingByte(char ch) +{ + return (((unsigned char)ch) & 0xC0) == 0xC0; +} + +SLANG_FORCE_INLINE bool isUtf8ContinuationByte(char ch) +{ + return (((unsigned char)ch) & 0xC0) == 0x80; +} - SLANG_FORCE_INLINE bool isUtf8LeadingByte(char ch) +/* A string slice that doesn't own the contained characters. +It is the responsibility of code using the type to keep the memory backing +the slice in scope. +A slice is generally *not* zero terminated. */ +struct SLANG_RT_API UnownedStringSlice +{ +public: + typedef UnownedStringSlice ThisType; + + // Type to indicate that a ctor is with a length to disabmiguate 0/nullptr + // causing ambiguity. + struct WithLength { - return (((unsigned char)ch) & 0xC0) == 0xC0; - } + }; - SLANG_FORCE_INLINE bool isUtf8ContinuationByte(char ch) + UnownedStringSlice() + : m_begin(nullptr), m_end(nullptr) { - return (((unsigned char)ch) & 0xC0) == 0x80; } - /* A string slice that doesn't own the contained characters. - It is the responsibility of code using the type to keep the memory backing - the slice in scope. - A slice is generally *not* zero terminated. */ - struct SLANG_RT_API UnownedStringSlice + explicit UnownedStringSlice(char const* a) + : m_begin(a), m_end(a ? a + strlen(a) : nullptr) { - public: - typedef UnownedStringSlice ThisType; - - // Type to indicate that a ctor is with a length to disabmiguate 0/nullptr - // causing ambiguity. - struct WithLength {}; - - UnownedStringSlice() - : m_begin(nullptr) - , m_end(nullptr) - {} - - explicit UnownedStringSlice(char const* a) : - m_begin(a), - m_end(a ? a + strlen(a) : nullptr) - {} - UnownedStringSlice(char const* b, char const* e) - : m_begin(b) - , m_end(e) - {} - UnownedStringSlice(char const* b, size_t len) - : m_begin(b) - , m_end(b + len) - {} - UnownedStringSlice(WithLength, char const* b, size_t len) - : m_begin(b) - , m_end(b + len) - {} + } + UnownedStringSlice(char const* b, char const* e) + : m_begin(b), m_end(e) + { + } + UnownedStringSlice(char const* b, size_t len) + : m_begin(b), m_end(b + len) + { + } + UnownedStringSlice(WithLength, char const* b, size_t len) + : m_begin(b), m_end(b + len) + { + } - SLANG_FORCE_INLINE char const* begin() const { return m_begin; } + SLANG_FORCE_INLINE char const* begin() const { return m_begin; } - SLANG_FORCE_INLINE char const* end() const { return m_end; } + SLANG_FORCE_INLINE char const* end() const { return m_end; } - /// True if slice is strictly contained in memory. - bool isMemoryContained(const UnownedStringSlice& slice) const - { - return slice.m_begin >= m_begin && slice.m_end <= m_end; - } - bool isMemoryContained(const char* pos) const - { - return pos >= m_begin && pos <= m_end; - } + /// True if slice is strictly contained in memory. + bool isMemoryContained(const UnownedStringSlice& slice) const + { + return slice.m_begin >= m_begin && slice.m_end <= m_end; + } + bool isMemoryContained(const char* pos) const { return pos >= m_begin && pos <= m_end; } - /// Get the length in *bytes* - Count getLength() const { return Index(m_end - m_begin); } + /// Get the length in *bytes* + Count getLength() const { return Index(m_end - m_begin); } - /// Finds first index of char 'c'. If not found returns -1. - Index indexOf(char c) const; - /// Find first index of slice. If not found returns -1 - Index indexOf(const UnownedStringSlice& slice) const; + /// Finds first index of char 'c'. If not found returns -1. + Index indexOf(char c) const; + /// Find first index of slice. If not found returns -1 + Index indexOf(const UnownedStringSlice& slice) const; - /// Returns a substring. idx is the start index, and len - /// is the amount of characters. - /// The returned length might be truncated, if len extends beyond slice. - UnownedStringSlice subString(Index idx, Index len) const; + /// Returns a substring. idx is the start index, and len + /// is the amount of characters. + /// The returned length might be truncated, if len extends beyond slice. + UnownedStringSlice subString(Index idx, Index len) const; - /// Return a head of the slice - everything up to the index - SLANG_FORCE_INLINE UnownedStringSlice head(Index idx) const { SLANG_ASSERT(idx >= 0 && idx <= getLength()); return UnownedStringSlice(m_begin, idx); } - /// Return a tail of the slice - everything from the index to the end of the slice - SLANG_FORCE_INLINE UnownedStringSlice tail(Index idx) const { SLANG_ASSERT(idx >= 0 && idx <= getLength()); return UnownedStringSlice(m_begin + idx, m_end); } + /// Return a head of the slice - everything up to the index + SLANG_FORCE_INLINE UnownedStringSlice head(Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx <= getLength()); + return UnownedStringSlice(m_begin, idx); + } + /// Return a tail of the slice - everything from the index to the end of the slice + SLANG_FORCE_INLINE UnownedStringSlice tail(Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx <= getLength()); + return UnownedStringSlice(m_begin + idx, m_end); + } - /// True if rhs and this are equal without having to take into account case - /// Note 'case' here is *not* locale specific - it is only A-Z and a-z - bool caseInsensitiveEquals(const ThisType& rhs) const; + /// True if rhs and this are equal without having to take into account case + /// Note 'case' here is *not* locale specific - it is only A-Z and a-z + bool caseInsensitiveEquals(const ThisType& rhs) const; - Index lastIndexOf(char c) const + Index lastIndexOf(char c) const + { + const Index size = Index(m_end - m_begin); + for (Index i = size - 1; i >= 0; --i) { - const Index size = Index(m_end - m_begin); - for (Index i = size - 1; i >= 0; --i) + if (m_begin[i] == c) { - if (m_begin[i] == c) - { - return i; - } + return i; } - return -1; } + return -1; + } - const char& operator[](Index i) const - { - assert(i >= 0 && i < Index(m_end - m_begin)); - return m_begin[i]; - } + const char& operator[](Index i) const + { + assert(i >= 0 && i < Index(m_end - m_begin)); + return m_begin[i]; + } - bool operator==(ThisType const& other) const; - bool operator!=(UnownedStringSlice const& other) const { return !(*this == other); } + bool operator==(ThisType const& other) const; + bool operator!=(UnownedStringSlice const& other) const { return !(*this == other); } - bool operator==(char const* str) const { return (*this) == UnownedStringSlice(str); } - bool operator!=(char const* str) const { return !(*this == str); } + bool operator==(char const* str) const { return (*this) == UnownedStringSlice(str); } + bool operator!=(char const* str) const { return !(*this == str); } - /// True if contents is a single char of c - SLANG_FORCE_INLINE bool isChar(char c) const { return getLength() == 1 && m_begin[0] == c; } + /// True if contents is a single char of c + SLANG_FORCE_INLINE bool isChar(char c) const { return getLength() == 1 && m_begin[0] == c; } - bool startsWithCaseInsensitive(UnownedStringSlice const& other) const; - bool startsWith(UnownedStringSlice const& other) const; - bool startsWith(char const* str) const; + bool startsWithCaseInsensitive(UnownedStringSlice const& other) const; + bool startsWith(UnownedStringSlice const& other) const; + bool startsWith(char const* str) const; - bool endsWithCaseInsensitive(UnownedStringSlice const& other) const; - bool endsWithCaseInsensitive(char const* str) const; + bool endsWithCaseInsensitive(UnownedStringSlice const& other) const; + bool endsWithCaseInsensitive(char const* str) const; - bool endsWith(UnownedStringSlice const& other) const; - bool endsWith(char const* str) const; + bool endsWith(UnownedStringSlice const& other) const; + bool endsWith(char const* str) const; - /// Trims any horizontal whitespace from the start and end and returns as a substring - UnownedStringSlice trim() const; - /// Trims any 'c' from the start or the end, and returns as a substring - UnownedStringSlice trim(char c) const; + /// Trims any horizontal whitespace from the start and end and returns as a substring + UnownedStringSlice trim() const; + /// Trims any 'c' from the start or the end, and returns as a substring + UnownedStringSlice trim(char c) const; - /// Trims any horizonatl whitespace from start and returns as a substring - UnownedStringSlice trimStart() const; + /// Trims any horizonatl whitespace from start and returns as a substring + UnownedStringSlice trimStart() const; - static constexpr bool kHasUniformHash = true; - HashCode64 getHashCode() const - { - return Slang::getHashCode(m_begin, size_t(m_end - m_begin)); - } + static constexpr bool kHasUniformHash = true; + HashCode64 getHashCode() const { return Slang::getHashCode(m_begin, size_t(m_end - m_begin)); } - template <size_t SIZE> - SLANG_FORCE_INLINE static UnownedStringSlice fromLiteral(const char (&in)[SIZE]) { return UnownedStringSlice(in, SIZE - 1); } + template<size_t SIZE> + SLANG_FORCE_INLINE static UnownedStringSlice fromLiteral(const char (&in)[SIZE]) + { + return UnownedStringSlice(in, SIZE - 1); + } - protected: +protected: + char const* m_begin; + char const* m_end; +}; - char const* m_begin; - char const* m_end; - }; +// A more convenient way to make slices from *string literals* +template<size_t SIZE> +SLANG_FORCE_INLINE UnownedStringSlice toSlice(const char (&in)[SIZE]) +{ + return UnownedStringSlice(in, SIZE - 1); +} - // A more convenient way to make slices from *string literals* - template <size_t SIZE> - SLANG_FORCE_INLINE UnownedStringSlice toSlice(const char (&in)[SIZE]) { return UnownedStringSlice(in, SIZE - 1); } - - /// Same as UnownedStringSlice, but must be zero terminated. - /// Zero termination is *not* included in the length. - struct SLANG_RT_API UnownedTerminatedStringSlice : public UnownedStringSlice - { - public: - typedef UnownedStringSlice Super; - typedef UnownedTerminatedStringSlice ThisType; - - /// We can turn into a regular zero terminated string - SLANG_FORCE_INLINE operator const char*() const { return m_begin; } - - /// Exists to match the equivalent function in String. - SLANG_FORCE_INLINE char const* getBuffer() const { return m_begin; } - - /// Construct from a literal directly. - template <size_t SIZE> - SLANG_FORCE_INLINE static ThisType fromLiteral(const char(&in)[SIZE]) { return ThisType(in, SIZE - 1); } - - /// Default constructor - UnownedTerminatedStringSlice():Super(Super::WithLength(), "", 0) {} - - /// Note, b cannot be null because if it were then the string would not be null terminated - UnownedTerminatedStringSlice(char const* b) - : Super(b, b + strlen(b)) - {} - UnownedTerminatedStringSlice(char const* b, size_t len) - : Super(b, len) - { - // b must be valid and it must be null terminated - SLANG_ASSERT(b && b[len] == 0); - } - }; +/// Same as UnownedStringSlice, but must be zero terminated. +/// Zero termination is *not* included in the length. +struct SLANG_RT_API UnownedTerminatedStringSlice : public UnownedStringSlice +{ +public: + typedef UnownedStringSlice Super; + typedef UnownedTerminatedStringSlice ThisType; + + /// We can turn into a regular zero terminated string + SLANG_FORCE_INLINE operator const char*() const { return m_begin; } - // A more convenient way to make terminated slices from *string literals* - template <size_t SIZE> - SLANG_FORCE_INLINE UnownedTerminatedStringSlice toTerminatedSlice(const char(&in)[SIZE]) { return UnownedTerminatedStringSlice(in, SIZE - 1); } + /// Exists to match the equivalent function in String. + SLANG_FORCE_INLINE char const* getBuffer() const { return m_begin; } - // A `StringRepresentation` provides the backing storage for - // all reference-counted string-related types. - class SLANG_RT_API StringRepresentation : public RefObject + /// Construct from a literal directly. + template<size_t SIZE> + SLANG_FORCE_INLINE static ThisType fromLiteral(const char (&in)[SIZE]) { - public: - Index length; - Index capacity; + return ThisType(in, SIZE - 1); + } - SLANG_FORCE_INLINE Index getLength() const - { - return length; - } + /// Default constructor + UnownedTerminatedStringSlice() + : Super(Super::WithLength(), "", 0) + { + } - SLANG_FORCE_INLINE char* getData() - { - return (char*) (this + 1); - } - SLANG_FORCE_INLINE const char* getData() const - { - return (const char*)(this + 1); - } + /// Note, b cannot be null because if it were then the string would not be null terminated + UnownedTerminatedStringSlice(char const* b) + : Super(b, b + strlen(b)) + { + } + UnownedTerminatedStringSlice(char const* b, size_t len) + : Super(b, len) + { + // b must be valid and it must be null terminated + SLANG_ASSERT(b && b[len] == 0); + } +}; - /// Set the contents to be the slice. Must be enough capacity to hold the slice. - void setContents(const UnownedStringSlice& slice); +// A more convenient way to make terminated slices from *string literals* +template<size_t SIZE> +SLANG_FORCE_INLINE UnownedTerminatedStringSlice toTerminatedSlice(const char (&in)[SIZE]) +{ + return UnownedTerminatedStringSlice(in, SIZE - 1); +} - static const char* getData(const StringRepresentation* stringRep) - { - return stringRep ? stringRep->getData() : ""; - } +// A `StringRepresentation` provides the backing storage for +// all reference-counted string-related types. +class SLANG_RT_API StringRepresentation : public RefObject +{ +public: + Index length; + Index capacity; - static UnownedStringSlice asSlice(const StringRepresentation* rep) - { - return rep ? UnownedStringSlice(rep->getData(), rep->getLength()) : UnownedStringSlice(); - } + SLANG_FORCE_INLINE Index getLength() const { return length; } - static bool equal(const StringRepresentation* a, const StringRepresentation* b) - { - return (a == b) || asSlice(a) == asSlice(b); - } + SLANG_FORCE_INLINE char* getData() { return (char*)(this + 1); } + SLANG_FORCE_INLINE const char* getData() const { return (const char*)(this + 1); } - static StringRepresentation* createWithCapacityAndLength(Index capacity, Index length) - { - SLANG_ASSERT(capacity >= length); - void* allocation = operator new(sizeof(StringRepresentation) + capacity + 1); - StringRepresentation* obj = new(allocation) StringRepresentation(); - obj->capacity = capacity; - obj->length = length; - obj->getData()[length] = 0; - return obj; - } + /// Set the contents to be the slice. Must be enough capacity to hold the slice. + void setContents(const UnownedStringSlice& slice); - static StringRepresentation* createWithCapacity(Index capacity) - { - return createWithCapacityAndLength(capacity, 0); - } + static const char* getData(const StringRepresentation* stringRep) + { + return stringRep ? stringRep->getData() : ""; + } - static StringRepresentation* createWithLength(Index length) - { - return createWithCapacityAndLength(length, length); - } + static UnownedStringSlice asSlice(const StringRepresentation* rep) + { + return rep ? UnownedStringSlice(rep->getData(), rep->getLength()) : UnownedStringSlice(); + } - /// Create a representation from the slice. If slice is empty will return nullptr. - static StringRepresentation* create(const UnownedStringSlice& slice); - /// Same as create, but representation will have refcount of 1 (if not nullptr) - static StringRepresentation* createWithReference(const UnownedStringSlice& slice); + static bool equal(const StringRepresentation* a, const StringRepresentation* b) + { + return (a == b) || asSlice(a) == asSlice(b); + } - StringRepresentation* cloneWithCapacity(Index newCapacity) - { - StringRepresentation* newObj = createWithCapacityAndLength(newCapacity, length); - memcpy(getData(), newObj->getData(), length + 1); - return newObj; - } + static StringRepresentation* createWithCapacityAndLength(Index capacity, Index length) + { + SLANG_ASSERT(capacity >= length); + void* allocation = operator new(sizeof(StringRepresentation) + capacity + 1); + StringRepresentation* obj = new (allocation) StringRepresentation(); + obj->capacity = capacity; + obj->length = length; + obj->getData()[length] = 0; + return obj; + } - StringRepresentation* clone() - { - return cloneWithCapacity(length); - } + static StringRepresentation* createWithCapacity(Index capacity) + { + return createWithCapacityAndLength(capacity, 0); + } - StringRepresentation* ensureCapacity(Index required) - { - if (capacity >= required) return this; + static StringRepresentation* createWithLength(Index length) + { + return createWithCapacityAndLength(length, length); + } - Index newCapacity = capacity; - if (!newCapacity) newCapacity = 16; // TODO: figure out good value for minimum capacity + /// Create a representation from the slice. If slice is empty will return nullptr. + static StringRepresentation* create(const UnownedStringSlice& slice); + /// Same as create, but representation will have refcount of 1 (if not nullptr) + static StringRepresentation* createWithReference(const UnownedStringSlice& slice); - while (newCapacity < required) - { - newCapacity = 2 * newCapacity; - } + StringRepresentation* cloneWithCapacity(Index newCapacity) + { + StringRepresentation* newObj = createWithCapacityAndLength(newCapacity, length); + memcpy(getData(), newObj->getData(), length + 1); + return newObj; + } - return cloneWithCapacity(newCapacity); - } + StringRepresentation* clone() { return cloneWithCapacity(length); } + + StringRepresentation* ensureCapacity(Index required) + { + if (capacity >= required) + return this; - /// Overload delete to silence ASAN new-delete-type-mismatch errors. - /// These occur because the allocation size of StringRepresentation - /// does not match deallocation size (due variable sized string payload). - void operator delete(void* p) + Index newCapacity = capacity; + if (!newCapacity) + newCapacity = 16; // TODO: figure out good value for minimum capacity + + while (newCapacity < required) { - StringRepresentation* str = (StringRepresentation*) p; - ::operator delete(str); - } - }; + newCapacity = 2 * newCapacity; + } - class String; + return cloneWithCapacity(newCapacity); + } - struct SLANG_RT_API StringSlice + /// Overload delete to silence ASAN new-delete-type-mismatch errors. + /// These occur because the allocation size of StringRepresentation + /// does not match deallocation size (due variable sized string payload). + void operator delete(void* p) { - public: - StringSlice(); + StringRepresentation* str = (StringRepresentation*)p; + ::operator delete(str); + } +}; - StringSlice(String const& str); +class String; - StringSlice(String const& str, UInt beginIndex, UInt endIndex); +struct SLANG_RT_API StringSlice +{ +public: + StringSlice(); - UInt getLength() const - { - return endIndex - beginIndex; - } + StringSlice(String const& str); - char const* begin() const - { - return representation ? representation->getData() + beginIndex : ""; - } + StringSlice(String const& str, UInt beginIndex, UInt endIndex); - char const* end() const - { - return begin() + getLength(); - } + UInt getLength() const { return endIndex - beginIndex; } - private: - RefPtr<StringRepresentation> representation; - UInt beginIndex; - UInt endIndex; + char const* begin() const + { + return representation ? representation->getData() + beginIndex : ""; + } - friend class String; + char const* end() const { return begin() + getLength(); } - StringSlice(RefPtr<StringRepresentation> const& representation, UInt beginIndex, UInt endIndex) - : representation(representation) - , beginIndex(beginIndex) - , endIndex(endIndex) - {} - }; +private: + RefPtr<StringRepresentation> representation; + UInt beginIndex; + UInt endIndex; - /// String as expected by underlying platform APIs - class SLANG_RT_API OSString - { - public: - /// Default - OSString(); - /// NOTE! This assumes that begin is a new wchar_t[] buffer, and it will - /// now be owned by the OSString - OSString(wchar_t* begin, wchar_t* end); - /// Move Ctor - OSString(OSString&& rhs): - m_begin(rhs.m_begin), - m_end(rhs.m_end) - { - rhs.m_begin = nullptr; - rhs.m_end = nullptr; - } - // Copy Ctor - OSString(const OSString& rhs) : - m_begin(nullptr), - m_end(nullptr) - { - set(rhs.m_begin, rhs.m_end); - } + friend class String; - /// = - void operator=(const OSString& rhs) { set(rhs.m_begin, rhs.m_end); } - void operator=(OSString&& rhs) - { - auto begin = m_begin; - auto end = m_end; - m_begin = rhs.m_begin; - m_end = rhs.m_end; - rhs.m_begin = begin; - rhs.m_end = end; - } + StringSlice(RefPtr<StringRepresentation> const& representation, UInt beginIndex, UInt endIndex) + : representation(representation), beginIndex(beginIndex), endIndex(endIndex) + { + } +}; - ~OSString() { _releaseBuffer(); } +/// String as expected by underlying platform APIs +class SLANG_RT_API OSString +{ +public: + /// Default + OSString(); + /// NOTE! This assumes that begin is a new wchar_t[] buffer, and it will + /// now be owned by the OSString + OSString(wchar_t* begin, wchar_t* end); + /// Move Ctor + OSString(OSString&& rhs) + : m_begin(rhs.m_begin), m_end(rhs.m_end) + { + rhs.m_begin = nullptr; + rhs.m_end = nullptr; + } + // Copy Ctor + OSString(const OSString& rhs) + : m_begin(nullptr), m_end(nullptr) + { + set(rhs.m_begin, rhs.m_end); + } - size_t getLength() const { return (m_end - m_begin); } - void set(const wchar_t* begin, const wchar_t* end); + /// = + void operator=(const OSString& rhs) { set(rhs.m_begin, rhs.m_end); } + void operator=(OSString&& rhs) + { + auto begin = m_begin; + auto end = m_end; + m_begin = rhs.m_begin; + m_end = rhs.m_end; + rhs.m_begin = begin; + rhs.m_end = end; + } - operator wchar_t const*() const - { - return begin(); - } + ~OSString() { _releaseBuffer(); } - wchar_t const* begin() const; - wchar_t const* end() const; + size_t getLength() const { return (m_end - m_begin); } + void set(const wchar_t* begin, const wchar_t* end); - private: + operator wchar_t const*() const { return begin(); } - void _releaseBuffer(); + wchar_t const* begin() const; + wchar_t const* end() const; - wchar_t* m_begin; ///< First character. This is a new wchar_t[] buffer - wchar_t* m_end; ///< Points to terminating 0 - }; +private: + void _releaseBuffer(); - /*! - @brief Represents a UTF-8 encoded string. - */ + wchar_t* m_begin; ///< First character. This is a new wchar_t[] buffer + wchar_t* m_end; ///< Points to terminating 0 +}; - class SLANG_RT_API String - { - friend struct StringSlice; - friend class StringBuilder; - private: +/*! +@brief Represents a UTF-8 encoded string. +*/ +class SLANG_RT_API String +{ + friend struct StringSlice; + friend class StringBuilder; - char* getData() const - { - return m_buffer ? m_buffer->getData() : (char*)""; - } +private: + char* getData() const { return m_buffer ? m_buffer->getData() : (char*)""; } - - void ensureUniqueStorageWithCapacity(Index capacity); - - RefPtr<StringRepresentation> m_buffer; - public: + void ensureUniqueStorageWithCapacity(Index capacity); - explicit String(StringRepresentation* buffer) - : m_buffer(buffer) - {} + RefPtr<StringRepresentation> m_buffer; - static String fromWString(const wchar_t* wstr); - static String fromWString(const wchar_t* wstr, const wchar_t* wend); - static String fromWChar(const wchar_t ch); - static String fromUnicodePoint(Char32 codePoint); +public: + explicit String(StringRepresentation* buffer) + : m_buffer(buffer) + { + } - String() - { - } + static String fromWString(const wchar_t* wstr); + static String fromWString(const wchar_t* wstr, const wchar_t* wend); + static String fromWChar(const wchar_t ch); + static String fromUnicodePoint(Char32 codePoint); - /// Returns a buffer which can hold at least count chars - char* prepareForAppend(Index count); - /// Append data written to buffer output via 'prepareForAppend' directly written 'inplace' - void appendInPlace(const char* chars, Index count); + String() {} - /// Get the internal string represenation - SLANG_FORCE_INLINE StringRepresentation* getStringRepresentation() const { return m_buffer; } + /// Returns a buffer which can hold at least count chars + char* prepareForAppend(Index count); + /// Append data written to buffer output via 'prepareForAppend' directly written 'inplace' + void appendInPlace(const char* chars, Index count); - /// Detach the representation (will leave string as empty). Rep ref count will remain unchanged. - SLANG_FORCE_INLINE StringRepresentation* detachStringRepresentation() { return m_buffer.detach(); } + /// Get the internal string represenation + SLANG_FORCE_INLINE StringRepresentation* getStringRepresentation() const { return m_buffer; } - const char* begin() const - { - return getData(); - } - const char* end() const - { - return getData() + getLength(); - } + /// Detach the representation (will leave string as empty). Rep ref count will remain unchanged. + SLANG_FORCE_INLINE StringRepresentation* detachStringRepresentation() + { + return m_buffer.detach(); + } - void append(int32_t value, int radix = 10); - void append(uint32_t value, int radix = 10); - void append(int64_t value, int radix = 10); - void append(uint64_t value, int radix = 10); - void append(float val, const char* format = "%g"); - void append(double val, const char* format = "%g"); + const char* begin() const { return getData(); } + const char* end() const { return getData() + getLength(); } - // Padded hex representations - void append(StableHashCode32 val); - void append(StableHashCode64 val); + void append(int32_t value, int radix = 10); + void append(uint32_t value, int radix = 10); + void append(int64_t value, int radix = 10); + void append(uint64_t value, int radix = 10); + void append(float val, const char* format = "%g"); + void append(double val, const char* format = "%g"); - void append(char const* str); - void append(char const* str, size_t len); - void append(const char* textBegin, char const* textEnd); - void append(char chr); - void append(String const& str); - void append(StringSlice const& slice); - void append(UnownedStringSlice const& slice); + // Padded hex representations + void append(StableHashCode32 val); + void append(StableHashCode64 val); - /// Append a character (to remove ambiguity with other integral types) - void appendChar(char chr); + void append(char const* str); + void append(char const* str, size_t len); + void append(const char* textBegin, char const* textEnd); + void append(char chr); + void append(String const& str); + void append(StringSlice const& slice); + void append(UnownedStringSlice const& slice); - /// Append the specified char count times - void appendRepeatedChar(char chr, Index count); + /// Append a character (to remove ambiguity with other integral types) + void appendChar(char chr); - String(const char* str) - { - append(str); + /// Append the specified char count times + void appendRepeatedChar(char chr, Index count); - } - String(const char* textBegin, char const* textEnd) - { - append(textBegin, textEnd); - } + String(const char* str) { append(str); } + String(const char* textBegin, char const* textEnd) { append(textBegin, textEnd); } - // Make all String ctors from a numeric explicit, to avoid unexpected/unnecessary conversions - explicit String(int32_t val, int radix = 10) - { - append(val, radix); - } - explicit String(uint32_t val, int radix = 10) - { - append(val, radix); - } - explicit String(int64_t val, int radix = 10) - { - append(val, radix); - } - explicit String(uint64_t val, int radix = 10) - { - append(val, radix); - } - explicit String(StableHashCode32 val) - { - append(val); - } - explicit String(StableHashCode64 val) - { - append(val); - } - explicit String(float val, const char* format = "%g") - { - append(val, format); - } - explicit String(double val, const char* format = "%g") - { - append(val, format); - } + // Make all String ctors from a numeric explicit, to avoid unexpected/unnecessary conversions + explicit String(int32_t val, int radix = 10) { append(val, radix); } + explicit String(uint32_t val, int radix = 10) { append(val, radix); } + explicit String(int64_t val, int radix = 10) { append(val, radix); } + explicit String(uint64_t val, int radix = 10) { append(val, radix); } + explicit String(StableHashCode32 val) { append(val); } + explicit String(StableHashCode64 val) { append(val); } + explicit String(float val, const char* format = "%g") { append(val, format); } + explicit String(double val, const char* format = "%g") { append(val, format); } - explicit String(char chr) - { - appendChar(chr); - } - String(String const& str) - { - m_buffer = str.m_buffer; - } - String(String&& other) - { - m_buffer = _Move(other.m_buffer); - } + explicit String(char chr) { appendChar(chr); } + String(String const& str) { m_buffer = str.m_buffer; } + String(String&& other) { m_buffer = _Move(other.m_buffer); } - String(StringSlice const& slice) - { - append(slice); - } + String(StringSlice const& slice) { append(slice); } - String(UnownedStringSlice const& slice) - { - append(slice); - } + String(UnownedStringSlice const& slice) { append(slice); } - ~String() - { - m_buffer.setNull(); - } + ~String() { m_buffer.setNull(); } - String& operator=(const String& str) - { - m_buffer = str.m_buffer; - return *this; - } - String& operator=(String&& other) - { - m_buffer = _Move(other.m_buffer); - return *this; - } - char operator[](Index id) const - { - SLANG_ASSERT(id >= 0 && id < getLength()); - // Silence a pedantic warning on GCC + String& operator=(const String& str) + { + m_buffer = str.m_buffer; + return *this; + } + String& operator=(String&& other) + { + m_buffer = _Move(other.m_buffer); + return *this; + } + char operator[](Index id) const + { + SLANG_ASSERT(id >= 0 && id < getLength()); + // Silence a pedantic warning on GCC #if __GNUC__ - if(id < 0) __builtin_unreachable(); + if (id < 0) + __builtin_unreachable(); #endif - return begin()[id]; - } + return begin()[id]; + } - Index getLength() const - { - return m_buffer ? m_buffer->getLength() : 0; - } - /// Make the length of the string the amount specified. Must be less than current size - void reduceLength(Index length); - - friend String operator+(const char*op1, const String & op2); - friend String operator+(const String & op1, const char * op2); - friend String operator+(const String & op1, const String & op2); - - StringSlice trimStart() const - { - if (!m_buffer) - return StringSlice(); - Index startIndex = 0; - const char*const data = getData(); - while (startIndex < getLength() && - (data[startIndex] == ' ' || data[startIndex] == '\t' || data[startIndex] == '\r' || data[startIndex] == '\n')) - startIndex++; - return StringSlice(m_buffer, startIndex, getLength()); - } + Index getLength() const { return m_buffer ? m_buffer->getLength() : 0; } + /// Make the length of the string the amount specified. Must be less than current size + void reduceLength(Index length); - StringSlice trimEnd() const - { - if (!m_buffer) - return StringSlice(); + friend String operator+(const char* op1, const String& op2); + friend String operator+(const String& op1, const char* op2); + friend String operator+(const String& op1, const String& op2); - Index endIndex = getLength(); - const char*const data = getData(); - while (endIndex > 0 && - (data[endIndex-1] == ' ' || data[endIndex-1] == '\t' || data[endIndex-1] == '\r' || data[endIndex-1] == '\n')) - endIndex--; + StringSlice trimStart() const + { + if (!m_buffer) + return StringSlice(); + Index startIndex = 0; + const char* const data = getData(); + while (startIndex < getLength() && (data[startIndex] == ' ' || data[startIndex] == '\t' || + data[startIndex] == '\r' || data[startIndex] == '\n')) + startIndex++; + return StringSlice(m_buffer, startIndex, getLength()); + } - return StringSlice(m_buffer, 0, endIndex); - } + StringSlice trimEnd() const + { + if (!m_buffer) + return StringSlice(); - StringSlice trim() const - { - if (!m_buffer) - return StringSlice(); - - Index startIndex = 0; - const char*const data = getData(); - while (startIndex < getLength() && - (data[startIndex] == ' ' || data[startIndex] == '\t' || data[startIndex] == '\r' || data[startIndex] == '\n')) - startIndex++; - Index endIndex = getLength(); - while (endIndex > startIndex && - (data[endIndex-1] == ' ' || data[endIndex-1] == '\t' || data[endIndex-1] == '\r' || data[endIndex-1] == '\n')) - endIndex--; - - return StringSlice(m_buffer, startIndex, endIndex); - } + Index endIndex = getLength(); + const char* const data = getData(); + while (endIndex > 0 && (data[endIndex - 1] == ' ' || data[endIndex - 1] == '\t' || + data[endIndex - 1] == '\r' || data[endIndex - 1] == '\n')) + endIndex--; - StringSlice subString(Index id, Index len) const - { - if (len == 0) - return StringSlice(); + return StringSlice(m_buffer, 0, endIndex); + } + + StringSlice trim() const + { + if (!m_buffer) + return StringSlice(); + + Index startIndex = 0; + const char* const data = getData(); + while (startIndex < getLength() && (data[startIndex] == ' ' || data[startIndex] == '\t' || + data[startIndex] == '\r' || data[startIndex] == '\n')) + startIndex++; + Index endIndex = getLength(); + while (endIndex > startIndex && (data[endIndex - 1] == ' ' || data[endIndex - 1] == '\t' || + data[endIndex - 1] == '\r' || data[endIndex - 1] == '\n')) + endIndex--; + + return StringSlice(m_buffer, startIndex, endIndex); + } + + StringSlice subString(Index id, Index len) const + { + if (len == 0) + return StringSlice(); - if (id + len > getLength()) - len = getLength() - id; + if (id + len > getLength()) + len = getLength() - id; #if _DEBUG - if (id < 0 || id >= getLength() || (id + len) > getLength()) - SLANG_ASSERT_FAILURE("SubString: index out of range."); - if (len < 0) - SLANG_ASSERT_FAILURE("SubString: length less than zero."); + if (id < 0 || id >= getLength() || (id + len) > getLength()) + SLANG_ASSERT_FAILURE("SubString: index out of range."); + if (len < 0) + SLANG_ASSERT_FAILURE("SubString: length less than zero."); #endif - return StringSlice(m_buffer, id, id + len); - } + return StringSlice(m_buffer, id, id + len); + } - char const* getBuffer() const - { - return getData(); - } + char const* getBuffer() const { return getData(); } - OSString toWString(Index* len = 0) const; + OSString toWString(Index* len = 0) const; - bool equals(const String& str, bool caseSensitive = true) + bool equals(const String& str, bool caseSensitive = true) + { + if (caseSensitive) + return (strcmp(begin(), str.begin()) == 0); + else { - if (caseSensitive) - return (strcmp(begin(), str.begin()) == 0); - else - { #ifdef _MSC_VER - return (_stricmp(begin(), str.begin()) == 0); + return (_stricmp(begin(), str.begin()) == 0); #else - return (strcasecmp(begin(), str.begin()) == 0); + return (strcasecmp(begin(), str.begin()) == 0); #endif - } - } - bool operator==(const char* strbuffer) const - { - return (strcmp(begin(), strbuffer) == 0); - } - - bool operator==(const String& str) const - { - return (strcmp(begin(), str.begin()) == 0); - } - bool operator!=(const char* strbuffer) const - { - return (strcmp(begin(), strbuffer) != 0); - } - bool operator!=(const String& str) const - { - return (strcmp(begin(), str.begin()) != 0); - } - bool operator>(const String& str) const - { - return (strcmp(begin(), str.begin()) > 0); - } - bool operator<(const String& str) const - { - return (strcmp(begin(), str.begin()) < 0); - } - bool operator>=(const String& str) const - { - return (strcmp(begin(), str.begin()) >= 0); - } - bool operator<=(const String& str) const - { - return (strcmp(begin(), str.begin()) <= 0); } + } + bool operator==(const char* strbuffer) const { return (strcmp(begin(), strbuffer) == 0); } - SLANG_FORCE_INLINE bool operator==(const UnownedStringSlice& slice) const { return getUnownedSlice() == slice; } - SLANG_FORCE_INLINE bool operator!=(const UnownedStringSlice& slice) const { return getUnownedSlice() != slice; } + bool operator==(const String& str) const { return (strcmp(begin(), str.begin()) == 0); } + bool operator!=(const char* strbuffer) const { return (strcmp(begin(), strbuffer) != 0); } + bool operator!=(const String& str) const { return (strcmp(begin(), str.begin()) != 0); } + bool operator>(const String& str) const { return (strcmp(begin(), str.begin()) > 0); } + bool operator<(const String& str) const { return (strcmp(begin(), str.begin()) < 0); } + bool operator>=(const String& str) const { return (strcmp(begin(), str.begin()) >= 0); } + bool operator<=(const String& str) const { return (strcmp(begin(), str.begin()) <= 0); } - String toUpper() const - { - String result; - for (auto c : *this) - { - char d = (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c; - result.append(d); - } - return result; - } + SLANG_FORCE_INLINE bool operator==(const UnownedStringSlice& slice) const + { + return getUnownedSlice() == slice; + } + SLANG_FORCE_INLINE bool operator!=(const UnownedStringSlice& slice) const + { + return getUnownedSlice() != slice; + } - String toLower() const + String toUpper() const + { + String result; + for (auto c : *this) { - String result; - for (auto c : *this) - { - char d = (c >= 'A' && c <= 'Z') ? (c - ('A' - 'a')) : c; - result.append(d); - } - return result; + char d = (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c; + result.append(d); } + return result; + } - Index indexOf(const char* str, Index id) const // String str + String toLower() const + { + String result; + for (auto c : *this) { - if (id >= getLength()) - return Index(-1); - auto findRs = strstr(begin() + id, str); - Index res = findRs ? findRs - begin() : Index(-1); - return res; + char d = (c >= 'A' && c <= 'Z') ? (c - ('A' - 'a')) : c; + result.append(d); } + return result; + } - Index indexOf(const String& str, Index id) const - { - return indexOf(str.begin(), id); - } + Index indexOf(const char* str, Index id) const // String str + { + if (id >= getLength()) + return Index(-1); + auto findRs = strstr(begin() + id, str); + Index res = findRs ? findRs - begin() : Index(-1); + return res; + } - Index indexOf(const char* str) const - { - return indexOf(str, 0); - } + Index indexOf(const String& str, Index id) const { return indexOf(str.begin(), id); } - Index indexOf(const String& str) const - { - return indexOf(str.begin(), 0); - } + Index indexOf(const char* str) const { return indexOf(str, 0); } - void swapWith(String& other) - { - m_buffer.swapWith(other.m_buffer); - } + Index indexOf(const String& str) const { return indexOf(str.begin(), 0); } - Index indexOf(char ch, Index id) const - { - const Index length = getLength(); - SLANG_ASSERT(id >= 0 && id <= length); + void swapWith(String& other) { m_buffer.swapWith(other.m_buffer); } - if (!m_buffer) - return Index(-1); + Index indexOf(char ch, Index id) const + { + const Index length = getLength(); + SLANG_ASSERT(id >= 0 && id <= length); - const char* data = getData(); - for (Index i = id; i < length; i++) - if (data[i] == ch) - return i; + if (!m_buffer) return Index(-1); - } - - Index indexOf(char ch) const - { - return indexOf(ch, 0); - } - Index lastIndexOf(char ch) const - { - const Index length = getLength(); - const char* data = getData(); + const char* data = getData(); + for (Index i = id; i < length; i++) + if (data[i] == ch) + return i; + return Index(-1); + } - for (Index i = length - 1; i >= 0; --i) - if (data[i] == ch) - return i; - return Index(-1); - } + Index indexOf(char ch) const { return indexOf(ch, 0); } - bool startsWith(const char* str) const - { - if (!m_buffer) - return false; - Index strLen = Index(::strlen(str)); - if (strLen > getLength()) - return false; + Index lastIndexOf(char ch) const + { + const Index length = getLength(); + const char* data = getData(); - const char*const data = getData(); + for (Index i = length - 1; i >= 0; --i) + if (data[i] == ch) + return i; + return Index(-1); + } - for (Index i = 0; i < strLen; i++) - if (str[i] != data[i]) - return false; - return true; - } + bool startsWith(const char* str) const + { + if (!m_buffer) + return false; + Index strLen = Index(::strlen(str)); + if (strLen > getLength()) + return false; - bool startsWith(const String& str) const - { - return startsWith(str.begin()); - } + const char* const data = getData(); - bool endsWith(char const* str) const // String str - { - if (!m_buffer) + for (Index i = 0; i < strLen; i++) + if (str[i] != data[i]) return false; + return true; + } + + bool startsWith(const String& str) const { return startsWith(str.begin()); } + + bool endsWith(char const* str) const // String str + { + if (!m_buffer) + return false; - const Index strLen = Index(::strlen(str)); - const Index len = getLength(); + const Index strLen = Index(::strlen(str)); + const Index len = getLength(); - if (strLen > len) + if (strLen > len) + return false; + const char* data = getData(); + for (Index i = strLen; i > 0; i--) + if (str[i - 1] != data[len - strLen + i - 1]) return false; - const char* data = getData(); - for (Index i = strLen; i > 0; i--) - if (str[i-1] != data[len - strLen + i-1]) - return false; - return true; - } + return true; + } - bool endsWith(const String& str) const - { - return endsWith(str.begin()); - } + bool endsWith(const String& str) const { return endsWith(str.begin()); } - bool contains(const char* str) const // String str - { - return m_buffer && indexOf(str) != Index(-1); - } + bool contains(const char* str) const // String str + { + return m_buffer && indexOf(str) != Index(-1); + } - bool contains(const String& str) const - { - return contains(str.begin()); - } + bool contains(const String& str) const { return contains(str.begin()); } - static constexpr bool kHasUniformHash = true; - HashCode64 getHashCode() const - { - return Slang::getHashCode(StringRepresentation::asSlice(m_buffer)); - } + static constexpr bool kHasUniformHash = true; + HashCode64 getHashCode() const + { + return Slang::getHashCode(StringRepresentation::asSlice(m_buffer)); + } - UnownedStringSlice getUnownedSlice() const - { - return StringRepresentation::asSlice(m_buffer); - } - }; + UnownedStringSlice getUnownedSlice() const { return StringRepresentation::asSlice(m_buffer); } +}; - class SLANG_RT_API StringBuilder : public String +class SLANG_RT_API StringBuilder : public String +{ +private: + enum { - private: - enum { InitialSize = 1024 }; - public: - typedef String Super; - using Super::append; + InitialSize = 1024 + }; - explicit StringBuilder(UInt bufferSize = InitialSize) - { - ensureUniqueStorageWithCapacity(bufferSize); - } +public: + typedef String Super; + using Super::append; - void ensureCapacity(UInt size) - { - ensureUniqueStorageWithCapacity(size); - } - StringBuilder& operator << (char ch) - { - appendChar(ch); - return *this; - } - StringBuilder& operator << (Int32 val) - { - append(val); - return *this; - } - StringBuilder& operator << (UInt32 val) - { - append(val); - return *this; - } - StringBuilder& operator << (Int64 val) - { - append(val); - return *this; - } - StringBuilder& operator << (UInt64 val) - { - append(val); - return *this; - } - StringBuilder& operator << (float val) - { - append(val); - return *this; - } - StringBuilder& operator << (double val) - { - append(val); - return *this; - } - StringBuilder& operator << (const char* str) - { - append(str, strlen(str)); - return *this; - } - StringBuilder& operator << (const String& str) - { - append(str); - return *this; - } - StringBuilder& operator << (UnownedStringSlice const& str) - { - append(str); - return *this; - } - StringBuilder& operator << (const _EndLine) - { - appendChar('\n'); - return *this; - } + explicit StringBuilder(UInt bufferSize = InitialSize) + { + ensureUniqueStorageWithCapacity(bufferSize); + } - String toString() - { - return *this; - } + void ensureCapacity(UInt size) { ensureUniqueStorageWithCapacity(size); } + StringBuilder& operator<<(char ch) + { + appendChar(ch); + return *this; + } + StringBuilder& operator<<(Int32 val) + { + append(val); + return *this; + } + StringBuilder& operator<<(UInt32 val) + { + append(val); + return *this; + } + StringBuilder& operator<<(Int64 val) + { + append(val); + return *this; + } + StringBuilder& operator<<(UInt64 val) + { + append(val); + return *this; + } + StringBuilder& operator<<(float val) + { + append(val); + return *this; + } + StringBuilder& operator<<(double val) + { + append(val); + return *this; + } + StringBuilder& operator<<(const char* str) + { + append(str, strlen(str)); + return *this; + } + StringBuilder& operator<<(const String& str) + { + append(str); + return *this; + } + StringBuilder& operator<<(UnownedStringSlice const& str) + { + append(str); + return *this; + } + StringBuilder& operator<<(const _EndLine) + { + appendChar('\n'); + return *this; + } - String produceString() - { - return *this; - } + String toString() { return *this; } + + String produceString() { return *this; } #if 0 void Remove(int id, int len) @@ -1000,20 +883,17 @@ namespace Slang length -= actualDelLength; } #endif - friend std::ostream& operator<< (std::ostream& stream, const String& s); + friend std::ostream& operator<<(std::ostream& stream, const String& s); - void clear() - { - m_buffer.setNull(); - } - }; + void clear() { m_buffer.setNull(); } +}; - int stringToInt(const String& str, int radix = 10); - unsigned int stringToUInt(const String& str, int radix = 10); - double stringToDouble(const String& str); - float stringToFloat(const String& str); -} +int stringToInt(const String& str, int radix = 10); +unsigned int stringToUInt(const String& str, int radix = 10); +double stringToDouble(const String& str); +float stringToFloat(const String& str); +} // namespace Slang -std::ostream& operator<< (std::ostream& stream, const Slang::String& s); +std::ostream& operator<<(std::ostream& stream, const Slang::String& s); #endif diff --git a/source/core/slang-test-tool-util.cpp b/source/core/slang-test-tool-util.cpp index d362d7043..a71048f10 100644 --- a/source/core/slang-test-tool-util.cpp +++ b/source/core/slang-test-tool-util.cpp @@ -2,29 +2,28 @@ #include "slang-test-tool-util.h" #include "slang-com-helper.h" - #include "slang-io.h" #include "slang-string-util.h" namespace Slang { -/* static */ToolReturnCode TestToolUtil::getReturnCode(SlangResult res) +/* static */ ToolReturnCode TestToolUtil::getReturnCode(SlangResult res) { switch (res) { - case SLANG_OK: return ToolReturnCode::Success; - case SLANG_E_INTERNAL_FAIL: return ToolReturnCode::CompilationFailed; - case SLANG_FAIL: return ToolReturnCode::Failed; - case SLANG_E_NOT_AVAILABLE: return ToolReturnCode::Ignored; - default: + case SLANG_OK: return ToolReturnCode::Success; + case SLANG_E_INTERNAL_FAIL: return ToolReturnCode::CompilationFailed; + case SLANG_FAIL: return ToolReturnCode::Failed; + case SLANG_E_NOT_AVAILABLE: return ToolReturnCode::Ignored; + default: { return (SLANG_SUCCEEDED(res)) ? ToolReturnCode::Success : ToolReturnCode::Failed; } } } -/* static */ToolReturnCode TestToolUtil::getReturnCodeFromInt(int code) +/* static */ ToolReturnCode TestToolUtil::getReturnCodeFromInt(int code) { if (code >= int(ToolReturnCodeSpan::First) && code <= int(ToolReturnCodeSpan::Last)) { @@ -37,7 +36,7 @@ namespace Slang } } -/* static */bool TestToolUtil::hasDeferredCoreModule(Index argc, const char*const* argv) +/* static */ bool TestToolUtil::hasDeferredCoreModule(Index argc, const char* const* argv) { for (Index i = 0; i < argc; ++i) { @@ -50,7 +49,10 @@ namespace Slang return false; } -/* static */SlangResult TestToolUtil::getIncludePath(const String& parentPath, const char* path, String& outIncludePath) +/* static */ SlangResult TestToolUtil::getIncludePath( + const String& parentPath, + const char* path, + String& outIncludePath) { String includePath; SLANG_RETURN_ON_FAIL(Path::getCanonical(Path::combine(parentPath, path), includePath)); @@ -73,7 +75,10 @@ static SlangResult _addCPPPrelude(const String& rootPath, slang::IGlobalSession* String includePath; SlangResult res = SLANG_FAIL; if (SLANG_FAILED(res)) - res = TestToolUtil::getIncludePath(Path::combine(rootPath, "include"), "slang-cpp-prelude.h", includePath); + res = TestToolUtil::getIncludePath( + Path::combine(rootPath, "include"), + "slang-cpp-prelude.h", + includePath); if (SLANG_FAILED(res)) res = TestToolUtil::getIncludePath(rootPath, "prelude/slang-cpp-prelude.h", includePath); SLANG_RETURN_ON_FAIL(res); @@ -88,7 +93,10 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession String includePath; SlangResult res = SLANG_FAIL; if (SLANG_FAILED(res)) - res = TestToolUtil::getIncludePath(Path::combine(rootPath, "include"), "slang-cuda-prelude.h", includePath); + res = TestToolUtil::getIncludePath( + Path::combine(rootPath, "include"), + "slang-cuda-prelude.h", + includePath); if (SLANG_FAILED(res)) res = TestToolUtil::getIncludePath(rootPath, "prelude/slang-cuda-prelude.h", includePath); SLANG_RETURN_ON_FAIL(res); @@ -98,7 +106,9 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession return SLANG_OK; } -/* static */SlangResult TestToolUtil::getExeDirectoryPath(const char* exePath, String& outExeDirectoryPath) +/* static */ SlangResult TestToolUtil::getExeDirectoryPath( + const char* exePath, + String& outExeDirectoryPath) { String canonicalPath; SLANG_RETURN_ON_FAIL(Path::getCanonical(exePath, canonicalPath)); @@ -107,7 +117,9 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession return SLANG_OK; } -/* static */SlangResult TestToolUtil::getDllDirectoryPath(const char* exePath, String& outDllDirectoryPath) +/* static */ SlangResult TestToolUtil::getDllDirectoryPath( + const char* exePath, + String& outDllDirectoryPath) { String canonicalPath; SLANG_RETURN_ON_FAIL(Path::getCanonical(exePath, canonicalPath)); @@ -115,7 +127,8 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession // Get the directory String binPath = Path::getParentDirectory(canonicalPath); - // Windows puts the dlls in the same directory as the exe, while on other platforms they are in a 'lib' directory + // Windows puts the dlls in the same directory as the exe, while on other platforms they are in + // a 'lib' directory #ifdef _WIN32 outDllDirectoryPath = binPath; #else @@ -125,7 +138,7 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession return SLANG_OK; } -/* static */SlangResult TestToolUtil::getRootPath(const char* inExePath, String& outExePath) +/* static */ SlangResult TestToolUtil::getRootPath(const char* inExePath, String& outExePath) { // Get the directory holding the exe String parentPath; @@ -137,21 +150,23 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession SLANG_RETURN_ON_FAIL(Path::getCanonical(parentPath, rootRelPath)); do { - if(File::exists(Path::combine(rootRelPath, "include/slang-cpp-prelude.h"))) + if (File::exists(Path::combine(rootRelPath, "include/slang-cpp-prelude.h"))) break; - if(File::exists(Path::combine(rootRelPath, "prelude/slang-cpp-prelude.h"))) + if (File::exists(Path::combine(rootRelPath, "prelude/slang-cpp-prelude.h"))) break; rootRelPath = Path::getParentDirectory(rootRelPath); - if(rootRelPath == "") + if (rootRelPath == "") return SLANG_E_NOT_AVAILABLE; - } while(1); + } while (1); outExePath = std::move(rootRelPath); return SLANG_OK; } -/* static */SlangResult TestToolUtil::setSessionDefaultPreludeFromExePath(const char* inExePath, slang::IGlobalSession* session) +/* static */ SlangResult TestToolUtil::setSessionDefaultPreludeFromExePath( + const char* inExePath, + slang::IGlobalSession* session) { String rootPath; SLANG_RETURN_ON_FAIL(getRootPath(inExePath, rootPath)); @@ -159,10 +174,12 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession return SLANG_OK; } -/* static */SlangResult TestToolUtil::setSessionDefaultPreludeFromRootPath(const String& rootPath, slang::IGlobalSession* session) +/* static */ SlangResult TestToolUtil::setSessionDefaultPreludeFromRootPath( + const String& rootPath, + slang::IGlobalSession* session) { // Set the prelude to a path - + if (SLANG_FAILED(_addCPPPrelude(rootPath, session))) { SLANG_ASSERT(!"Couldn't find the C++ prelude relative to the executable"); @@ -172,9 +189,8 @@ static SlangResult _addCUDAPrelude(const String& rootPath, slang::IGlobalSession { SLANG_ASSERT(!"Couldn't find the CUDA prelude relative to the executable"); } - - return SLANG_OK; -} + return SLANG_OK; } +} // namespace Slang diff --git a/source/core/slang-test-tool-util.h b/source/core/slang-test-tool-util.h index 967dc0fa8..241166111 100644 --- a/source/core/slang-test-tool-util.h +++ b/source/core/slang-test-tool-util.h @@ -3,24 +3,27 @@ #include "slang-std-writers.h" -namespace Slang { +namespace Slang +{ #ifdef SLANG_SHARED_LIBRARY_TOOL -# define SLANG_TEST_TOOL_API SLANG_EXTERN_C SLANG_DLL_EXPORT +#define SLANG_TEST_TOOL_API SLANG_EXTERN_C SLANG_DLL_EXPORT #else -# define SLANG_TEST_TOOL_API +#define SLANG_TEST_TOOL_API #endif /* When a tool is run as an executable the return code is the code returned from -the last return of main. On unix this can be up to 8 bits. +the last return of main. On unix this can be up to 8 bits. By normal command line tool conventions returning 0 means success. */ enum class ToolReturnCode { - CompilationFailed = -1, ///< Compilation failure (-1 to maintain compatibility). This may still produce output and may mean a test was successful. - Success = 0, ///< Tool ran normally - Failed, ///< Tool failed - Ignored, ///< The run was ignored because it couldn't be run (because some optional feature was not present for example) - FailedToRun, ///< Could not even run the test + CompilationFailed = -1, ///< Compilation failure (-1 to maintain compatibility). This may still + ///< produce output and may mean a test was successful. + Success = 0, ///< Tool ran normally + Failed, ///< Tool failed + Ignored, ///< The run was ignored because it couldn't be run (because some optional feature was + ///< not present for example) + FailedToRun, ///< Could not even run the test }; enum class ToolReturnCodeSpan @@ -36,36 +39,53 @@ enum class ToolReturnCodeSpan /* Utility functions for 'test tools' */ struct TestToolUtil { - typedef SlangResult(*InnerMainFunc)(Slang::StdWriters* stdWriters, SlangSession* session, int argc, const char*const* argv); - - /// If the test failed to run or was ignored then we are done - static bool isDone(ToolReturnCode code) { return int(code) >= int(ToolReturnCodeSpan::FirstIsDone) && int(code) <= int(ToolReturnCodeSpan::LastIsDone); } - - /// Convert from an int + typedef SlangResult (*InnerMainFunc)( + Slang::StdWriters* stdWriters, + SlangSession* session, + int argc, + const char* const* argv); + + /// If the test failed to run or was ignored then we are done + static bool isDone(ToolReturnCode code) + { + return int(code) >= int(ToolReturnCodeSpan::FirstIsDone) && + int(code) <= int(ToolReturnCodeSpan::LastIsDone); + } + + /// Convert from an int static ToolReturnCode getReturnCodeFromInt(int code); - /// Given a slang result, returns a return code that can be returned from an executable + /// Given a slang result, returns a return code that can be returned from an executable static ToolReturnCode getReturnCode(SlangResult res); - /// Given the executable path (as located in Slang directory hierarchy), works out the absolute path to the root + /// Given the executable path (as located in Slang directory hierarchy), works out the absolute + /// path to the root static SlangResult getRootPath(const char* exePath, String& outRootPath); - /// Given the exePath, give return the absolute path to the directory the exe is in + /// Given the exePath, give return the absolute path to the directory the exe is in static SlangResult getExeDirectoryPath(const char* exePath, String& outExeDirectoryPath); - /// Sets the default preludes on the session based on an explicit path - static SlangResult setSessionDefaultPreludeFromRootPath(const String& rootPath, slang::IGlobalSession* session); + /// Sets the default preludes on the session based on an explicit path + static SlangResult setSessionDefaultPreludeFromRootPath( + const String& rootPath, + slang::IGlobalSession* session); + + /// Calculates the path that is the combination of parentPath, and relPath + /// And converts such that can be used as an include path (handling slashes) + static SlangResult getIncludePath( + const String& parentPath, + const char* relPath, + String& outIncludePath); - /// Calculates the path that is the combination of parentPath, and relPath - /// And converts such that can be used as an include path (handling slashes) - static SlangResult getIncludePath(const String& parentPath, const char* relPath, String& outIncludePath); - - /// Sets the default preludes on the session based on the executable path - static SlangResult setSessionDefaultPreludeFromExePath(const char* exePath, slang::IGlobalSession* session); + /// Sets the default preludes on the session based on the executable path + static SlangResult setSessionDefaultPreludeFromExePath( + const char* exePath, + slang::IGlobalSession* session); - /// Returns true if the core module should not be initialized immediately (eg when doing a -load-core-module). - static bool hasDeferredCoreModule(Index numArgs, const char*const* args); + /// Returns true if the core module should not be initialized immediately (eg when doing a + /// -load-core-module). + static bool hasDeferredCoreModule(Index numArgs, const char* const* args); static SlangResult getDllDirectoryPath(const char* exePath, String& outDllDirectoryPath); }; diff --git a/source/core/slang-text-io.cpp b/source/core/slang-text-io.cpp index f7257c1ee..9cc3896fd 100644 --- a/source/core/slang-text-io.cpp +++ b/source/core/slang-text-io.cpp @@ -16,16 +16,16 @@ SlangResult StreamWriter::init(const String& path, CharEncoding* encoding) SlangResult StreamWriter::init(RefPtr<Stream> stream, CharEncoding* encoding) { - m_stream = stream; - m_encoding = encoding; - if (encoding == CharEncoding::UTF16) - { - SLANG_RETURN_ON_FAIL(m_stream->write(&kUTF16Header, 2)); - } - else if (encoding == CharEncoding::UTF16Reversed) - { - SLANG_RETURN_ON_FAIL(m_stream->write(&kUTF16ReversedHeader, 2)); - } + m_stream = stream; + m_encoding = encoding; + if (encoding == CharEncoding::UTF16) + { + SLANG_RETURN_ON_FAIL(m_stream->write(&kUTF16Header, 2)); + } + else if (encoding == CharEncoding::UTF16Reversed) + { + SLANG_RETURN_ON_FAIL(m_stream->write(&kUTF16ReversedHeader, 2)); + } return SLANG_OK; } @@ -33,42 +33,42 @@ SlangResult StreamWriter::init(RefPtr<Stream> stream, CharEncoding* encoding) SlangResult StreamWriter::writeSlice(const UnownedStringSlice& slice) { // TODO(JS): - // We can do better here. On Linux, this is a no-op and can just write directly (assuming slice only contains \n) - - m_encodingBuffer.clear(); + // We can do better here. On Linux, this is a no-op and can just write directly (assuming slice + // only contains \n) + + m_encodingBuffer.clear(); StringBuilder sb; #ifdef _WIN32 - const char newLine[] = "\r\n"; + const char newLine[] = "\r\n"; #else - const char newLine[] = "\n"; + const char newLine[] = "\n"; #endif const Index length = slice.getLength(); - - for (Index i = 0; i < length; i++) - { - if (slice[i] == '\r') - sb << newLine; - else if (slice[i] == '\n') - { - if (i > 0 && slice[i - 1] != '\r') - sb << newLine; - } - else - sb << slice[i]; - } - - // NOTE! This assumes that sb contains *complete* utf8 code points, which it might not, as encoder is only able to handle complete code points. + + for (Index i = 0; i < length; i++) + { + if (slice[i] == '\r') + sb << newLine; + else if (slice[i] == '\n') + { + if (i > 0 && slice[i - 1] != '\r') + sb << newLine; + } + else + sb << slice[i]; + } + + // NOTE! This assumes that sb contains *complete* utf8 code points, which it might not, as + // encoder is only able to handle complete code points. m_encodingBuffer.clear(); - m_encoding->encode(sb.getUnownedSlice(), m_encodingBuffer); - return m_stream->write(m_encodingBuffer.getBuffer(), m_encodingBuffer.getCount()); + m_encoding->encode(sb.getUnownedSlice(), m_encodingBuffer); + return m_stream->write(m_encodingBuffer.getBuffer(), m_encodingBuffer.getCount()); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StreamReader !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -StreamReader::StreamReader() -{ -} +StreamReader::StreamReader() {} SlangResult StreamReader::init(const String& path) { @@ -81,12 +81,15 @@ SlangResult StreamReader::init(RefPtr<Stream> stream, CharEncoding* encoding) { m_stream = stream; m_encoding = encoding; - SLANG_RETURN_ON_FAIL(readBuffer()); + SLANG_RETURN_ON_FAIL(readBuffer()); if (encoding == nullptr) { size_t offset; - m_encodingType = CharEncoding::determineEncoding((const Byte*)m_buffer.getBuffer(), m_buffer.getCount(), offset); + m_encodingType = CharEncoding::determineEncoding( + (const Byte*)m_buffer.getBuffer(), + m_buffer.getCount(), + offset); m_encoding = CharEncoding::getEncoding(m_encodingType); m_index = Index(offset); } @@ -98,7 +101,7 @@ SlangResult StreamReader::init(RefPtr<Stream> stream, CharEncoding* encoding) return SLANG_OK; } - + SlangResult StreamReader::readBuffer() { m_buffer.setCount(0); @@ -109,7 +112,7 @@ SlangResult StreamReader::readBuffer() return SLANG_OK; } - m_buffer.setCount(4096); + m_buffer.setCount(4096); // TODO(JS): Not clear this is necessary memset(m_buffer.getBuffer(), 0, m_buffer.getCount() * sizeof(m_buffer[0])); @@ -117,46 +120,46 @@ SlangResult StreamReader::readBuffer() size_t readBytes; SLANG_RETURN_ON_FAIL(m_stream->read(m_buffer.getBuffer(), m_buffer.getCount(), readBytes)); - m_buffer.setCount(Index(readBytes)); - m_index = 0; + m_buffer.setCount(Index(readBytes)); + m_index = 0; return SLANG_OK; } char StreamReader::readBufferChar() { - if (m_index < m_buffer.getCount()) - { - return m_buffer[m_index++]; - } + if (m_index < m_buffer.getCount()) + { + return m_buffer[m_index++]; + } - readBuffer(); + readBuffer(); if (m_index < m_buffer.getCount()) - { - return m_buffer[m_index++]; - } - return 0; + { + return m_buffer[m_index++]; + } + return 0; } SlangResult StreamReader::readToEnd(String& outString) { - StringBuilder sb(16384); - while (!isEnd()) - { - auto ch = read(); - if (isEnd()) - break; - if (ch == '\r') - { - sb.append('\n'); - if (peek() == '\n') - read(); - } - else - sb.append(ch); - } - - outString = sb.produceString(); + StringBuilder sb(16384); + while (!isEnd()) + { + auto ch = read(); + if (isEnd()) + break; + if (ch == '\r') + { + sb.append('\n'); + if (peek() == '\n') + read(); + } + else + sb.append(ch); + } + + outString = sb.produceString(); return SLANG_OK; } diff --git a/source/core/slang-text-io.h b/source/core/slang-text-io.h index 0ee381c46..7c13ebec8 100644 --- a/source/core/slang-text-io.h +++ b/source/core/slang-text-io.h @@ -1,9 +1,9 @@ #ifndef SLANG_CORE_TEXT_IO_H #define SLANG_CORE_TEXT_IO_H +#include "slang-char-encode.h" #include "slang-secure-crt.h" #include "slang-stream.h" -#include "slang-char-encode.h" namespace Slang { @@ -12,29 +12,29 @@ using Slang::_EndLine; class TextReader { -public: - virtual void close(){} +public: + virtual void close() {} virtual SlangResult readToEnd(String& outString) = 0; - virtual bool isEnd() = 0; - - char read() - { - if (m_decodedCharIndex == m_decodedCharSize) - readChar(); - if (m_decodedCharIndex < m_decodedCharSize) - return m_decodedChar[m_decodedCharIndex++]; - else - return 0; - } - char peek() - { - if (m_decodedCharIndex == m_decodedCharSize) - readChar(); - if (m_decodedCharIndex < m_decodedCharSize) - return m_decodedChar[m_decodedCharIndex]; - else - return 0; - } + virtual bool isEnd() = 0; + + char read() + { + if (m_decodedCharIndex == m_decodedCharSize) + readChar(); + if (m_decodedCharIndex < m_decodedCharSize) + return m_decodedChar[m_decodedCharIndex++]; + else + return 0; + } + char peek() + { + if (m_decodedCharIndex == m_decodedCharSize) + readChar(); + if (m_decodedCharIndex < m_decodedCharSize) + return m_decodedChar[m_decodedCharIndex]; + else + return 0; + } virtual ~TextReader() { close(); } @@ -51,7 +51,10 @@ class StreamReader : public TextReader { public: virtual SlangResult readToEnd(String& outString) SLANG_OVERRIDE; - virtual bool isEnd() SLANG_OVERRIDE { return m_index == m_buffer.getCount() && m_stream->isEnd(); } + virtual bool isEnd() SLANG_OVERRIDE + { + return m_index == m_buffer.getCount() && m_stream->isEnd(); + } virtual void close() SLANG_OVERRIDE { m_stream->close(); } void releaseStream() { m_stream.setNull(); } @@ -69,24 +72,25 @@ protected: Char32 codePoint = 0; switch (m_encodingType) { - case CharEncodeType::UTF8: + case CharEncodeType::UTF8: { - codePoint = getUnicodePointFromUTF8([&]() -> Byte {return readBufferChar(); }); + codePoint = getUnicodePointFromUTF8([&]() -> Byte { return readBufferChar(); }); break; } - case CharEncodeType::UTF16: + case CharEncodeType::UTF16: { - codePoint = getUnicodePointFromUTF16([&]() -> Byte {return readBufferChar(); }); + codePoint = getUnicodePointFromUTF16([&]() -> Byte { return readBufferChar(); }); break; } - case CharEncodeType::UTF16Reversed: + case CharEncodeType::UTF16Reversed: { - codePoint = getUnicodePointFromUTF16Reversed([&]() -> Byte {return readBufferChar(); }); + codePoint = + getUnicodePointFromUTF16Reversed([&]() -> Byte { return readBufferChar(); }); break; } - case CharEncodeType::UTF32: + case CharEncodeType::UTF32: { - codePoint = getUnicodePointFromUTF32([&]() -> Byte {return readBufferChar(); }); + codePoint = getUnicodePointFromUTF32([&]() -> Byte { return readBufferChar(); }); break; } } @@ -97,21 +101,20 @@ protected: private: char readBufferChar(); SlangResult readBuffer(); - + RefPtr<Stream> m_stream; List<char> m_buffer; CharEncodeType m_encodingType = CharEncodeType::UTF8; CharEncoding* m_encoding = nullptr; - Index m_index = 0; ///< Index into buffer + Index m_index = 0; ///< Index into buffer }; class TextWriter { public: - - virtual SlangResult writeSlice(const UnownedStringSlice& slice) = 0; - virtual void close(){} + virtual SlangResult writeSlice(const UnownedStringSlice& slice) = 0; + virtual void close() {} SlangResult write(const UnownedStringSlice& slice) { return writeSlice(slice); } SlangResult write(const char* str) { return writeSlice(UnownedStringSlice(str)); } @@ -119,59 +122,59 @@ public: virtual ~TextWriter() { close(); } - template<typename T> - TextWriter& operator << (const T& val) - { - write(val.ToString()); - return *this; - } - TextWriter& operator << (int value) - { - write(String(value)); - return *this; - } - TextWriter& operator << (float value) - { - write(String(value)); - return *this; - } - TextWriter& operator << (double value) - { - write(String(value)); - return *this; - } - TextWriter& operator << (const char* value) - { - writeSlice(UnownedStringSlice(value)); - return *this; - } - TextWriter& operator << (const String & val) - { - writeSlice(val.getUnownedSlice()); - return *this; - } - TextWriter& operator << (const _EndLine &) - { + template<typename T> + TextWriter& operator<<(const T& val) + { + write(val.ToString()); + return *this; + } + TextWriter& operator<<(int value) + { + write(String(value)); + return *this; + } + TextWriter& operator<<(float value) + { + write(String(value)); + return *this; + } + TextWriter& operator<<(double value) + { + write(String(value)); + return *this; + } + TextWriter& operator<<(const char* value) + { + writeSlice(UnownedStringSlice(value)); + return *this; + } + TextWriter& operator<<(const String& val) + { + writeSlice(val.getUnownedSlice()); + return *this; + } + TextWriter& operator<<(const _EndLine&) + { #ifdef _WIN32 - writeSlice(UnownedStringSlice::fromLiteral("\r\n")); + writeSlice(UnownedStringSlice::fromLiteral("\r\n")); #else - writeSlice(UnownedStringSlice::fromLiteral("\n")); + writeSlice(UnownedStringSlice::fromLiteral("\n")); #endif - return *this; - } + return *this; + } }; - + class StreamWriter : public TextWriter { public: - // TextWriter + // TextWriter virtual SlangResult writeSlice(const UnownedStringSlice& slice) SLANG_OVERRIDE; virtual void close() SLANG_OVERRIDE { m_stream->close(); } - void releaseStream() { m_stream.setNull(); } + void releaseStream() { m_stream.setNull(); } StreamWriter() {} - + SlangResult init(const String& path, CharEncoding* encoding = CharEncoding::UTF8); SlangResult init(RefPtr<Stream> stream, CharEncoding* encoding = CharEncoding::UTF8); @@ -181,6 +184,6 @@ private: CharEncoding* m_encoding = nullptr; }; -} +} // namespace Slang #endif diff --git a/source/core/slang-token-reader.cpp b/source/core/slang-token-reader.cpp index e8ebfb9ec..d37ee0ed4 100644 --- a/source/core/slang-token-reader.cpp +++ b/source/core/slang-token-reader.cpp @@ -1,462 +1,475 @@ #include "slang-token-reader.h" -namespace Slang { -namespace Misc { +namespace Slang +{ +namespace Misc +{ - enum class TokenizeErrorType - { - InvalidCharacter, InvalidEscapeSequence - }; +enum class TokenizeErrorType +{ + InvalidCharacter, + InvalidEscapeSequence +}; - enum class State - { - Start, Identifier, Operator, Int, Hex, Fixed, Double, Char, String, MultiComment, SingleComment - }; +enum class State +{ + Start, + Identifier, + Operator, + Int, + Hex, + Fixed, + Double, + Char, + String, + MultiComment, + SingleComment +}; - enum class LexDerivative - { - None, Line, File - }; +enum class LexDerivative +{ + None, + Line, + File +}; - inline bool IsLetter(char ch) - { - return ((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || ch == '_'); - } +inline bool IsLetter(char ch) +{ + return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'); +} - inline bool IsDigit(char ch) - { - return ch >= '0' && ch <= '9'; - } +inline bool IsDigit(char ch) +{ + return ch >= '0' && ch <= '9'; +} - inline bool IsPunctuation(char ch) - { - return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || - ch == '!' || ch == '^' || ch == '&' || ch == '(' || ch == ')' || - ch == '=' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || - ch == '|' || ch == ';' || ch == ',' || ch == '.' || ch == '<' || - ch == '>' || ch == '~' || ch == '@' || ch == ':' || ch == '?' || ch == '#'; - } +inline bool IsPunctuation(char ch) +{ + return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '!' || + ch == '^' || ch == '&' || ch == '(' || ch == ')' || ch == '=' || ch == '{' || + ch == '}' || ch == '[' || ch == ']' || ch == '|' || ch == ';' || ch == ',' || + ch == '.' || ch == '<' || ch == '>' || ch == '~' || ch == '@' || ch == ':' || + ch == '?' || ch == '#'; +} - inline bool IsWhiteSpace(char ch) - { - return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v'); - } +inline bool IsWhiteSpace(char ch) +{ + return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v'); +} - void ParseOperators(const String & str, List<Token> & tokens, TokenFlags& tokenFlags, int line, int col, int startPos, String fileName) +void ParseOperators( + const String& str, + List<Token>& tokens, + TokenFlags& tokenFlags, + int line, + int col, + int startPos, + String fileName) +{ + Index pos = 0; + while (pos < str.getLength()) { - Index pos = 0; - while (pos < str.getLength()) + wchar_t curChar = str[pos]; + wchar_t nextChar = (pos < str.getLength() - 1) ? str[pos + 1] : '\0'; + wchar_t nextNextChar = (pos < str.getLength() - 2) ? str[pos + 2] : '\0'; + auto InsertToken = [&](TokenType type, const String& ct) { - wchar_t curChar = str[pos]; - wchar_t nextChar = (pos < str.getLength() - 1) ? str[pos + 1] : '\0'; - wchar_t nextNextChar = (pos < str.getLength() - 2) ? str[pos + 2] : '\0'; - auto InsertToken = [&](TokenType type, const String & ct) - { - tokens.add(Token(type, ct, line, int(col + pos), int(pos + startPos), fileName, tokenFlags)); - tokenFlags = 0; - }; - switch (curChar) - { - case '+': - if (nextChar == '+') - { - InsertToken(TokenType::OpInc, "++"); - pos += 2; - } - else if (nextChar == '=') - { - InsertToken(TokenType::OpAddAssign, "+="); - pos += 2; - } - else - { - InsertToken(TokenType::OpAdd, "+"); - pos++; - } - break; - case '-': - if (nextChar == '-') - { - InsertToken(TokenType::OpDec, "--"); - pos += 2; - } - else if (nextChar == '=') - { - InsertToken(TokenType::OpSubAssign, "-="); - pos += 2; - } - else if (nextChar == '>') - { - InsertToken(TokenType::RightArrow, "->"); - pos += 2; - } - else - { - InsertToken(TokenType::OpSub, "-"); - pos++; - } - break; - case '*': - if (nextChar == '=') - { - InsertToken(TokenType::OpMulAssign, "*="); - pos += 2; - } - else - { - InsertToken(TokenType::OpMul, "*"); - pos++; - } - break; - case '/': - if (nextChar == '=') - { - InsertToken(TokenType::OpDivAssign, "/="); - pos += 2; - } - else - { - InsertToken(TokenType::OpDiv, "/"); - pos++; - } - break; - case '%': - if (nextChar == '=') - { - InsertToken(TokenType::OpModAssign, "%="); - pos += 2; - } - else - { - InsertToken(TokenType::OpMod, "%"); - pos++; - } - break; - case '|': - if (nextChar == '|') - { - InsertToken(TokenType::OpOr, "||"); - pos += 2; - } - else if (nextChar == '=') - { - InsertToken(TokenType::OpOrAssign, "|="); - pos += 2; - } - else - { - InsertToken(TokenType::OpBitOr, "|"); - pos++; - } - break; - case '&': - if (nextChar == '&') - { - InsertToken(TokenType::OpAnd, "&&"); - pos += 2; - } - else if (nextChar == '=') - { - InsertToken(TokenType::OpAndAssign, "&="); - pos += 2; - } - else - { - InsertToken(TokenType::OpBitAnd, "&"); - pos++; - } - break; - case '^': - if (nextChar == '=') - { - InsertToken(TokenType::OpXorAssign, "^="); - pos += 2; - } - else - { - InsertToken(TokenType::OpBitXor, "^"); - pos++; - } - break; - case '>': - if (nextChar == '>') - { - if (nextNextChar == '=') - { - InsertToken(TokenType::OpShrAssign, ">>="); - pos += 3; - } - else - { - InsertToken(TokenType::OpRsh, ">>"); - pos += 2; - } - } - else if (nextChar == '=') - { - InsertToken(TokenType::OpGeq, ">="); - pos += 2; - } - else - { - InsertToken(TokenType::OpGreater, ">"); - pos++; - } - break; - case '<': - if (nextChar == '<') - { - if (nextNextChar == '=') - { - InsertToken(TokenType::OpShlAssign, "<<="); - pos += 3; - } - else - { - InsertToken(TokenType::OpLsh, "<<"); - pos += 2; - } - } - else if (nextChar == '=') - { - InsertToken(TokenType::OpLeq, "<="); - pos += 2; - } - else - { - InsertToken(TokenType::OpLess, "<"); - pos++; - } - break; - case '=': - if (nextChar == '=') + tokens.add( + Token(type, ct, line, int(col + pos), int(pos + startPos), fileName, tokenFlags)); + tokenFlags = 0; + }; + switch (curChar) + { + case '+': + if (nextChar == '+') + { + InsertToken(TokenType::OpInc, "++"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpAddAssign, "+="); + pos += 2; + } + else + { + InsertToken(TokenType::OpAdd, "+"); + pos++; + } + break; + case '-': + if (nextChar == '-') + { + InsertToken(TokenType::OpDec, "--"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpSubAssign, "-="); + pos += 2; + } + else if (nextChar == '>') + { + InsertToken(TokenType::RightArrow, "->"); + pos += 2; + } + else + { + InsertToken(TokenType::OpSub, "-"); + pos++; + } + break; + case '*': + if (nextChar == '=') + { + InsertToken(TokenType::OpMulAssign, "*="); + pos += 2; + } + else + { + InsertToken(TokenType::OpMul, "*"); + pos++; + } + break; + case '/': + if (nextChar == '=') + { + InsertToken(TokenType::OpDivAssign, "/="); + pos += 2; + } + else + { + InsertToken(TokenType::OpDiv, "/"); + pos++; + } + break; + case '%': + if (nextChar == '=') + { + InsertToken(TokenType::OpModAssign, "%="); + pos += 2; + } + else + { + InsertToken(TokenType::OpMod, "%"); + pos++; + } + break; + case '|': + if (nextChar == '|') + { + InsertToken(TokenType::OpOr, "||"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpOrAssign, "|="); + pos += 2; + } + else + { + InsertToken(TokenType::OpBitOr, "|"); + pos++; + } + break; + case '&': + if (nextChar == '&') + { + InsertToken(TokenType::OpAnd, "&&"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpAndAssign, "&="); + pos += 2; + } + else + { + InsertToken(TokenType::OpBitAnd, "&"); + pos++; + } + break; + case '^': + if (nextChar == '=') + { + InsertToken(TokenType::OpXorAssign, "^="); + pos += 2; + } + else + { + InsertToken(TokenType::OpBitXor, "^"); + pos++; + } + break; + case '>': + if (nextChar == '>') + { + if (nextNextChar == '=') { - InsertToken(TokenType::OpEql, "=="); - pos += 2; + InsertToken(TokenType::OpShrAssign, ">>="); + pos += 3; } else { - InsertToken(TokenType::OpAssign, "="); - pos++; - } - break; - case '!': - if (nextChar == '=') - { - InsertToken(TokenType::OpNeq, "!="); + InsertToken(TokenType::OpRsh, ">>"); pos += 2; } - else - { - InsertToken(TokenType::OpNot, "!"); - pos++; - } - break; - case '?': - InsertToken(TokenType::QuestionMark, "?"); - pos++; - break; - case '@': - InsertToken(TokenType::At, "@"); + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpGeq, ">="); + pos += 2; + } + else + { + InsertToken(TokenType::OpGreater, ">"); pos++; - break; - case '#': - if (nextChar == '#') + } + break; + case '<': + if (nextChar == '<') + { + if (nextNextChar == '=') { - InsertToken(TokenType::PoundPound, "##"); - pos += 2; + InsertToken(TokenType::OpShlAssign, "<<="); + pos += 3; } else { - InsertToken(TokenType::Pound, "#"); - pos++; + InsertToken(TokenType::OpLsh, "<<"); + pos += 2; } + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpLeq, "<="); + pos += 2; + } + else + { + InsertToken(TokenType::OpLess, "<"); pos++; - break; - case ':': - InsertToken(TokenType::Colon, ":"); - pos++; - break; - case '~': - InsertToken(TokenType::OpBitNot, "~"); - pos++; - break; - case ';': - InsertToken(TokenType::Semicolon, ";"); - pos++; - break; - case ',': - InsertToken(TokenType::Comma, ","); - pos++; - break; - case '.': - InsertToken(TokenType::Dot, "."); - pos++; - break; - case '{': - InsertToken(TokenType::LBrace, "{"); - pos++; - break; - case '}': - InsertToken(TokenType::RBrace, "}"); - pos++; - break; - case '[': - InsertToken(TokenType::LBracket, "["); - pos++; - break; - case ']': - InsertToken(TokenType::RBracket, "]"); + } + break; + case '=': + if (nextChar == '=') + { + InsertToken(TokenType::OpEql, "=="); + pos += 2; + } + else + { + InsertToken(TokenType::OpAssign, "="); pos++; - break; - case '(': - InsertToken(TokenType::LParent, "("); + } + break; + case '!': + if (nextChar == '=') + { + InsertToken(TokenType::OpNeq, "!="); + pos += 2; + } + else + { + InsertToken(TokenType::OpNot, "!"); pos++; - break; - case ')': - InsertToken(TokenType::RParent, ")"); + } + break; + case '?': + InsertToken(TokenType::QuestionMark, "?"); + pos++; + break; + case '@': + InsertToken(TokenType::At, "@"); + pos++; + break; + case '#': + if (nextChar == '#') + { + InsertToken(TokenType::PoundPound, "##"); + pos += 2; + } + else + { + InsertToken(TokenType::Pound, "#"); pos++; - break; } + pos++; + break; + case ':': + InsertToken(TokenType::Colon, ":"); + pos++; + break; + case '~': + InsertToken(TokenType::OpBitNot, "~"); + pos++; + break; + case ';': + InsertToken(TokenType::Semicolon, ";"); + pos++; + break; + case ',': + InsertToken(TokenType::Comma, ","); + pos++; + break; + case '.': + InsertToken(TokenType::Dot, "."); + pos++; + break; + case '{': + InsertToken(TokenType::LBrace, "{"); + pos++; + break; + case '}': + InsertToken(TokenType::RBrace, "}"); + pos++; + break; + case '[': + InsertToken(TokenType::LBracket, "["); + pos++; + break; + case ']': + InsertToken(TokenType::RBracket, "]"); + pos++; + break; + case '(': + InsertToken(TokenType::LParent, "("); + pos++; + break; + case ')': + InsertToken(TokenType::RParent, ")"); + pos++; + break; } } +} - List<Token> TokenizeText(const String & fileName, const String & text) +List<Token> TokenizeText(const String& fileName, const String& text) +{ + Index lastPos = 0, pos = 0; + int line = 1, col = 0; + String file = fileName; + State state = State::Start; + StringBuilder tokenBuilder; + int tokenLine, tokenCol; + List<Token> tokenList; + LexDerivative derivative = LexDerivative::None; + TokenFlags tokenFlags = TokenFlag::AtStartOfLine; + auto InsertToken = [&](TokenType type) + { + derivative = LexDerivative::None; + tokenList.add( + Token(type, tokenBuilder.toString(), tokenLine, tokenCol, int(pos), file, tokenFlags)); + tokenFlags = 0; + tokenBuilder.clear(); + }; + auto ProcessTransferChar = [&](char nextChar) { - Index lastPos = 0, pos = 0; - int line = 1, col = 0; - String file = fileName; - State state = State::Start; - StringBuilder tokenBuilder; - int tokenLine, tokenCol; - List<Token> tokenList; - LexDerivative derivative = LexDerivative::None; - TokenFlags tokenFlags = TokenFlag::AtStartOfLine; - auto InsertToken = [&](TokenType type) + switch (nextChar) { - derivative = LexDerivative::None; - tokenList.add(Token(type, tokenBuilder.toString(), tokenLine, tokenCol, int(pos), file, tokenFlags)); - tokenFlags = 0; - tokenBuilder.clear(); - }; - auto ProcessTransferChar = [&](char nextChar) + case '\\': + case '\"': + case '\'': tokenBuilder.append(nextChar); break; + case 't': tokenBuilder.append('\t'); break; + case 's': tokenBuilder.append(' '); break; + case 'n': tokenBuilder.append('\n'); break; + case 'r': tokenBuilder.append('\r'); break; + case 'b': tokenBuilder.append('\b'); break; + } + }; + while (pos <= text.getLength()) + { + char curChar = (pos < text.getLength() ? text[pos] : ' '); + char nextChar = (pos < text.getLength() - 1) ? text[pos + 1] : '\0'; + if (lastPos != pos) { - switch (nextChar) - { - case '\\': - case '\"': - case '\'': - tokenBuilder.append(nextChar); - break; - case 't': - tokenBuilder.append('\t'); - break; - case 's': - tokenBuilder.append(' '); - break; - case 'n': - tokenBuilder.append('\n'); - break; - case 'r': - tokenBuilder.append('\r'); - break; - case 'b': - tokenBuilder.append('\b'); - break; + if (curChar == '\n') + { + line++; + col = 0; } - }; - while (pos <= text.getLength()) + else + col++; + lastPos = pos; + } + + switch (state) { - char curChar = (pos < text.getLength() ? text[pos] : ' '); - char nextChar = (pos < text.getLength() - 1) ? text[pos + 1] : '\0'; - if (lastPos != pos) + case State::Start: + if (IsLetter(curChar)) { - if (curChar == '\n') - { - line++; - col = 0; - } - else - col++; - lastPos = pos; + state = State::Identifier; + tokenLine = line; + tokenCol = col; } - - switch (state) + else if (IsDigit(curChar)) { - case State::Start: - if (IsLetter(curChar)) - { - state = State::Identifier; - tokenLine = line; - tokenCol = col; - } - else if (IsDigit(curChar)) - { - state = State::Int; - tokenLine = line; - tokenCol = col; - } - else if (curChar == '\'') - { - state = State::Char; - pos++; - tokenLine = line; - tokenCol = col; - } - else if (curChar == '"') - { - state = State::String; - pos++; - tokenLine = line; - tokenCol = col; - } - else if (curChar == '\r' || curChar == '\n') - { - tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; - pos++; - } - else if (curChar == ' ' || curChar == '\t' || curChar == '\xC2' || curChar == '\xA0') // -62/-96:non-break space - { - tokenFlags |= TokenFlag::AfterWhitespace; - pos++; - } - else if (curChar == '/' && nextChar == '/') - { - state = State::SingleComment; - pos += 2; - } - else if (curChar == '/' && nextChar == '*') - { - pos += 2; - state = State::MultiComment; - } - else if (curChar == '.' && IsDigit(nextChar)) - { - tokenBuilder.append("0."); - state = State::Fixed; - pos++; - } - else if (IsPunctuation(curChar)) - { - state = State::Operator; - tokenLine = line; - tokenCol = col; - } - else - { - pos++; - } - break; - case State::Identifier: - if (IsLetter(curChar) || IsDigit(curChar)) - { - tokenBuilder.append(curChar); - pos++; - } - else - { - auto tokenStr = tokenBuilder.toString(); + state = State::Int; + tokenLine = line; + tokenCol = col; + } + else if (curChar == '\'') + { + state = State::Char; + pos++; + tokenLine = line; + tokenCol = col; + } + else if (curChar == '"') + { + state = State::String; + pos++; + tokenLine = line; + tokenCol = col; + } + else if (curChar == '\r' || curChar == '\n') + { + tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; + pos++; + } + else if ( + curChar == ' ' || curChar == '\t' || curChar == '\xC2' || + curChar == '\xA0') // -62/-96:non-break space + { + tokenFlags |= TokenFlag::AfterWhitespace; + pos++; + } + else if (curChar == '/' && nextChar == '/') + { + state = State::SingleComment; + pos += 2; + } + else if (curChar == '/' && nextChar == '*') + { + pos += 2; + state = State::MultiComment; + } + else if (curChar == '.' && IsDigit(nextChar)) + { + tokenBuilder.append("0."); + state = State::Fixed; + pos++; + } + else if (IsPunctuation(curChar)) + { + state = State::Operator; + tokenLine = line; + tokenCol = col; + } + else + { + pos++; + } + break; + case State::Identifier: + if (IsLetter(curChar) || IsDigit(curChar)) + { + tokenBuilder.append(curChar); + pos++; + } + else + { + auto tokenStr = tokenBuilder.toString(); #if 0 if (tokenStr == "#line_reset#") { @@ -478,204 +491,213 @@ namespace Misc { } else #endif - InsertToken(TokenType::Identifier); - state = State::Start; - } - break; - case State::Operator: - if (IsPunctuation(curChar) && !((curChar == '/' && nextChar == '/') || (curChar == '/' && nextChar == '*'))) + InsertToken(TokenType::Identifier); + state = State::Start; + } + break; + case State::Operator: + if (IsPunctuation(curChar) && + !((curChar == '/' && nextChar == '/') || (curChar == '/' && nextChar == '*'))) + { + tokenBuilder.append(curChar); + pos++; + } + else + { + // do token analyze + ParseOperators( + tokenBuilder.toString(), + tokenList, + tokenFlags, + tokenLine, + tokenCol, + (int)(pos - tokenBuilder.getLength()), + file); + tokenBuilder.clear(); + state = State::Start; + } + break; + case State::Int: + if (IsDigit(curChar)) + { + tokenBuilder.append(curChar); + pos++; + } + else if (curChar == '.') + { + state = State::Fixed; + tokenBuilder.append(curChar); + pos++; + } + else if (curChar == 'e' || curChar == 'E') + { + state = State::Double; + tokenBuilder.append(curChar); + if (nextChar == '-' || nextChar == '+') { - tokenBuilder.append(curChar); + tokenBuilder.append(nextChar); pos++; } - else + pos++; + } + else if (curChar == 'x') + { + state = State::Hex; + tokenBuilder.append(curChar); + pos++; + } + else if (curChar == 'u') + { + pos++; + tokenBuilder.append(curChar); + InsertToken(TokenType::IntLiteral); + state = State::Start; + } + else + { + if (derivative == LexDerivative::Line) { - //do token analyze - ParseOperators(tokenBuilder.toString(), tokenList, tokenFlags, tokenLine, tokenCol, (int)(pos - tokenBuilder.getLength()), file); + derivative = LexDerivative::None; + line = stringToInt(tokenBuilder.toString()) - 1; + col = 0; tokenBuilder.clear(); - state = State::Start; - } - break; - case State::Int: - if (IsDigit(curChar)) - { - tokenBuilder.append(curChar); - pos++; } - else if (curChar == '.') + else { - state = State::Fixed; - tokenBuilder.append(curChar); - pos++; + InsertToken(TokenType::IntLiteral); } - else if (curChar == 'e' || curChar == 'E') + state = State::Start; + } + break; + case State::Hex: + if (IsDigit(curChar) || (curChar >= 'a' && curChar <= 'f') || + (curChar >= 'A' && curChar <= 'F')) + { + tokenBuilder.append(curChar); + pos++; + } + else + { + InsertToken(TokenType::IntLiteral); + state = State::Start; + } + break; + case State::Fixed: + if (IsDigit(curChar)) + { + tokenBuilder.append(curChar); + pos++; + } + else if (curChar == 'e' || curChar == 'E') + { + state = State::Double; + tokenBuilder.append(curChar); + if (nextChar == '-' || nextChar == '+') { - state = State::Double; - tokenBuilder.append(curChar); - if (nextChar == '-' || nextChar == '+') - { - tokenBuilder.append(nextChar); - pos++; - } + tokenBuilder.append(nextChar); pos++; } - else if (curChar == 'x') - { - state = State::Hex; - tokenBuilder.append(curChar); + pos++; + } + else + { + if (curChar == 'f') pos++; - } - else if (curChar == 'u') - { + InsertToken(TokenType::DoubleLiteral); + state = State::Start; + } + break; + case State::Double: + if (IsDigit(curChar)) + { + tokenBuilder.append(curChar); + pos++; + } + else + { + if (curChar == 'f') pos++; - tokenBuilder.append(curChar); - InsertToken(TokenType::IntLiteral); - state = State::Start; - } - else - { - if (derivative == LexDerivative::Line) - { - derivative = LexDerivative::None; - line = stringToInt(tokenBuilder.toString()) - 1; - col = 0; - tokenBuilder.clear(); - } - else - { - InsertToken(TokenType::IntLiteral); - } - state = State::Start; - } - break; - case State::Hex: - if (IsDigit(curChar) || (curChar >= 'a' && curChar <= 'f') || (curChar >= 'A' && curChar <= 'F')) + InsertToken(TokenType::DoubleLiteral); + state = State::Start; + } + break; + case State::String: + if (curChar != '"') + { + if (curChar == '\\') { - tokenBuilder.append(curChar); + ProcessTransferChar(nextChar); pos++; } else - { - InsertToken(TokenType::IntLiteral); - state = State::Start; - } - break; - case State::Fixed: - if (IsDigit(curChar)) - { tokenBuilder.append(curChar); - pos++; - } - else if (curChar == 'e' || curChar == 'E') + } + else + { + if (derivative == LexDerivative::File) { - state = State::Double; - tokenBuilder.append(curChar); - if (nextChar == '-' || nextChar == '+') - { - tokenBuilder.append(nextChar); - pos++; - } - pos++; + derivative = LexDerivative::None; + file = tokenBuilder.toString(); + tokenBuilder.clear(); } else { - if (curChar == 'f') - pos++; - InsertToken(TokenType::DoubleLiteral); - state = State::Start; + InsertToken(TokenType::StringLiteral); } - break; - case State::Double: - if (IsDigit(curChar)) + state = State::Start; + } + pos++; + break; + case State::Char: + if (curChar != '\'') + { + if (curChar == '\\') { - tokenBuilder.append(curChar); + ProcessTransferChar(nextChar); pos++; } else - { - if (curChar == 'f') - pos++; - InsertToken(TokenType::DoubleLiteral); - state = State::Start; - } - break; - case State::String: - if (curChar != '"') - { - if (curChar == '\\') - { - ProcessTransferChar(nextChar); - pos++; - } - else - tokenBuilder.append(curChar); - } - else - { - if (derivative == LexDerivative::File) - { - derivative = LexDerivative::None; - file = tokenBuilder.toString(); - tokenBuilder.clear(); - } - else - { - InsertToken(TokenType::StringLiteral); - } - state = State::Start; - } - pos++; - break; - case State::Char: - if (curChar != '\'') - { - if (curChar == '\\') - { - ProcessTransferChar(nextChar); - pos++; - } - else - tokenBuilder.append(curChar); - } - else - { - InsertToken(TokenType::CharLiteral); - state = State::Start; - } - pos++; - break; - case State::SingleComment: - if (curChar == '\n') - { - state = State::Start; - tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; - } - pos++; - break; - case State::MultiComment: - if (curChar == '*' && nextChar == '/') - { - state = State::Start; - tokenFlags |= TokenFlag::AfterWhitespace; - pos += 2; - } - else - pos++; - break; + tokenBuilder.append(curChar); + } + else + { + InsertToken(TokenType::CharLiteral); + state = State::Start; } + pos++; + break; + case State::SingleComment: + if (curChar == '\n') + { + state = State::Start; + tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; + } + pos++; + break; + case State::MultiComment: + if (curChar == '*' && nextChar == '/') + { + state = State::Start; + tokenFlags |= TokenFlag::AfterWhitespace; + pos += 2; + } + else + pos++; + break; } - return tokenList; - } - List<Token> TokenizeText(const String & text) - { - return TokenizeText("", text); } + return tokenList; +} +List<Token> TokenizeText(const String& text) +{ + return TokenizeText("", text); +} - TokenReader::TokenReader(String text) - { - this->tokens = TokenizeText("", text); - tokenPtr = 0; - } +TokenReader::TokenReader(String text) +{ + this->tokens = TokenizeText("", text); + tokenPtr = 0; +} } // namespace Misc } // namespace Slang diff --git a/source/core/slang-token-reader.h b/source/core/slang-token-reader.h index c4b552d29..41affb1d0 100644 --- a/source/core/slang-token-reader.h +++ b/source/core/slang-token-reader.h @@ -3,306 +3,351 @@ #include "slang-basic.h" -namespace Slang { -namespace Misc { +namespace Slang +{ +namespace Misc +{ - /* NOTE! This TokenReader is NOT used by the main slang compiler !*/ +/* NOTE! This TokenReader is NOT used by the main slang compiler !*/ - enum class TokenType - { - EndOfFile = -1, - // illegal - Unknown, - // identifier - Identifier, - // constant - IntLiteral, DoubleLiteral, StringLiteral, CharLiteral, - // operators - Semicolon, Comma, Dot, LBrace, RBrace, LBracket, RBracket, LParent, RParent, - OpAssign, OpAdd, OpSub, OpMul, OpDiv, OpMod, OpNot, OpBitNot, OpLsh, OpRsh, - OpEql, OpNeq, OpGreater, OpLess, OpGeq, OpLeq, - OpAnd, OpOr, OpBitXor, OpBitAnd, OpBitOr, - OpInc, OpDec, OpAddAssign, OpSubAssign, OpMulAssign, OpDivAssign, OpModAssign, - OpShlAssign, OpShrAssign, OpOrAssign, OpAndAssign, OpXorAssign, +enum class TokenType +{ + EndOfFile = -1, + // illegal + Unknown, + // identifier + Identifier, + // constant + IntLiteral, + DoubleLiteral, + StringLiteral, + CharLiteral, + // operators + Semicolon, + Comma, + Dot, + LBrace, + RBrace, + LBracket, + RBracket, + LParent, + RParent, + OpAssign, + OpAdd, + OpSub, + OpMul, + OpDiv, + OpMod, + OpNot, + OpBitNot, + OpLsh, + OpRsh, + OpEql, + OpNeq, + OpGreater, + OpLess, + OpGeq, + OpLeq, + OpAnd, + OpOr, + OpBitXor, + OpBitAnd, + OpBitOr, + OpInc, + OpDec, + OpAddAssign, + OpSubAssign, + OpMulAssign, + OpDivAssign, + OpModAssign, + OpShlAssign, + OpShrAssign, + OpOrAssign, + OpAndAssign, + OpXorAssign, - QuestionMark, Colon, RightArrow, At, Pound, PoundPound, Scope, - }; + QuestionMark, + Colon, + RightArrow, + At, + Pound, + PoundPound, + Scope, +}; - class CodePosition +class CodePosition +{ +public: + int Line = -1, Col = -1, Pos = -1; + String FileName; + String ToString() { - public: - int Line = -1, Col = -1, Pos = -1; - String FileName; - String ToString() - { - StringBuilder sb(100); - sb << FileName; - if (Line != -1) - sb << "(" << Line << ")"; - return sb.produceString(); - } - CodePosition() = default; - CodePosition(int line, int col, int pos, String fileName) - { - Line = line; - Col = col; - Pos = pos; - this->FileName = fileName; - } - bool operator < (const CodePosition & pos) const - { - return FileName < pos.FileName || (FileName == pos.FileName && Line < pos.Line) || - (FileName == pos.FileName && Line == pos.Line && Col < pos.Col); - } - bool operator == (const CodePosition & pos) const - { - return FileName == pos.FileName && Line == pos.Line && Col == pos.Col; - } - }; - - enum TokenFlag : unsigned int + StringBuilder sb(100); + sb << FileName; + if (Line != -1) + sb << "(" << Line << ")"; + return sb.produceString(); + } + CodePosition() = default; + CodePosition(int line, int col, int pos, String fileName) + { + Line = line; + Col = col; + Pos = pos; + this->FileName = fileName; + } + bool operator<(const CodePosition& pos) const + { + return FileName < pos.FileName || (FileName == pos.FileName && Line < pos.Line) || + (FileName == pos.FileName && Line == pos.Line && Col < pos.Col); + } + bool operator==(const CodePosition& pos) const { - AtStartOfLine = 1 << 0, - AfterWhitespace = 1 << 1, - }; - typedef unsigned int TokenFlags; + return FileName == pos.FileName && Line == pos.Line && Col == pos.Col; + } +}; - class Token +enum TokenFlag : unsigned int +{ + AtStartOfLine = 1 << 0, + AfterWhitespace = 1 << 1, +}; +typedef unsigned int TokenFlags; + +class Token +{ +public: + TokenType Type = TokenType::Unknown; + String Content; + CodePosition Position; + TokenFlags flags = 0; + Token() = default; + Token( + TokenType type, + const String& content, + int line, + int col, + int pos, + String fileName, + TokenFlags flags = 0) + : flags(flags) { - public: - TokenType Type = TokenType::Unknown; - String Content; - CodePosition Position; - TokenFlags flags = 0; - Token() = default; - Token(TokenType type, const String & content, int line, int col, int pos, String fileName, TokenFlags flags = 0) - : flags(flags) - { - Type = type; - Content = content; - Position = CodePosition(line, col, pos, fileName); - } - }; + Type = type; + Content = content; + Position = CodePosition(line, col, pos, fileName); + } +}; - class TextFormatException : public Exception +class TextFormatException : public Exception +{ +public: + TextFormatException(String message) + : Exception(message) { - public: - TextFormatException(String message) - : Exception(message) - {} - }; + } +}; + +class TokenReader +{ +private: + bool legal; + List<Token> tokens; + int tokenPtr; - class TokenReader +public: + TokenReader(String text); + int ReadInt() { - private: - bool legal; - List<Token> tokens; - int tokenPtr; - public: - TokenReader(String text); - int ReadInt() + auto token = ReadToken(); + bool neg = false; + if (token.Content.getUnownedSlice().isChar('-')) { - auto token = ReadToken(); - bool neg = false; - if (token.Content.getUnownedSlice().isChar('-')) - { - neg = true; - token = ReadToken(); - } - if (token.Type == TokenType::IntLiteral) - { - if (neg) - return -stringToInt(token.Content); - else - return stringToInt(token.Content); - } - throw TextFormatException("Text parsing error: int expected."); + neg = true; + token = ReadToken(); } - unsigned int ReadUInt() + if (token.Type == TokenType::IntLiteral) { - auto token = ReadToken(); - if (token.Type == TokenType::IntLiteral) - { - return stringToUInt(token.Content); - } - throw TextFormatException("Text parsing error: int expected."); + if (neg) + return -stringToInt(token.Content); + else + return stringToInt(token.Content); } - double ReadDouble() + throw TextFormatException("Text parsing error: int expected."); + } + unsigned int ReadUInt() + { + auto token = ReadToken(); + if (token.Type == TokenType::IntLiteral) { - auto token = ReadToken(); - bool neg = false; - if (token.Content.getUnownedSlice().isChar('-')) - { - neg = true; - token = ReadToken(); - } - if (token.Type == TokenType::DoubleLiteral || token.Type == TokenType::IntLiteral) - { - if (neg) - return -stringToDouble(token.Content); - else - return stringToDouble(token.Content); - } - throw TextFormatException("Text parsing error: floating point value expected."); + return stringToUInt(token.Content); } - float ReadFloat() + throw TextFormatException("Text parsing error: int expected."); + } + double ReadDouble() + { + auto token = ReadToken(); + bool neg = false; + if (token.Content.getUnownedSlice().isChar('-')) { - return (float)ReadDouble(); + neg = true; + token = ReadToken(); } - String ReadWord() + if (token.Type == TokenType::DoubleLiteral || token.Type == TokenType::IntLiteral) { - auto token = ReadToken(); - if (token.Type == TokenType::Identifier) - { - return token.Content; - } - throw TextFormatException("Text parsing error: identifier expected."); + if (neg) + return -stringToDouble(token.Content); + else + return stringToDouble(token.Content); } - String Read(const char * expectedStr) + throw TextFormatException("Text parsing error: floating point value expected."); + } + float ReadFloat() { return (float)ReadDouble(); } + String ReadWord() + { + auto token = ReadToken(); + if (token.Type == TokenType::Identifier) { - auto token = ReadToken(); - if (token.Content == expectedStr) - { - return token.Content; - } - throw TextFormatException("Text parsing error: \'" + String(expectedStr) + "\' expected."); + return token.Content; } - String Read(String expectedStr) + throw TextFormatException("Text parsing error: identifier expected."); + } + String Read(const char* expectedStr) + { + auto token = ReadToken(); + if (token.Content == expectedStr) { - auto token = ReadToken(); - if (token.Content == expectedStr) - { - return token.Content; - } - throw TextFormatException("Text parsing error: \'" + expectedStr + "\' expected."); + return token.Content; } - bool Read(TokenType tokenType) + throw TextFormatException("Text parsing error: \'" + String(expectedStr) + "\' expected."); + } + String Read(String expectedStr) + { + auto token = ReadToken(); + if (token.Content == expectedStr) { - if( NextToken().Type == tokenType ) - { - ReadToken(); - return true; - } - throw TextFormatException("Text parsing error: unexpected '" + NextToken().Content + "'."); + return token.Content; } - - String ReadStringLiteral() + throw TextFormatException("Text parsing error: \'" + expectedStr + "\' expected."); + } + bool Read(TokenType tokenType) + { + if (NextToken().Type == tokenType) { - auto token = ReadToken(); - if (token.Type == TokenType::StringLiteral) - { - return token.Content; - } - throw TextFormatException("Text parsing error: string literal expected."); + ReadToken(); + return true; } - void Back(int count) + throw TextFormatException("Text parsing error: unexpected '" + NextToken().Content + "'."); + } + + String ReadStringLiteral() + { + auto token = ReadToken(); + if (token.Type == TokenType::StringLiteral) { - tokenPtr -= count; + return token.Content; } - Token ReadMatchingToken(TokenType type) + throw TextFormatException("Text parsing error: string literal expected."); + } + void Back(int count) { tokenPtr -= count; } + Token ReadMatchingToken(TokenType type) + { + auto token = ReadToken(); + if (token.Type != type) { - auto token = ReadToken(); - if (token.Type != type) - { - throw TextFormatException("Text parsing error: unexpected token."); - } - return token; + throw TextFormatException("Text parsing error: unexpected token."); } - Token ReadToken() + return token; + } + Token ReadToken() + { + if (tokenPtr < (int)tokens.getCount()) { - if (tokenPtr < (int)tokens.getCount()) - { - auto &rs = tokens[tokenPtr]; - tokenPtr++; - return rs; - } - throw TextFormatException("Unexpected ending."); + auto& rs = tokens[tokenPtr]; + tokenPtr++; + return rs; } - Token NextToken(int offset = 0) + throw TextFormatException("Unexpected ending."); + } + Token NextToken(int offset = 0) + { + if (tokenPtr + offset < (int)tokens.getCount()) + return tokens[tokenPtr + offset]; + else { - if (tokenPtr + offset < (int)tokens.getCount()) - return tokens[tokenPtr + offset]; - else - { - Token rs; - rs.Type = TokenType::Unknown; - return rs; - } + Token rs; + rs.Type = TokenType::Unknown; + return rs; } - bool LookAhead(String token) + } + bool LookAhead(String token) + { + if (tokenPtr < (int)tokens.getCount()) { - if (tokenPtr < (int)tokens.getCount()) - { - auto next = NextToken(); - return next.Content == token; - } - else - { - return false; - } + auto next = NextToken(); + return next.Content == token; } - bool LookAhead(TokenType tokenType) + else { - if (tokenPtr < (int)tokens.getCount()) - { - auto next = NextToken(); - return next.Type == tokenType; - } - else - { - return false; - } + return false; } - bool AdvanceIf(String token) + } + bool LookAhead(TokenType tokenType) + { + if (tokenPtr < (int)tokens.getCount()) { - if( LookAhead(token) ) - { - ReadToken(); - return true; - } - return false; + auto next = NextToken(); + return next.Type == tokenType; } - bool AdvanceIf(TokenType token) + else { - if( LookAhead(token) ) - { - ReadToken(); - return true; - } return false; } - bool IsEnd() + } + bool AdvanceIf(String token) + { + if (LookAhead(token)) { - return tokenPtr == (int)tokens.getCount(); + ReadToken(); + return true; } - public: - bool IsLegalText() + return false; + } + bool AdvanceIf(TokenType token) + { + if (LookAhead(token)) { - return legal; + ReadToken(); + return true; } - }; + return false; + } + bool IsEnd() { return tokenPtr == (int)tokens.getCount(); } + +public: + bool IsLegalText() { return legal; } +}; - inline List<String> Split(String text, char c) +inline List<String> Split(String text, char c) +{ + List<String> result; + StringBuilder sb; + for (Index i = 0; i < text.getLength(); i++) { - List<String> result; - StringBuilder sb; - for (Index i = 0; i < text.getLength(); i++) + if (text[i] == c) { - if (text[i] == c) - { - auto str = sb.toString(); - if (str.getLength() != 0) - result.add(str); - sb.clear(); - } - else - sb << text[i]; + auto str = sb.toString(); + if (str.getLength() != 0) + result.add(str); + sb.clear(); } - auto lastStr = sb.toString(); - if (lastStr.getLength()) - result.add(lastStr); - return result; + else + sb << text[i]; } + auto lastStr = sb.toString(); + if (lastStr.getLength()) + result.add(lastStr); + return result; +} } // namespace Misc } // namespace Slang diff --git a/source/core/slang-type-convert-util.cpp b/source/core/slang-type-convert-util.cpp index 12908f211..3eb053726 100644 --- a/source/core/slang-type-convert-util.cpp +++ b/source/core/slang-type-convert-util.cpp @@ -4,39 +4,40 @@ namespace Slang { -/* static */SlangSourceLanguage TypeConvertUtil::getSourceLanguageFromTarget(SlangCompileTarget target) +/* static */ SlangSourceLanguage TypeConvertUtil::getSourceLanguageFromTarget( + SlangCompileTarget target) { switch (target) { - case SLANG_GLSL: + case SLANG_GLSL: { return SLANG_SOURCE_LANGUAGE_GLSL; } - case SLANG_HLSL: return SLANG_SOURCE_LANGUAGE_HLSL; - case SLANG_C_SOURCE: return SLANG_SOURCE_LANGUAGE_C; - case SLANG_CPP_SOURCE: return SLANG_SOURCE_LANGUAGE_CPP; - case SLANG_CPP_PYTORCH_BINDING:return SLANG_SOURCE_LANGUAGE_CPP; - case SLANG_HOST_CPP_SOURCE: return SLANG_SOURCE_LANGUAGE_CPP; - case SLANG_CUDA_SOURCE: return SLANG_SOURCE_LANGUAGE_CUDA; - case SLANG_WGSL: return SLANG_SOURCE_LANGUAGE_WGSL; - default: break; + case SLANG_HLSL: return SLANG_SOURCE_LANGUAGE_HLSL; + case SLANG_C_SOURCE: return SLANG_SOURCE_LANGUAGE_C; + case SLANG_CPP_SOURCE: return SLANG_SOURCE_LANGUAGE_CPP; + case SLANG_CPP_PYTORCH_BINDING: return SLANG_SOURCE_LANGUAGE_CPP; + case SLANG_HOST_CPP_SOURCE: return SLANG_SOURCE_LANGUAGE_CPP; + case SLANG_CUDA_SOURCE: return SLANG_SOURCE_LANGUAGE_CUDA; + case SLANG_WGSL: return SLANG_SOURCE_LANGUAGE_WGSL; + default: break; } return SLANG_SOURCE_LANGUAGE_UNKNOWN; } -/* static */SlangCompileTarget TypeConvertUtil::getCompileTargetFromSourceLanguage(SlangSourceLanguage lang) +/* static */ SlangCompileTarget TypeConvertUtil::getCompileTargetFromSourceLanguage( + SlangSourceLanguage lang) { switch (lang) { - case SLANG_SOURCE_LANGUAGE_GLSL: return SLANG_GLSL; - case SLANG_SOURCE_LANGUAGE_HLSL: return SLANG_HLSL; - case SLANG_SOURCE_LANGUAGE_C: return SLANG_C_SOURCE; - case SLANG_SOURCE_LANGUAGE_CPP: return SLANG_CPP_SOURCE; - case SLANG_SOURCE_LANGUAGE_CUDA: return SLANG_CUDA_SOURCE; + case SLANG_SOURCE_LANGUAGE_GLSL: return SLANG_GLSL; + case SLANG_SOURCE_LANGUAGE_HLSL: return SLANG_HLSL; + case SLANG_SOURCE_LANGUAGE_C: return SLANG_C_SOURCE; + case SLANG_SOURCE_LANGUAGE_CPP: return SLANG_CPP_SOURCE; + case SLANG_SOURCE_LANGUAGE_CUDA: return SLANG_CUDA_SOURCE; } return SLANG_TARGET_UNKNOWN; } -} - +} // namespace Slang diff --git a/source/core/slang-type-convert-util.h b/source/core/slang-type-convert-util.h index 70565b896..d4c80abf8 100644 --- a/source/core/slang-type-convert-util.h +++ b/source/core/slang-type-convert-util.h @@ -9,13 +9,14 @@ namespace Slang /// Utility class for simple conversions between types struct TypeConvertUtil { - /// Convert a target into it's equivalent language if ones available. If not returns SOURCE_LANGUAGE_UNKNOWN + /// Convert a target into it's equivalent language if ones available. If not returns + /// SOURCE_LANGUAGE_UNKNOWN static SlangSourceLanguage getSourceLanguageFromTarget(SlangCompileTarget target); - /// Convert a language into the equivalent target. If not available returns SLANG_TARGET_UNKNOWN + /// Convert a language into the equivalent target. If not available returns SLANG_TARGET_UNKNOWN static SlangCompileTarget getCompileTargetFromSourceLanguage(SlangSourceLanguage lang); }; -} +} // namespace Slang #endif // SLANG_CORE_TYPE_TEXT_UTIL_H diff --git a/source/core/slang-type-text-util.cpp b/source/core/slang-type-text-util.cpp index 51ed2060e..0afd25342 100644 --- a/source/core/slang-type-text-util.cpp +++ b/source/core/slang-type-text-util.cpp @@ -1,13 +1,14 @@ #include "slang-type-text-util.h" -#include "slang-array-view.h" +#include "slang-array-view.h" #include "slang-string-util.h" namespace Slang { -namespace { // anonymous +namespace +{ // anonymous // clang-format off #define SLANG_SCALAR_TYPES(x) \ @@ -20,7 +21,7 @@ namespace { // anonymous x(Int64, int64_t) \ x(UInt64, uint64_t) \ x(Float32, float) \ - x(Float64, double) + x(Float64, double) // clang-format on struct ScalarTypeInfo @@ -29,198 +30,235 @@ struct ScalarTypeInfo UnownedStringSlice text; }; -static const ScalarTypeInfo s_scalarTypeInfos[] = -{ - #define SLANG_SCALAR_TYPE_INFO(value, text) \ - { slang::TypeReflection::ScalarType::value, UnownedStringSlice::fromLiteral(#text) }, - SLANG_SCALAR_TYPES(SLANG_SCALAR_TYPE_INFO) -}; +static const ScalarTypeInfo s_scalarTypeInfos[] = { +#define SLANG_SCALAR_TYPE_INFO(value, text) \ + {slang::TypeReflection::ScalarType::value, UnownedStringSlice::fromLiteral(#text)}, + SLANG_SCALAR_TYPES(SLANG_SCALAR_TYPE_INFO)}; // Make sure to keep this table in sync with that in slang/slang-options.cpp getHelpText -static const TypeTextUtil::CompileTargetInfo s_compileTargetInfos[] = -{ - { SLANG_TARGET_UNKNOWN, "", "unknown"}, - { SLANG_TARGET_NONE, "", "none"}, - { SLANG_HLSL, "hlsl,fx", "hlsl", "HLSL source code"}, - { SLANG_DXBC, "dxbc", "dxbc", "DirectX shader bytecode binary"}, - { SLANG_DXBC_ASM, "dxbc-asm", "dxbc-asm,dxbc-assembly", "DirectX shader bytecode assembly" }, - { SLANG_DXIL, "dxil", "dxil", "DirectX Intermediate Language binary" }, - { SLANG_DXIL_ASM, "dxil-asm", "dxil-asm,dxil-assembly", "DirectX Intermediate Language assembly"}, - { SLANG_GLSL, "glsl,vert,frag,geom,tesc,tese,comp", "glsl", "GLSL(Vulkan) source code" }, - { SLANG_SPIRV, "spv", "spirv", "SPIR-V binary"}, - { SLANG_SPIRV_ASM, "spv-asm", "spirv-asm,spirv-assembly", "SPIR-V assembly" }, - { SLANG_C_SOURCE, "c", "c", "C source code" }, - { SLANG_CPP_SOURCE, "cpp,c++,cxx", "cpp,c++,cxx", "C++ source code" }, - { SLANG_CPP_PYTORCH_BINDING, "cpp,c++,cxx", "torch,torch-binding,torch-cpp,torch-cpp-binding", "C++ for pytorch binding" }, - { SLANG_HOST_CPP_SOURCE, "cpp,c++,cxx", "host-cpp,host-c++,host-cxx", "C++ source for host execution"}, - { SLANG_HOST_EXECUTABLE,"exe", "exe,executable", "Executable binary" }, - { SLANG_SHADER_SHARED_LIBRARY, "shader-dll,shader-so", "shader-sharedlib,shader-sharedlibrary,shader-dll", "Shared library/Dll for shader kernel" }, - { SLANG_HOST_SHARED_LIBRARY, "dll,so", "sharedlib,sharedlibrary,dll", "Shared library/Dll for host execution" }, - { SLANG_CUDA_SOURCE, "cu", "cuda,cu", "CUDA source code" }, - { SLANG_PTX, "ptx", "ptx", "PTX assembly" }, - { SLANG_CUDA_OBJECT_CODE, "obj,o", "cuobj,cubin", "CUDA binary" }, - { SLANG_SHADER_HOST_CALLABLE, "", "host-callable,callable", "Host callable" }, - { SLANG_OBJECT_CODE, "obj,o", "object-code", "Object code" }, - { SLANG_HOST_HOST_CALLABLE, "", "host-host-callable", "Host callable for host execution" }, - { SLANG_METAL, "metal", "metal", "Metal shader source" }, - { SLANG_METAL_LIB, "metallib", "metallib", "Metal Library Bytecode" }, - { SLANG_METAL_LIB_ASM, "metallib-asm" "metallib-asm", "Metal Library Bytecode assembly" }, - { SLANG_WGSL, "wgsl", "wgsl", "WebGPU shading language source" }, - { SLANG_WGSL_SPIRV_ASM, "wgsl-spirv-asm", "wgsl-spirv-asm,wgsl-spirv-assembly", "SPIR-V assembly via WebGPU shading language" }, - { SLANG_WGSL_SPIRV, "wgsl-spirv", "wgsl-spirv", "SPIR-V via WebGPU shading language" }, +static const TypeTextUtil::CompileTargetInfo s_compileTargetInfos[] = { + {SLANG_TARGET_UNKNOWN, "", "unknown"}, + {SLANG_TARGET_NONE, "", "none"}, + {SLANG_HLSL, "hlsl,fx", "hlsl", "HLSL source code"}, + {SLANG_DXBC, "dxbc", "dxbc", "DirectX shader bytecode binary"}, + {SLANG_DXBC_ASM, "dxbc-asm", "dxbc-asm,dxbc-assembly", "DirectX shader bytecode assembly"}, + {SLANG_DXIL, "dxil", "dxil", "DirectX Intermediate Language binary"}, + {SLANG_DXIL_ASM, + "dxil-asm", + "dxil-asm,dxil-assembly", + "DirectX Intermediate Language assembly"}, + {SLANG_GLSL, "glsl,vert,frag,geom,tesc,tese,comp", "glsl", "GLSL(Vulkan) source code"}, + {SLANG_SPIRV, "spv", "spirv", "SPIR-V binary"}, + {SLANG_SPIRV_ASM, "spv-asm", "spirv-asm,spirv-assembly", "SPIR-V assembly"}, + {SLANG_C_SOURCE, "c", "c", "C source code"}, + {SLANG_CPP_SOURCE, "cpp,c++,cxx", "cpp,c++,cxx", "C++ source code"}, + {SLANG_CPP_PYTORCH_BINDING, + "cpp,c++,cxx", + "torch,torch-binding,torch-cpp,torch-cpp-binding", + "C++ for pytorch binding"}, + {SLANG_HOST_CPP_SOURCE, + "cpp,c++,cxx", + "host-cpp,host-c++,host-cxx", + "C++ source for host execution"}, + {SLANG_HOST_EXECUTABLE, "exe", "exe,executable", "Executable binary"}, + {SLANG_SHADER_SHARED_LIBRARY, + "shader-dll,shader-so", + "shader-sharedlib,shader-sharedlibrary,shader-dll", + "Shared library/Dll for shader kernel"}, + {SLANG_HOST_SHARED_LIBRARY, + "dll,so", + "sharedlib,sharedlibrary,dll", + "Shared library/Dll for host execution"}, + {SLANG_CUDA_SOURCE, "cu", "cuda,cu", "CUDA source code"}, + {SLANG_PTX, "ptx", "ptx", "PTX assembly"}, + {SLANG_CUDA_OBJECT_CODE, "obj,o", "cuobj,cubin", "CUDA binary"}, + {SLANG_SHADER_HOST_CALLABLE, "", "host-callable,callable", "Host callable"}, + {SLANG_OBJECT_CODE, "obj,o", "object-code", "Object code"}, + {SLANG_HOST_HOST_CALLABLE, "", "host-host-callable", "Host callable for host execution"}, + {SLANG_METAL, "metal", "metal", "Metal shader source"}, + {SLANG_METAL_LIB, "metallib", "metallib", "Metal Library Bytecode"}, + {SLANG_METAL_LIB_ASM, + "metallib-asm" + "metallib-asm", + "Metal Library Bytecode assembly"}, + {SLANG_WGSL, "wgsl", "wgsl", "WebGPU shading language source"}, + {SLANG_WGSL_SPIRV_ASM, + "wgsl-spirv-asm", + "wgsl-spirv-asm,wgsl-spirv-assembly", + "SPIR-V assembly via WebGPU shading language"}, + {SLANG_WGSL_SPIRV, "wgsl-spirv", "wgsl-spirv", "SPIR-V via WebGPU shading language"}, }; -static const NamesDescriptionValue s_languageInfos[] = -{ - { SLANG_SOURCE_LANGUAGE_C, "c,C", "C language" }, - { SLANG_SOURCE_LANGUAGE_CPP, "cpp,c++,C++,cxx", "C++ language" }, - { SLANG_SOURCE_LANGUAGE_SLANG, "slang", "Slang language" }, - { SLANG_SOURCE_LANGUAGE_GLSL, "glsl", "GLSL language" }, - { SLANG_SOURCE_LANGUAGE_HLSL, "hlsl", "HLSL language" }, - { SLANG_SOURCE_LANGUAGE_CUDA, "cu,cuda", "CUDA" }, -}; - -static const NamesDescriptionValue s_compilerInfos[] = -{ - { SLANG_PASS_THROUGH_NONE, "none", "Unknown" }, - { SLANG_PASS_THROUGH_FXC, "fxc", "FXC HLSL compiler" }, - { SLANG_PASS_THROUGH_DXC, "dxc", "DXC HLSL compiler" }, - { SLANG_PASS_THROUGH_GLSLANG, "glslang", "GLSLANG GLSL compiler" }, - { SLANG_PASS_THROUGH_SPIRV_DIS, "spirv-dis", "spirv-tools SPIRV disassembler" }, - { SLANG_PASS_THROUGH_CLANG, "clang", "Clang C/C++ compiler" }, - { SLANG_PASS_THROUGH_VISUAL_STUDIO, "visualstudio,vs", "Visual Studio C/C++ compiler" }, - { SLANG_PASS_THROUGH_GCC, "gcc", "GCC C/C++ compiler" }, - { SLANG_PASS_THROUGH_GENERIC_C_CPP, "genericcpp,c,cpp", "A generic C++ compiler (can be any one of visual studio, clang or gcc depending on system and availability)" }, - { SLANG_PASS_THROUGH_NVRTC, "nvrtc", "NVRTC CUDA compiler" }, - { SLANG_PASS_THROUGH_LLVM, "llvm", "LLVM/Clang `slang-llvm`" }, - { SLANG_PASS_THROUGH_SPIRV_OPT, "spirv-opt", "spirv-tools SPIRV optimizer" }, - { SLANG_PASS_THROUGH_METAL, "metal", "Metal shader compiler" }, - { SLANG_PASS_THROUGH_TINT, "tint", "Tint compiler" }, +static const NamesDescriptionValue s_languageInfos[] = { + {SLANG_SOURCE_LANGUAGE_C, "c,C", "C language"}, + {SLANG_SOURCE_LANGUAGE_CPP, "cpp,c++,C++,cxx", "C++ language"}, + {SLANG_SOURCE_LANGUAGE_SLANG, "slang", "Slang language"}, + {SLANG_SOURCE_LANGUAGE_GLSL, "glsl", "GLSL language"}, + {SLANG_SOURCE_LANGUAGE_HLSL, "hlsl", "HLSL language"}, + {SLANG_SOURCE_LANGUAGE_CUDA, "cu,cuda", "CUDA"}, }; -static const NamesDescriptionValue s_archiveTypeInfos[] = -{ - { SLANG_ARCHIVE_TYPE_RIFF_DEFLATE, "riff-deflate", "Slang RIFF using deflate compression" }, - { SLANG_ARCHIVE_TYPE_RIFF_LZ4, "riff-lz4", "Slang RIFF using LZ4 compression" }, - { SLANG_ARCHIVE_TYPE_ZIP, "zip", "Zip file" }, - { SLANG_ARCHIVE_TYPE_RIFF, "riff", "Slang RIFF without compression" }, +static const NamesDescriptionValue s_compilerInfos[] = { + {SLANG_PASS_THROUGH_NONE, "none", "Unknown"}, + {SLANG_PASS_THROUGH_FXC, "fxc", "FXC HLSL compiler"}, + {SLANG_PASS_THROUGH_DXC, "dxc", "DXC HLSL compiler"}, + {SLANG_PASS_THROUGH_GLSLANG, "glslang", "GLSLANG GLSL compiler"}, + {SLANG_PASS_THROUGH_SPIRV_DIS, "spirv-dis", "spirv-tools SPIRV disassembler"}, + {SLANG_PASS_THROUGH_CLANG, "clang", "Clang C/C++ compiler"}, + {SLANG_PASS_THROUGH_VISUAL_STUDIO, "visualstudio,vs", "Visual Studio C/C++ compiler"}, + {SLANG_PASS_THROUGH_GCC, "gcc", "GCC C/C++ compiler"}, + {SLANG_PASS_THROUGH_GENERIC_C_CPP, + "genericcpp,c,cpp", + "A generic C++ compiler (can be any one of visual studio, clang or gcc depending on system " + "and availability)"}, + {SLANG_PASS_THROUGH_NVRTC, "nvrtc", "NVRTC CUDA compiler"}, + {SLANG_PASS_THROUGH_LLVM, "llvm", "LLVM/Clang `slang-llvm`"}, + {SLANG_PASS_THROUGH_SPIRV_OPT, "spirv-opt", "spirv-tools SPIRV optimizer"}, + {SLANG_PASS_THROUGH_METAL, "metal", "Metal shader compiler"}, + {SLANG_PASS_THROUGH_TINT, "tint", "Tint compiler"}, }; -static const NamesDescriptionValue s_debugInfoFormatInfos[] = -{ - { SLANG_DEBUG_INFO_FORMAT_DEFAULT, "default-format", "Use the default debugging format for the target" }, - { SLANG_DEBUG_INFO_FORMAT_C7, "c7", "CodeView C7 format (typically means debugging infomation is embedded in the binary)" }, - { SLANG_DEBUG_INFO_FORMAT_PDB, "pdb", "Program database" }, - { SLANG_DEBUG_INFO_FORMAT_STABS, "stabs", "STABS debug format" }, - { SLANG_DEBUG_INFO_FORMAT_COFF, "coff", "COFF debug format" }, - { SLANG_DEBUG_INFO_FORMAT_DWARF, "dwarf", "DWARF debug format"}, +static const NamesDescriptionValue s_archiveTypeInfos[] = { + {SLANG_ARCHIVE_TYPE_RIFF_DEFLATE, "riff-deflate", "Slang RIFF using deflate compression"}, + {SLANG_ARCHIVE_TYPE_RIFF_LZ4, "riff-lz4", "Slang RIFF using LZ4 compression"}, + {SLANG_ARCHIVE_TYPE_ZIP, "zip", "Zip file"}, + {SLANG_ARCHIVE_TYPE_RIFF, "riff", "Slang RIFF without compression"}, }; -static const NamesDescriptionValue s_lineDirectiveInfos[] = -{ - { SLANG_LINE_DIRECTIVE_MODE_NONE, "none", "Don't emit `#line` directives at all"}, - { SLANG_LINE_DIRECTIVE_MODE_SOURCE_MAP, "source-map", "Use source map to track line associations (doen't emit #line)"}, - { SLANG_LINE_DIRECTIVE_MODE_DEFAULT, "default", "Default behavior"}, - { SLANG_LINE_DIRECTIVE_MODE_STANDARD, "standard", "Emit standard C-style `#line` directives." }, - { SLANG_LINE_DIRECTIVE_MODE_GLSL, "glsl", "Emit GLSL-style directives with file *number* instead of name." }, +static const NamesDescriptionValue s_debugInfoFormatInfos[] = { + {SLANG_DEBUG_INFO_FORMAT_DEFAULT, + "default-format", + "Use the default debugging format for the target"}, + {SLANG_DEBUG_INFO_FORMAT_C7, + "c7", + "CodeView C7 format (typically means debugging infomation is embedded in the binary)"}, + {SLANG_DEBUG_INFO_FORMAT_PDB, "pdb", "Program database"}, + {SLANG_DEBUG_INFO_FORMAT_STABS, "stabs", "STABS debug format"}, + {SLANG_DEBUG_INFO_FORMAT_COFF, "coff", "COFF debug format"}, + {SLANG_DEBUG_INFO_FORMAT_DWARF, "dwarf", "DWARF debug format"}, }; -static const NamesDescriptionValue s_floatingPointModes[] = -{ - { SLANG_FLOATING_POINT_MODE_PRECISE, "precise", - "Disable optimization that could change the output of floating-" - "point computations, including around infinities, NaNs, denormalized " - "values, and negative zero. Prefer the most precise versions of special " - "functions supported by the target."}, - { SLANG_FLOATING_POINT_MODE_FAST,"fast", - "Allow optimizations that may change results of floating-point " - "computations. Prefer the fastest version of special functions supported " - "by the target."}, - { SLANG_FLOATING_POINT_MODE_DEFAULT, "default", - "Default floating point mode" } +static const NamesDescriptionValue s_lineDirectiveInfos[] = { + {SLANG_LINE_DIRECTIVE_MODE_NONE, "none", "Don't emit `#line` directives at all"}, + {SLANG_LINE_DIRECTIVE_MODE_SOURCE_MAP, + "source-map", + "Use source map to track line associations (doen't emit #line)"}, + {SLANG_LINE_DIRECTIVE_MODE_DEFAULT, "default", "Default behavior"}, + {SLANG_LINE_DIRECTIVE_MODE_STANDARD, "standard", "Emit standard C-style `#line` directives."}, + {SLANG_LINE_DIRECTIVE_MODE_GLSL, + "glsl", + "Emit GLSL-style directives with file *number* instead of name."}, }; -static const NamesDescriptionValue s_optimizationLevels[] = -{ - { SLANG_OPTIMIZATION_LEVEL_NONE, "0,none", "Disable all optimizations" }, - { SLANG_OPTIMIZATION_LEVEL_DEFAULT, "1,default", "Enable a default level of optimization.This is the default if no -o options are used." }, - { SLANG_OPTIMIZATION_LEVEL_HIGH, "2,high", "Enable aggressive optimizations for speed." }, - { SLANG_OPTIMIZATION_LEVEL_MAXIMAL, "3,maximal", "Enable further optimizations, which might have a significant impact on compile time, or involve unwanted tradeoffs in terms of code size." }, +static const NamesDescriptionValue s_floatingPointModes[] = { + {SLANG_FLOATING_POINT_MODE_PRECISE, + "precise", + "Disable optimization that could change the output of floating-" + "point computations, including around infinities, NaNs, denormalized " + "values, and negative zero. Prefer the most precise versions of special " + "functions supported by the target."}, + {SLANG_FLOATING_POINT_MODE_FAST, + "fast", + "Allow optimizations that may change results of floating-point " + "computations. Prefer the fastest version of special functions supported " + "by the target."}, + {SLANG_FLOATING_POINT_MODE_DEFAULT, "default", "Default floating point mode"}}; + +static const NamesDescriptionValue s_optimizationLevels[] = { + {SLANG_OPTIMIZATION_LEVEL_NONE, "0,none", "Disable all optimizations"}, + {SLANG_OPTIMIZATION_LEVEL_DEFAULT, + "1,default", + "Enable a default level of optimization.This is the default if no -o options are used."}, + {SLANG_OPTIMIZATION_LEVEL_HIGH, "2,high", "Enable aggressive optimizations for speed."}, + {SLANG_OPTIMIZATION_LEVEL_MAXIMAL, + "3,maximal", + "Enable further optimizations, which might have a significant impact on compile time, or " + "involve unwanted tradeoffs in terms of code size."}, }; -static const NamesDescriptionValue s_debugLevels[] = -{ - { SLANG_DEBUG_INFO_LEVEL_NONE, "0,none", "Don't emit debug information at all." }, - { SLANG_DEBUG_INFO_LEVEL_MINIMAL, "1,minimal", "Emit as little debug information as possible, while still supporting stack traces." }, - { SLANG_DEBUG_INFO_LEVEL_STANDARD, "2,standard", "Emit whatever is the standard level of debug information for each target." }, - { SLANG_DEBUG_INFO_LEVEL_MAXIMAL, "3,maximal", "Emit as much debug information as possible for each target." }, +static const NamesDescriptionValue s_debugLevels[] = { + {SLANG_DEBUG_INFO_LEVEL_NONE, "0,none", "Don't emit debug information at all."}, + {SLANG_DEBUG_INFO_LEVEL_MINIMAL, + "1,minimal", + "Emit as little debug information as possible, while still supporting stack traces."}, + {SLANG_DEBUG_INFO_LEVEL_STANDARD, + "2,standard", + "Emit whatever is the standard level of debug information for each target."}, + {SLANG_DEBUG_INFO_LEVEL_MAXIMAL, + "3,maximal", + "Emit as much debug information as possible for each target."}, }; -static const NamesDescriptionValue s_fileSystemTypes[] = -{ - { ValueInt(TypeTextUtil::FileSystemType::Default), "default", "Default file system." }, - { ValueInt(TypeTextUtil::FileSystemType::LoadFile), "load-file", "Just implements loadFile interface, so will be wrapped with CacheFileSystem internally." }, - { ValueInt(TypeTextUtil::FileSystemType::Os), "os", "Use the OS based file system directly (without file system caching)" }, +static const NamesDescriptionValue s_fileSystemTypes[] = { + {ValueInt(TypeTextUtil::FileSystemType::Default), "default", "Default file system."}, + {ValueInt(TypeTextUtil::FileSystemType::LoadFile), + "load-file", + "Just implements loadFile interface, so will be wrapped with CacheFileSystem internally."}, + {ValueInt(TypeTextUtil::FileSystemType::Os), + "os", + "Use the OS based file system directly (without file system caching)"}, }; -} // anonymous +} // namespace -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getFileSystemTypeInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getFileSystemTypeInfos() { return makeConstArrayView(s_fileSystemTypes); } -/* static */ConstArrayView<TypeTextUtil::CompileTargetInfo> TypeTextUtil::getCompileTargetInfos() +/* static */ ConstArrayView<TypeTextUtil::CompileTargetInfo> TypeTextUtil::getCompileTargetInfos() { return makeConstArrayView(s_compileTargetInfos); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getLanguageInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getLanguageInfos() { return makeConstArrayView(s_languageInfos); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getCompilerInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getCompilerInfos() { return makeConstArrayView(s_compilerInfos); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getArchiveTypeInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getArchiveTypeInfos() { return makeConstArrayView(s_archiveTypeInfos); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getDebugInfoFormatInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getDebugInfoFormatInfos() { return makeConstArrayView(s_debugInfoFormatInfos); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getLineDirectiveInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getLineDirectiveInfos() { return makeConstArrayView(s_lineDirectiveInfos); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getFloatingPointModeInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getFloatingPointModeInfos() { return makeConstArrayView(s_floatingPointModes); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getOptimizationLevelInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getOptimizationLevelInfos() { return makeConstArrayView(s_optimizationLevels); } -/* static */ConstArrayView<NamesDescriptionValue> TypeTextUtil::getDebugLevelInfos() +/* static */ ConstArrayView<NamesDescriptionValue> TypeTextUtil::getDebugLevelInfos() { return makeConstArrayView(s_debugLevels); } -/* static */SlangArchiveType TypeTextUtil::findArchiveType(const UnownedStringSlice& slice) +/* static */ SlangArchiveType TypeTextUtil::findArchiveType(const UnownedStringSlice& slice) { return NameValueUtil::findValue(getArchiveTypeInfos(), slice, SLANG_ARCHIVE_TYPE_UNDEFINED); } -/* static */SlangResult TypeTextUtil::findDebugInfoFormat(const Slang::UnownedStringSlice& text, SlangDebugInfoFormat& out) +/* static */ SlangResult TypeTextUtil::findDebugInfoFormat( + const Slang::UnownedStringSlice& text, + SlangDebugInfoFormat& out) { const ValueInt value = NameValueUtil::findValue(getDebugInfoFormatInfos(), text, -1); if (value >= 0) @@ -231,25 +269,28 @@ static const NamesDescriptionValue s_fileSystemTypes[] = return SLANG_FAIL; } -/* static */UnownedStringSlice TypeTextUtil::getDebugInfoFormatName(SlangDebugInfoFormat format) +/* static */ UnownedStringSlice TypeTextUtil::getDebugInfoFormatName(SlangDebugInfoFormat format) { return NameValueUtil::findName(getDebugInfoFormatInfos(), format, toSlice("unknown")); } -/* static */UnownedStringSlice TypeTextUtil::getScalarTypeName(slang::TypeReflection::ScalarType scalarType) -{ +/* static */ UnownedStringSlice TypeTextUtil::getScalarTypeName( + slang::TypeReflection::ScalarType scalarType) +{ typedef slang::TypeReflection::ScalarType ScalarType; switch (scalarType) { -#define SLANG_SCALAR_TYPE_TO_TEXT(value, text) case ScalarType::value: return UnownedStringSlice::fromLiteral(#text); +#define SLANG_SCALAR_TYPE_TO_TEXT(value, text) \ + case ScalarType::value: return UnownedStringSlice::fromLiteral(#text); SLANG_SCALAR_TYPES(SLANG_SCALAR_TYPE_TO_TEXT) - default: break; + default: break; } return UnownedStringSlice(); } -/* static */slang::TypeReflection::ScalarType TypeTextUtil::findScalarType(const UnownedStringSlice& inText) +/* static */ slang::TypeReflection::ScalarType TypeTextUtil::findScalarType( + const UnownedStringSlice& inText) { for (Index i = 0; i < SLANG_COUNT_OF(s_scalarTypeInfos); ++i) { @@ -263,38 +304,42 @@ static const NamesDescriptionValue s_fileSystemTypes[] = } -/* static */UnownedStringSlice TypeTextUtil::getPassThroughAsHumanText(SlangPassThrough type) +/* static */ UnownedStringSlice TypeTextUtil::getPassThroughAsHumanText(SlangPassThrough type) { return NameValueUtil::findName(getCompilerInfos(), type, toSlice("unknown")); } -/* static */SlangSourceLanguage TypeTextUtil::findSourceLanguage(const UnownedStringSlice& text) +/* static */ SlangSourceLanguage TypeTextUtil::findSourceLanguage(const UnownedStringSlice& text) { return NameValueUtil::findValue(getLanguageInfos(), text, SLANG_SOURCE_LANGUAGE_UNKNOWN); } -/* static */SlangPassThrough TypeTextUtil::findPassThrough(const UnownedStringSlice& slice) +/* static */ SlangPassThrough TypeTextUtil::findPassThrough(const UnownedStringSlice& slice) { return NameValueUtil::findValue(getCompilerInfos(), slice, SLANG_PASS_THROUGH_NONE); } -/* static */SlangResult TypeTextUtil::findPassThrough(const UnownedStringSlice& slice, SlangPassThrough& outPassThrough) +/* static */ SlangResult TypeTextUtil::findPassThrough( + const UnownedStringSlice& slice, + SlangPassThrough& outPassThrough) { outPassThrough = findPassThrough(slice); // It could be none on error - if it's not equal to "none" then it must be an error - if (outPassThrough == SLANG_PASS_THROUGH_NONE && slice != UnownedStringSlice::fromLiteral("none")) + if (outPassThrough == SLANG_PASS_THROUGH_NONE && + slice != UnownedStringSlice::fromLiteral("none")) { return SLANG_FAIL; } return SLANG_OK; } -/* static */UnownedStringSlice TypeTextUtil::getPassThroughName(SlangPassThrough passThru) +/* static */ UnownedStringSlice TypeTextUtil::getPassThroughName(SlangPassThrough passThru) { return NameValueUtil::findName(getCompilerInfos(), passThru, toSlice("unknown")); } -/* static */SlangCompileTarget TypeTextUtil::findCompileTargetFromExtension(const UnownedStringSlice& slice) +/* static */ SlangCompileTarget TypeTextUtil::findCompileTargetFromExtension( + const UnownedStringSlice& slice) { if (slice.getLength()) { @@ -309,7 +354,8 @@ static const NamesDescriptionValue s_fileSystemTypes[] = return SLANG_TARGET_UNKNOWN; } -/* static */ SlangCompileTarget TypeTextUtil::findCompileTargetFromName(const UnownedStringSlice& slice) +/* static */ SlangCompileTarget TypeTextUtil::findCompileTargetFromName( + const UnownedStringSlice& slice) { if (slice.getLength()) { @@ -340,8 +386,11 @@ UnownedStringSlice TypeTextUtil::getCompileTargetName(SlangCompileTarget target) { const Index index = _getTargetInfoIndex(target); // Return the first name - return index >= 0 ? StringUtil::getAtInSplit(UnownedStringSlice(s_compileTargetInfos[index].names), ',', 0) : UnownedStringSlice(); -} - + return index >= 0 ? StringUtil::getAtInSplit( + UnownedStringSlice(s_compileTargetInfos[index].names), + ',', + 0) + : UnownedStringSlice(); } +} // namespace Slang diff --git a/source/core/slang-type-text-util.h b/source/core/slang-type-text-util.h index 6d07e7d58..730888254 100644 --- a/source/core/slang-type-text-util.h +++ b/source/core/slang-type-text-util.h @@ -1,11 +1,10 @@ #ifndef SLANG_CORE_TYPE_TEXT_UTIL_H #define SLANG_CORE_TYPE_TEXT_UTIL_H -#include "slang.h" - -#include "slang-string.h" #include "slang-array-view.h" #include "slang-name-value.h" +#include "slang-string.h" +#include "slang.h" namespace Slang { @@ -22,74 +21,80 @@ struct TypeTextUtil struct CompileTargetInfo { - SlangCompileTarget target; ///< The target - const char* extensions; ///< Comma delimited list of extensions associated with the target - const char* names; ///< Comma delimited list of names associated with the target. NOTE! First name is taken as the normal display name. - const char* description = nullptr; ///< Description, can be null + SlangCompileTarget target; ///< The target + const char* extensions; ///< Comma delimited list of extensions associated with the target + const char* names; ///< Comma delimited list of names associated with the target. NOTE! + ///< First name is taken as the normal display name. + const char* description = nullptr; ///< Description, can be null }; - - /// Get the compile target infos + + /// Get the compile target infos static ConstArrayView<CompileTargetInfo> getCompileTargetInfos(); - /// Get the language infos + /// Get the language infos static ConstArrayView<NamesDescriptionValue> getLanguageInfos(); - /// Get the compiler infos + /// Get the compiler infos static ConstArrayView<NamesDescriptionValue> getCompilerInfos(); - /// Get the archive type infos + /// Get the archive type infos static ConstArrayView<NamesDescriptionValue> getArchiveTypeInfos(); - /// Get the debug format types + /// Get the debug format types static ConstArrayView<NamesDescriptionValue> getDebugInfoFormatInfos(); - /// Get the debug levels + /// Get the debug levels static ConstArrayView<NamesDescriptionValue> getDebugLevelInfos(); - /// Get the floating point modes + /// Get the floating point modes static ConstArrayView<NamesDescriptionValue> getFloatingPointModeInfos(); - // Get the line directive infos + // Get the line directive infos static ConstArrayView<NamesDescriptionValue> getLineDirectiveInfos(); - /// Get the optimization level info + /// Get the optimization level info static ConstArrayView<NamesDescriptionValue> getOptimizationLevelInfos(); - /// Get the file system type infos + /// Get the file system type infos static ConstArrayView<NamesDescriptionValue> getFileSystemTypeInfos(); - /// Get the scalar type as text. - static Slang::UnownedStringSlice getScalarTypeName(slang::TypeReflection::ScalarType scalarType); + /// Get the scalar type as text. + static Slang::UnownedStringSlice getScalarTypeName( + slang::TypeReflection::ScalarType scalarType); - // Converts text to scalar type. Returns 'none' if not determined + // Converts text to scalar type. Returns 'none' if not determined static slang::TypeReflection::ScalarType findScalarType(const Slang::UnownedStringSlice& text); - /// Given a slice finds the associated debug info format - static SlangResult findDebugInfoFormat(const Slang::UnownedStringSlice& text, SlangDebugInfoFormat& out); + /// Given a slice finds the associated debug info format + static SlangResult findDebugInfoFormat( + const Slang::UnownedStringSlice& text, + SlangDebugInfoFormat& out); - /// Get the text name for a format + /// Get the text name for a format static UnownedStringSlice getDebugInfoFormatName(SlangDebugInfoFormat format); - /// As human readable text + /// As human readable text static UnownedStringSlice getPassThroughAsHumanText(SlangPassThrough type); - - /// Given a source language name returns a source language. Name here is distinct from extension + + /// Given a source language name returns a source language. Name here is distinct from extension static SlangSourceLanguage findSourceLanguage(const UnownedStringSlice& text); - /// Given a name returns the pass through + /// Given a name returns the pass through static SlangPassThrough findPassThrough(const UnownedStringSlice& slice); - static SlangResult findPassThrough(const UnownedStringSlice& slice, SlangPassThrough& outPassThrough); + static SlangResult findPassThrough( + const UnownedStringSlice& slice, + SlangPassThrough& outPassThrough); - /// Get the compilers name + /// Get the compilers name static UnownedStringSlice getPassThroughName(SlangPassThrough passThru); - /// Given a file extension determines suitable target - /// If doesn't match any target will return SLANG_TARGET_UNKNOWN + /// Given a file extension determines suitable target + /// If doesn't match any target will return SLANG_TARGET_UNKNOWN static SlangCompileTarget findCompileTargetFromExtension(const UnownedStringSlice& slice); - /// Given a name suitable target - /// If doesn't match any target will return SLANG_TARGET_UNKNOWN + /// Given a name suitable target + /// If doesn't match any target will return SLANG_TARGET_UNKNOWN static SlangCompileTarget findCompileTargetFromName(const UnownedStringSlice& slice); - /// Given a target returns the associated name. + /// Given a target returns the associated name. static UnownedStringSlice getCompileTargetName(SlangCompileTarget target); - /// Returns SLANG_ARCHIVE_TYPE_UNKNOWN if a match is not found + /// Returns SLANG_ARCHIVE_TYPE_UNKNOWN if a match is not found static SlangArchiveType findArchiveType(const UnownedStringSlice& slice); }; -} +} // namespace Slang #endif // SLANG_CORE_TYPE_TEXT_UTIL_H diff --git a/source/core/slang-type-traits.h b/source/core/slang-type-traits.h index ccd1fb29c..193dc948f 100644 --- a/source/core/slang-type-traits.h +++ b/source/core/slang-type-traits.h @@ -3,44 +3,58 @@ namespace Slang { - struct TraitResultYes - { - char x; - }; - struct TraitResultNo - { - char x[2]; - }; +struct TraitResultYes +{ + char x; +}; +struct TraitResultNo +{ + char x[2]; +}; - template <typename B, typename D> - struct IsBaseOfTraitHost - { - operator B*() const { return nullptr; } - operator D*() { return nullptr; } - }; +template<typename B, typename D> +struct IsBaseOfTraitHost +{ + operator B*() const { return nullptr; } + operator D*() { return nullptr; } +}; - template <typename B, typename D> - struct IsBaseOf - { - template <typename T> - static TraitResultYes Check(D*, T) { return TraitResultYes(); } - static TraitResultNo Check(B*, int) { return TraitResultNo(); } - enum { Value = sizeof(Check(IsBaseOfTraitHost<B, D>(), int())) == sizeof(TraitResultYes) }; - }; +template<typename B, typename D> +struct IsBaseOf +{ + template<typename T> + static TraitResultYes Check(D*, T) + { + return TraitResultYes(); + } + static TraitResultNo Check(B*, int) { return TraitResultNo(); } + enum + { + Value = sizeof(Check(IsBaseOfTraitHost<B, D>(), int())) == sizeof(TraitResultYes) + }; +}; - template<bool B, class T = void> - struct EnableIf {}; +template<bool B, class T = void> +struct EnableIf +{ +}; - template<class T> - struct EnableIf<true, T> { typedef T type; }; +template<class T> +struct EnableIf<true, T> +{ + typedef T type; +}; - template <typename B, typename D> - struct IsConvertible - { - static TraitResultYes Use(B) { return TraitResultYes(); }; - static TraitResultNo Use(...) { return TraitResultNo(); }; - enum { Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) }; - }; -} +template<typename B, typename D> +struct IsConvertible +{ + static TraitResultYes Use(B) { return TraitResultYes(); }; + static TraitResultNo Use(...) { return TraitResultNo(); }; + enum + { + Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) + }; +}; +} // namespace Slang #endif diff --git a/source/core/slang-uint-set.cpp b/source/core/slang-uint-set.cpp index 457915449..ec086c5de 100644 --- a/source/core/slang-uint-set.cpp +++ b/source/core/slang-uint-set.cpp @@ -40,13 +40,14 @@ HashCode UIntSet::getHashCode() const { int rs = 0; for (auto val : m_buffer) - rs ^= val; + rs ^= val; return rs; } void UIntSet::resizeAndClear(UInt val) { - // TODO(JS): This could be faster in that if the resize is larger the additional area is cleared twice + // TODO(JS): This could be faster in that if the resize is larger the additional area is cleared + // twice resize(val); clear(); } @@ -86,7 +87,9 @@ void UIntSet::unionWith(const UIntSet& set) } if (set.m_buffer.getCount() > m_buffer.getCount()) - m_buffer.addRange(set.m_buffer.getBuffer() + m_buffer.getCount(), set.m_buffer.getCount() - m_buffer.getCount()); + m_buffer.addRange( + set.m_buffer.getBuffer() + m_buffer.getCount(), + set.m_buffer.getCount() - m_buffer.getCount()); } bool UIntSet::operator==(const UIntSet& set) const @@ -98,16 +101,19 @@ bool UIntSet::operator==(const UIntSet& set) const const auto bElems = set.m_buffer.getBuffer(); const Index minCount = Math::Min(aCount, bCount); - - return ::memcmp(aElems, bElems, minCount*sizeof(Element)) == 0 && - _areAllZero(aElems + minCount, aCount - minCount) && - _areAllZero(bElems + minCount, bCount - minCount); + + return ::memcmp(aElems, bElems, minCount * sizeof(Element)) == 0 && + _areAllZero(aElems + minCount, aCount - minCount) && + _areAllZero(bElems + minCount, bCount - minCount); } void UIntSet::intersectWith(const UIntSet& set) { if (set.m_buffer.getCount() < m_buffer.getCount()) - ::memset(m_buffer.getBuffer() + set.m_buffer.getCount(), 0, (m_buffer.getCount() - set.m_buffer.getCount()) * sizeof(Element)); + ::memset( + m_buffer.getBuffer() + set.m_buffer.getCount(), + 0, + (m_buffer.getCount() - set.m_buffer.getCount()) * sizeof(Element)); const Index minCount = Math::Min(set.m_buffer.getCount(), m_buffer.getCount()); for (Index i = 0; i < minCount; i++) @@ -125,9 +131,10 @@ void UIntSet::subtractWith(const UIntSet& set) } } -/* static */void UIntSet::calcUnion(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2) +/* static */ void UIntSet::calcUnion(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2) { - outRs.resizeBackingBufferDirectly(Math::Max(set1.m_buffer.getCount(), set2.m_buffer.getCount())); + outRs.resizeBackingBufferDirectly( + Math::Max(set1.m_buffer.getCount(), set2.m_buffer.getCount())); outRs.clear(); for (Index i = 0; i < set1.m_buffer.getCount(); i++) outRs.m_buffer[i] |= set1.m_buffer[i]; @@ -135,7 +142,10 @@ void UIntSet::subtractWith(const UIntSet& set) outRs.m_buffer[i] |= set2.m_buffer[i]; } -/* static */void UIntSet::calcIntersection(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2) +/* static */ void UIntSet::calcIntersection( + UIntSet& outRs, + const UIntSet& set1, + const UIntSet& set2) { const Index minCount = Math::Min(set1.m_buffer.getCount(), set2.m_buffer.getCount()); outRs.resizeBackingBufferDirectly(minCount); @@ -144,7 +154,7 @@ void UIntSet::subtractWith(const UIntSet& set) outRs.m_buffer[i] = set1.m_buffer[i] & set2.m_buffer[i]; } -/* static */void UIntSet::calcSubtract(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2) +/* static */ void UIntSet::calcSubtract(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2) { outRs.resizeBackingBufferDirectly(set1.m_buffer.getCount()); @@ -153,7 +163,7 @@ void UIntSet::subtractWith(const UIntSet& set) outRs.m_buffer[i] = set1.m_buffer[i] & (~set2.m_buffer[i]); } -/* static */bool UIntSet::hasIntersection(const UIntSet& set1, const UIntSet& set2) +/* static */ bool UIntSet::hasIntersection(const UIntSet& set1, const UIntSet& set2) { const Index minCount = Math::Min(set1.m_buffer.getCount(), set2.m_buffer.getCount()); for (Index i = 0; i < minCount; i++) @@ -168,7 +178,8 @@ Index UIntSet::countElements() const { // TODO: This can be made faster using SIMD intrinsics to count set bits. uint64_t tmp; - constexpr Index loopSize = ((sizeof(Element) / sizeof(tmp)) != 0) ? sizeof(Element) / sizeof(tmp) : 1; + constexpr Index loopSize = + ((sizeof(Element) / sizeof(tmp)) != 0) ? sizeof(Element) / sizeof(tmp) : 1; Index count = 0; for (auto index = 0; index < this->m_buffer.getCount(); index++) { @@ -183,5 +194,4 @@ Index UIntSet::countElements() const return count; } -} - +} // namespace Slang diff --git a/source/core/slang-uint-set.h b/source/core/slang-uint-set.h index 3531e5cfb..ef2668d5a 100644 --- a/source/core/slang-uint-set.h +++ b/source/core/slang-uint-set.h @@ -1,10 +1,10 @@ #ifndef SLANG_CORE_UINT_SET_H #define SLANG_CORE_UINT_SET_H -#include "slang-list.h" -#include "slang-math.h" #include "slang-common.h" #include "slang-hash.h" +#include "slang-list.h" +#include "slang-math.h" #if defined(_MSC_VER) #include <intrin.h> @@ -34,32 +34,36 @@ static inline Index bitscanForward(uint64_t in) // check for 0s in 0bit->31bit. If all 0's, check for 0s in 32bit->63bit if (_BitScanForward((unsigned long*)&out, *(((uint32_t*)&in)))) return Index(out); - _BitScanForward((unsigned long*)&out, *(((uint32_t*)&in)+1)); - return Index(out)+32; -#endif// #ifdef _WIN64 + _BitScanForward((unsigned long*)&out, *(((uint32_t*)&in) + 1)); + return Index(out) + 32; +#endif // #ifdef _WIN64 -#else +#else return Index(__builtin_ctzll(in)); -#endif// #if defined(_MSC_VER) +#endif // #if defined(_MSC_VER) } /* Hold a set of UInt values. Implementation works by storing as a bit per value */ /// UIntSet is essentially a Element[], where each Element is `b` bits big. -/// Each index has `b` number of integers. If the bit is 1, we have an element there. +/// Each index has `b` number of integers. If the bit is 1, we have an element there. /// Value of each element is equal to the binary offset from Element[0], bit 0. class UIntSet { public: typedef UIntSet ThisType; - typedef uint64_t Element; ///< Type that holds the bits to say if value is present - - constexpr static Index kElementSize = sizeof(Element) * 8; ///< The number of bits in an element. This also determines how many values a element can hold. + typedef uint64_t Element; ///< Type that holds the bits to say if value is present + + constexpr static Index kElementSize = + sizeof(Element) * 8; ///< The number of bits in an element. This also determines how many + ///< values a element can hold. constexpr static Index kElementMask = kElementSize - 1; ///< Mask to get shift from an index - constexpr static Index kElementShift = intLog2(sizeof(Element)*8); ///< How many bits to shift to get Element index from an index. 5 for 2^5=32 elements in a uint32_t. 6 for 2^6=64 in a uint64_t. + constexpr static Index kElementShift = intLog2( + sizeof(Element) * 8); ///< How many bits to shift to get Element index from an index. 5 for + ///< 2^5=32 elements in a uint32_t. 6 for 2^6=64 in a uint64_t. UIntSet() {} UIntSet(const UIntSet& other) { m_buffer = other.m_buffer; } - UIntSet(UIntSet && other) { *this = (_Move(other)); } + UIntSet(UIntSet&& other) { *this = (_Move(other)); } UIntSet(UInt maxVal) { resizeAndClear(maxVal); } UIntSet& operator=(UIntSet&& other); @@ -72,65 +76,66 @@ public: const List<Element>& getBuffer() const { return m_buffer; } - /// Resize such that val can be stored and clear contents + /// Resize such that val can be stored and clear contents void resizeAndClear(UInt val); - /// Set all of the values up to count, as set + /// Set all of the values up to count, as set void setAll(); - /// Resize (but maintain contents) up to bit size. - /// NOTE! That since storage is in Element blocks, it may mean some values after size are set (up to the Element boundary) + /// Resize (but maintain contents) up to bit size. + /// NOTE! That since storage is in Element blocks, it may mean some values after size are set + /// (up to the Element boundary) void resize(UInt size); void resizeBackingBufferDirectly(Index size); - /// Clear all of the contents (by clearing the bits) + /// Clear all of the contents (by clearing the bits) void clear(); - /// Clear all the contents and free memory + /// Clear all the contents and free memory void clearAndDeallocate(); - /// Add a value + /// Add a value inline void add(UInt val); inline void add(const UIntSet& val); inline void addRange(const List<UInt>& other); inline void addRawElement(Element val, Index bitOffset); - /// Remove a value + /// Remove a value inline void remove(UInt val); - /// Returns true if the value is present + /// Returns true if the value is present inline bool contains(UInt val) const; inline bool contains(const UIntSet& set) const; - /// == + /// == bool operator==(const UIntSet& set) const; - /// != + /// != bool operator!=(const UIntSet& set) const { return !(*this == set); } - /// Store the union between this and set + /// Store the union between this and set void unionWith(const UIntSet& set); - /// Store the intersection between this and set + /// Store the intersection between this and set void intersectWith(const UIntSet& set); - /// Store the subtraction between this and set + /// Store the subtraction between this and set void subtractWith(const UIntSet& set); - /// + /// bool isEmpty() const; - /// Swap this with rhs + /// Swap this with rhs void swapWith(ThisType& rhs) { m_buffer.swapWith(rhs.m_buffer); } template<typename T> List<T> getElements() const; Index countElements() const; - /// Store the union of set1 and set2 in outRs + /// Store the union of set1 and set2 in outRs static void calcUnion(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2); - /// Store the intersection of set1 and set2 in outRs + /// Store the intersection of set1 and set2 in outRs static void calcIntersection(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2); - /// Store the subtraction of set2 from set1 in outRs + /// Store the subtraction of set2 from set1 in outRs static void calcSubtract(UIntSet& outRs, const UIntSet& set1, const UIntSet& set2); - /// Returns true if set1 and set2 have a same value set (ie there is an intersection) + /// Returns true if set1 and set2 have a same value set (ie there is an intersection) static bool hasIntersection(const UIntSet& set1, const UIntSet& set2); /// Get LSB Zero of UIntSet. LSB Zero is the smallest value missing from this UIntSet. @@ -139,6 +144,7 @@ public: struct Iterator { friend class UIntSet; + private: const List<Element>* m_context; Index m_block = 0; @@ -151,16 +157,10 @@ public: m_processedElement &= m_processedElement - 1; } - Iterator(const List<Element>* context) - { - m_context = context; - } - public: + Iterator(const List<Element>* context) { m_context = context; } - Element operator*() - { - return Element(m_LSB + (kElementSize * m_block)); - } + public: + Element operator*() { return Element(m_LSB + (kElementSize * m_block)); } Iterator& operator++() { @@ -176,19 +176,13 @@ public: clearLSB(); return *this; } - Iterator& operator++(int) - { - return ++(*this); - } + Iterator& operator++(int) { return ++(*this); } bool operator==(const Iterator& other) const { - return other.m_block == this->m_block - && other.m_processedElement == this->m_processedElement; - } - bool operator!=(const Iterator& other) const - { - return !(other == *this); + return other.m_block == this->m_block && + other.m_processedElement == this->m_processedElement; } + bool operator!=(const Iterator& other) const { return !(other == *this); } }; Iterator begin() const { @@ -214,10 +208,7 @@ public: return tmp; } - bool areAllZero() - { - return _areAllZero(m_buffer.getBuffer(), m_buffer.getCount()); - } + bool areAllZero() { return _areAllZero(m_buffer.getBuffer(), m_buffer.getCount()); } protected: static bool _areAllZero(const UIntSet::Element* elems, Index count) @@ -250,7 +241,7 @@ inline bool UIntSet::contains(UInt val) const { const Index idx = Index(val >> kElementShift); return idx < m_buffer.getCount() && - ((m_buffer[idx] & (Element(1) << (val & kElementMask))) != 0); + ((m_buffer[idx] & (Element(1) << (val & kElementMask))) != 0); } // -------------------------------------------------------------------------- @@ -313,8 +304,8 @@ inline void UIntSet::addRange(const List<UInt>& other) inline void UIntSet::addRawElement(Element other, Index elementIndex) { - if(this->m_buffer.getCount() <= elementIndex) - resizeBackingBufferDirectly(elementIndex+1); + if (this->m_buffer.getCount() <= elementIndex) + resizeBackingBufferDirectly(elementIndex + 1); m_buffer[elementIndex] |= other; } @@ -325,7 +316,8 @@ List<T> UIntSet::getElements() const if (count == 0) return {}; - // Specific path for uint64_t. If using SIMD we should not use this path due to larger data types. + // Specific path for uint64_t. If using SIMD we should not use this path due to larger data + // types. List<T> elements; elements.reserve(count); @@ -341,5 +333,5 @@ List<T> UIntSet::getElements() const return elements; } -} +} // namespace Slang #endif diff --git a/source/core/slang-virtual-object-pool.h b/source/core/slang-virtual-object-pool.h index c1247acb7..6e8682c16 100644 --- a/source/core/slang-virtual-object-pool.h +++ b/source/core/slang-virtual-object-pool.h @@ -4,10 +4,10 @@ namespace Slang { - /// A virtual free-list allocater. - /// This class doesn't actually allocates memory, instead it operates on a - /// virtual integer space. Can be used to implement various types of object pools - /// that needs to support contiguous allocations of more than one elements. +/// A virtual free-list allocater. +/// This class doesn't actually allocates memory, instead it operates on a +/// virtual integer space. Can be used to implement various types of object pools +/// that needs to support contiguous allocations of more than one elements. class VirtualObjectPool { public: diff --git a/source/core/slang-writer.cpp b/source/core/slang-writer.cpp index 74a39f871..eb315323c 100644 --- a/source/core/slang-writer.cpp +++ b/source/core/slang-writer.cpp @@ -1,4 +1,4 @@ -#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS #include "slang-writer.h" @@ -9,9 +9,9 @@ // output when writing assembly dumps. #include <fcntl.h> #ifdef _WIN32 -# include <io.h> +#include <io.h> #else -# include <unistd.h> +#include <unistd.h> #endif #include <stdarg.h> @@ -64,7 +64,9 @@ SlangResult WriterHelper::put(const UnownedStringSlice& text) ISlangUnknown* BaseWriter::getInterface(const Guid& guid) { - return (guid == ISlangUnknown::getTypeGuid() || guid == ISlangWriter::getTypeGuid()) ? static_cast<ISlangWriter*>(this) : nullptr; + return (guid == ISlangUnknown::getTypeGuid() || guid == ISlangWriter::getTypeGuid()) + ? static_cast<ISlangWriter*>(this) + : nullptr; } /* !!!!!!!!!!!!!!!!!!!!!!!!! AppendBufferWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ @@ -76,7 +78,8 @@ SLANG_NO_THROW char* SLANG_MCALL AppendBufferWriter::beginAppendBuffer(size_t ma return m_appendBuffer.getBuffer(); } -SLANG_NO_THROW SlangResult SLANG_MCALL AppendBufferWriter::endAppendBuffer(char* buffer, size_t numChars) +SLANG_NO_THROW SlangResult SLANG_MCALL +AppendBufferWriter::endAppendBuffer(char* buffer, size_t numChars) { SLANG_ASSERT(m_appendBuffer.getBuffer() == buffer && buffer + numChars <= m_appendBuffer.end()); // Do the actual write @@ -102,7 +105,8 @@ SlangResult CallbackWriter::write(const char* chars, size_t numChars) { char* appendBuffer = m_appendBuffer.getBuffer(); // See if it's from an append buffer - if (chars >= appendBuffer && (chars + numChars) < (appendBuffer + m_appendBuffer.getCount())) + if (chars >= appendBuffer && + (chars + numChars) < (appendBuffer + m_appendBuffer.getCount())) { // Set terminating 0 appendBuffer[(chars + numChars) - appendBuffer] = 0; @@ -153,7 +157,7 @@ void FileWriter::flush() ::fflush(m_file); } -/* static */bool FileWriter::isConsole(FILE* file) +/* static */ bool FileWriter::isConsole(FILE* file) { const int stdoutFileDesc = _fileno(file); return _isatty(stdoutFileDesc) != 0; @@ -164,21 +168,25 @@ SlangResult FileWriter::setMode(SlangWriterMode mode) switch (mode) { case SLANG_WRITER_MODE_BINARY: - { + { #ifdef _WIN32 - int stdoutFileDesc = _fileno(m_file); - _setmode(stdoutFileDesc, _O_BINARY); - return SLANG_OK; + int stdoutFileDesc = _fileno(m_file); + _setmode(stdoutFileDesc, _O_BINARY); + return SLANG_OK; #else - break; + break; #endif - } + } default: break; } return SLANG_FAIL; } -/* static */SlangResult FileWriter::create(const char* filePath, const char* writeOptions, WriterFlags flags, ComPtr<ISlangWriter>& outWriter) +/* static */ SlangResult FileWriter::create( + const char* filePath, + const char* writeOptions, + WriterFlags flags, + ComPtr<ISlangWriter>& outWriter) { flags &= ~WriterFlag::IsUnowned; @@ -215,5 +223,4 @@ SlangResult StringWriter::write(const char* chars, size_t numChars) return SLANG_OK; } -} - +} // namespace Slang diff --git a/source/core/slang-writer.h b/source/core/slang-writer.h index e29939161..c6822a6e3 100644 --- a/source/core/slang-writer.h +++ b/source/core/slang-writer.h @@ -1,12 +1,10 @@ #ifndef SLANG_CORE_WRITER_H #define SLANG_CORE_WRITER_H -#include "slang-string.h" - #include "slang-com-helper.h" #include "slang-com-ptr.h" - #include "slang-list.h" +#include "slang-string.h" #include <mutex> @@ -20,12 +18,18 @@ public: SlangResult print(const char* format, ...); SlangResult put(const char* text); SlangResult put(const UnownedStringSlice& text); - SLANG_FORCE_INLINE SlangResult write(const char* chars, size_t numChars) { return m_writer->write(chars, numChars); } + SLANG_FORCE_INLINE SlangResult write(const char* chars, size_t numChars) + { + return m_writer->write(chars, numChars); + } SLANG_FORCE_INLINE void flush() { m_writer->flush(); } - - ISlangWriter* getWriter() const { return m_writer; } - WriterHelper(ISlangWriter* writer) :m_writer(writer) {} + ISlangWriter* getWriter() const { return m_writer; } + + WriterHelper(ISlangWriter* writer) + : m_writer(writer) + { + } protected: ISlangWriter* m_writer; @@ -33,13 +37,14 @@ protected: struct WriterFlag { - enum Enum :uint32_t + enum Enum : uint32_t { - IsStatic = 0x1, ///< Means non ref counted - IsConsole = 0x2, ///< True if console - IsUnowned = 0x4, ///< True if doesn't own contained type - AutoFlush = 0x8, ///< Automatically flushes after every call + IsStatic = 0x1, ///< Means non ref counted + IsConsole = 0x2, ///< True if console + IsUnowned = 0x4, ///< True if doesn't own contained type + AutoFlush = 0x8, ///< Automatically flushes after every call }; + private: WriterFlag() = delete; }; @@ -51,24 +56,36 @@ public: // ISlangUnknown SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE SLANG_REF_OBJECT_IUNKNOWN_ADD_REF - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return (m_flags & WriterFlag::IsStatic) ? (uint32_t)decreaseReference() : (uint32_t)releaseReference(); } + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE + { + return (m_flags & WriterFlag::IsStatic) ? (uint32_t)decreaseReference() + : (uint32_t)releaseReference(); + } // ISlangWriter - default impl SLANG_NO_THROW virtual void SLANG_MCALL flush() SLANG_OVERRIDE {} - SLANG_NO_THROW virtual bool SLANG_MCALL isConsole() SLANG_OVERRIDE { return (m_flags & WriterFlag::IsConsole) != 0; } - SLANG_NO_THROW virtual SlangResult SLANG_MCALL setMode(SlangWriterMode mode) SLANG_OVERRIDE { SLANG_UNUSED(mode); return SLANG_FAIL; } + SLANG_NO_THROW virtual bool SLANG_MCALL isConsole() SLANG_OVERRIDE + { + return (m_flags & WriterFlag::IsConsole) != 0; + } + SLANG_NO_THROW virtual SlangResult SLANG_MCALL setMode(SlangWriterMode mode) SLANG_OVERRIDE + { + SLANG_UNUSED(mode); + return SLANG_FAIL; + } - BaseWriter(WriterFlags flags) : - m_flags(flags) + BaseWriter(WriterFlags flags) + : m_flags(flags) { } protected: - ISlangUnknown * getInterface(const Guid& guid); + ISlangUnknown* getInterface(const Guid& guid); WriterFlags m_flags; }; -/* Implemented the append buffer part of the writer, such that calls to begin/endAppendBuffer are transformed into appropriate calls to write method */ +/* Implemented the append buffer part of the writer, such that calls to begin/endAppendBuffer are + * transformed into appropriate calls to write method */ class AppendBufferWriter : public BaseWriter { public: @@ -76,11 +93,13 @@ public: // ISlangWriter default impl for appendBuffer SLANG_NO_THROW char* SLANG_MCALL beginAppendBuffer(size_t maxNumChars) SLANG_OVERRIDE; - SLANG_NO_THROW SlangResult SLANG_MCALL endAppendBuffer(char* buffer, size_t numChars) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL endAppendBuffer(char* buffer, size_t numChars) + SLANG_OVERRIDE; - AppendBufferWriter(WriterFlags flags) : - Parent(flags) - {} + AppendBufferWriter(WriterFlags flags) + : Parent(flags) + { + } protected: List<char> m_appendBuffer; @@ -93,16 +112,15 @@ public: typedef AppendBufferWriter Parent; // ISlangWriter SLANG_NO_THROW char* SLANG_MCALL beginAppendBuffer(size_t maxNumChars) SLANG_OVERRIDE; - SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) SLANG_OVERRIDE; - - CallbackWriter(SlangDiagnosticCallback callback, const void* data, WriterFlags flags) : - Parent(flags), - m_callback(callback), - m_data(data) - {} + SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) + SLANG_OVERRIDE; + + CallbackWriter(SlangDiagnosticCallback callback, const void* data, WriterFlags flags) + : Parent(flags), m_callback(callback), m_data(data) + { + } protected: - SlangDiagnosticCallback m_callback; const void* m_data; }; @@ -112,26 +130,46 @@ class FileWriter : public AppendBufferWriter public: typedef AppendBufferWriter Parent; // ISlangWriter - SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) SLANG_OVERRIDE; + SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) + SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL flush() SLANG_OVERRIDE; SLANG_NO_THROW virtual SlangResult SLANG_MCALL setMode(SlangWriterMode mode) SLANG_OVERRIDE; static bool isConsole(FILE* file); - static WriterFlags getDefaultFlags(FILE* file) { return isConsole(file) ? WriterFlags(WriterFlag::IsConsole) : 0; } - - /// Ctor - FileWriter(FILE* file, WriterFlags flags) : - Parent(flags | getDefaultFlags(file)), - m_file(file) - {} + static WriterFlags getDefaultFlags(FILE* file) + { + return isConsole(file) ? WriterFlags(WriterFlag::IsConsole) : 0; + } - /// - static SlangResult create(const char* filePath, const char* writeOptions, WriterFlags flags, ComPtr<ISlangWriter>& outWriter); + /// Ctor + FileWriter(FILE* file, WriterFlags flags) + : Parent(flags | getDefaultFlags(file)), m_file(file) + { + } - static SlangResult createBinary(const char* filePath, WriterFlags flags, ComPtr<ISlangWriter>& outWriter) { return create(filePath, "wb", flags, outWriter); } - static SlangResult createText(const char* filePath, WriterFlags flags, ComPtr<ISlangWriter>& outWriter) { return create(filePath, "w", flags, outWriter); } + /// + static SlangResult create( + const char* filePath, + const char* writeOptions, + WriterFlags flags, + ComPtr<ISlangWriter>& outWriter); + + static SlangResult createBinary( + const char* filePath, + WriterFlags flags, + ComPtr<ISlangWriter>& outWriter) + { + return create(filePath, "wb", flags, outWriter); + } + static SlangResult createText( + const char* filePath, + WriterFlags flags, + ComPtr<ISlangWriter>& outWriter) + { + return create(filePath, "w", flags, outWriter); + } - /// Dtor + /// Dtor ~FileWriter(); protected: @@ -144,14 +182,16 @@ public: typedef BaseWriter Parent; // ISlangWriter SLANG_NO_THROW char* SLANG_MCALL beginAppendBuffer(size_t maxNumChars) SLANG_OVERRIDE; - SLANG_NO_THROW SlangResult SLANG_MCALL endAppendBuffer(char* buffer, size_t numChars) SLANG_OVERRIDE; - SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) SLANG_OVERRIDE; - - /// Ctor - StringWriter(StringBuilder* builder, WriterFlags flags) : - Parent(flags), - m_builder(builder) - {} + SLANG_NO_THROW SlangResult SLANG_MCALL endAppendBuffer(char* buffer, size_t numChars) + SLANG_OVERRIDE; + SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) + SLANG_OVERRIDE; + + /// Ctor + StringWriter(StringBuilder* builder, WriterFlags flags) + : Parent(flags), m_builder(builder) + { + } ~StringWriter() {} protected: @@ -163,13 +203,20 @@ class NullWriter : public AppendBufferWriter public: typedef AppendBufferWriter Parent; // ISlangWriter - SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) SLANG_OVERRIDE { SLANG_UNUSED(chars); SLANG_UNUSED(numChars); return SLANG_OK; } + SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) + SLANG_OVERRIDE + { + SLANG_UNUSED(chars); + SLANG_UNUSED(numChars); + return SLANG_OK; + } /// Ctor - NullWriter(WriterFlags flags) : - Parent(flags) - {} + NullWriter(WriterFlags flags) + : Parent(flags) + { + } }; -} +} // namespace Slang #endif // SLANG_TEXT_WRITER_H diff --git a/source/core/slang-zip-file-system.cpp b/source/core/slang-zip-file-system.cpp index 02d4c9a2b..b3c50ab57 100644 --- a/source/core/slang-zip-file-system.cpp +++ b/source/core/slang-zip-file-system.cpp @@ -1,68 +1,86 @@ #include "slang-zip-file-system.h" +#include "slang-blob.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" - +#include "slang-implicit-directory-collector.h" #include "slang-io.h" -#include "slang-string-util.h" -#include "slang-blob.h" +#include "slang-riff.h" #include "slang-string-slice-pool.h" +#include "slang-string-util.h" #include "slang-uint-set.h" -#include "slang-riff.h" - -#include "slang-implicit-directory-collector.h" #include <miniz.h> namespace Slang { -class ZipFileSystemImpl : public ISlangMutableFileSystem, public IArchiveFileSystem, public ComBaseObject +class ZipFileSystemImpl : public ISlangMutableFileSystem, + public IArchiveFileSystem, + public ComBaseObject { public: - // ISlangUnknown + // ISlangUnknown SLANG_COM_BASE_IUNKNOWN_ALL // ISlangCastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // ISlangFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) + SLANG_OVERRIDE; // ISlangFileSystemExt - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPath(PathKind pathKind, const char* path, ISlangBlob** outPath) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE {} - virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE; - virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE { return OSPathKind::None; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) SLANG_OVERRIDE; + virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE + { + return OSPathKind::None; + } // ISlangModifyableFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFileBlob(const char* path, ISlangBlob* dataBlob) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE; // IArchiveFileSystem - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadArchive(const void* archive, size_t archiveSizeInBytes) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) SLANG_OVERRIDE; - virtual SLANG_NO_THROW void SLANG_MCALL setCompressionStyle(const CompressionStyle& style) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadArchive(const void* archive, size_t archiveSizeInBytes) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL setCompressionStyle(const CompressionStyle& style) + SLANG_OVERRIDE; ZipFileSystemImpl(); ~ZipFileSystemImpl(); protected: - enum class Mode { - None, // m_archive is not initialized - Read, // m_archive is a reader - ReadWrite, // m_archive is a writer (that can be read from) + None, // m_archive is not initialized + Read, // m_archive is a reader + ReadWrite, // m_archive is a writer (that can be read from) }; SlangResult _requireMode(Mode mode); - /// Do the mode change. + /// Do the mode change. SlangResult _requireModeImpl(Mode newMode); bool _hasArchive() { return m_mode != Mode::None; } @@ -72,14 +90,16 @@ protected: SlangResult _copyToAndInitWriter(mz_zip_archive& outWriter); - /// Returns SLANG_E_NOT_FOUND if no directory or contents found - /// terminationState controls when search terminates. If State::Undefined, will enumerate everything. - /// If outContents not set, will just determine if the directory exists - SlangResult _getPathContents(ImplicitDirectoryCollector::State terminationState, ImplicitDirectoryCollector* outCollector); + /// Returns SLANG_E_NOT_FOUND if no directory or contents found + /// terminationState controls when search terminates. If State::Undefined, will enumerate + /// everything. If outContents not set, will just determine if the directory exists + SlangResult _getPathContents( + ImplicitDirectoryCollector::State terminationState, + ImplicitDirectoryCollector* outCollector); void _rebuildMap(); - /// Returns true if the named item is at the index + /// Returns true if the named item is at the index UnownedStringSlice _getPathAtIndex(Index index); void* getInterface(const Guid& guid); @@ -99,19 +119,18 @@ protected: mz_file_read_func m_readFunc; - mz_zip_archive m_archive; + mz_zip_archive m_archive; }; void* ZipFileSystemImpl::getInterface(const Guid& guid) { - if ( guid == ISlangUnknown::getTypeGuid() || - guid == ISlangCastable::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangCastable::getTypeGuid()) { return static_cast<ISlangMutableFileSystem*>(this); } - else if (guid == ISlangFileSystem::getTypeGuid() || - guid == ISlangFileSystemExt::getTypeGuid() || - guid == ISlangMutableFileSystem::getTypeGuid()) + else if ( + guid == ISlangFileSystem::getTypeGuid() || guid == ISlangFileSystemExt::getTypeGuid() || + guid == ISlangMutableFileSystem::getTypeGuid()) { return static_cast<ISlangMutableFileSystem*>(this); } @@ -137,8 +156,9 @@ void* ZipFileSystemImpl::castAs(const Guid& guid) return getObject(guid); } -// This is a very awkward hack to make it so we can get a read func, without having to implement all of the tracking etc. -// All this does is create an empty zip, convert into a reader, and then grab the read function +// This is a very awkward hack to make it so we can get a read func, without having to implement all +// of the tracking etc. All this does is create an empty zip, convert into a reader, and then grab +// the read function static mz_file_read_func _calcReadFunc() { mz_zip_archive archive; @@ -169,16 +189,16 @@ static mz_file_read_func _getReadFunc() return readFunc; } -ZipFileSystemImpl::ZipFileSystemImpl(): - m_mode(Mode::None) +ZipFileSystemImpl::ZipFileSystemImpl() + : m_mode(Mode::None) { - m_readFunc = _getReadFunc(); + m_readFunc = _getReadFunc(); } - ZipFileSystemImpl::~ZipFileSystemImpl() - { - _requireMode(Mode::None); - } +ZipFileSystemImpl::~ZipFileSystemImpl() +{ + _requireMode(Mode::None); +} void ZipFileSystemImpl::_rebuildMap() { @@ -231,13 +251,13 @@ SlangResult ZipFileSystemImpl::_copyToAndInitWriter(mz_zip_archive& outWriter) mz_zip_zero_struct(&outWriter); switch (m_mode) { - case Mode::None: + case Mode::None: { _initReadWrite(outWriter); return SLANG_OK; } - case Mode::Read: - case Mode::ReadWrite: + case Mode::Read: + case Mode::ReadWrite: { _initReadWrite(outWriter); @@ -250,14 +270,16 @@ SlangResult ZipFileSystemImpl::_copyToAndInitWriter(mz_zip_archive& outWriter) continue; } - // It's worth noting - it's not clear if this will work, because m_archive might not be a reader, in the miniz docs. - // If it's a writer, it's not clear how to convert a writer to a reader *selectively* which - // we require if we are going to lazily handle removals. + // It's worth noting - it's not clear if this will work, because m_archive might not + // be a reader, in the miniz docs. If it's a writer, it's not clear how to convert a + // writer to a reader *selectively* which we require if we are going to lazily + // handle removals. // - // The fix to make this work is the hack that sets the m_reader, such that in effect the writer is both read and write. - // That works because the default writer behavior is a single block of memory for the archive, and that is compatible - // with the reader. - if (! mz_zip_writer_add_from_zip_reader(&outWriter, &m_archive, i)) + // The fix to make this work is the hack that sets the m_reader, such that in effect + // the writer is both read and write. That works because the default writer behavior + // is a single block of memory for the archive, and that is compatible with the + // reader. + if (!mz_zip_writer_add_from_zip_reader(&outWriter, &m_archive, i)) { mz_zip_end(&outWriter); return SLANG_FAIL; @@ -267,9 +289,9 @@ SlangResult ZipFileSystemImpl::_copyToAndInitWriter(mz_zip_archive& outWriter) return SLANG_OK; } - default: break; + default: break; } - return SLANG_FAIL; + return SLANG_FAIL; } SlangResult ZipFileSystemImpl::_requireModeImpl(Mode newMode) @@ -278,37 +300,37 @@ SlangResult ZipFileSystemImpl::_requireModeImpl(Mode newMode) switch (m_mode) { - case Mode::None: + case Mode::None: { switch (newMode) { - case Mode::Read: + case Mode::Read: { mz_uint flags = 0; mz_zip_zero_struct(&m_archive); mz_zip_reader_init(&m_archive, 0, flags); break; } - case Mode::ReadWrite: + case Mode::ReadWrite: { _initReadWrite(m_archive); break; } - default: break; + default: break; } break; } - case Mode::Read: + case Mode::Read: { switch (newMode) { - case Mode::None: + case Mode::None: { m_data.deallocate(); mz_zip_end(&m_archive); break; } - case Mode::ReadWrite: + case Mode::ReadWrite: { // If nothing is removed, we can just convert if (m_removedSet.isEmpty()) @@ -343,18 +365,19 @@ SlangResult ZipFileSystemImpl::_requireModeImpl(Mode newMode) } break; } - case Mode::ReadWrite: + case Mode::ReadWrite: { switch (newMode) { - case Mode::None: + case Mode::None: { mz_zip_writer_end(&m_archive); break; } - case Mode::Read: + case Mode::Read: { - // If anything has been removed we copy selectively into a new writer, and then convert that + // If anything has been removed we copy selectively into a new writer, and then + // convert that if (!m_removedSet.isEmpty()) { // There are entries that are deleted... so we need to copy selectively @@ -378,14 +401,18 @@ SlangResult ZipFileSystemImpl::_requireModeImpl(Mode newMode) // Read mz_zip_zero_struct(&m_archive); - if (!mz_zip_reader_init_mem(&m_archive, m_data.getData(), m_data.getSizeInBytes(), 0)) + if (!mz_zip_reader_init_mem( + &m_archive, + m_data.getData(), + m_data.getSizeInBytes(), + 0)) { m_data.deallocate(); return SLANG_FAIL; } break; } - default: break; + default: break; } } } @@ -415,12 +442,15 @@ SlangResult ZipFileSystemImpl::_requireMode(Mode newMode) SlangResult ZipFileSystemImpl::_getFixedPath(const char* path, String& outPath) { StringBuilder simplifiedPath; - SLANG_RETURN_ON_FAIL(Path::simplify(path, Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, simplifiedPath)); + SLANG_RETURN_ON_FAIL( + Path::simplify(path, Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, simplifiedPath)); outPath = simplifiedPath; return SLANG_OK; } -SlangResult ZipFileSystemImpl::_findEntryIndexFromFixedPath(const String& fixedPath, mz_uint& outIndex) +SlangResult ZipFileSystemImpl::_findEntryIndexFromFixedPath( + const String& fixedPath, + mz_uint& outIndex) { const Index index = m_pathMap.getValue(fixedPath.getUnownedSlice()); @@ -463,7 +493,12 @@ SlangResult ZipFileSystemImpl::loadFile(char const* path, ISlangBlob** outBlob) const mz_uint flags = 0; // Extract to memory - if (!mz_zip_reader_extract_to_mem(&m_archive, index, alloc.getData(), alloc.getSizeInBytes(), flags)) + if (!mz_zip_reader_extract_to_mem( + &m_archive, + index, + alloc.getData(), + alloc.getSizeInBytes(), + flags)) { return SLANG_FAIL; } @@ -499,7 +534,8 @@ SlangResult ZipFileSystemImpl::getPathType(const char* path, SlangPathType* outP { // It could be an *implicit* directory (ie as part of a path). So lets look for that... ImplicitDirectoryCollector collector(fixedPath); - SLANG_RETURN_ON_FAIL(_getPathContents(ImplicitDirectoryCollector::State::DirectoryExists, &collector)); + SLANG_RETURN_ON_FAIL( + _getPathContents(ImplicitDirectoryCollector::State::DirectoryExists, &collector)); if (collector.getDirectoryExists()) { *outPathType = SLANG_PATH_TYPE_DIRECTORY; @@ -514,8 +550,8 @@ SlangResult ZipFileSystemImpl::getPath(PathKind pathKind, const char* path, ISla { switch (pathKind) { - case PathKind::Display: - case PathKind::Canonical: + case PathKind::Display: + case PathKind::Canonical: { // Get the fixed path String fixedPath; @@ -540,33 +576,39 @@ SlangResult ZipFileSystemImpl::getPath(PathKind pathKind, const char* path, ISla *outPath = StringUtil::createStringBlob(fixedPath).detach(); return SLANG_OK; } - case PathKind::Simplified: + case PathKind::Simplified: { *outPath = StringUtil::createStringBlob(Path::simplify(path)).detach(); return SLANG_OK; } - default: break; + default: break; } return SLANG_E_NOT_AVAILABLE; } -SlangResult ZipFileSystemImpl::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) +SlangResult ZipFileSystemImpl::getFileUniqueIdentity( + const char* path, + ISlangBlob** outUniqueIdentity) { return getPath(PathKind::Canonical, path, outUniqueIdentity); } -SlangResult ZipFileSystemImpl::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +SlangResult ZipFileSystemImpl::calcCombinedPath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) { String relPath; switch (fromPathType) { - case SLANG_PATH_TYPE_FILE: + case SLANG_PATH_TYPE_FILE: { relPath = Path::combine(Path::getParentDirectory(fromPath), path); break; } - case SLANG_PATH_TYPE_DIRECTORY: + case SLANG_PATH_TYPE_DIRECTORY: { relPath = Path::combine(fromPath, path); break; @@ -577,7 +619,9 @@ SlangResult ZipFileSystemImpl::calcCombinedPath(SlangPathType fromPathType, cons return SLANG_OK; } -SlangResult ZipFileSystemImpl::_getPathContents(ImplicitDirectoryCollector::State terminationState, ImplicitDirectoryCollector* outCollector) +SlangResult ZipFileSystemImpl::_getPathContents( + ImplicitDirectoryCollector::State terminationState, + ImplicitDirectoryCollector* outCollector) { if (!_hasArchive()) { @@ -602,11 +646,13 @@ SlangResult ZipFileSystemImpl::_getPathContents(ImplicitDirectoryCollector::Stat } UnownedStringSlice currentPath(fileStat.m_filename); - SlangPathType pathType = fileStat.m_is_directory ? SLANG_PATH_TYPE_DIRECTORY : SLANG_PATH_TYPE_FILE; + SlangPathType pathType = + fileStat.m_is_directory ? SLANG_PATH_TYPE_DIRECTORY : SLANG_PATH_TYPE_FILE; outCollector->addPath(pathType, currentPath); // If a termination state is defined, and we reach it, we are done - if (terminationState != ImplicitDirectoryCollector::State::None && outCollector->hasState(terminationState)) + if (terminationState != ImplicitDirectoryCollector::State::None && + outCollector->hasState(terminationState)) { return SLANG_OK; } @@ -615,7 +661,10 @@ SlangResult ZipFileSystemImpl::_getPathContents(ImplicitDirectoryCollector::Stat return outCollector->getDirectoryExists() ? SLANG_OK : SLANG_E_NOT_FOUND; } -SlangResult ZipFileSystemImpl::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) +SlangResult ZipFileSystemImpl::enumeratePathContents( + const char* path, + FileSystemContentsCallBack callback, + void* userData) { if (!_hasArchive()) { @@ -699,8 +748,9 @@ SlangResult ZipFileSystemImpl::remove(const char* path) if (fileStat.m_is_directory) { // Find the directory contents - ImplicitDirectoryCollector collector(fixedPath); - SLANG_RETURN_ON_FAIL(_getPathContents(ImplicitDirectoryCollector::State::HasContent, &collector)); + ImplicitDirectoryCollector collector(fixedPath); + SLANG_RETURN_ON_FAIL( + _getPathContents(ImplicitDirectoryCollector::State::HasContent, &collector)); if (collector.hasContent()) { @@ -744,7 +794,7 @@ SlangResult ZipFileSystemImpl::createDirectory(const char* path) SLANG_ASSERT(_getPathAtIndex(entryCount) == fixedPath.getUnownedSlice()); // Set the index, that we added at end - m_pathMap.add(fixedPath.getUnownedSlice(), entryCount); + m_pathMap.add(fixedPath.getUnownedSlice(), entryCount); return SLANG_OK; } @@ -755,7 +805,7 @@ SlangResult ZipFileSystemImpl::storeArchive(bool blobOwnsContent, ISlangBlob** o { _requireMode(Mode::ReadWrite); } - + _requireMode(Mode::Read); ComPtr<ISlangBlob> blob; @@ -776,7 +826,7 @@ SlangResult ZipFileSystemImpl::storeArchive(bool blobOwnsContent, ISlangBlob** o SlangResult ZipFileSystemImpl::loadArchive(const void* archive, size_t archiveSizeInBytes) { - // Making the mode None empties the archive + // Making the mode None empties the archive SLANG_RETURN_ON_FAIL(_requireMode(Mode::None)); // Store a copy of the archive contents @@ -806,10 +856,10 @@ void ZipFileSystemImpl::setCompressionStyle(const CompressionStyle& style) { switch (style.m_type) { - case CompressionStyle::Type::BestSpeed: m_compressionLevel = MZ_BEST_SPEED; break; - case CompressionStyle::Type::BestCompression: m_compressionLevel = MZ_BEST_COMPRESSION; break; - case CompressionStyle::Type::Default: m_compressionLevel = MZ_DEFAULT_LEVEL; break; - case CompressionStyle::Type::Level: + case CompressionStyle::Type::BestSpeed: m_compressionLevel = MZ_BEST_SPEED; break; + case CompressionStyle::Type::BestCompression: m_compressionLevel = MZ_BEST_COMPRESSION; break; + case CompressionStyle::Type::Default: m_compressionLevel = MZ_DEFAULT_LEVEL; break; + case CompressionStyle::Type::Level: { int level = int(style.m_level * 10.0f + 0.5); level = (level < 0) ? 0 : level; @@ -820,13 +870,13 @@ void ZipFileSystemImpl::setCompressionStyle(const CompressionStyle& style) } } -/* static */SlangResult ZipFileSystem::create(ComPtr<ISlangMutableFileSystem>& out) +/* static */ SlangResult ZipFileSystem::create(ComPtr<ISlangMutableFileSystem>& out) { out = new ZipFileSystemImpl; return SLANG_OK; } -/* static */bool ZipFileSystem::isArchive(const void* data, size_t dataSizeInBytes) +/* static */ bool ZipFileSystem::isArchive(const void* data, size_t dataSizeInBytes) { if (dataSizeInBytes < sizeof(FourCC)) { @@ -839,9 +889,9 @@ void ZipFileSystemImpl::setCompressionStyle(const CompressionStyle& style) // https://en.wikipedia.org/wiki/List_of_file_signatures switch (fourCC) { - case SLANG_FOUR_CC(0x50, 0x4B, 0x03, 0x04): - case SLANG_FOUR_CC(0x50, 0x4B, 0x05, 0x06): - case SLANG_FOUR_CC(0x50, 0x4B, 0x07, 0x08): + case SLANG_FOUR_CC(0x50, 0x4B, 0x03, 0x04): + case SLANG_FOUR_CC(0x50, 0x4B, 0x05, 0x06): + case SLANG_FOUR_CC(0x50, 0x4B, 0x07, 0x08): { // It's a zip return true; diff --git a/source/core/slang-zip-file-system.h b/source/core/slang-zip-file-system.h index 120d5003a..6491a6403 100644 --- a/source/core/slang-zip-file-system.h +++ b/source/core/slang-zip-file-system.h @@ -1,21 +1,20 @@ #ifndef SLANG_ZIP_FILE_SYSTEM_H #define SLANG_ZIP_FILE_SYSTEM_H -#include "slang-basic.h" - #include "slang-archive-file-system.h" +#include "slang-basic.h" namespace Slang { struct ZipFileSystem { - /// Create an empty zip + /// Create an empty zip static SlangResult create(ComPtr<ISlangMutableFileSystem>& out); - /// True if this appears to be a zip archive + /// True if this appears to be a zip archive static bool isArchive(const void* data, size_t size); }; -} +} // namespace Slang #endif diff --git a/source/core/unix/slang-unix-process.cpp b/source/core/unix/slang-unix-process.cpp index ee5484fd8..97b59f21c 100644 --- a/source/core/unix/slang-unix-process.cpp +++ b/source/core/unix/slang-unix-process.cpp @@ -1,50 +1,49 @@ // slang-unix-process.cpp -#include "../slang-process.h" - #include "../slang-common.h" -#include "../slang-string-util.h" -#include "../slang-string-escape-util.h" #include "../slang-memory-arena.h" +#include "../slang-process.h" +#include "../slang-string-escape-util.h" +#include "../slang-string-util.h" #include <stdio.h> #include <stdlib.h> #include <string.h> -//#include <dirent.h> +// #include <dirent.h> #include <errno.h> -#include <poll.h> #include <fcntl.h> - +#include <poll.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #if SLANG_OSX -# include <signal.h> +#include <signal.h> #endif #include <time.h> -namespace Slang { +namespace Slang +{ class UnixProcess : public Process { public: - // Process + // Process virtual bool isTerminated() SLANG_OVERRIDE; virtual bool waitForTermination(Int timeInMs) SLANG_OVERRIDE; virtual void terminate(int32_t returnValue) SLANG_OVERRIDE; virtual void kill(int32_t returnValue) SLANG_OVERRIDE; - UnixProcess(pid_t pid, Stream*const* streams); + UnixProcess(pid_t pid, Stream* const* streams); protected: - /// Returns true if terminated + /// Returns true if terminated bool _updateTerminationState(int options); - bool m_isTerminated = false; ///< True if ths process is terminated - pid_t m_pid; ///< The process id + bool m_isTerminated = false; ///< True if ths process is terminated + pid_t m_pid; ///< The process id }; class UnixPipeStream : public Stream @@ -54,7 +53,12 @@ public: // Stream virtual Int64 getPosition() SLANG_OVERRIDE { return 0; } - virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE { SLANG_UNUSED(origin); SLANG_UNUSED(offset); return SLANG_E_NOT_AVAILABLE; } + virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE + { + SLANG_UNUSED(origin); + SLANG_UNUSED(offset); + return SLANG_E_NOT_AVAILABLE; + } virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) SLANG_OVERRIDE; virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE; virtual bool isEnd() SLANG_OVERRIDE { return m_isClosed; } @@ -63,18 +67,15 @@ public: virtual void close() SLANG_OVERRIDE; virtual SlangResult flush() SLANG_OVERRIDE; - UnixPipeStream(int fd, FileAccess access, bool isOwned) : - m_fd(fd), - m_access(access), - m_isOwned(isOwned), - m_isClosed(false) + UnixPipeStream(int fd, FileAccess access, bool isOwned) + : m_fd(fd), m_access(access), m_isOwned(isOwned), m_isClosed(false) { } protected: - /// This read file descriptor non blocking. Doing so will change the behavior of - /// read - it can fail and return an error indicating there is no data, instead of blocking. - /// Currently this mechanism isn't used, as checking via poll seemed to work. + /// This read file descriptor non blocking. Doing so will change the behavior of + /// read - it can fail and return an error indicating there is no data, instead of blocking. + /// Currently this mechanism isn't used, as checking via poll seemed to work. void _setReadNonBlocking() { // Makes non blocking @@ -86,16 +87,16 @@ protected: } bool _has(FileAccess access) const { return (Index(access) & Index(m_access)) != 0; } - bool m_isClosed; ///< If true this stream has been closed (ie cannot read/write to anymore) - bool m_isOwned; ///< True if m_fd is owned by this object. - FileAccess m_access; ///< Access allowed to this stream - either Read or Write - int m_fd; /// The 'file descriptor' for the pipe + bool m_isClosed; ///< If true this stream has been closed (ie cannot read/write to anymore) + bool m_isOwned; ///< True if m_fd is owned by this object. + FileAccess m_access; ///< Access allowed to this stream - either Read or Write + int m_fd; /// The 'file descriptor' for the pipe }; /* !!!!!!!!!!!!!!!!!!!!!! UnixProcess !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -UnixProcess::UnixProcess(pid_t pid, Stream* const* streams): - m_pid(pid) +UnixProcess::UnixProcess(pid_t pid, Stream* const* streams) + : m_pid(pid) { // Set to an 'odd value' m_returnValue = -1; @@ -145,15 +146,16 @@ bool UnixProcess::waitForTermination(Int timeInMs) // If < 0 we will wait blocking until terminated if (timeInMs < 0) { - while (!_updateTerminationState(0)); + while (!_updateTerminationState(0)) + ; return true; } - // Note that the amount of time waiting is very approximate (we are relying on sleeps time and don't take into - // account time outside of sleeping) + // Note that the amount of time waiting is very approximate (we are relying on sleeps time and + // don't take into account time outside of sleeping) // How often to test - const Int checkRateMs = 100; /// Check every 0.1 seconds + const Int checkRateMs = 100; /// Check every 0.1 seconds while (timeInMs > 0) { @@ -283,7 +285,7 @@ SlangResult UnixPipeStream::read(void* buffer, size_t length, size_t& outReadByt { return SLANG_OK; } - // Okay - guess we have an error then + // Okay - guess we have an error then return SLANG_FAIL; } @@ -291,7 +293,7 @@ SlangResult UnixPipeStream::read(void* buffer, size_t length, size_t& outReadByt // If no bytes were wanted, then there could still be bytes in the pipe // before a HUP. So don't fall through to check for HUP. - // + // // If some bytes *were* wanted and none were read, we can allow fall through to // handle HUP. if (length == 0 || count > 0) @@ -355,7 +357,7 @@ SlangResult UnixPipeStream::write(const void* buffer, size_t length) /* !!!!!!!!!!!!!!!!!!!!!! Process !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */UnownedStringSlice Process::getExecutableSuffix() +/* static */ UnownedStringSlice Process::getExecutableSuffix() { #if __CYGWIN__ return UnownedStringSlice::fromLiteral(".exe"); @@ -364,7 +366,7 @@ SlangResult UnixPipeStream::write(const void* buffer, size_t length) #endif } -/* static */StringEscapeHandler* Process::getEscapeHandler() +/* static */ StringEscapeHandler* Process::getEscapeHandler() { return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space); } @@ -377,9 +379,8 @@ static int pipeCLOEXEC(int pipefd[2]) // without pipe2 on macOS, there's an unavoidable race here where // another process could fork and execv with execWatchPipe before we // can set CLOEXEC on it... - if(pipe(pipefd) == -1 || - fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1 || - fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) == -1) + if (pipe(pipefd) == -1 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1 || + fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) == -1) { return -1; } @@ -389,7 +390,10 @@ static int pipeCLOEXEC(int pipefd[2]) #endif } -/* static */SlangResult Process::create(const CommandLine& commandLine, Process::Flags, RefPtr<Process>& outProcess) +/* static */ SlangResult Process::create( + const CommandLine& commandLine, + Process::Flags, + RefPtr<Process>& outProcess) { const char* whatFailed = nullptr; pid_t childPid; @@ -404,7 +408,7 @@ static int pipeCLOEXEC(int pipefd[2]) // Add the command argPtrs.add(exe.m_pathOrName.getBuffer()); - // Add all the args - they don't need any explicit escaping + // Add all the args - they don't need any explicit escaping for (auto arg : commandLine.m_args) { // All args for this target must be unescaped (as they are in CommandLine) @@ -425,9 +429,7 @@ static int pipeCLOEXEC(int pipefd[2]) // automatically if the child's exec succeeds int execWatchPipe[2] = {-1, -1}; - if (pipe(stdinPipe) == -1 || - pipe(stdoutPipe) == -1 || - pipe(stderrPipe) == -1 || + if (pipe(stdinPipe) == -1 || pipe(stdoutPipe) == -1 || pipe(stderrPipe) == -1 || pipeCLOEXEC(execWatchPipe) == -1) { whatFailed = "pipe"; @@ -438,36 +440,36 @@ static int pipeCLOEXEC(int pipefd[2]) // 0,1,2 in the child. whatFailed = "fcntl"; int next; - if(stdinPipe[0] < 3) + if (stdinPipe[0] < 3) { - if(-1 == (next = fcntl(stdinPipe[0], F_DUPFD, 3))) + if (-1 == (next = fcntl(stdinPipe[0], F_DUPFD, 3))) { goto reportErr; } close(stdinPipe[0]); stdinPipe[0] = next; } - if(stdoutPipe[1] < 3) + if (stdoutPipe[1] < 3) { - if(-1 == (next = fcntl(stdoutPipe[1], F_DUPFD, 3))) + if (-1 == (next = fcntl(stdoutPipe[1], F_DUPFD, 3))) { goto reportErr; } close(stdoutPipe[1]); stdoutPipe[1] = next; } - if(stderrPipe[1] < 3) + if (stderrPipe[1] < 3) { - if(-1 == (next = fcntl(stderrPipe[1], F_DUPFD, 3))) + if (-1 == (next = fcntl(stderrPipe[1], F_DUPFD, 3))) { goto reportErr; } close(stderrPipe[1]); stderrPipe[1] = next; } - if(execWatchPipe[1] < 3) + if (execWatchPipe[1] < 3) { - if(-1 == (next = fcntl(execWatchPipe[1], F_DUPFD_CLOEXEC, 3))) + if (-1 == (next = fcntl(execWatchPipe[1], F_DUPFD_CLOEXEC, 3))) { goto reportErr; } @@ -516,14 +518,14 @@ static int pipeCLOEXEC(int pipefd[2]) // Signal the failure to our parent int execErr = errno; - if(::write(execWatchPipe[1], &execErr, sizeof(execErr))) + if (::write(execWatchPipe[1], &execErr, sizeof(execErr))) fprintf(stderr, "error: `exec` watch pipe write failed\n"); // NOTE! Because we have dup2 into STDERR_FILENO, this error will *not* generally appear on - // the terminal but in the stderrPipe. + // the terminal but in the stderrPipe. fprintf(stderr, "error: `exec` failed\n"); - // Terminate with failure. + // Terminate with failure. // Call _exit() rather than exit() so we don't run anything registered with atexit() ::_exit(kCannotExecute); } @@ -538,11 +540,14 @@ static int pipeCLOEXEC(int pipefd[2]) RefPtr<Stream> streams[Index(StdStreamType::CountOf)]; // Previously code didn't need to close, so we'll make stream now own the handles - streams[Index(StdStreamType::Out)] = new UnixPipeStream(stdoutPipe[0], FileAccess::Read, true); + streams[Index(StdStreamType::Out)] = + new UnixPipeStream(stdoutPipe[0], FileAccess::Read, true); stdoutPipe[0] = -1; - streams[Index(StdStreamType::ErrorOut)] = new UnixPipeStream(stderrPipe[0], FileAccess::Read, true); + streams[Index(StdStreamType::ErrorOut)] = + new UnixPipeStream(stderrPipe[0], FileAccess::Read, true); stderrPipe[0] = -1; - streams[Index(StdStreamType::In)] = new UnixPipeStream(stdinPipe[1], FileAccess::Write, true); + streams[Index(StdStreamType::In)] = + new UnixPipeStream(stdinPipe[1], FileAccess::Write, true); stdinPipe[1] = -1; // Check that the exec actually succeeded @@ -550,7 +555,7 @@ static int pipeCLOEXEC(int pipefd[2]) // Our success is if we read zero bytes, indicating that the pipe was // closed by the child's exec and O_CLOEXEC. (and us just above) const int readRes = ::read(execWatchPipe[0], &execErrCode, sizeof(execErrCode)); - if(readRes < 0) + if (readRes < 0) { whatFailed = "read from forked process"; goto reportErr; @@ -563,11 +568,14 @@ static int pipeCLOEXEC(int pipefd[2]) const bool verbose = false; if (verbose) { - fprintf(stderr, "error: exec for \"%s\" failed: %s\n", argPtrs[0], - ::strerror(execErrCode)); + fprintf( + stderr, + "error: exec for \"%s\" failed: %s\n", + argPtrs[0], + ::strerror(execErrCode)); } whatFailed = "exec"; - // Don't report the exec as we expect some of them to fail + // Don't report the exec as we expect some of them to fail goto closePipes; } @@ -592,19 +600,19 @@ closePipes: return whatFailed ? SLANG_FAIL : SLANG_OK; } -/* static */uint64_t Process::getClockFrequency() +/* static */ uint64_t Process::getClockFrequency() { return 1000000000; } -/* static */uint64_t Process::getClockTick() +/* static */ uint64_t Process::getClockTick() { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return uint64_t(now.tv_sec) * 1000000000 + now.tv_nsec; } -/* static */void Process::sleepCurrentThread(Int timeInMs) +/* static */ void Process::sleepCurrentThread(Int timeInMs) { struct timespec timeSpec; @@ -626,26 +634,26 @@ closePipes: nanosleep(&timeSpec, nullptr); } -/* static */SlangResult Process::getStdStream(StdStreamType type, RefPtr<Stream>& out) +/* static */ SlangResult Process::getStdStream(StdStreamType type, RefPtr<Stream>& out) { switch (type) { - case StdStreamType::In: + case StdStreamType::In: { out = new UnixPipeStream(STDIN_FILENO, FileAccess::Read, false); break; } - case StdStreamType::Out: + case StdStreamType::Out: { out = new UnixPipeStream(STDOUT_FILENO, FileAccess::Write, false); - break; + break; } - case StdStreamType::ErrorOut: + case StdStreamType::ErrorOut: { out = new UnixPipeStream(STDERR_FILENO, FileAccess::Write, false); break; } - default: return SLANG_FAIL; + default: return SLANG_FAIL; } return SLANG_OK; } diff --git a/source/core/windows/slang-win-process.cpp b/source/core/windows/slang-win-process.cpp index 3aa21deb5..8569a0854 100644 --- a/source/core/windows/slang-win-process.cpp +++ b/source/core/windows/slang-win-process.cpp @@ -1,45 +1,64 @@ // slang-win-process-util.cpp +#include "../slang-process-util.h" #include "../slang-process.h" - -#include "../slang-string.h" #include "../slang-string-escape-util.h" #include "../slang-string-util.h" -#include "../slang-process-util.h" - +#include "../slang-string.h" #include "slang-com-helper.h" #ifdef _WIN32 // TODO: We could try to avoid including this at all, but it would // mean trying to hide certain struct layouts, which would add // more dynamic allocation. -# include <windows.h> +#include <windows.h> #endif #include <stdio.h> #include <stdlib.h> #ifndef SLANG_RETURN_FAIL_ON_FALSE -# define SLANG_RETURN_FAIL_ON_FALSE(x) if (!(x)) return SLANG_FAIL; +#define SLANG_RETURN_FAIL_ON_FALSE(x) \ + if (!(x)) \ + return SLANG_FAIL; #endif -namespace Slang { +namespace Slang +{ // Has behavior very similar to unique_ptr - assignment is a move. class WinHandle { public: - /// Detach the encapsulated handle. Returns the handle (which now must be externally handled) - HANDLE detach() { HANDLE handle = m_handle; m_handle = nullptr; return handle; } + /// Detach the encapsulated handle. Returns the handle (which now must be externally handled) + HANDLE detach() + { + HANDLE handle = m_handle; + m_handle = nullptr; + return handle; + } /// Return as a handle operator HANDLE() const { return m_handle; } /// Assign - void operator=(HANDLE handle) { setNull(); m_handle = handle; } - void operator=(WinHandle&& rhs) { HANDLE handle = m_handle; m_handle = rhs.m_handle; rhs.m_handle = handle; } + void operator=(HANDLE handle) + { + setNull(); + m_handle = handle; + } + void operator=(WinHandle&& rhs) + { + HANDLE handle = m_handle; + m_handle = rhs.m_handle; + rhs.m_handle = handle; + } - /// Get ready for writing - SLANG_FORCE_INLINE HANDLE* writeRef() { setNull(); return &m_handle; } + /// Get ready for writing + SLANG_FORCE_INLINE HANDLE* writeRef() + { + setNull(); + return &m_handle; + } /// Get for read access SLANG_FORCE_INLINE const HANDLE* readRef() const { return &m_handle; } @@ -54,21 +73,28 @@ public: bool isNull() const { return m_handle == nullptr; } /// Ctor - WinHandle(HANDLE handle = nullptr) :m_handle(handle) {} - WinHandle(WinHandle&& rhs) :m_handle(rhs.m_handle) { rhs.m_handle = nullptr; } + WinHandle(HANDLE handle = nullptr) + : m_handle(handle) + { + } + WinHandle(WinHandle&& rhs) + : m_handle(rhs.m_handle) + { + rhs.m_handle = nullptr; + } /// Dtor ~WinHandle() { setNull(); } private: - WinHandle(const WinHandle&) = delete; void operator=(const WinHandle& rhs) = delete; HANDLE m_handle; }; -/* A simple Stream implementation of a File HANDLE (or Pipe). Note that currently does not allow getPosition/seek/atEnd */ +/* A simple Stream implementation of a File HANDLE (or Pipe). Note that currently does not allow + * getPosition/seek/atEnd */ class WinPipeStream : public Stream { public: @@ -76,12 +102,23 @@ public: // Stream virtual Int64 getPosition() SLANG_OVERRIDE { return 0; } - virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE { SLANG_UNUSED(origin); SLANG_UNUSED(offset); return SLANG_E_NOT_AVAILABLE; } + virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE + { + SLANG_UNUSED(origin); + SLANG_UNUSED(offset); + return SLANG_E_NOT_AVAILABLE; + } virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) SLANG_OVERRIDE; virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE; virtual bool isEnd() SLANG_OVERRIDE { return m_streamHandle.isNull(); } - virtual bool canRead() SLANG_OVERRIDE { return _has(FileAccess::Read) && !m_streamHandle.isNull(); } - virtual bool canWrite() SLANG_OVERRIDE { return _has(FileAccess::Write) && !m_streamHandle.isNull(); } + virtual bool canRead() SLANG_OVERRIDE + { + return _has(FileAccess::Read) && !m_streamHandle.isNull(); + } + virtual bool canWrite() SLANG_OVERRIDE + { + return _has(FileAccess::Write) && !m_streamHandle.isNull(); + } virtual void close() SLANG_OVERRIDE; virtual SlangResult flush() SLANG_OVERRIDE; @@ -90,7 +127,6 @@ public: ~WinPipeStream() { close(); } protected: - bool _has(FileAccess access) const { return (Index(access) & Index(m_access)) != 0; } SlangResult _updateState(BOOL res); @@ -104,15 +140,14 @@ protected: class WinProcess : public Process { public: - // Process virtual bool isTerminated() SLANG_OVERRIDE; virtual bool waitForTermination(Int timeInMs) SLANG_OVERRIDE; virtual void terminate(int32_t returnCode) SLANG_OVERRIDE; virtual void kill(int32_t returnCode) SLANG_OVERRIDE; - WinProcess(HANDLE handle, Stream* const* streams) : - m_processHandle(handle) + WinProcess(HANDLE handle, Stream* const* streams) + : m_processHandle(handle) { for (Index i = 0; i < Index(StdStreamType::CountOf); ++i) { @@ -121,17 +156,14 @@ public: } protected: - void _hasTerminated(); - WinHandle m_processHandle; ///< If not set the process has terminated + WinHandle m_processHandle; ///< If not set the process has terminated }; /* !!!!!!!!!!!!!!!!!!!!!!!!!!! WinPipeStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -WinPipeStream::WinPipeStream(HANDLE handle, FileAccess access, bool isOwned) : - m_streamHandle(handle), - m_access(access), - m_isOwned(isOwned) +WinPipeStream::WinPipeStream(HANDLE handle, FileAccess access, bool isOwned) + : m_streamHandle(handle), m_access(access), m_isOwned(isOwned) { // On Win32 a HANDLE has to be handled differently if it's a PIPE or FILE, so first determine @@ -198,7 +230,13 @@ SlangResult WinPipeStream::read(void* buffer, size_t length, size_t& outReadByte // Works on anonymous pipes too // https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe - SLANG_RETURN_ON_FAIL(_updateState(::PeekNamedPipe(m_streamHandle, nullptr, DWORD(0), &pipeBytesRead, &pipeTotalBytesAvailable, &pipeRemainingBytes))); + SLANG_RETURN_ON_FAIL(_updateState(::PeekNamedPipe( + m_streamHandle, + nullptr, + DWORD(0), + &pipeBytesRead, + &pipeTotalBytesAvailable, + &pipeRemainingBytes))); // If there is nothing to read we are done // If we don't do this ReadFile will *block* if there is nothing available if (pipeTotalBytesAvailable == 0) @@ -206,11 +244,13 @@ SlangResult WinPipeStream::read(void* buffer, size_t length, size_t& outReadByte return SLANG_OK; } - SLANG_RETURN_ON_FAIL(_updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); + SLANG_RETURN_ON_FAIL( + _updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); } else { - SLANG_RETURN_ON_FAIL(_updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); + SLANG_RETURN_ON_FAIL( + _updateState(::ReadFile(m_streamHandle, buffer, DWORD(length), &bytesRead, nullptr))); // If it's not a pipe, and there is nothing left, then we are done. if (length > 0 && bytesRead == 0) @@ -248,7 +288,7 @@ SlangResult WinPipeStream::write(const void* buffer, size_t length) close(); return SLANG_FAIL; } - + SLANG_UNUSED(err); return SLANG_FAIL; } @@ -265,7 +305,7 @@ void WinPipeStream::close() { if (!m_isOwned) { - // If we don't own it just detach it + // If we don't own it just detach it m_streamHandle.detach(); } m_streamHandle.setNull(); @@ -357,31 +397,31 @@ void WinProcess::kill(int32_t returnCode) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */StringEscapeHandler* Process::getEscapeHandler() +/* static */ StringEscapeHandler* Process::getEscapeHandler() { return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space); } -/* static */UnownedStringSlice Process::getExecutableSuffix() +/* static */ UnownedStringSlice Process::getExecutableSuffix() { return UnownedStringSlice::fromLiteral(".exe"); } -/* static */SlangResult Process::getStdStream(StdStreamType type, RefPtr<Stream>& out) +/* static */ SlangResult Process::getStdStream(StdStreamType type, RefPtr<Stream>& out) { switch (type) { - case StdStreamType::In: + case StdStreamType::In: { out = new WinPipeStream(GetStdHandle(STD_INPUT_HANDLE), FileAccess::Read, false); return SLANG_OK; } - case StdStreamType::Out: + case StdStreamType::Out: { out = new WinPipeStream(GetStdHandle(STD_OUTPUT_HANDLE), FileAccess::Write, false); return SLANG_OK; } - case StdStreamType::ErrorOut: + case StdStreamType::ErrorOut: { out = new WinPipeStream(GetStdHandle(STD_ERROR_HANDLE), FileAccess::Write, false); return SLANG_OK; @@ -391,10 +431,13 @@ void WinProcess::kill(int32_t returnCode) return SLANG_FAIL; } -/* static */SlangResult Process::create(const CommandLine& commandLine, Process::Flags flags, RefPtr<Process>& outProcess) -{ +/* static */ SlangResult Process::create( + const CommandLine& commandLine, + Process::Flags flags, + RefPtr<Process>& outProcess) +{ WinHandle childStdOutRead; - WinHandle childStdErrRead; + WinHandle childStdErrRead; WinHandle childStdInWrite; WinHandle processHandle; @@ -409,7 +452,7 @@ void WinProcess::kill(int32_t returnCode) securityAttributes.bInheritHandle = true; // 0 means use the 'system default' - //const DWORD bufferSize = 64 * 1024; + // const DWORD bufferSize = 64 * 1024; const DWORD bufferSize = 0; { @@ -417,26 +460,59 @@ void WinProcess::kill(int32_t returnCode) WinHandle childStdErrReadTmp; WinHandle childStdInWriteTmp; // create stdout pipe for child process - SLANG_RETURN_FAIL_ON_FALSE(CreatePipe(childStdOutReadTmp.writeRef(), childStdOutWrite.writeRef(), &securityAttributes, bufferSize)); + SLANG_RETURN_FAIL_ON_FALSE(CreatePipe( + childStdOutReadTmp.writeRef(), + childStdOutWrite.writeRef(), + &securityAttributes, + bufferSize)); if ((flags & Process::Flag::DisableStdErrRedirection) == 0) { // create stderr pipe for child process - SLANG_RETURN_FAIL_ON_FALSE(CreatePipe(childStdErrReadTmp.writeRef(), childStdErrWrite.writeRef(), &securityAttributes, bufferSize)); + SLANG_RETURN_FAIL_ON_FALSE(CreatePipe( + childStdErrReadTmp.writeRef(), + childStdErrWrite.writeRef(), + &securityAttributes, + bufferSize)); } - // create stdin pipe for child process - SLANG_RETURN_FAIL_ON_FALSE(CreatePipe(childStdInRead.writeRef(), childStdInWriteTmp.writeRef(), &securityAttributes, bufferSize)); + // create stdin pipe for child process + SLANG_RETURN_FAIL_ON_FALSE(CreatePipe( + childStdInRead.writeRef(), + childStdInWriteTmp.writeRef(), + &securityAttributes, + bufferSize)); const HANDLE currentProcess = GetCurrentProcess(); // https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle - // create a non-inheritable duplicate of the stdout reader - SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle(currentProcess, childStdOutReadTmp, currentProcess, childStdOutRead.writeRef(), 0, FALSE, DUPLICATE_SAME_ACCESS)); + // create a non-inheritable duplicate of the stdout reader + SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle( + currentProcess, + childStdOutReadTmp, + currentProcess, + childStdOutRead.writeRef(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); // create a non-inheritable duplicate of the stderr reader if (childStdErrReadTmp) - SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle(currentProcess, childStdErrReadTmp, currentProcess, childStdErrRead.writeRef(), 0, FALSE, DUPLICATE_SAME_ACCESS)); + SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle( + currentProcess, + childStdErrReadTmp, + currentProcess, + childStdErrRead.writeRef(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); // create a non-inheritable duplicate of the stdin writer - SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle(currentProcess, childStdInWriteTmp, currentProcess, childStdInWrite.writeRef(), 0, FALSE, DUPLICATE_SAME_ACCESS)); + SLANG_RETURN_FAIL_ON_FALSE(DuplicateHandle( + currentProcess, + childStdInWriteTmp, + currentProcess, + childStdInWrite.writeRef(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); } // TODO: switch to proper wide-character versions of these... @@ -478,12 +554,14 @@ void WinProcess::kill(int32_t returnCode) } // From docs: - // If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName - // specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. + // If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string + // pointed to by lpApplicationName specifies the module to execute, and the null-terminated + // string pointed to by lpCommandLine specifies the command line. // JS: - // Somewhat confusingly this means that even if lpApplicationName is specified, it muse *ALSO* be included as the first - // whitespace delimited arg must *also* be the (possibly) quoted executable + // Somewhat confusingly this means that even if lpApplicationName is specified, it muse + // *ALSO* be included as the first whitespace delimited arg must *also* be the (possibly) + // quoted executable // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa // `CreateProcess` requires write access to this, for some reason... @@ -510,9 +588,9 @@ void WinProcess::kill(int32_t returnCode) { // Lets see if we can set up to debug // https://docs.microsoft.com/en-us/windows/win32/debug/debugging-a-running-process - - //DebugActiveProcess(processInfo.dwProcessId); - + + // DebugActiveProcess(processInfo.dwProcessId); + // Resume the thread ResumeThread(processInfo.hThread); } @@ -527,15 +605,18 @@ void WinProcess::kill(int32_t returnCode) RefPtr<Stream> streams[Index(StdStreamType::CountOf)]; if (childStdErrRead) - streams[Index(StdStreamType::ErrorOut)] = new WinPipeStream(childStdErrRead.detach(), FileAccess::Read); - streams[Index(StdStreamType::Out)] = new WinPipeStream(childStdOutRead.detach(), FileAccess::Read); - streams[Index(StdStreamType::In)] = new WinPipeStream(childStdInWrite.detach(), FileAccess::Write); + streams[Index(StdStreamType::ErrorOut)] = + new WinPipeStream(childStdErrRead.detach(), FileAccess::Read); + streams[Index(StdStreamType::Out)] = + new WinPipeStream(childStdOutRead.detach(), FileAccess::Read); + streams[Index(StdStreamType::In)] = + new WinPipeStream(childStdInWrite.detach(), FileAccess::Write); outProcess = new WinProcess(processHandle.detach(), streams[0].readRef()); return SLANG_OK; } -/* static */void Process::sleepCurrentThread(Int timeInMs) +/* static */ void Process::sleepCurrentThread(Int timeInMs) { ::Sleep(DWORD(timeInMs)); } @@ -549,12 +630,12 @@ static uint64_t _getClockFrequency() static const uint64_t g_frequency = _getClockFrequency(); -/* static */uint64_t Process::getClockFrequency() +/* static */ uint64_t Process::getClockFrequency() { return g_frequency; } -/* static */uint64_t Process::getClockTick() +/* static */ uint64_t Process::getClockTick() { LARGE_INTEGER counter; QueryPerformanceCounter(&counter); |
