From 6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Fri, 31 May 2019 17:20:37 -0400 Subject: Use slang- prefix on slang compiler and core source (#973) * Prefixing source files in source/slang with slang- * Prefix source in source/slang with slang- prefix. * Rename core source files with slang- prefix. * Update project files. * Fix problems from automatic merge. --- source/core/allocator.h | 64 --- source/core/array-view.h | 112 ----- source/core/array.h | 135 ------ source/core/basic.h | 13 - source/core/common.h | 95 ---- source/core/core.vcxproj | 40 +- source/core/core.vcxproj.filters | 78 ++-- source/core/dictionary.h | 619 ------------------------- source/core/exception.h | 137 ------ source/core/hash.h | 153 ------ source/core/list.h | 631 ------------------------- source/core/platform.cpp | 172 ------- source/core/platform.h | 67 --- source/core/secure-crt.h | 88 ---- source/core/slang-allocator.h | 64 +++ source/core/slang-array-view.h | 112 +++++ source/core/slang-array.h | 135 ++++++ source/core/slang-basic.h | 13 + source/core/slang-byte-encode-util.cpp | 2 - source/core/slang-byte-encode-util.h | 6 +- source/core/slang-common.h | 95 ++++ source/core/slang-dictionary.h | 620 +++++++++++++++++++++++++ source/core/slang-exception.h | 137 ++++++ source/core/slang-free-list.h | 6 +- source/core/slang-hash.h | 153 ++++++ source/core/slang-io.cpp | 2 +- source/core/slang-io.h | 10 +- source/core/slang-list.h | 631 +++++++++++++++++++++++++ source/core/slang-math.h | 4 +- source/core/slang-memory-arena.h | 4 +- source/core/slang-object-scope-manager.h | 8 +- source/core/slang-platform.cpp | 172 +++++++ source/core/slang-platform.h | 67 +++ source/core/slang-random-generator.h | 6 +- source/core/slang-render-api-util.cpp | 6 +- source/core/slang-render-api-util.h | 4 +- source/core/slang-secure-crt.h | 88 ++++ source/core/slang-shared-library.cpp | 5 +- source/core/slang-shared-library.h | 12 +- source/core/slang-smart-pointer.h | 250 ++++++++++ source/core/slang-std-writers.h | 4 +- source/core/slang-stream.cpp | 294 ++++++++++++ source/core/slang-stream.h | 113 +++++ source/core/slang-string-slice-pool.h | 8 +- source/core/slang-string-util.h | 6 +- source/core/slang-string.cpp | 2 +- source/core/slang-string.h | 12 +- source/core/slang-test-tool-util.h | 4 +- source/core/slang-text-io.cpp | 343 ++++++++++++++ source/core/slang-text-io.h | 316 +++++++++++++ source/core/slang-token-reader.cpp | 768 +++++++++++++++++++++++++++++++ source/core/slang-token-reader.h | 260 +++++++++++ source/core/slang-type-traits.h | 46 ++ source/core/slang-uint-set.h | 8 +- source/core/slang-writer.cpp | 2 +- source/core/slang-writer.h | 6 +- source/core/smart-pointer.h | 250 ---------- source/core/stream.cpp | 294 ------------ source/core/stream.h | 113 ----- source/core/text-io.cpp | 343 -------------- source/core/text-io.h | 316 ------------- source/core/token-reader.cpp | 768 ------------------------------- source/core/token-reader.h | 258 ----------- source/core/type-traits.h | 46 -- 64 files changed, 4799 insertions(+), 4797 deletions(-) delete mode 100644 source/core/allocator.h delete mode 100644 source/core/array-view.h delete mode 100644 source/core/array.h delete mode 100644 source/core/basic.h delete mode 100644 source/core/common.h delete mode 100644 source/core/dictionary.h delete mode 100644 source/core/exception.h delete mode 100644 source/core/hash.h delete mode 100644 source/core/list.h delete mode 100644 source/core/platform.cpp delete mode 100644 source/core/platform.h delete mode 100644 source/core/secure-crt.h create mode 100644 source/core/slang-allocator.h create mode 100644 source/core/slang-array-view.h create mode 100644 source/core/slang-array.h create mode 100644 source/core/slang-basic.h create mode 100644 source/core/slang-common.h create mode 100644 source/core/slang-dictionary.h create mode 100644 source/core/slang-exception.h create mode 100644 source/core/slang-hash.h create mode 100644 source/core/slang-list.h create mode 100644 source/core/slang-platform.cpp create mode 100644 source/core/slang-platform.h create mode 100644 source/core/slang-secure-crt.h create mode 100644 source/core/slang-smart-pointer.h create mode 100644 source/core/slang-stream.cpp create mode 100644 source/core/slang-stream.h create mode 100644 source/core/slang-text-io.cpp create mode 100644 source/core/slang-text-io.h create mode 100644 source/core/slang-token-reader.cpp create mode 100644 source/core/slang-token-reader.h create mode 100644 source/core/slang-type-traits.h delete mode 100644 source/core/smart-pointer.h delete mode 100644 source/core/stream.cpp delete mode 100644 source/core/stream.h delete mode 100644 source/core/text-io.cpp delete mode 100644 source/core/text-io.h delete mode 100644 source/core/token-reader.cpp delete mode 100644 source/core/token-reader.h delete mode 100644 source/core/type-traits.h (limited to 'source/core') diff --git a/source/core/allocator.h b/source/core/allocator.h deleted file mode 100644 index 5832d0b84..000000000 --- a/source/core/allocator.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef CORE_LIB_ALLOCATOR_H -#define CORE_LIB_ALLOCATOR_H - -#include -#ifdef _MSC_VER -# include -#endif - -namespace Slang -{ - inline void* alignedAllocate(size_t size, size_t alignment) - { -#ifdef _MSC_VER - return _aligned_malloc(size, alignment); -#elif defined(__CYGWIN__) - return aligned_alloc(alignment, size); -#else - void * rs = 0; - int succ = posix_memalign(&rs, alignment, size); - if (succ!=0) - rs = 0; - return rs; -#endif - } - - inline void alignedDeallocate(void* ptr) - { -#ifdef _MSC_VER - _aligned_free(ptr); -#else - free(ptr); -#endif - } - - class StandardAllocator - { - public: - // not really called - void* allocate(size_t size) - { - return ::malloc(size); - } - void deallocate(void * ptr) - { - return ::free(ptr); - } - }; - - template - class AlignedAllocator - { - public: - void* allocate(size_t size) - { - return alignedAllocate(size, ALIGNMENT); - } - void deallocate(void * ptr) - { - return alignedDeallocate(ptr); - } - }; -} - -#endif diff --git a/source/core/array-view.h b/source/core/array-view.h deleted file mode 100644 index ad9673e2e..000000000 --- a/source/core/array-view.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef CORE_LIB_ARRAY_VIEW_H -#define CORE_LIB_ARRAY_VIEW_H - -#include "common.h" - -namespace Slang -{ - template - class ArrayView - { - private: - T* m_buffer; - int m_count; - public: - const T* begin() const { return m_buffer; } - T* begin() { return m_buffer; } - - const T* end() const { return m_buffer + m_count; } - T* end() { return m_buffer + m_count; } - - public: - ArrayView(): - m_buffer(nullptr), - m_count(0) - { - } - ArrayView(T& singleObj): - m_buffer(&singleObj), - m_count(1) - { - } - ArrayView(T* buffer, int size): - m_buffer(buffer), - m_count(size) - { - } - - inline int getCount() const { return m_count; } - - inline const T& operator [](int idx) const - { - SLANG_ASSERT(idx >= 0 && idx <= m_count); - return m_buffer[idx]; - } - inline T& operator [](int 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; } - - template - int indexOf(const T2 & val) const - { - for (int i = 0; i < m_count; i++) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } - - template - int lastIndexOf(const T2 & val) const - { - for (int i = m_count - 1; i >= 0; i--) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } - - template - int findFirstIndex(const Func& predicate) const - { - for (int i = 0; i < m_count; i++) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; - } - - template - int findLastIndex(const Func& predicate) const - { - for (int i = m_count - 1; i >= 0; i--) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; - } - }; - - template - ArrayView makeArrayView(T& obj) - { - return ArrayView(obj); - } - - template - ArrayView makeArrayView(T* buffer, int count) - { - return ArrayView(buffer, count); - } -} - -#endif diff --git a/source/core/array.h b/source/core/array.h deleted file mode 100644 index 2a5fa0aa7..000000000 --- a/source/core/array.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef CORE_LIB_ARRAY_H -#define CORE_LIB_ARRAY_H - -#include "exception.h" -#include "array-view.h" - -namespace Slang -{ - template - class Array - { - private: - T m_buffer[COUNT]; - int m_count = 0; - 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; } - - public: - inline int getCapacity() const { return COUNT; } - inline int 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(int 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 [](int idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - inline T& operator [](int 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 - int indexOf(const T2& val) const - { - for (int i = 0; i < m_count; i++) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } - - template - int lastIndexOf(const T2& val) const - { - for (int i = m_count - 1; i >= 0; i--) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } - - inline ArrayView getArrayView() const - { - return ArrayView((T*)m_buffer, m_count); - } - inline ArrayView getArrayView(int start, int count) const - { - return ArrayView((T*)m_buffer + start, count); - } - }; - - template - struct FirstType - { - typedef T Type; - }; - - - template - void insertArray(Array&) {} - - template - void insertArray(Array& arr, const T& val, TArgs... args) - { - arr.add(val); - insertArray(arr, args...); - } - - template - auto makeArray(TArgs ...args) -> Array::Type, sizeof...(args)> - { - Array::Type, sizeof...(args)> rs; - insertArray(rs, args...); - return rs; - } -} - -#endif diff --git a/source/core/basic.h b/source/core/basic.h deleted file mode 100644 index e89d740bf..000000000 --- a/source/core/basic.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CORE_LIB_BASIC_H -#define CORE_LIB_BASIC_H - -#include "common.h" -#include "slang-math.h" -#include "slang-string.h" -#include "array.h" -#include "list.h" -#include "smart-pointer.h" -#include "exception.h" -#include "dictionary.h" - -#endif \ No newline at end of file diff --git a/source/core/common.h b/source/core/common.h deleted file mode 100644 index 0e5396caf..000000000 --- a/source/core/common.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef CORE_LIB_COMMON_H -#define CORE_LIB_COMMON_H - -#include "../../slang.h" - -#include - -#include - -#ifdef __GNUC__ -#define CORE_LIB_ALIGN_16(x) x __attribute__((aligned(16))) -#else -#define CORE_LIB_ALIGN_16(x) __declspec(align(16)) x -#endif - -#define VARIADIC_TEMPLATE - -namespace Slang -{ - typedef int32_t Int32; - typedef uint32_t UInt32; - - typedef int64_t Int64; - typedef uint64_t UInt64; - - // Define - typedef SlangUInt UInt; - typedef SlangInt Int; - -// typedef unsigned short Word; - - typedef intptr_t PtrInt; - - // Type used for indexing, in arrays/views etc - typedef Int Index; - - template - inline T&& _Move(T & obj) - { - return static_cast(obj); - } - - template - inline void Swap(T & v0, T & v1) - { - T tmp = _Move(v0); - v0 = _Move(v1); - v1 = _Move(tmp); - } - -#ifdef _MSC_VER -# define SLANG_RETURN_NEVER __declspec(noreturn) -//#elif SLANG_CLANG -//# define SLANG_RETURN_NEVER [[noreturn]] -#else -# define SLANG_RETURN_NEVER [[noreturn]] -//# define SLANG_RETURN_NEVER /* empty */ -#endif - -#ifdef _MSC_VER -#define UNREACHABLE_RETURN(x) -#define UNREACHABLE(x) -#else -#define UNREACHABLE_RETURN(x) return x; -#define UNREACHABLE(x) x; -#endif - - SLANG_RETURN_NEVER void signalUnexpectedError(char const* message); -} - -#define SLANG_UNEXPECTED(reason) \ - Slang::signalUnexpectedError("unexpected: " reason) - -#define SLANG_UNIMPLEMENTED_X(what) \ - Slang::signalUnexpectedError("unimplemented: " what) - -#define SLANG_UNREACHABLE(msg) \ - Slang::signalUnexpectedError("unreachable code executed: " msg) - -#ifdef _DEBUG -#define SLANG_EXPECT(VALUE, MSG) if(VALUE) {} else Slang::signalUnexpectedError("assertion failed: '" MSG "'") -#define SLANG_ASSERT(VALUE) SLANG_EXPECT(VALUE, #VALUE) -#else -#define SLANG_EXPECT(VALUE, MSG) do {} while(0) -#define SLANG_ASSERT(VALUE) do {} while(0) -#endif - -#define SLANG_RELEASE_ASSERT(VALUE) if(VALUE) {} else Slang::signalUnexpectedError("assertion failed") -#define SLANG_RELEASE_EXPECT(VALUE, WHAT) if(VALUE) {} else SLANG_UNEXPECTED(WHAT) - -template void slang_use_obj(T&) {} - -#define SLANG_UNREFERENCED_PARAMETER(P) slang_use_obj(P) -#define SLANG_UNREFERENCED_VARIABLE(P) slang_use_obj(P) -#endif diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index 0416eaed6..a8e92949f 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -170,59 +170,59 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + - - - diff --git a/source/core/core.vcxproj.filters b/source/core/core.vcxproj.filters index 0a0ea93fa..8656ab49b 100644 --- a/source/core/core.vcxproj.filters +++ b/source/core/core.vcxproj.filters @@ -9,46 +9,40 @@ - + Header Files - + Header Files - + Header Files - + Header Files - - Header Files - - - Header Files - - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files @@ -60,18 +54,30 @@ Header Files + + Header Files + Header Files Header Files + + Header Files + Header Files + + Header Files + Header Files + + Header Files + Header Files @@ -84,32 +90,23 @@ Header Files - - Header Files - - - Header Files - - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - - Source Files - Source Files @@ -125,6 +122,9 @@ Source Files + + Source Files + Source Files @@ -137,6 +137,9 @@ Source Files + + Source Files + Source Files @@ -149,19 +152,16 @@ Source Files - + Source Files - + Source Files - - Source Files - - + Source Files - + Source Files diff --git a/source/core/dictionary.h b/source/core/dictionary.h deleted file mode 100644 index 1b3525756..000000000 --- a/source/core/dictionary.h +++ /dev/null @@ -1,619 +0,0 @@ -#ifndef CORE_LIB_DICTIONARY_H -#define CORE_LIB_DICTIONARY_H -#include "list.h" -#include "common.h" -#include "slang-uint-set.h" -#include "exception.h" -#include "slang-math.h" -#include "hash.h" - -namespace Slang -{ - template - class KeyValuePair - { - public: - TKey Key; - TValue Value; - KeyValuePair() - {} - KeyValuePair(const TKey & key, const TValue & value) - { - Key = key; - Value = value; - } - KeyValuePair(TKey && key, TValue && value) - { - Key = _Move(key); - Value = _Move(value); - } - KeyValuePair(TKey && key, const TValue & value) - { - Key = _Move(key); - Value = value; - } - KeyValuePair(const KeyValuePair & _that) - { - Key = _that.Key; - Value = _that.Value; - } - KeyValuePair(KeyValuePair && _that) - { - operator=(_Move(_that)); - } - KeyValuePair & operator=(KeyValuePair && that) - { - Key = _Move(that.Key); - Value = _Move(that.Value); - return *this; - } - KeyValuePair & operator=(const KeyValuePair & that) - { - Key = that.Key; - Value = that.Value; - return *this; - } - int GetHashCode() - { - return GetHashCode(Key); - } - }; - - template - inline KeyValuePair KVPair(const TKey & k, const TValue & v) - { - return KeyValuePair(k, v); - } - - const float MaxLoadFactor = 0.7f; - - template - class Dictionary - { - friend class Iterator; - friend class ItemProxy; - private: - inline int GetProbeOffset(int /*probeId*/) const - { - // quadratic probing - return 1; - } - private: - int bucketSizeMinusOne; - int _count; - UIntSet marks; - KeyValuePair* hashMap; - void Free() - { - if (hashMap) - delete[] hashMap; - hashMap = 0; - } - inline bool IsDeleted(int pos) const - { - return marks.contains((pos << 1) + 1); - } - inline bool IsEmpty(int pos) const - { - return !marks.contains((pos << 1)); - } - inline void SetDeleted(int pos, bool val) - { - if (val) - marks.add((pos << 1) + 1); - else - marks.remove((pos << 1) + 1); - } - inline void SetEmpty(int pos, bool val) - { - if (val) - marks.remove((pos << 1)); - else - marks.add((pos << 1)); - } - struct FindPositionResult - { - int ObjectPosition; - int InsertionPosition; - FindPositionResult() - { - ObjectPosition = -1; - InsertionPosition = -1; - } - FindPositionResult(int objPos, int insertPos) - { - ObjectPosition = objPos; - InsertionPosition = insertPos; - } - - }; - inline int GetHashPos(TKey& key) const - { - return ((unsigned int)(GetHashCode(key) * 2654435761)) % bucketSizeMinusOne; - } - FindPositionResult FindPosition(const TKey& key) const - { - int hashPos = GetHashPos(const_cast(key)); - int insertPos = -1; - int numProbes = 0; - while (numProbes <= bucketSizeMinusOne) - { - 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 (hashMap[hashPos].Key == key) - { - return FindPositionResult(hashPos, -1); - } - numProbes++; - hashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne; - } - if (insertPos != -1) - return FindPositionResult(-1, insertPos); - throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode."); - } - TValue & _Insert(KeyValuePair&& kvPair, int pos) - { - hashMap[pos] = _Move(kvPair); - SetEmpty(pos, false); - SetDeleted(pos, false); - return hashMap[pos].Value; - } - void Rehash() - { - if (bucketSizeMinusOne == -1 || _count >= int(MaxLoadFactor * bucketSizeMinusOne)) - { - int newSize = (bucketSizeMinusOne + 1) * 2; - if (newSize == 0) - { - newSize = 16; - } - Dictionary newDict; - newDict.bucketSizeMinusOne = newSize - 1; - newDict.hashMap = new KeyValuePair[newSize]; - newDict.marks.resizeAndClear(newSize * 2); - if (hashMap) - { - for (auto & kvPair : *this) - { - newDict.Add(_Move(kvPair)); - } - } - *this = _Move(newDict); - } - } - - bool AddIfNotExists(KeyValuePair&& kvPair) - { - Rehash(); - auto pos = FindPosition(kvPair.Key); - if (pos.ObjectPosition != -1) - return false; - else if (pos.InsertionPosition != -1) - { - _count++; - _Insert(_Move(kvPair), pos.InsertionPosition); - return true; - } - else - throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); - } - void Add(KeyValuePair&& kvPair) - { - if (!AddIfNotExists(_Move(kvPair))) - throw KeyExistsException("The key already exists in Dictionary."); - } - TValue& Set(KeyValuePair&& kvPair) - { - Rehash(); - auto pos = FindPosition(kvPair.Key); - if (pos.ObjectPosition != -1) - return _Insert(_Move(kvPair), pos.ObjectPosition); - else if (pos.InsertionPosition != -1) - { - _count++; - return _Insert(_Move(kvPair), pos.InsertionPosition); - } - else - throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); - } - public: - class Iterator - { - private: - const Dictionary * dict; - int pos; - public: - KeyValuePair & operator *() const - { - return dict->hashMap[pos]; - } - KeyValuePair * operator ->() const - { - return dict->hashMap + pos; - } - Iterator & operator ++() - { - if (pos > dict->bucketSizeMinusOne) - return *this; - pos++; - while (pos <= dict->bucketSizeMinusOne && (dict->IsDeleted(pos) || dict->IsEmpty(pos))) - { - pos++; - } - return *this; - } - Iterator operator ++(int) - { - Iterator rs = *this; - operator++(); - return rs; - } - bool operator != (const Iterator & _that) const - { - return pos != _that.pos || dict != _that.dict; - } - bool operator == (const Iterator & _that) const - { - return pos == _that.pos && dict == _that.dict; - } - Iterator(const Dictionary * _dict, int _pos) - { - this->dict = _dict; - this->pos = _pos; - } - Iterator() - { - this->dict = 0; - this->pos = 0; - } - }; - - Iterator begin() const - { - int pos = 0; - while (pos < bucketSizeMinusOne + 1) - { - if (IsEmpty(pos) || IsDeleted(pos)) - pos++; - else - break; - } - return Iterator(this, pos); - } - Iterator end() const - { - return Iterator(this, bucketSizeMinusOne + 1); - } - public: - void Add(const TKey & key, const TValue & value) - { - Add(KeyValuePair(key, value)); - } - void Add(TKey && key, TValue && value) - { - Add(KeyValuePair(_Move(key), _Move(value))); - } - bool AddIfNotExists(const TKey & key, const TValue & value) - { - return AddIfNotExists(KeyValuePair(key, value)); - } - bool AddIfNotExists(TKey && key, TValue && value) - { - return AddIfNotExists(KeyValuePair(_Move(key), _Move(value))); - } - void Remove(const TKey & key) - { - if (_count == 0) - return; - auto pos = FindPosition(key); - if (pos.ObjectPosition != -1) - { - SetDeleted(pos.ObjectPosition, true); - _count--; - } - } - void Clear() - { - _count = 0; - - marks.clear(); - } - - TValue* TryGetValueOrAdd(const TKey& key, const TValue& value) - { - Rehash(); - auto pos = FindPosition(key); - if (pos.ObjectPosition != -1) - { - return &hashMap[pos.ObjectPosition].Value; - } - else if (pos.InsertionPosition != -1) - { - // Make pair - KeyValuePair kvPair(_Move(key), _Move(value)); - _count++; - _Insert(_Move(kvPair), pos.InsertionPosition); - return nullptr; - } - else - throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); - } - - bool ContainsKey(const TKey& key) const - { - if (bucketSizeMinusOne == -1) - return false; - auto pos = FindPosition(key); - return pos.ObjectPosition != -1; - } - bool TryGetValue(const TKey& key, TValue& value) const - { - if (bucketSizeMinusOne == -1) - return false; - auto pos = FindPosition(key); - if (pos.ObjectPosition != -1) - { - value = hashMap[pos.ObjectPosition].Value; - return true; - } - return false; - } - TValue* TryGetValue(const TKey& key) const - { - if (bucketSizeMinusOne == -1) - return nullptr; - auto pos = FindPosition(key); - if (pos.ObjectPosition != -1) - { - return &hashMap[pos.ObjectPosition].Value; - } - return nullptr; - } - - class ItemProxy - { - private: - const Dictionary * dict; - TKey key; - public: - ItemProxy(const TKey& _key, const Dictionary* _dict) - { - this->dict = _dict; - this->key = _key; - } - ItemProxy(TKey&& _key, const Dictionary* _dict) - { - this->dict = _dict; - this->key = _Move(_key); - } - TValue & GetValue() const - { - auto pos = dict->FindPosition(key); - if (pos.ObjectPosition != -1) - { - return dict->hashMap[pos.ObjectPosition].Value; - } - else - throw KeyNotFoundException("The key does not exists in dictionary."); - } - inline TValue & operator()() const - { - return GetValue(); - } - operator TValue&() const - { - return GetValue(); - } - TValue & operator = (const TValue & val) const - { - return ((Dictionary*)dict)->Set(KeyValuePair(_Move(key), val)); - } - TValue & operator = (TValue && val) const - { - return ((Dictionary*)dict)->Set(KeyValuePair(_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 Count() const - { - return _count; - } - private: - template - void Init(const KeyValuePair & kvPair, Args... args) - { - Add(kvPair); - Init(args...); - } - public: - Dictionary() - { - bucketSizeMinusOne = -1; - _count = 0; - hashMap = nullptr; - } - template - Dictionary(Arg arg, Args... args) - { - Init(arg, args...); - } - Dictionary(const Dictionary& other) - : bucketSizeMinusOne(-1), _count(0), hashMap(nullptr) - { - *this = other; - } - Dictionary(Dictionary&& other) - : bucketSizeMinusOne(-1), _count(0), hashMap(nullptr) - { - *this = (_Move(other)); - } - Dictionary& operator = (const Dictionary& other) - { - if (this == &other) - return *this; - Free(); - bucketSizeMinusOne = other.bucketSizeMinusOne; - _count = other._count; - hashMap = new KeyValuePair[other.bucketSizeMinusOne + 1]; - marks = other.marks; - for (int i = 0; i <= bucketSizeMinusOne; i++) - hashMap[i] = other.hashMap[i]; - return *this; - } - Dictionary & operator = (Dictionary&& other) - { - if (this == &other) - return *this; - Free(); - bucketSizeMinusOne = other.bucketSizeMinusOne; - _count = other._count; - hashMap = other.hashMap; - marks = _Move(other.marks); - other.hashMap = 0; - other._count = 0; - other.bucketSizeMinusOne = -1; - return *this; - } - ~Dictionary() - { - Free(); - } - }; - - class _DummyClass - {}; - - template - class HashSetBase - { - protected: - DictionaryType dict; - private: - template - void Init(const T & v, Args... args) - { - Add(v); - Init(args...); - } - public: - HashSetBase() - {} - template - 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::Iterator iter; - public: - Iterator() = default; - T & operator *() const - { - return (*iter).Key; - } - T * operator ->() const - { - return &(*iter).Key; - } - 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::Iterator & _iter) - { - this->iter = _iter; - } - }; - Iterator begin() const - { - return Iterator(dict.begin()); - } - Iterator end() const - { - return Iterator(dict.end()); - } - public: - int Count() const - { - return dict.Count(); - } - 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 - class HashSet : public HashSetBase> - {}; -} - -#endif diff --git a/source/core/exception.h b/source/core/exception.h deleted file mode 100644 index fc7aa48e2..000000000 --- a/source/core/exception.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef CORE_LIB_EXCEPTION_H -#define CORE_LIB_EXCEPTION_H - -#include "common.h" -#include "slang-string.h" - -namespace Slang -{ - class Exception - { - public: - String Message; - Exception() - {} - Exception(const String & message) - : Message(message) - { - } - - virtual ~Exception() - {} - }; - - class IndexOutofRangeException : public Exception - { - public: - IndexOutofRangeException() - {} - IndexOutofRangeException(const String & message) - : Exception(message) - { - } - - }; - - class InvalidOperationException : public Exception - { - public: - InvalidOperationException() - {} - InvalidOperationException(const String & message) - : Exception(message) - { - } - - }; - - class ArgumentException : public Exception - { - public: - ArgumentException() - {} - ArgumentException(const String & message) - : Exception(message) - { - } - - }; - - class KeyNotFoundException : public Exception - { - public: - KeyNotFoundException() - {} - KeyNotFoundException(const String & message) - : Exception(message) - { - } - }; - class KeyExistsException : public Exception - { - public: - KeyExistsException() - {} - KeyExistsException(const String & message) - : Exception(message) - { - } - }; - - class NotSupportedException : public Exception - { - public: - NotSupportedException() - {} - NotSupportedException(const String & message) - : Exception(message) - { - } - }; - - class NotImplementedException : public Exception - { - public: - NotImplementedException() - {} - NotImplementedException(const String & message) - : Exception(message) - { - } - }; - - class InvalidProgramException : public Exception - { - public: - InvalidProgramException() - {} - InvalidProgramException(const String & message) - : Exception(message) - { - } - }; - - class InternalError : public Exception - { - public: - InternalError() - {} - InternalError(const String & message) - : Exception(message) - { - } - }; - - class AbortCompilationException : public Exception - { - public: - AbortCompilationException() - {} - AbortCompilationException(const String & message) - : Exception(message) - { - } - }; -} - -#endif \ No newline at end of file diff --git a/source/core/hash.h b/source/core/hash.h deleted file mode 100644 index 83e99179b..000000000 --- a/source/core/hash.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef CORELIB_HASH_H -#define CORELIB_HASH_H - -#include "slang-math.h" -#include -#include - -namespace Slang -{ - typedef int HashCode; - - inline int GetHashCode(double key) - { - return FloatAsInt((float)key); - } - inline int GetHashCode(float key) - { - return FloatAsInt(key); - } - inline int GetHashCode(const char * buffer) - { - if (!buffer) - return 0; - int hash = 0; - int c; - auto str = buffer; - c = *str++; - while (c) - { - hash = c + (hash << 6) + (hash << 16) - hash; - c = *str++; - } - return hash; - } - inline int GetHashCode(char * buffer) - { - return GetHashCode(const_cast(buffer)); - } - inline int GetHashCode(const char * buffer, size_t numChars) - { - int hash = 0; - for (size_t i = 0; i < numChars; ++i) - { - hash = int(buffer[i]) + (hash << 6) + (hash << 16) - hash; - } - return hash; - } - - inline uint64_t GetHashCode64(const char * buffer, size_t numChars) - { - // Use uints because hash requires wrap around behavior and int is undefined on over/underflows - uint64_t hash = 0; - for (size_t i = 0; i < numChars; ++i) - { - hash = uint64_t(int64_t(buffer[i])) + (hash << 6) + (hash << 16) - hash; - } - return hash; - } - - template - class Hash - { - public: - }; - template<> - class Hash<1> - { - public: - template - static int GetHashCode(TKey & key) - { - return (int)key; - } - }; - template<> - class Hash<0> - { - public: - template - static int GetHashCode(TKey & key) - { - return int(key.GetHashCode()); - } - }; - template - class PointerHash - {}; - template<> - class PointerHash<1> - { - public: - template - static int GetHashCode(TKey const& key) - { - return (int)((PtrInt)key) / 16; // sizeof(typename std::remove_pointer::type); - } - }; - template<> - class PointerHash<0> - { - public: - template - static int GetHashCode(TKey & key) - { - return Hash::value || std::is_enum::value>::GetHashCode(key); - } - }; - - template - int GetHashCode(const TKey & key) - { - return PointerHash::value>::GetHashCode(key); - } - - template - int GetHashCode(TKey & key) - { - return PointerHash::value>::GetHashCode(key); - } - - inline int combineHash(int left, int right) - { - return (left * 16777619) ^ right; - } - - struct Hasher - { - public: - Hasher() {} - - template - void hashValue(T const& value) - { - m_hashCode = combineHash(m_hashCode, GetHashCode(value)); - } - - template - void hashObject(T const& object) - { - m_hashCode = combineHash(m_hashCode, object->GetHashCode()); - } - - HashCode getResult() const - { - return m_hashCode; - } - - private: - HashCode m_hashCode = 0; - }; -} - -#endif diff --git a/source/core/list.h b/source/core/list.h deleted file mode 100644 index 7ba313305..000000000 --- a/source/core/list.h +++ /dev/null @@ -1,631 +0,0 @@ -#ifndef FUNDAMENTAL_LIB_LIST_H -#define FUNDAMENTAL_LIB_LIST_H - -#include "../../slang.h" - -#include "allocator.h" -#include "slang-math.h" -#include "array-view.h" - -#include -#include -#include - - -namespace Slang -{ - - template - class Initializer - { - - }; - - template - class Initializer - { - public: - static void initialize(T* buffer, int size) - { - for (int i = 0; i - class Initializer - { - public: - static void initialize(T* buffer, int size) - { - // It's pod so no initialization required - //for (int i = 0; i < size; i++) - // new (buffer + i) T; - } - }; - - template - class AllocateMethod - { - public: - static inline T* allocateArray(Index count) - { - TAllocator allocator; - T * rs = (T*)allocator.allocate(count * sizeof(T)); - Initializer::value>::initialize(rs, count); - return rs; - } - static inline void deallocateArray(T* ptr, Index count) - { - TAllocator allocator; - if (!std::is_trivially_destructible::value) - { - for (Index i = 0; i < count; i++) - ptr[i].~T(); - } - allocator.deallocate(ptr); - } - }; - - template - class AllocateMethod - { - public: - static inline T* allocateArray(Index count) - { - return new T[count]; - } - static inline void deallocateArray(T* ptr, Index /*bufferSize*/) - { - delete [] ptr; - } - }; - - - template - class List - { - private: - static const Index kInitialCount = 16; - - public: - List() - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - } - template - List(const T& val, Args... args) - { - _init(val, args...); - } - List(const List& list) - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - this->operator=(list); - } - List(List&& list) - : m_buffer(nullptr), m_count(0), m_capacity(0) - { - this->operator=(static_cast&&>(list)); - } - static List makeRepeated(const T& val, Index count) - { - List rs; - rs.setCount(count); - for (Index i = 0; i < count; i++) - rs[i] = val; - return rs; - } - ~List() - { - _deallocateBuffer(); - } - List& operator=(const List& list) - { - clearAndDeallocate(); - addRange(list); - return *this; - } - - List& operator=(List&& 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; - return *this; - } - - // TODO(JS): These should be made const safe but some other code depends on this behavior for now. - T* begin() const { return m_buffer; } - T* end() const { return m_buffer + m_count; } - - const T& getFirst() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - - const T& getLast() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count-1]; - } - - T& getFirst() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - - T& getLast() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } - - void removeLast() - { - SLANG_ASSERT(m_count > 0); - m_count--; - } - - inline void swapWith(List& other) - { - T* buffer = m_buffer; - m_buffer = other.m_buffer; - other.m_buffer = buffer; - - auto bufferSize = m_capacity; - m_capacity = other.m_capacity; - other.m_capacity = bufferSize; - - auto count = m_count; - m_count = other.m_count; - other.m_count = count; - } - - T* detachBuffer() - { - T* rs = m_buffer; - m_buffer = nullptr; - m_count = 0; - m_capacity = 0; - return rs; - } - - inline ArrayView getArrayView() const - { - return ArrayView(m_buffer, m_count); - } - - inline ArrayView getArrayView(Index start, Index count) const - { - SLANG_ASSERT(start >= 0 && count >= 0 && start + count <= m_count); - return ArrayView(m_buffer + start, count); - } - - void add(T&& obj) - { - if (m_capacity < m_count + 1) - { - Index newBufferSize = kInitialCount; - if (m_capacity) - newBufferSize = (m_capacity << 1); - - reserve(newBufferSize); - } - m_buffer[m_count++] = static_cast(obj); - } - - void add(const T& obj) - { - if (m_capacity < m_count + 1) - { - Index newBufferSize = kInitialCount; - if (m_capacity) - newBufferSize = (m_capacity << 1); - - reserve(newBufferSize); - } - m_buffer[m_count++] = obj; - - } - - Index getCount() const { return m_count; } - Index getCapacity() const { return m_capacity; } - - const T* getBuffer() const { return m_buffer; } - T* getBuffer() { return m_buffer; } - - void insert(Index idx, const T& val) { insertRange(idx, &val, 1); } - - void insertRange(Index idx, const T* vals, Index n) - { - if (m_capacity < m_count + n) - { - Index newBufferCount = kInitialCount; - while (newBufferCount < m_count + n) - newBufferCount = newBufferCount << 1; - - T* newBuffer = _allocate(newBufferCount); - if (m_capacity) - { - /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::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(m_buffer[i])); - } - _deallocateBuffer(); - } - m_buffer = newBuffer; - m_capacity = newBufferCount; - } - else - { - /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::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(m_buffer[i - 1]); - } - } - /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::value) - memcpy(buffer + id, vals, sizeof(T) * n); - else*/ - for (Index i = 0; i < n; i++) - m_buffer[idx + i] = vals[i]; - - m_count += n; - } - - //slower than original edition - //void Add(const T & val) - //{ - // InsertRange(_count, &val, 1); - //} - - void insertRange(Index id, const List& list) { insertRange(id, list.m_buffer, list.m_count); } - - void addRange(ArrayView list) { insertRange(m_count, list.getBuffer(), list.Count()); } - - void addRange(const T* vals, Index n) { insertRange(m_count, vals, n); } - - void addRange(const List& list) { insertRange(m_count, list.m_buffer, list.m_count); } - - 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(m_buffer[i]); - m_count -= actualDeleteCount; - } - - void removeAt(Index id) { removeRange(id, 1); } - - void remove(const T& val) - { - Index idx = indexOf(val); - if (idx != -1) - removeAt(idx); - } - - void reverse() - { - for (Index i = 0; i < (m_count >> 1); i++) - { - swapElements(m_buffer, i, m_count - i - 1); - } - } - - void fastRemove(const T& val) - { - Index idx = indexOf(val); - fastRemoveAt(idx); - } - - void fastRemoveAt(Index idx) - { - if (idx != -1 && m_count - 1 != idx) - { - m_buffer[idx] = _Move(m_buffer[m_count - 1]); - } - m_count--; - } - - void clear() { m_count = 0; } - - void clearAndDeallocate() - { - _deallocateBuffer(); - m_count = m_capacity = 0; - } - - void reserve(Index size) - { - if(size > m_capacity) - { - T* newBuffer = _allocate(size); - if (m_capacity) - { - /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::value) - memcpy(newBuffer, buffer, _count * sizeof(T)); - else*/ - { - for (Index i = 0; i < m_count; i++) - newBuffer[i] = static_cast(m_buffer[i]); - - // Default-initialize the remaining elements - for(Index i = m_count; i < size; i++) - { - new(newBuffer + i) T(); - } - } - _deallocateBuffer(); - } - m_buffer = newBuffer; - m_capacity = size; - } - } - - void growToCount(Index count) - { - Index newBufferCount = Index(1) << Math::Log2Ceil(count); - if (m_capacity < newBufferCount) - { - reserve(newBufferCount); - } - m_count = count; - } - - void setCount(Index count) - { - reserve(count); - m_count = count; - } - - void unsafeShrinkToCount(Index count) { m_count = count; } - - void compress() - { - 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(m_buffer[i]); - - _deallocateBuffer(); - m_buffer = newBuffer; - m_capacity = m_count; - } - } - - SLANG_FORCE_INLINE T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx <= m_count); - return m_buffer[idx]; - } - - template - Index findFirstIndex(const Func& predicate) const - { - for (Index i = 0; i < m_count; i++) - { - if (predicate(m_buffer[i])) - return i; - } - return (Index)-1; - } - - template - Index findLastIndex(const Func& predicate) const - { - for (Index i = m_count; i > 0; i--) - { - if (predicate(m_buffer[i-1])) - return i-1; - } - return (Index)-1; - } - - template - Index indexOf(const T2& val) const - { - for (Index i = 0; i < m_count; i++) - { - if (m_buffer[i] == val) - return i; - } - return (Index)-1; - } - - template - Index lastIndexOf(const T2& val) const - { - for (Index i = m_count; i > 0; i--) - { - if(m_buffer[i-1] == val) - return i-1; - } - return (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 - 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 - void forEach(IterateFunc f) const - { - for (Index i = 0; i< m_count; i++) - f(m_buffer[i]); - } - - template - void quickSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) - { - static const Index kMinQSortSize = 32; - - 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 - 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++) - { - if (comparer(vals[i], pivotValue)) - { - swapElements(vals, i, storeIndex); - storeIndex++; - } - } - swapElements(vals, storeIndex, right); - return storeIndex; - } - template - void insertionSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) - { - for (Index i = startIndex + 1; i <= endIndex; i++) - { - T insertValue = static_cast(vals[i]); - Index insertIndex = i - 1; - while (insertIndex >= startIndex && comparer(insertValue, vals[insertIndex])) - { - vals[insertIndex + 1] = static_cast(vals[insertIndex]); - insertIndex--; - } - vals[insertIndex + 1] = static_cast(insertValue); - } - } - - inline void swapElements(T* vals, Index index1, Index index2) - { - if (index1 != index2) - { - T tmp = static_cast(vals[index1]); - vals[index1] = static_cast(vals[index2]); - vals[index2] = static_cast(tmp); - } - } - - template - Index binarySearch(const T2& obj, Comparer comparer) - { - Index imin = 0, imax = m_count - 1; - while (imax >= imin) - { - Index imid = (imin + imax) >> 1; - int compareResult = comparer(m_buffer[imid], obj); - if (compareResult == 0) - return imid; - else if (compareResult < 0) - imin = imid + 1; - else - imax = imid - 1; - } - return -1; - } - - template - int 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; - }); - } - 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) - { - AllocateMethod::deallocateArray(m_buffer, m_capacity); - m_buffer = nullptr; - } - } - static inline T* _allocate(Index count) - { - return AllocateMethod::allocateArray(count); - } - - template - void _init(const T& val, Args... args) - { - add(val); - _init(args...); - } - }; - - template - T calcMin(const List& list) - { - T minVal = list.getFirst(); - for (Index i = 1; i < list.getCount(); i++) - if (list[i] < minVal) - minVal = list[i]; - return minVal; - } - - template - T calcMax(const List& list) - { - T maxVal = list.getFirst(); - for (Index i = 1; i< list.getCount(); i++) - if (list[i] > maxVal) - maxVal = list[i]; - return maxVal; - } -} - -#endif diff --git a/source/core/platform.cpp b/source/core/platform.cpp deleted file mode 100644 index 0deec8ed6..000000000 --- a/source/core/platform.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// platform.cpp -#include "platform.h" - -#include "common.h" - -#ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #define NOMINMAX - #include - #undef WIN32_LEAN_AND_MEAN - #undef NOMINMAX -#else - #include "slang-string.h" - #include -#endif - -namespace Slang -{ - // SharedLibrary - -/* static */SlangResult SharedLibrary::load(const char* filename, SharedLibrary::Handle& handleOut) -{ - StringBuilder builder; - appendPlatformFileName(UnownedStringSlice(filename), builder); - return loadWithPlatformFilename(builder.begin(), handleOut); -} - -#ifdef _WIN32 - -// Make sure SlangResult match for common standard window HRESULT -SLANG_COMPILE_TIME_ASSERT(E_FAIL == SLANG_FAIL); -SLANG_COMPILE_TIME_ASSERT(E_NOINTERFACE == SLANG_E_NO_INTERFACE); -SLANG_COMPILE_TIME_ASSERT(E_HANDLE == SLANG_E_INVALID_HANDLE); -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::appendResult(SlangResult res, StringBuilder& builderOut) -{ - if (SLANG_FAILED(res) && res != SLANG_FAIL) - { - LPWSTR buffer = nullptr; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, - nullptr, - res, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPWSTR)&buffer, - 0, - nullptr); - - if (buffer) - { - builderOut << " "; - // Convert to string - builderOut.Append(String::fromWString(buffer)); - LocalFree(buffer); - return SLANG_OK; - } - } - return SLANG_FAIL; -} - -/* static */SlangResult SharedLibrary::loadWithPlatformFilename(char const* platformFileName, SharedLibrary::Handle& handleOut) -{ - handleOut = nullptr; - // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibrarya - const HMODULE h = LoadLibraryA(platformFileName); - if (!h) - { - const DWORD lastError = GetLastError(); - switch (lastError) - { - 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: - { - return SLANG_E_CANNOT_OPEN; - } - default: break; - } - // Turn to Result, if not one of the well known errors - return HRESULT_FROM_WIN32(lastError); - } - handleOut = (Handle)h; - return SLANG_OK; -} - -/* static */void SharedLibrary::unload(Handle handle) -{ - SLANG_ASSERT(handle); - ::FreeLibrary((HMODULE)handle); -} - -/* static */SharedLibrary::FuncPtr SharedLibrary::findFuncByName(Handle handle, char const* name) -{ - SLANG_ASSERT(handle); - return (FuncPtr)GetProcAddress((HMODULE)handle, name); -} - -/* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) -{ - // Windows doesn't need the extension or any prefix to work - dst.Append(name); -} - -#else // _WIN32 - -/* static */SlangResult PlatformUtil::appendResult(SlangResult res, StringBuilder& builderOut) -{ - return SLANG_E_NOT_IMPLEMENTED; -} - -/* static */SlangResult SharedLibrary::loadWithPlatformFilename(char const* platformFileName, Handle& handleOut) -{ - handleOut = nullptr; - - void* h = dlopen(platformFileName, RTLD_NOW | RTLD_LOCAL); - if(!h) - { -#if 0 - // We can't output the error message here, because it will cause output when testing what code gen is available - if(auto msg = dlerror()) - { - fprintf(stderr, "error: %s\n", msg); - } -#endif - return SLANG_FAIL; - } - handleOut = (Handle)h; - return SLANG_OK; -} - -/* static */void SharedLibrary::unload(Handle handle) -{ - SLANG_ASSERT(handle); - dlclose(handle); -} - -/* static */SharedLibrary::FuncPtr SharedLibrary::findFuncByName(Handle handle, char const* name) -{ - SLANG_ASSERT(handle); - return (FuncPtr)dlsym((void*)handle, name); -} - -/* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) -{ -#if __CYGWIN__ - dst.Append(name); - dst.Append(".dll"); -#elif SLANG_APPLE_FAMILY - dst.Append("lib"); - dst.Append(name); - dst.Append(".dylib"); -#elif SLANG_LINUX_FAMILY - dst.Append("lib"); - dst.Append(name); - dst.Append(".so"); -#else - // Just guess we can do with the name on it's own - dst.Append(name); -#endif -} - -#endif // _WIN32 - -} diff --git a/source/core/platform.h b/source/core/platform.h deleted file mode 100644 index 544ae8c16..000000000 --- a/source/core/platform.h +++ /dev/null @@ -1,67 +0,0 @@ -// platform.h -#ifndef SLANG_CORE_PLATFORM_H_INCLUDED -#define SLANG_CORE_PLATFORM_H_INCLUDED - -#include "../../slang.h" -#include "../core/slang-string.h" - -namespace Slang -{ - // 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 filename - /// - /// @param the unadorned filename - /// @return Returns a non null handle for the shared library on success. nullptr indicated failure - static SlangResult load(const char* filename, 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 platformFileName the platform specific file name. - /// @return Returns a non null handle for the shared library on success. nullptr indicated failure - static SlangResult loadWithPlatformFilename(char const* platformFileName, 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 function - /// Return nullptr if function is not found - /// @param The shared library handle as returned by loadPlatformLibrary - static FuncPtr findFuncByName(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); - - 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); - }; - -#ifndef _MSC_VER - #define _fileno fileno - #define _isatty isatty - #define _setmode setmode - #define _O_BINARY O_BINARY -#endif -} - -#endif diff --git a/source/core/secure-crt.h b/source/core/secure-crt.h deleted file mode 100644 index 52a0d4870..000000000 --- a/source/core/secure-crt.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef _MSC_VER -#ifndef CORE_LIB_SECURE_CRT_H -#define CORE_LIB_SECURE_CRT_H -#include -#include -#include -#include -#include - -#include - -inline void memcpy_s(void *dest, size_t numberOfElements, const void * src, size_t count) -{ - memcpy(dest, src, count); -} - -#define _TRUNCATE ((size_t)-1) -#define _stricmp strcasecmp - -inline void fopen_s(FILE**f, const char * fileName, const char * mode) -{ - *f = fopen(fileName, mode); -} - -inline size_t fread_s(void * buffer, size_t bufferSize, size_t elementSize, size_t count, FILE * stream) -{ - return fread(buffer, elementSize, count, stream); -} - -inline size_t wcsnlen_s(const wchar_t * str, size_t /*numberofElements*/) -{ - return wcslen(str); -} - -inline size_t strnlen_s(const char * str, size_t numberOfElements) -{ -#if defined( __CYGWIN__ ) - const char* cur = str; - if (str) - { - const char*const end = str + numberOfElements; - while (*cur && cur < end) cur++; - } - return size_t(cur - str); -#else - return strnlen(str, numberOfElements); -#endif -} - -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; -} - -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; -} - -inline void wcscpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource) -{ - wcscpy(strDestination, strSource); -} -inline void strcpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource) -{ - strcpy(strDestination, strSource); -} - -inline void wcsncpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource, size_t count) -{ - wcscpy(strDestination, strSource); - //wcsncpy(strDestination, strSource, count); -} -inline void strncpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource, size_t count) -{ - strncpy(strDestination, strSource, count); - //wcsncpy(strDestination, strSource, count); -} -#endif -#endif diff --git a/source/core/slang-allocator.h b/source/core/slang-allocator.h new file mode 100644 index 000000000..481f8810f --- /dev/null +++ b/source/core/slang-allocator.h @@ -0,0 +1,64 @@ +#ifndef SLANG_CORE_ALLOCATOR_H +#define SLANG_CORE_ALLOCATOR_H + +#include +#ifdef _MSC_VER +# include +#endif + +namespace Slang +{ + inline void* alignedAllocate(size_t size, size_t alignment) + { +#ifdef _MSC_VER + return _aligned_malloc(size, alignment); +#elif defined(__CYGWIN__) + return aligned_alloc(alignment, size); +#else + void * rs = 0; + int succ = posix_memalign(&rs, alignment, size); + if (succ!=0) + rs = 0; + return rs; +#endif + } + + inline void alignedDeallocate(void* ptr) + { +#ifdef _MSC_VER + _aligned_free(ptr); +#else + free(ptr); +#endif + } + + class StandardAllocator + { + public: + // not really called + void* allocate(size_t size) + { + return ::malloc(size); + } + void deallocate(void * ptr) + { + return ::free(ptr); + } + }; + + template + class AlignedAllocator + { + public: + void* allocate(size_t size) + { + return alignedAllocate(size, ALIGNMENT); + } + void deallocate(void * ptr) + { + return alignedDeallocate(ptr); + } + }; +} + +#endif diff --git a/source/core/slang-array-view.h b/source/core/slang-array-view.h new file mode 100644 index 000000000..8b653f4c7 --- /dev/null +++ b/source/core/slang-array-view.h @@ -0,0 +1,112 @@ +#ifndef SLANG_CORE_ARRAY_VIEW_H +#define SLANG_CORE_ARRAY_VIEW_H + +#include "slang-common.h" + +namespace Slang +{ + template + class ArrayView + { + private: + T* m_buffer; + int m_count; + public: + const T* begin() const { return m_buffer; } + T* begin() { return m_buffer; } + + const T* end() const { return m_buffer + m_count; } + T* end() { return m_buffer + m_count; } + + public: + ArrayView(): + m_buffer(nullptr), + m_count(0) + { + } + ArrayView(T& singleObj): + m_buffer(&singleObj), + m_count(1) + { + } + ArrayView(T* buffer, int size): + m_buffer(buffer), + m_count(size) + { + } + + inline int getCount() const { return m_count; } + + inline const T& operator [](int idx) const + { + SLANG_ASSERT(idx >= 0 && idx <= m_count); + return m_buffer[idx]; + } + inline T& operator [](int 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; } + + template + int indexOf(const T2 & val) const + { + for (int i = 0; i < m_count; i++) + { + if (m_buffer[i] == val) + return i; + } + return -1; + } + + template + int lastIndexOf(const T2 & val) const + { + for (int i = m_count - 1; i >= 0; i--) + { + if (m_buffer[i] == val) + return i; + } + return -1; + } + + template + int findFirstIndex(const Func& predicate) const + { + for (int i = 0; i < m_count; i++) + { + if (predicate(m_buffer[i])) + return i; + } + return -1; + } + + template + int findLastIndex(const Func& predicate) const + { + for (int i = m_count - 1; i >= 0; i--) + { + if (predicate(m_buffer[i])) + return i; + } + return -1; + } + }; + + template + ArrayView makeArrayView(T& obj) + { + return ArrayView(obj); + } + + template + ArrayView makeArrayView(T* buffer, int count) + { + return ArrayView(buffer, count); + } +} + +#endif diff --git a/source/core/slang-array.h b/source/core/slang-array.h new file mode 100644 index 000000000..d4bb7386f --- /dev/null +++ b/source/core/slang-array.h @@ -0,0 +1,135 @@ +#ifndef SLANG_CORE_ARRAY_H +#define SLANG_CORE_ARRAY_H + +#include "slang-exception.h" +#include "slang-array-view.h" + +namespace Slang +{ + template + class Array + { + private: + T m_buffer[COUNT]; + int m_count = 0; + 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; } + + public: + inline int getCapacity() const { return COUNT; } + inline int 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(int 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 [](int idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + inline T& operator [](int 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 + int indexOf(const T2& val) const + { + for (int i = 0; i < m_count; i++) + { + if (m_buffer[i] == val) + return i; + } + return -1; + } + + template + int lastIndexOf(const T2& val) const + { + for (int i = m_count - 1; i >= 0; i--) + { + if (m_buffer[i] == val) + return i; + } + return -1; + } + + inline ArrayView getArrayView() const + { + return ArrayView((T*)m_buffer, m_count); + } + inline ArrayView getArrayView(int start, int count) const + { + return ArrayView((T*)m_buffer + start, count); + } + }; + + template + struct FirstType + { + typedef T Type; + }; + + + template + void insertArray(Array&) {} + + template + void insertArray(Array& arr, const T& val, TArgs... args) + { + arr.add(val); + insertArray(arr, args...); + } + + template + auto makeArray(TArgs ...args) -> Array::Type, sizeof...(args)> + { + Array::Type, sizeof...(args)> rs; + insertArray(rs, args...); + return rs; + } +} + +#endif diff --git a/source/core/slang-basic.h b/source/core/slang-basic.h new file mode 100644 index 000000000..7931749f4 --- /dev/null +++ b/source/core/slang-basic.h @@ -0,0 +1,13 @@ +#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-list.h" +#include "slang-smart-pointer.h" +#include "slang-exception.h" +#include "slang-dictionary.h" + +#endif diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index 47ab824a4..32eb96a29 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -1,7 +1,5 @@ #include "slang-byte-encode-util.h" - - namespace Slang { // Descriptions of algorithms here... diff --git a/source/core/slang-byte-encode-util.h b/source/core/slang-byte-encode-util.h index 5936cae60..cb601d522 100644 --- a/source/core/slang-byte-encode-util.h +++ b/source/core/slang-byte-encode-util.h @@ -1,7 +1,7 @@ -#ifndef SLANG_BYTE_ENCODE_UTIL_H -#define SLANG_BYTE_ENCODE_UTIL_H +#ifndef SLANG_CORE_BYTE_ENCODE_UTIL_H +#define SLANG_CORE_BYTE_ENCODE_UTIL_H -#include "list.h" +#include "slang-list.h" namespace Slang { diff --git a/source/core/slang-common.h b/source/core/slang-common.h new file mode 100644 index 000000000..7d8568642 --- /dev/null +++ b/source/core/slang-common.h @@ -0,0 +1,95 @@ +#ifndef SLANG_CORE_COMMON_H +#define SLANG_CORE_COMMON_H + +#include "../../slang.h" + +#include + +#include + +#ifdef __GNUC__ +#define CORE_LIB_ALIGN_16(x) x __attribute__((aligned(16))) +#else +#define CORE_LIB_ALIGN_16(x) __declspec(align(16)) x +#endif + +#define VARIADIC_TEMPLATE + +namespace Slang +{ + typedef int32_t Int32; + typedef uint32_t UInt32; + + typedef int64_t Int64; + typedef uint64_t UInt64; + + // Define + typedef SlangUInt UInt; + typedef SlangInt Int; + +// typedef unsigned short Word; + + typedef intptr_t PtrInt; + + // Type used for indexing, in arrays/views etc + typedef Int Index; + + template + inline T&& _Move(T & obj) + { + return static_cast(obj); + } + + template + inline void Swap(T & v0, T & v1) + { + T tmp = _Move(v0); + v0 = _Move(v1); + v1 = _Move(tmp); + } + +#ifdef _MSC_VER +# define SLANG_RETURN_NEVER __declspec(noreturn) +//#elif SLANG_CLANG +//# define SLANG_RETURN_NEVER [[noreturn]] +#else +# define SLANG_RETURN_NEVER [[noreturn]] +//# define SLANG_RETURN_NEVER /* empty */ +#endif + +#ifdef _MSC_VER +#define UNREACHABLE_RETURN(x) +#define UNREACHABLE(x) +#else +#define UNREACHABLE_RETURN(x) return x; +#define UNREACHABLE(x) x; +#endif + + SLANG_RETURN_NEVER void signalUnexpectedError(char const* message); +} + +#define SLANG_UNEXPECTED(reason) \ + Slang::signalUnexpectedError("unexpected: " reason) + +#define SLANG_UNIMPLEMENTED_X(what) \ + Slang::signalUnexpectedError("unimplemented: " what) + +#define SLANG_UNREACHABLE(msg) \ + Slang::signalUnexpectedError("unreachable code executed: " msg) + +#ifdef _DEBUG +#define SLANG_EXPECT(VALUE, MSG) if(VALUE) {} else Slang::signalUnexpectedError("assertion failed: '" MSG "'") +#define SLANG_ASSERT(VALUE) SLANG_EXPECT(VALUE, #VALUE) +#else +#define SLANG_EXPECT(VALUE, MSG) do {} while(0) +#define SLANG_ASSERT(VALUE) do {} while(0) +#endif + +#define SLANG_RELEASE_ASSERT(VALUE) if(VALUE) {} else Slang::signalUnexpectedError("assertion failed") +#define SLANG_RELEASE_EXPECT(VALUE, WHAT) if(VALUE) {} else SLANG_UNEXPECTED(WHAT) + +template void slang_use_obj(T&) {} + +#define SLANG_UNREFERENCED_PARAMETER(P) slang_use_obj(P) +#define SLANG_UNREFERENCED_VARIABLE(P) slang_use_obj(P) +#endif diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h new file mode 100644 index 000000000..69e8022dd --- /dev/null +++ b/source/core/slang-dictionary.h @@ -0,0 +1,620 @@ +#ifndef SLANG_CORE_DICTIONARY_H +#define SLANG_CORE_DICTIONARY_H + +#include "slang-list.h" +#include "slang-common.h" +#include "slang-uint-set.h" +#include "slang-exception.h" +#include "slang-math.h" +#include "slang-hash.h" + +namespace Slang +{ + template + class KeyValuePair + { + public: + TKey Key; + TValue Value; + KeyValuePair() + {} + KeyValuePair(const TKey & key, const TValue & value) + { + Key = key; + Value = value; + } + KeyValuePair(TKey && key, TValue && value) + { + Key = _Move(key); + Value = _Move(value); + } + KeyValuePair(TKey && key, const TValue & value) + { + Key = _Move(key); + Value = value; + } + KeyValuePair(const KeyValuePair & _that) + { + Key = _that.Key; + Value = _that.Value; + } + KeyValuePair(KeyValuePair && _that) + { + operator=(_Move(_that)); + } + KeyValuePair & operator=(KeyValuePair && that) + { + Key = _Move(that.Key); + Value = _Move(that.Value); + return *this; + } + KeyValuePair & operator=(const KeyValuePair & that) + { + Key = that.Key; + Value = that.Value; + return *this; + } + int GetHashCode() + { + return GetHashCode(Key); + } + }; + + template + inline KeyValuePair KVPair(const TKey & k, const TValue & v) + { + return KeyValuePair(k, v); + } + + const float MaxLoadFactor = 0.7f; + + template + class Dictionary + { + friend class Iterator; + friend class ItemProxy; + private: + inline int GetProbeOffset(int /*probeId*/) const + { + // quadratic probing + return 1; + } + private: + int bucketSizeMinusOne; + int _count; + UIntSet marks; + KeyValuePair* hashMap; + void Free() + { + if (hashMap) + delete[] hashMap; + hashMap = 0; + } + inline bool IsDeleted(int pos) const + { + return marks.contains((pos << 1) + 1); + } + inline bool IsEmpty(int pos) const + { + return !marks.contains((pos << 1)); + } + inline void SetDeleted(int pos, bool val) + { + if (val) + marks.add((pos << 1) + 1); + else + marks.remove((pos << 1) + 1); + } + inline void SetEmpty(int pos, bool val) + { + if (val) + marks.remove((pos << 1)); + else + marks.add((pos << 1)); + } + struct FindPositionResult + { + int ObjectPosition; + int InsertionPosition; + FindPositionResult() + { + ObjectPosition = -1; + InsertionPosition = -1; + } + FindPositionResult(int objPos, int insertPos) + { + ObjectPosition = objPos; + InsertionPosition = insertPos; + } + + }; + inline int GetHashPos(TKey& key) const + { + return ((unsigned int)(GetHashCode(key) * 2654435761)) % bucketSizeMinusOne; + } + FindPositionResult FindPosition(const TKey& key) const + { + int hashPos = GetHashPos(const_cast(key)); + int insertPos = -1; + int numProbes = 0; + while (numProbes <= bucketSizeMinusOne) + { + 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 (hashMap[hashPos].Key == key) + { + return FindPositionResult(hashPos, -1); + } + numProbes++; + hashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne; + } + if (insertPos != -1) + return FindPositionResult(-1, insertPos); + throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode."); + } + TValue & _Insert(KeyValuePair&& kvPair, int pos) + { + hashMap[pos] = _Move(kvPair); + SetEmpty(pos, false); + SetDeleted(pos, false); + return hashMap[pos].Value; + } + void Rehash() + { + if (bucketSizeMinusOne == -1 || _count >= int(MaxLoadFactor * bucketSizeMinusOne)) + { + int newSize = (bucketSizeMinusOne + 1) * 2; + if (newSize == 0) + { + newSize = 16; + } + Dictionary newDict; + newDict.bucketSizeMinusOne = newSize - 1; + newDict.hashMap = new KeyValuePair[newSize]; + newDict.marks.resizeAndClear(newSize * 2); + if (hashMap) + { + for (auto & kvPair : *this) + { + newDict.Add(_Move(kvPair)); + } + } + *this = _Move(newDict); + } + } + + bool AddIfNotExists(KeyValuePair&& kvPair) + { + Rehash(); + auto pos = FindPosition(kvPair.Key); + if (pos.ObjectPosition != -1) + return false; + else if (pos.InsertionPosition != -1) + { + _count++; + _Insert(_Move(kvPair), pos.InsertionPosition); + return true; + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + void Add(KeyValuePair&& kvPair) + { + if (!AddIfNotExists(_Move(kvPair))) + throw KeyExistsException("The key already exists in Dictionary."); + } + TValue& Set(KeyValuePair&& kvPair) + { + Rehash(); + auto pos = FindPosition(kvPair.Key); + if (pos.ObjectPosition != -1) + return _Insert(_Move(kvPair), pos.ObjectPosition); + else if (pos.InsertionPosition != -1) + { + _count++; + return _Insert(_Move(kvPair), pos.InsertionPosition); + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + public: + class Iterator + { + private: + const Dictionary * dict; + int pos; + public: + KeyValuePair & operator *() const + { + return dict->hashMap[pos]; + } + KeyValuePair * operator ->() const + { + return dict->hashMap + pos; + } + Iterator & operator ++() + { + if (pos > dict->bucketSizeMinusOne) + return *this; + pos++; + while (pos <= dict->bucketSizeMinusOne && (dict->IsDeleted(pos) || dict->IsEmpty(pos))) + { + pos++; + } + return *this; + } + Iterator operator ++(int) + { + Iterator rs = *this; + operator++(); + return rs; + } + bool operator != (const Iterator & _that) const + { + return pos != _that.pos || dict != _that.dict; + } + bool operator == (const Iterator & _that) const + { + return pos == _that.pos && dict == _that.dict; + } + Iterator(const Dictionary * _dict, int _pos) + { + this->dict = _dict; + this->pos = _pos; + } + Iterator() + { + this->dict = 0; + this->pos = 0; + } + }; + + Iterator begin() const + { + int pos = 0; + while (pos < bucketSizeMinusOne + 1) + { + if (IsEmpty(pos) || IsDeleted(pos)) + pos++; + else + break; + } + return Iterator(this, pos); + } + Iterator end() const + { + return Iterator(this, bucketSizeMinusOne + 1); + } + public: + void Add(const TKey & key, const TValue & value) + { + Add(KeyValuePair(key, value)); + } + void Add(TKey && key, TValue && value) + { + Add(KeyValuePair(_Move(key), _Move(value))); + } + bool AddIfNotExists(const TKey & key, const TValue & value) + { + return AddIfNotExists(KeyValuePair(key, value)); + } + bool AddIfNotExists(TKey && key, TValue && value) + { + return AddIfNotExists(KeyValuePair(_Move(key), _Move(value))); + } + void Remove(const TKey & key) + { + if (_count == 0) + return; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + SetDeleted(pos.ObjectPosition, true); + _count--; + } + } + void Clear() + { + _count = 0; + + marks.clear(); + } + + TValue* TryGetValueOrAdd(const TKey& key, const TValue& value) + { + Rehash(); + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + return &hashMap[pos.ObjectPosition].Value; + } + else if (pos.InsertionPosition != -1) + { + // Make pair + KeyValuePair kvPair(_Move(key), _Move(value)); + _count++; + _Insert(_Move(kvPair), pos.InsertionPosition); + return nullptr; + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + + bool ContainsKey(const TKey& key) const + { + if (bucketSizeMinusOne == -1) + return false; + auto pos = FindPosition(key); + return pos.ObjectPosition != -1; + } + bool TryGetValue(const TKey& key, TValue& value) const + { + if (bucketSizeMinusOne == -1) + return false; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + value = hashMap[pos.ObjectPosition].Value; + return true; + } + return false; + } + TValue* TryGetValue(const TKey& key) const + { + if (bucketSizeMinusOne == -1) + return nullptr; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + return &hashMap[pos.ObjectPosition].Value; + } + return nullptr; + } + + class ItemProxy + { + private: + const Dictionary * dict; + TKey key; + public: + ItemProxy(const TKey& _key, const Dictionary* _dict) + { + this->dict = _dict; + this->key = _key; + } + ItemProxy(TKey&& _key, const Dictionary* _dict) + { + this->dict = _dict; + this->key = _Move(_key); + } + TValue & GetValue() const + { + auto pos = dict->FindPosition(key); + if (pos.ObjectPosition != -1) + { + return dict->hashMap[pos.ObjectPosition].Value; + } + else + throw KeyNotFoundException("The key does not exists in dictionary."); + } + inline TValue & operator()() const + { + return GetValue(); + } + operator TValue&() const + { + return GetValue(); + } + TValue & operator = (const TValue & val) const + { + return ((Dictionary*)dict)->Set(KeyValuePair(_Move(key), val)); + } + TValue & operator = (TValue && val) const + { + return ((Dictionary*)dict)->Set(KeyValuePair(_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 Count() const + { + return _count; + } + private: + template + void Init(const KeyValuePair & kvPair, Args... args) + { + Add(kvPair); + Init(args...); + } + public: + Dictionary() + { + bucketSizeMinusOne = -1; + _count = 0; + hashMap = nullptr; + } + template + Dictionary(Arg arg, Args... args) + { + Init(arg, args...); + } + Dictionary(const Dictionary& other) + : bucketSizeMinusOne(-1), _count(0), hashMap(nullptr) + { + *this = other; + } + Dictionary(Dictionary&& other) + : bucketSizeMinusOne(-1), _count(0), hashMap(nullptr) + { + *this = (_Move(other)); + } + Dictionary& operator = (const Dictionary& other) + { + if (this == &other) + return *this; + Free(); + bucketSizeMinusOne = other.bucketSizeMinusOne; + _count = other._count; + hashMap = new KeyValuePair[other.bucketSizeMinusOne + 1]; + marks = other.marks; + for (int i = 0; i <= bucketSizeMinusOne; i++) + hashMap[i] = other.hashMap[i]; + return *this; + } + Dictionary & operator = (Dictionary&& other) + { + if (this == &other) + return *this; + Free(); + bucketSizeMinusOne = other.bucketSizeMinusOne; + _count = other._count; + hashMap = other.hashMap; + marks = _Move(other.marks); + other.hashMap = 0; + other._count = 0; + other.bucketSizeMinusOne = -1; + return *this; + } + ~Dictionary() + { + Free(); + } + }; + + class _DummyClass + {}; + + template + class HashSetBase + { + protected: + DictionaryType dict; + private: + template + void Init(const T & v, Args... args) + { + Add(v); + Init(args...); + } + public: + HashSetBase() + {} + template + 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::Iterator iter; + public: + Iterator() = default; + T & operator *() const + { + return (*iter).Key; + } + T * operator ->() const + { + return &(*iter).Key; + } + 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::Iterator & _iter) + { + this->iter = _iter; + } + }; + Iterator begin() const + { + return Iterator(dict.begin()); + } + Iterator end() const + { + return Iterator(dict.end()); + } + public: + int Count() const + { + return dict.Count(); + } + 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 + class HashSet : public HashSetBase> + {}; +} + +#endif diff --git a/source/core/slang-exception.h b/source/core/slang-exception.h new file mode 100644 index 000000000..91139e298 --- /dev/null +++ b/source/core/slang-exception.h @@ -0,0 +1,137 @@ +#ifndef SLANG_CORE_EXCEPTION_H +#define SLANG_CORE_EXCEPTION_H + +#include "slang-common.h" +#include "slang-string.h" + +namespace Slang +{ + class Exception + { + public: + String Message; + Exception() + {} + Exception(const String & message) + : Message(message) + { + } + + virtual ~Exception() + {} + }; + + class IndexOutofRangeException : public Exception + { + public: + IndexOutofRangeException() + {} + IndexOutofRangeException(const String & message) + : Exception(message) + { + } + + }; + + class InvalidOperationException : public Exception + { + public: + InvalidOperationException() + {} + InvalidOperationException(const String & message) + : Exception(message) + { + } + + }; + + class ArgumentException : public Exception + { + public: + ArgumentException() + {} + ArgumentException(const String & message) + : Exception(message) + { + } + + }; + + class KeyNotFoundException : public Exception + { + public: + KeyNotFoundException() + {} + KeyNotFoundException(const String & message) + : Exception(message) + { + } + }; + class KeyExistsException : public Exception + { + public: + KeyExistsException() + {} + KeyExistsException(const String & message) + : Exception(message) + { + } + }; + + class NotSupportedException : public Exception + { + public: + NotSupportedException() + {} + NotSupportedException(const String & message) + : Exception(message) + { + } + }; + + class NotImplementedException : public Exception + { + public: + NotImplementedException() + {} + NotImplementedException(const String & message) + : Exception(message) + { + } + }; + + class InvalidProgramException : public Exception + { + public: + InvalidProgramException() + {} + InvalidProgramException(const String & message) + : Exception(message) + { + } + }; + + class InternalError : public Exception + { + public: + InternalError() + {} + InternalError(const String & message) + : Exception(message) + { + } + }; + + class AbortCompilationException : public Exception + { + public: + AbortCompilationException() + {} + AbortCompilationException(const String & message) + : Exception(message) + { + } + }; +} + +#endif diff --git a/source/core/slang-free-list.h b/source/core/slang-free-list.h index 62c2b9d93..ee0158279 100644 --- a/source/core/slang-free-list.h +++ b/source/core/slang-free-list.h @@ -1,9 +1,9 @@ -#ifndef SLANG_FREE_LIST_H -#define SLANG_FREE_LIST_H +#ifndef SLANG_CORE_FREE_LIST_H +#define SLANG_CORE_FREE_LIST_H #include "../../slang.h" -#include "common.h" +#include "slang-common.h" #include #include diff --git a/source/core/slang-hash.h b/source/core/slang-hash.h new file mode 100644 index 000000000..08a40491c --- /dev/null +++ b/source/core/slang-hash.h @@ -0,0 +1,153 @@ +#ifndef SLANG_CORE_HASH_H +#define SLANG_CORE_HASH_H + +#include "slang-math.h" +#include +#include + +namespace Slang +{ + typedef int HashCode; + + inline int GetHashCode(double key) + { + return FloatAsInt((float)key); + } + inline int GetHashCode(float key) + { + return FloatAsInt(key); + } + inline int GetHashCode(const char * buffer) + { + if (!buffer) + return 0; + int hash = 0; + int c; + auto str = buffer; + c = *str++; + while (c) + { + hash = c + (hash << 6) + (hash << 16) - hash; + c = *str++; + } + return hash; + } + inline int GetHashCode(char * buffer) + { + return GetHashCode(const_cast(buffer)); + } + inline int GetHashCode(const char * buffer, size_t numChars) + { + int hash = 0; + for (size_t i = 0; i < numChars; ++i) + { + hash = int(buffer[i]) + (hash << 6) + (hash << 16) - hash; + } + return hash; + } + + inline uint64_t GetHashCode64(const char * buffer, size_t numChars) + { + // Use uints because hash requires wrap around behavior and int is undefined on over/underflows + uint64_t hash = 0; + for (size_t i = 0; i < numChars; ++i) + { + hash = uint64_t(int64_t(buffer[i])) + (hash << 6) + (hash << 16) - hash; + } + return hash; + } + + template + class Hash + { + public: + }; + template<> + class Hash<1> + { + public: + template + static int GetHashCode(TKey & key) + { + return (int)key; + } + }; + template<> + class Hash<0> + { + public: + template + static int GetHashCode(TKey & key) + { + return int(key.GetHashCode()); + } + }; + template + class PointerHash + {}; + template<> + class PointerHash<1> + { + public: + template + static int GetHashCode(TKey const& key) + { + return (int)((PtrInt)key) / 16; // sizeof(typename std::remove_pointer::type); + } + }; + template<> + class PointerHash<0> + { + public: + template + static int GetHashCode(TKey & key) + { + return Hash::value || std::is_enum::value>::GetHashCode(key); + } + }; + + template + int GetHashCode(const TKey & key) + { + return PointerHash::value>::GetHashCode(key); + } + + template + int GetHashCode(TKey & key) + { + return PointerHash::value>::GetHashCode(key); + } + + inline int combineHash(int left, int right) + { + return (left * 16777619) ^ right; + } + + struct Hasher + { + public: + Hasher() {} + + template + void hashValue(T const& value) + { + m_hashCode = combineHash(m_hashCode, GetHashCode(value)); + } + + template + void hashObject(T const& object) + { + m_hashCode = combineHash(m_hashCode, object->GetHashCode()); + } + + HashCode getResult() const + { + return m_hashCode; + } + + private: + HashCode m_hashCode = 0; + }; +} + +#endif diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index 82a2e5a35..ae2520a78 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -1,5 +1,5 @@ #include "slang-io.h" -#include "exception.h" +#include "slang-exception.h" #include "../../slang-com-helper.h" diff --git a/source/core/slang-io.h b/source/core/slang-io.h index 9df8d8d57..64ec11c5a 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -1,10 +1,10 @@ -#ifndef CORE_LIB_IO_H -#define CORE_LIB_IO_H +#ifndef SLANG_CORE_IO_H +#define SLANG_CORE_IO_H #include "slang-string.h" -#include "stream.h" -#include "text-io.h" -#include "secure-crt.h" +#include "slang-stream.h" +#include "slang-text-io.h" +#include "slang-secure-crt.h" namespace Slang { diff --git a/source/core/slang-list.h b/source/core/slang-list.h new file mode 100644 index 000000000..0affbfd66 --- /dev/null +++ b/source/core/slang-list.h @@ -0,0 +1,631 @@ +#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 +#include +#include + + +namespace Slang +{ + + template + class Initializer + { + + }; + + template + class Initializer + { + public: + static void initialize(T* buffer, int size) + { + for (int i = 0; i + class Initializer + { + public: + static void initialize(T* buffer, int size) + { + // It's pod so no initialization required + //for (int i = 0; i < size; i++) + // new (buffer + i) T; + } + }; + + template + class AllocateMethod + { + public: + static inline T* allocateArray(Index count) + { + TAllocator allocator; + T * rs = (T*)allocator.allocate(count * sizeof(T)); + Initializer::value>::initialize(rs, count); + return rs; + } + static inline void deallocateArray(T* ptr, Index count) + { + TAllocator allocator; + if (!std::is_trivially_destructible::value) + { + for (Index i = 0; i < count; i++) + ptr[i].~T(); + } + allocator.deallocate(ptr); + } + }; + + template + class AllocateMethod + { + public: + static inline T* allocateArray(Index count) + { + return new T[count]; + } + static inline void deallocateArray(T* ptr, Index /*bufferSize*/) + { + delete [] ptr; + } + }; + + + template + class List + { + private: + static const Index kInitialCount = 16; + + public: + List() + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + } + template + List(const T& val, Args... args) + { + _init(val, args...); + } + List(const List& list) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + this->operator=(list); + } + List(List&& list) + : m_buffer(nullptr), m_count(0), m_capacity(0) + { + this->operator=(static_cast&&>(list)); + } + static List makeRepeated(const T& val, Index count) + { + List rs; + rs.setCount(count); + for (Index i = 0; i < count; i++) + rs[i] = val; + return rs; + } + ~List() + { + _deallocateBuffer(); + } + List& operator=(const List& list) + { + clearAndDeallocate(); + addRange(list); + return *this; + } + + List& operator=(List&& 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; + return *this; + } + + // TODO(JS): These should be made const safe but some other code depends on this behavior for now. + T* begin() const { return m_buffer; } + T* end() const { return m_buffer + m_count; } + + const T& getFirst() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } + + const T& getLast() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count-1]; + } + + T& getFirst() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } + + T& getLast() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } + + void removeLast() + { + SLANG_ASSERT(m_count > 0); + m_count--; + } + + inline void swapWith(List& other) + { + T* buffer = m_buffer; + m_buffer = other.m_buffer; + other.m_buffer = buffer; + + auto bufferSize = m_capacity; + m_capacity = other.m_capacity; + other.m_capacity = bufferSize; + + auto count = m_count; + m_count = other.m_count; + other.m_count = count; + } + + T* detachBuffer() + { + T* rs = m_buffer; + m_buffer = nullptr; + m_count = 0; + m_capacity = 0; + return rs; + } + + inline ArrayView getArrayView() const + { + return ArrayView(m_buffer, m_count); + } + + inline ArrayView getArrayView(Index start, Index count) const + { + SLANG_ASSERT(start >= 0 && count >= 0 && start + count <= m_count); + return ArrayView(m_buffer + start, count); + } + + void add(T&& obj) + { + if (m_capacity < m_count + 1) + { + Index newBufferSize = kInitialCount; + if (m_capacity) + newBufferSize = (m_capacity << 1); + + reserve(newBufferSize); + } + m_buffer[m_count++] = static_cast(obj); + } + + void add(const T& obj) + { + if (m_capacity < m_count + 1) + { + Index newBufferSize = kInitialCount; + if (m_capacity) + newBufferSize = (m_capacity << 1); + + reserve(newBufferSize); + } + m_buffer[m_count++] = obj; + + } + + Index getCount() const { return m_count; } + Index getCapacity() const { return m_capacity; } + + const T* getBuffer() const { return m_buffer; } + T* getBuffer() { return m_buffer; } + + void insert(Index idx, const T& val) { insertRange(idx, &val, 1); } + + void insertRange(Index idx, const T* vals, Index n) + { + if (m_capacity < m_count + n) + { + Index newBufferCount = kInitialCount; + while (newBufferCount < m_count + n) + newBufferCount = newBufferCount << 1; + + T* newBuffer = _allocate(newBufferCount); + if (m_capacity) + { + /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::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(m_buffer[i])); + } + _deallocateBuffer(); + } + m_buffer = newBuffer; + m_capacity = newBufferCount; + } + else + { + /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::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(m_buffer[i - 1]); + } + } + /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::value) + memcpy(buffer + id, vals, sizeof(T) * n); + else*/ + for (Index i = 0; i < n; i++) + m_buffer[idx + i] = vals[i]; + + m_count += n; + } + + //slower than original edition + //void Add(const T & val) + //{ + // InsertRange(_count, &val, 1); + //} + + void insertRange(Index id, const List& list) { insertRange(id, list.m_buffer, list.m_count); } + + void addRange(ArrayView list) { insertRange(m_count, list.getBuffer(), list.Count()); } + + void addRange(const T* vals, Index n) { insertRange(m_count, vals, n); } + + void addRange(const List& list) { insertRange(m_count, list.m_buffer, list.m_count); } + + 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(m_buffer[i]); + m_count -= actualDeleteCount; + } + + void removeAt(Index id) { removeRange(id, 1); } + + void remove(const T& val) + { + Index idx = indexOf(val); + if (idx != -1) + removeAt(idx); + } + + void reverse() + { + for (Index i = 0; i < (m_count >> 1); i++) + { + swapElements(m_buffer, i, m_count - i - 1); + } + } + + void fastRemove(const T& val) + { + Index idx = indexOf(val); + fastRemoveAt(idx); + } + + void fastRemoveAt(Index idx) + { + if (idx != -1 && m_count - 1 != idx) + { + m_buffer[idx] = _Move(m_buffer[m_count - 1]); + } + m_count--; + } + + void clear() { m_count = 0; } + + void clearAndDeallocate() + { + _deallocateBuffer(); + m_count = m_capacity = 0; + } + + void reserve(Index size) + { + if(size > m_capacity) + { + T* newBuffer = _allocate(size); + if (m_capacity) + { + /*if (std::has_trivial_copy_assign::value && std::has_trivial_destructor::value) + memcpy(newBuffer, buffer, _count * sizeof(T)); + else*/ + { + for (Index i = 0; i < m_count; i++) + newBuffer[i] = static_cast(m_buffer[i]); + + // Default-initialize the remaining elements + for(Index i = m_count; i < size; i++) + { + new(newBuffer + i) T(); + } + } + _deallocateBuffer(); + } + m_buffer = newBuffer; + m_capacity = size; + } + } + + void growToCount(Index count) + { + Index newBufferCount = Index(1) << Math::Log2Ceil(count); + if (m_capacity < newBufferCount) + { + reserve(newBufferCount); + } + m_count = count; + } + + void setCount(Index count) + { + reserve(count); + m_count = count; + } + + void unsafeShrinkToCount(Index count) { m_count = count; } + + void compress() + { + 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(m_buffer[i]); + + _deallocateBuffer(); + m_buffer = newBuffer; + m_capacity = m_count; + } + } + + SLANG_FORCE_INLINE T& operator [](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx <= m_count); + return m_buffer[idx]; + } + + template + Index findFirstIndex(const Func& predicate) const + { + for (Index i = 0; i < m_count; i++) + { + if (predicate(m_buffer[i])) + return i; + } + return (Index)-1; + } + + template + Index findLastIndex(const Func& predicate) const + { + for (Index i = m_count; i > 0; i--) + { + if (predicate(m_buffer[i-1])) + return i-1; + } + return (Index)-1; + } + + template + Index indexOf(const T2& val) const + { + for (Index i = 0; i < m_count; i++) + { + if (m_buffer[i] == val) + return i; + } + return (Index)-1; + } + + template + Index lastIndexOf(const T2& val) const + { + for (Index i = m_count; i > 0; i--) + { + if(m_buffer[i-1] == val) + return i-1; + } + return (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 + 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 + void forEach(IterateFunc f) const + { + for (Index i = 0; i< m_count; i++) + f(m_buffer[i]); + } + + template + void quickSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) + { + static const Index kMinQSortSize = 32; + + 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 + 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++) + { + if (comparer(vals[i], pivotValue)) + { + swapElements(vals, i, storeIndex); + storeIndex++; + } + } + swapElements(vals, storeIndex, right); + return storeIndex; + } + template + void insertionSort(T* vals, Index startIndex, Index endIndex, Comparer comparer) + { + for (Index i = startIndex + 1; i <= endIndex; i++) + { + T insertValue = static_cast(vals[i]); + Index insertIndex = i - 1; + while (insertIndex >= startIndex && comparer(insertValue, vals[insertIndex])) + { + vals[insertIndex + 1] = static_cast(vals[insertIndex]); + insertIndex--; + } + vals[insertIndex + 1] = static_cast(insertValue); + } + } + + inline void swapElements(T* vals, Index index1, Index index2) + { + if (index1 != index2) + { + T tmp = static_cast(vals[index1]); + vals[index1] = static_cast(vals[index2]); + vals[index2] = static_cast(tmp); + } + } + + template + Index binarySearch(const T2& obj, Comparer comparer) + { + Index imin = 0, imax = m_count - 1; + while (imax >= imin) + { + Index imid = (imin + imax) >> 1; + int compareResult = comparer(m_buffer[imid], obj); + if (compareResult == 0) + return imid; + else if (compareResult < 0) + imin = imid + 1; + else + imax = imid - 1; + } + return -1; + } + + template + int 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; + }); + } + 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) + { + AllocateMethod::deallocateArray(m_buffer, m_capacity); + m_buffer = nullptr; + } + } + static inline T* _allocate(Index count) + { + return AllocateMethod::allocateArray(count); + } + + template + void _init(const T& val, Args... args) + { + add(val); + _init(args...); + } + }; + + template + T calcMin(const List& list) + { + T minVal = list.getFirst(); + for (Index i = 1; i < list.getCount(); i++) + if (list[i] < minVal) + minVal = list[i]; + return minVal; + } + + template + T calcMax(const List& list) + { + T maxVal = list.getFirst(); + for (Index i = 1; i< list.getCount(); i++) + if (list[i] > maxVal) + maxVal = list[i]; + return maxVal; + } +} + +#endif diff --git a/source/core/slang-math.h b/source/core/slang-math.h index a245e2d2c..0daad0d5a 100644 --- a/source/core/slang-math.h +++ b/source/core/slang-math.h @@ -1,5 +1,5 @@ -#ifndef CORE_LIB_MATH_H -#define CORE_LIB_MATH_H +#ifndef SLANG_CORE_MATH_H +#define SLANG_CORE_MATH_H #include diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h index b9066e198..75744710f 100644 --- a/source/core/slang-memory-arena.h +++ b/source/core/slang-memory-arena.h @@ -1,5 +1,5 @@ -#ifndef SLANG_MEMORY_ARENA_H -#define SLANG_MEMORY_ARENA_H +#ifndef SLANG_CORE_MEMORY_ARENA_H +#define SLANG_CORE_MEMORY_ARENA_H #include "../../slang.h" diff --git a/source/core/slang-object-scope-manager.h b/source/core/slang-object-scope-manager.h index 660a7cace..9930e46ea 100644 --- a/source/core/slang-object-scope-manager.h +++ b/source/core/slang-object-scope-manager.h @@ -1,8 +1,8 @@ -#ifndef SLANG_OBJECT_SCOPE_MANAGER_H -#define SLANG_OBJECT_SCOPE_MANAGER_H +#ifndef SLANG_CORE_OBJECT_SCOPE_MANAGER_H +#define SLANG_CORE_OBJECT_SCOPE_MANAGER_H -#include "smart-pointer.h" -#include "list.h" +#include "slang-smart-pointer.h" +#include "slang-list.h" namespace Slang { diff --git a/source/core/slang-platform.cpp b/source/core/slang-platform.cpp new file mode 100644 index 000000000..1cb2bc56e --- /dev/null +++ b/source/core/slang-platform.cpp @@ -0,0 +1,172 @@ +// slang-platform.cpp +#include "slang-platform.h" + +#include "slang-common.h" + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #define NOMINMAX + #include + #undef WIN32_LEAN_AND_MEAN + #undef NOMINMAX +#else + #include "slang-string.h" + #include +#endif + +namespace Slang +{ + // SharedLibrary + +/* static */SlangResult SharedLibrary::load(const char* filename, SharedLibrary::Handle& handleOut) +{ + StringBuilder builder; + appendPlatformFileName(UnownedStringSlice(filename), builder); + return loadWithPlatformFilename(builder.begin(), handleOut); +} + +#ifdef _WIN32 + +// Make sure SlangResult match for common standard window HRESULT +SLANG_COMPILE_TIME_ASSERT(E_FAIL == SLANG_FAIL); +SLANG_COMPILE_TIME_ASSERT(E_NOINTERFACE == SLANG_E_NO_INTERFACE); +SLANG_COMPILE_TIME_ASSERT(E_HANDLE == SLANG_E_INVALID_HANDLE); +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::appendResult(SlangResult res, StringBuilder& builderOut) +{ + if (SLANG_FAILED(res) && res != SLANG_FAIL) + { + LPWSTR buffer = nullptr; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + nullptr, + res, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPWSTR)&buffer, + 0, + nullptr); + + if (buffer) + { + builderOut << " "; + // Convert to string + builderOut.Append(String::fromWString(buffer)); + LocalFree(buffer); + return SLANG_OK; + } + } + return SLANG_FAIL; +} + +/* static */SlangResult SharedLibrary::loadWithPlatformFilename(char const* platformFileName, SharedLibrary::Handle& handleOut) +{ + handleOut = nullptr; + // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibrarya + const HMODULE h = LoadLibraryA(platformFileName); + if (!h) + { + const DWORD lastError = GetLastError(); + switch (lastError) + { + 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: + { + return SLANG_E_CANNOT_OPEN; + } + default: break; + } + // Turn to Result, if not one of the well known errors + return HRESULT_FROM_WIN32(lastError); + } + handleOut = (Handle)h; + return SLANG_OK; +} + +/* static */void SharedLibrary::unload(Handle handle) +{ + SLANG_ASSERT(handle); + ::FreeLibrary((HMODULE)handle); +} + +/* static */SharedLibrary::FuncPtr SharedLibrary::findFuncByName(Handle handle, char const* name) +{ + SLANG_ASSERT(handle); + return (FuncPtr)GetProcAddress((HMODULE)handle, name); +} + +/* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) +{ + // Windows doesn't need the extension or any prefix to work + dst.Append(name); +} + +#else // _WIN32 + +/* static */SlangResult PlatformUtil::appendResult(SlangResult res, StringBuilder& builderOut) +{ + return SLANG_E_NOT_IMPLEMENTED; +} + +/* static */SlangResult SharedLibrary::loadWithPlatformFilename(char const* platformFileName, Handle& handleOut) +{ + handleOut = nullptr; + + void* h = dlopen(platformFileName, RTLD_NOW | RTLD_LOCAL); + if(!h) + { +#if 0 + // We can't output the error message here, because it will cause output when testing what code gen is available + if(auto msg = dlerror()) + { + fprintf(stderr, "error: %s\n", msg); + } +#endif + return SLANG_FAIL; + } + handleOut = (Handle)h; + return SLANG_OK; +} + +/* static */void SharedLibrary::unload(Handle handle) +{ + SLANG_ASSERT(handle); + dlclose(handle); +} + +/* static */SharedLibrary::FuncPtr SharedLibrary::findFuncByName(Handle handle, char const* name) +{ + SLANG_ASSERT(handle); + return (FuncPtr)dlsym((void*)handle, name); +} + +/* static */void SharedLibrary::appendPlatformFileName(const UnownedStringSlice& name, StringBuilder& dst) +{ +#if __CYGWIN__ + dst.Append(name); + dst.Append(".dll"); +#elif SLANG_APPLE_FAMILY + dst.Append("lib"); + dst.Append(name); + dst.Append(".dylib"); +#elif SLANG_LINUX_FAMILY + dst.Append("lib"); + dst.Append(name); + dst.Append(".so"); +#else + // Just guess we can do with the name on it's own + dst.Append(name); +#endif +} + +#endif // _WIN32 + +} diff --git a/source/core/slang-platform.h b/source/core/slang-platform.h new file mode 100644 index 000000000..e33c5599d --- /dev/null +++ b/source/core/slang-platform.h @@ -0,0 +1,67 @@ +// slang-platform.h +#ifndef SLANG_CORE_PLATFORM_H +#define SLANG_CORE_PLATFORM_H + +#include "../../slang.h" +#include "../core/slang-string.h" + +namespace Slang +{ + // 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 filename + /// + /// @param the unadorned filename + /// @return Returns a non null handle for the shared library on success. nullptr indicated failure + static SlangResult load(const char* filename, 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 platformFileName the platform specific file name. + /// @return Returns a non null handle for the shared library on success. nullptr indicated failure + static SlangResult loadWithPlatformFilename(char const* platformFileName, 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 function + /// Return nullptr if function is not found + /// @param The shared library handle as returned by loadPlatformLibrary + static FuncPtr findFuncByName(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); + + 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); + }; + +#ifndef _MSC_VER + #define _fileno fileno + #define _isatty isatty + #define _setmode setmode + #define _O_BINARY O_BINARY +#endif +} + +#endif diff --git a/source/core/slang-random-generator.h b/source/core/slang-random-generator.h index cc25aadf3..8b4d1759b 100644 --- a/source/core/slang-random-generator.h +++ b/source/core/slang-random-generator.h @@ -1,12 +1,12 @@ -#ifndef SLANG_RANDOM_GENERATOR_H -#define SLANG_RANDOM_GENERATOR_H +#ifndef SLANG_CORE_RANDOM_GENERATOR_H +#define SLANG_CORE_RANDOM_GENERATOR_H #include "../../slang.h" #include #include -#include "smart-pointer.h" +#include "slang-smart-pointer.h" namespace Slang { diff --git a/source/core/slang-render-api-util.cpp b/source/core/slang-render-api-util.cpp index 05def0fe3..3df971219 100644 --- a/source/core/slang-render-api-util.cpp +++ b/source/core/slang-render-api-util.cpp @@ -3,10 +3,10 @@ #include "../../slang.h" -#include "../../source/core/list.h" -#include "../../source/core/slang-string-util.h" +#include "slang-list.h" +#include "slang-string-util.h" -#include "platform.h" +#include "slang-platform.h" namespace Slang { diff --git a/source/core/slang-render-api-util.h b/source/core/slang-render-api-util.h index 42e88a6ac..fbdd3930c 100644 --- a/source/core/slang-render-api-util.h +++ b/source/core/slang-render-api-util.h @@ -1,5 +1,5 @@ -#ifndef SLANG_RENDER_API_UTIL_H -#define SLANG_RENDER_API_UTIL_H +#ifndef SLANG_CORE_RENDER_API_UTIL_H +#define SLANG_CORE_RENDER_API_UTIL_H #include "../../source/core/slang-string.h" diff --git a/source/core/slang-secure-crt.h b/source/core/slang-secure-crt.h new file mode 100644 index 000000000..991fe939e --- /dev/null +++ b/source/core/slang-secure-crt.h @@ -0,0 +1,88 @@ +#ifndef _MSC_VER +#ifndef SLANG_CORE_SECURE_CRT_H +#define SLANG_CORE_SECURE_CRT_H +#include +#include +#include +#include +#include + +#include + +inline void memcpy_s(void *dest, size_t numberOfElements, const void * src, size_t count) +{ + memcpy(dest, src, count); +} + +#define _TRUNCATE ((size_t)-1) +#define _stricmp strcasecmp + +inline void fopen_s(FILE**f, const char * fileName, const char * mode) +{ + *f = fopen(fileName, mode); +} + +inline size_t fread_s(void * buffer, size_t bufferSize, size_t elementSize, size_t count, FILE * stream) +{ + return fread(buffer, elementSize, count, stream); +} + +inline size_t wcsnlen_s(const wchar_t * str, size_t /*numberofElements*/) +{ + return wcslen(str); +} + +inline size_t strnlen_s(const char * str, size_t numberOfElements) +{ +#if defined( __CYGWIN__ ) + const char* cur = str; + if (str) + { + const char*const end = str + numberOfElements; + while (*cur && cur < end) cur++; + } + return size_t(cur - str); +#else + return strnlen(str, numberOfElements); +#endif +} + +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; +} + +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; +} + +inline void wcscpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource) +{ + wcscpy(strDestination, strSource); +} +inline void strcpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource) +{ + strcpy(strDestination, strSource); +} + +inline void wcsncpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource, size_t count) +{ + wcscpy(strDestination, strSource); + //wcsncpy(strDestination, strSource, count); +} +inline void strncpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource, size_t count) +{ + strncpy(strDestination, strSource, count); + //wcsncpy(strDestination, strSource, count); +} +#endif +#endif diff --git a/source/core/slang-shared-library.cpp b/source/core/slang-shared-library.cpp index 20d457840..009abf921 100644 --- a/source/core/slang-shared-library.cpp +++ b/source/core/slang-shared-library.cpp @@ -1,8 +1,9 @@ #include "slang-shared-library.h" #include "../../slang-com-ptr.h" -#include "../core/slang-io.h" -#include "../core/slang-string-util.h" + +#include "slang-io.h" +#include "slang-string-util.h" namespace Slang { diff --git a/source/core/slang-shared-library.h b/source/core/slang-shared-library.h index 62d15b6b4..5a4eb7229 100644 --- a/source/core/slang-shared-library.h +++ b/source/core/slang-shared-library.h @@ -1,13 +1,13 @@ -#ifndef SLANG_SHARED_LIBRARY_H_INCLUDED -#define SLANG_SHARED_LIBRARY_H_INCLUDED +#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/platform.h" -#include "../core/common.h" -#include "../core/dictionary.h" +#include "../core/slang-platform.h" +#include "../core/slang-common.h" +#include "../core/slang-dictionary.h" namespace Slang { @@ -119,4 +119,4 @@ public: } -#endif // SLANG_SHARED_LIBRARY_H_INCLUDED \ No newline at end of file +#endif // SLANG_SHARED_LIBRARY_H_INCLUDED diff --git a/source/core/slang-smart-pointer.h b/source/core/slang-smart-pointer.h new file mode 100644 index 000000000..bae30de37 --- /dev/null +++ b/source/core/slang-smart-pointer.h @@ -0,0 +1,250 @@ +#ifndef SLANG_CORE_SMART_POINTER_H +#define SLANG_CORE_SMART_POINTER_H + +#include "slang-common.h" +#include "slang-hash.h" +#include "slang-type-traits.h" + +#include "../../slang.h" + +namespace Slang +{ + // Base class for all reference-counted objects + class RefObject + { + private: + UInt referenceCount; + + public: + RefObject() + : referenceCount(0) + {} + + RefObject(const RefObject &) + : referenceCount(0) + {} + + virtual ~RefObject() + {} + + UInt addReference() + { + return ++referenceCount; + } + + UInt decreaseReference() + { + 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; + } + + UInt debugGetReferenceCount() + { + return referenceCount; + } + }; + + SLANG_FORCE_INLINE void addReference(RefObject* obj) + { + if(obj) obj->addReference(); + } + + 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 + SLANG_FORCE_INLINE T* dynamicCast(RefObject* obj) { return dynamic_cast(obj); } + template + SLANG_FORCE_INLINE const T* dynamicCast(const RefObject* obj) { return dynamic_cast(obj); } + + // Like a dynamicCast, but allows a type to implement a specific implementation that is suitable for it + template + SLANG_FORCE_INLINE T* as(RefObject* obj) { return dynamicCast(obj); } + template + SLANG_FORCE_INLINE const T* as(const RefObject* obj) { return dynamicCast(obj); } + + // "Smart" pointer to a reference-counted object + template + struct RefPtr + { + RefPtr() + : pointer(nullptr) + {} + + RefPtr(T* p) + : pointer(p) + { + addReference(p); + } + + RefPtr(RefPtr const& p) + : pointer(p.pointer) + { + addReference(p.pointer); + } + + RefPtr(RefPtr&& p) + : pointer(p.pointer) + { + p.pointer = nullptr; + } + + template + RefPtr(RefPtr const& p, + typename EnableIf::Value, void>::type * = 0) + : pointer((U*) p) + { + addReference((U*) p); + } + +#if 0 + void operator=(T* p) + { + T* old = pointer; + addReference(p); + pointer = p; + releaseReference(old); + } +#endif + + void operator=(RefPtr const& p) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } + + void operator=(RefPtr&& p) + { + T* old = pointer; + pointer = p.pointer; + p.pointer = old; + } + + template + typename EnableIf::value, void>::type + operator=(RefPtr const& p) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } + + int GetHashCode() + { + // Note: We need a `RefPtr` to hash the same as a `T*`, + // so that a `T*` can be used as a key in a dictionary with + // `RefPtr` 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==(RefPtr const& ptr) const + { + return pointer == ptr.pointer; + } + + bool operator!=(RefPtr const& ptr) const + { + return pointer != ptr.pointer; + } + + template + RefPtr dynamicCast() const + { + return RefPtr(Slang::dynamicCast(pointer)); + } + + template + RefPtr as() const + { + return RefPtr(Slang::as(pointer)); + } + + template + bool is() const { return Slang::as(pointer) != nullptr; } + + ~RefPtr() + { + releaseReference((Slang::RefObject*) pointer); + } + + T& operator*() const + { + return *pointer; + } + + T* operator->() const + { + return pointer; + } + + T * Ptr() const + { + return pointer; + } + + operator T*() const + { + return pointer; + } + + void attach(T* p) + { + T* old = pointer; + pointer = p; + releaseReference(old); + } + + T* detach() + { + auto rs = pointer; + pointer = nullptr; + return rs; + } + + /// 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; } + + private: + T* pointer; + + }; +} + +#endif diff --git a/source/core/slang-std-writers.h b/source/core/slang-std-writers.h index b35d3d037..8ecb89227 100644 --- a/source/core/slang-std-writers.h +++ b/source/core/slang-std-writers.h @@ -1,5 +1,5 @@ -#ifndef SLANG_STD_WRITERS_H -#define SLANG_STD_WRITERS_H +#ifndef SLANG_CORE_STD_WRITERS_H +#define SLANG_CORE_STD_WRITERS_H #include "slang-writer.h" #include "../../slang-com-ptr.h" diff --git a/source/core/slang-stream.cpp b/source/core/slang-stream.cpp new file mode 100644 index 000000000..ee194c451 --- /dev/null +++ b/source/core/slang-stream.cpp @@ -0,0 +1,294 @@ +#include "slang-stream.h" +#ifdef _WIN32 +#include +#endif +#include "slang-io.h" + +namespace Slang +{ + FileStream::FileStream(const Slang::String & fileName, FileMode fileMode) + { + Init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None); + } + FileStream::FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share) + { + Init(fileName, fileMode, access, share); + } + void FileStream::Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share) + { + const wchar_t * mode = L"rt"; + const char* modeMBCS = "rt"; + switch (fileMode) + { + case Slang::FileMode::Create: + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Create mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"w+b"; + modeMBCS = "w+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + modeMBCS = "wb"; + this->fileAccess = FileAccess::Write; + } + break; + case Slang::FileMode::Open: + if (access == FileAccess::Read) + { + mode = L"rb"; + modeMBCS = "rb"; + this->fileAccess = FileAccess::Read; + } + else if (access == FileAccess::ReadWrite) + { + mode = L"r+b"; + modeMBCS = "r+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + modeMBCS = "wb"; + this->fileAccess = FileAccess::Write; + } + break; + case Slang::FileMode::CreateNew: + if (File::exists(fileName)) + { + throw IOException("Failed opening '" + fileName + "', file already exists."); + } + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Create mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"w+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + this->fileAccess = FileAccess::Write; + } + break; + case Slang::FileMode::Append: + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Append mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"a+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"ab"; + this->fileAccess = FileAccess::Write; + } + break; + default: + break; + } +#ifdef _WIN32 + int shFlag = _SH_DENYRW; + switch (share) + { + case Slang::FileShare::None: + shFlag = _SH_DENYRW; + break; + case Slang::FileShare::ReadOnly: + shFlag = _SH_DENYWR; + break; + case Slang::FileShare::WriteOnly: + shFlag = _SH_DENYRD; + break; + case Slang::FileShare::ReadWrite: + shFlag = _SH_DENYNO; + break; + default: + throw ArgumentException("Invalid file share mode."); + break; + } + if (share == Slang::FileShare::None) +#pragma warning(suppress:4996) + handle = _wfopen(fileName.toWString(), mode); + else + handle = _wfsopen(fileName.toWString(), mode, shFlag); +#else + handle = fopen(fileName.getBuffer(), modeMBCS); +#endif + if (!handle) + { + throw IOException("Cannot open file '" + fileName + "'"); + } + } + FileStream::~FileStream() + { + Close(); + } + Int64 FileStream::GetPosition() + { +#if defined(_WIN32) || defined(__CYGWIN__) + fpos_t pos; + fgetpos(handle, &pos); + return pos; +#elif defined(__APPLE__) + return ftell(handle); +#else + fpos64_t pos; + fgetpos64(handle, &pos); + return *(Int64*)(&pos); +#endif + } + void FileStream::Seek(SeekOrigin origin, Int64 offset) + { + int _origin; + switch (origin) + { + case Slang::SeekOrigin::Start: + _origin = SEEK_SET; + endReached = false; + break; + case Slang::SeekOrigin::End: + _origin = SEEK_END; + // JS TODO: This doesn't seem right, the offset can mean it's not at the end + endReached = true; + break; + case Slang::SeekOrigin::Current: + _origin = SEEK_CUR; + endReached = false; + break; + default: + throw NotSupportedException("Unsupported seek origin."); + break; + } +#ifdef _WIN32 + int rs = _fseeki64(handle, offset, _origin); +#else + int rs = fseek(handle, (int)offset, _origin); +#endif + if (rs != 0) + { + throw IOException("FileStream seek failed."); + } + } + Int64 FileStream::Read(void * buffer, Int64 length) + { + auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle); + if (bytes == 0 && length > 0) + { + if (!feof(handle)) + throw IOException("FileStream read failed."); + else if (endReached) + throw EndOfStreamException("End of file is reached."); + endReached = true; + } + return (int)bytes; + } + Int64 FileStream::Write(const void * buffer, Int64 length) + { + auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle); + if (bytes < length) + { + throw IOException("FileStream write failed."); + } + return bytes; + } + bool FileStream::CanRead() + { + return ((int)fileAccess & (int)FileAccess::Read) != 0; + } + bool FileStream::CanWrite() + { + return ((int)fileAccess & (int)FileAccess::Write) != 0; + } + void FileStream::Close() + { + if (handle) + { + fclose(handle); + handle = 0; + } + } + bool FileStream::IsEnd() + { + return endReached; + } + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MemoryStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + void MemoryStream::Seek(SeekOrigin origin, Int64 offset) + { + Int64 pos = 0; + switch (origin) + { + case Slang::SeekOrigin::Start: + pos = offset; + break; + case Slang::SeekOrigin::End: + pos = Int64(m_contents.getCount()) + offset; + break; + case Slang::SeekOrigin::Current: + pos = Int64(m_position) + offset; + break; + default: + throw NotSupportedException("Unsupported seek origin."); + break; + } + + m_atEnd = false; + + // Clamp to the valid range + pos = (pos < 0) ? 0 : pos; + pos = (pos > Int64(m_contents.getCount())) ? Int64(m_contents.getCount()) : pos; + + m_position = UInt(pos); + } + + Int64 MemoryStream::Read(void * buffer, Int64 length) + { + if (!CanRead()) + { + throw IOException("Cannot read this stream."); + } + + const Int64 maxRead = Int64(m_contents.getCount() - m_position); + + if (maxRead == 0 && length > 0) + { + m_atEnd = true; + throw EndOfStreamException("End of file is reached."); + } + + length = length > maxRead ? maxRead : length; + + ::memcpy(buffer, m_contents.begin() + m_position, size_t(length)); + m_position += UInt(length); + return maxRead; + } + + Int64 MemoryStream::Write(const void * buffer, Int64 length) + { + if (!CanWrite()) + { + throw IOException("Cannot write this stream."); + } + + if (m_position == m_contents.getCount()) + { + m_contents.addRange((const uint8_t*)buffer, UInt(length)); + } + else + { + m_contents.insertRange(m_position, (const uint8_t*)buffer, UInt(length)); + } + + m_atEnd = false; + + m_position += UInt(length); + return length; + } + +} diff --git a/source/core/slang-stream.h b/source/core/slang-stream.h new file mode 100644 index 000000000..67e04fa6a --- /dev/null +++ b/source/core/slang-stream.h @@ -0,0 +1,113 @@ +#ifndef SLANG_CORE_STREAM_H +#define SLANG_CORE_STREAM_H + +#include "slang-basic.h" + +namespace Slang +{ + class IOException : public Exception + { + public: + IOException() + {} + IOException(const String & message) + : Slang::Exception(message) + { + } + }; + + class EndOfStreamException : public IOException + { + public: + EndOfStreamException() + {} + EndOfStreamException(const String & message) + : IOException(message) + { + } + }; + + enum class SeekOrigin + { + Start, End, Current + }; + + class Stream : public RefObject + { + public: + virtual ~Stream() {} + virtual Int64 GetPosition()=0; + virtual void Seek(SeekOrigin origin, Int64 offset)=0; + virtual Int64 Read(void * buffer, Int64 length) = 0; + virtual Int64 Write(const void * buffer, Int64 length) = 0; + virtual bool IsEnd() = 0; + virtual bool CanRead() = 0; + virtual bool CanWrite() = 0; + virtual void Close() = 0; + }; + + enum class FileMode + { + Create, Open, CreateNew, Append + }; + + enum class FileAccess + { + None = 0, Read = 1, Write = 2, ReadWrite = 3 + }; + + enum class FileShare + { + None, ReadOnly, WriteOnly, ReadWrite + }; + + class MemoryStream : public Stream + { + public: + virtual Int64 GetPosition() SLANG_OVERRIDE { return m_position; } + virtual void Seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; + virtual Int64 Read(void * buffer, Int64 length) SLANG_OVERRIDE; + virtual Int64 Write(const void * buffer, Int64 length) SLANG_OVERRIDE; + 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; } + + MemoryStream(FileAccess access) : + m_access(access), + m_position(0), + m_atEnd(false) + {} + + Index m_position; + + bool m_atEnd; ///< Happens when a read is done and nothing can be returned because already at end + + FileAccess m_access; + List m_contents; + }; + + class FileStream : public Stream + { + private: + FILE * handle; + FileAccess fileAccess; + bool endReached = false; + void Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share); + public: + FileStream(const Slang::String & fileName, FileMode fileMode = FileMode::Open); + FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share); + ~FileStream(); + public: + virtual Int64 GetPosition(); + virtual void Seek(SeekOrigin origin, Int64 offset); + virtual Int64 Read(void * buffer, Int64 length); + virtual Int64 Write(const void * buffer, Int64 length); + virtual bool CanRead(); + virtual bool CanWrite(); + virtual void Close(); + virtual bool IsEnd(); + }; +} + +#endif diff --git a/source/core/slang-string-slice-pool.h b/source/core/slang-string-slice-pool.h index cf8f63c81..4d5f91e37 100644 --- a/source/core/slang-string-slice-pool.h +++ b/source/core/slang-string-slice-pool.h @@ -1,11 +1,11 @@ -#ifndef SLANG_STRING_SLICE_POOL_H -#define SLANG_STRING_SLICE_POOL_H +#ifndef SLANG_CORE_STRING_SLICE_POOL_H +#define SLANG_CORE_STRING_SLICE_POOL_H #include "slang-string.h" -#include "list.h" +#include "slang-list.h" #include "slang-memory-arena.h" -#include "dictionary.h" +#include "slang-dictionary.h" namespace Slang { diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h index 40fda31c4..fcae23bb3 100644 --- a/source/core/slang-string-util.h +++ b/source/core/slang-string-util.h @@ -1,8 +1,8 @@ -#ifndef SLANG_STRING_UTIL_H -#define SLANG_STRING_UTIL_H +#ifndef SLANG_CORE_STRING_UTIL_H +#define SLANG_CORE_STRING_UTIL_H #include "slang-string.h" -#include "list.h" +#include "slang-list.h" #include diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index 9a908c93e..64b8e4dc1 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -1,5 +1,5 @@ #include "slang-string.h" -#include "text-io.h" +#include "slang-text-io.h" namespace Slang { diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 82eda74ac..1cd9e5413 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -1,14 +1,14 @@ -#ifndef FUNDAMENTAL_LIB_STRING_H -#define FUNDAMENTAL_LIB_STRING_H +#ifndef SLANG_CORE_STRING_H +#define SLANG_CORE_STRING_H #include #include #include -#include "smart-pointer.h" -#include "common.h" -#include "hash.h" -#include "secure-crt.h" +#include "slang-smart-pointer.h" +#include "slang-common.h" +#include "slang-hash.h" +#include "slang-secure-crt.h" #include diff --git a/source/core/slang-test-tool-util.h b/source/core/slang-test-tool-util.h index 3ec655cad..a5d7541ec 100644 --- a/source/core/slang-test-tool-util.h +++ b/source/core/slang-test-tool-util.h @@ -1,5 +1,5 @@ -#ifndef SLANG_TEST_TOOL_UTIL_H -#define SLANG_TEST_TOOL_UTIL_H +#ifndef SLANG_CORE_TEST_TOOL_UTIL_H +#define SLANG_CORE_TEST_TOOL_UTIL_H #include "slang-std-writers.h" diff --git a/source/core/slang-text-io.cpp b/source/core/slang-text-io.cpp new file mode 100644 index 000000000..18039e41b --- /dev/null +++ b/source/core/slang-text-io.cpp @@ -0,0 +1,343 @@ +#include "slang-text-io.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#undef WIN32_LEAN_AND_MEAN +#undef NOMINMAX +#define CONVERT_END_OF_LINE +#endif + +namespace Slang +{ + class Utf8Encoding : public Encoding + { + public: + virtual void GetBytes(List & result, const String & str) override + { + result.addRange(str.getBuffer(), str.getLength()); + } + virtual String ToString(const char * bytes, int /*length*/) override + { + return String(bytes); + } + }; + + class Utf32Encoding : public Encoding + { + public: + virtual void GetBytes(List & result, const String & str) override + { + Index ptr = 0; + while (ptr < str.getLength()) + { + int codePoint = GetUnicodePointFromUTF8([&](int) + { + if (ptr < str.getLength()) + return str[ptr++]; + else + return '\0'; + }); + result.addRange((char*)&codePoint, 4); + } + } + virtual String ToString(const char * bytes, int length) override + { + StringBuilder sb; + int * content = (int*)bytes; + for (int i = 0; i < (length >> 2); i++) + { + char buf[5]; + int count = EncodeUnicodePointToUTF8(buf, content[i]); + for (int j = 0; j < count; j++) + sb.Append(buf[j]); + } + return sb.ProduceString(); + } + }; + + class Utf16Encoding : public Encoding //UTF16 + { + private: + bool reverseOrder = false; + public: + Utf16Encoding(bool pReverseOrder) + : reverseOrder(pReverseOrder) + {} + virtual void GetBytes(List & result, const String & str) override + { + Index ptr = 0; + while (ptr < str.getLength()) + { + int codePoint = GetUnicodePointFromUTF8([&](int) + { + if (ptr < str.getLength()) + return str[ptr++]; + else + return '\0'; + }); + unsigned short buffer[2]; + int count; + if (!reverseOrder) + count = EncodeUnicodePointToUTF16(buffer, codePoint); + else + count = EncodeUnicodePointToUTF16Reversed(buffer, codePoint); + result.addRange((char*)buffer, count * 2); + } + } + virtual String ToString(const char * bytes, int length) override + { + int ptr = 0; + StringBuilder sb; + while (ptr < length) + { + int codePoint = GetUnicodePointFromUTF16([&](int) + { + if (ptr < length) + return bytes[ptr++]; + else + return '\0'; + }); + char buf[5]; + int count = EncodeUnicodePointToUTF8(buf, codePoint); + for (int i = 0; i < count; i++) + sb.Append(buf[i]); + } + return sb.ProduceString(); + } + }; + + Utf8Encoding __utf8Encoding; + Utf16Encoding __utf16Encoding(false); + Utf16Encoding __utf16EncodingReversed(true); + Utf32Encoding __utf32Encoding; + + Encoding * Encoding::UTF8 = &__utf8Encoding; + Encoding * Encoding::UTF16 = &__utf16Encoding; + Encoding * Encoding::UTF16Reversed = &__utf16EncodingReversed; + Encoding * Encoding::UTF32 = &__utf32Encoding; + + const unsigned short Utf16Header = 0xFEFF; + const unsigned short Utf16ReversedHeader = 0xFFFE; + + StreamWriter::StreamWriter(const String & path, Encoding * encoding) + { + this->stream = new FileStream(path, FileMode::Create); + this->encoding = encoding; + if (encoding == Encoding::UTF16) + { + this->stream->Write(&Utf16Header, 2); + } + else if (encoding == Encoding::UTF16Reversed) + { + this->stream->Write(&Utf16ReversedHeader, 2); + } + } + StreamWriter::StreamWriter(RefPtr stream, Encoding * encoding) + { + this->stream = stream; + this->encoding = encoding; + if (encoding == Encoding::UTF16) + { + this->stream->Write(&Utf16Header, 2); + } + else if (encoding == Encoding::UTF16Reversed) + { + this->stream->Write(&Utf16ReversedHeader, 2); + } + } + void StreamWriter::Write(const String & str) + { + encodingBuffer.clear(); + StringBuilder sb; + String newLine; +#ifdef _WIN32 + newLine = "\r\n"; +#else + newLine = "\n"; +#endif + for (Index i = 0; i < str.getLength(); i++) + { + if (str[i] == '\r') + sb << newLine; + else if (str[i] == '\n') + { + if (i > 0 && str[i - 1] != '\r') + sb << newLine; + } + else + sb << str[i]; + } + encoding->GetBytes(encodingBuffer, sb.ProduceString()); + stream->Write(encodingBuffer.getBuffer(), encodingBuffer.getCount()); + } + void StreamWriter::Write(const char * str) + { + Write(String(str)); + } + + StreamReader::StreamReader(const String & path) + { + stream = new FileStream(path, FileMode::Open); + ReadBuffer(); + encoding = DetermineEncoding(); + if (encoding == 0) + encoding = Encoding::UTF8; + } + StreamReader::StreamReader(RefPtr stream, Encoding * encoding) + { + this->stream = stream; + this->encoding = encoding; + ReadBuffer(); + auto determinedEncoding = DetermineEncoding(); + if (this->encoding == nullptr) + this->encoding = determinedEncoding; + } + + bool HasNullBytes(char * str, int len) + { + bool hasSeenNull = false; + for (int i = 0; i < len - 1; i++) + if (str[i] == 0) + hasSeenNull = true; + else if (hasSeenNull) + return true; + return false; + } + + Encoding * StreamReader::DetermineEncoding() + { + if (buffer.getCount() >= 3 && (unsigned char)(buffer[0]) == 0xEF && (unsigned char)(buffer[1]) == 0xBB && (unsigned char)(buffer[2]) == 0xBF) + { + ptr += 3; + return Encoding::UTF8; + } + else if (*((unsigned short*)(buffer.getBuffer())) == 0xFEFF) + { + ptr += 2; + return Encoding::UTF16; + } + else if (*((unsigned short*)(buffer.getBuffer())) == 0xFFFE) + { + ptr += 2; + return Encoding::UTF16Reversed; + } + else + { + // find null bytes + if (HasNullBytes(buffer.getBuffer(), (int)buffer.getCount())) + { + return Encoding::UTF16; + } + return Encoding::UTF8; + } + } + + void StreamReader::ReadBuffer() + { + buffer.setCount(4096); + memset(buffer.getBuffer(), 0, buffer.getCount() * sizeof(buffer[0])); + auto len = stream->Read(buffer.getBuffer(), buffer.getCount()); + buffer.setCount((int)len); + ptr = 0; + } + + char StreamReader::ReadBufferChar() + { + if (ptrIsEnd()) + ReadBuffer(); + if (ptr + 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) + { + Write(value); + return *this; + } + TextWriter & operator << (const String & val) + { + Write(val); + return *this; + } + TextWriter & operator << (const _EndLine &) + { +#ifdef _WIN32 + Write("\r\n"); +#else + Write("\n"); +#endif + return *this; + } + }; + + template + int GetUnicodePointFromUTF8(const ReadCharFunc & get) + { + int codePoint = 0; + int leading = get(0); + int mask = 0x80; + int count = 0; + while (leading & mask) + { + count++; + mask >>= 1; + } + codePoint = (leading & (mask - 1)); + for (int i = 1; i <= count - 1; i++) + { + codePoint <<= 6; + codePoint += (get(i) & 0x3F); + } + return codePoint; + } + + template + int GetUnicodePointFromUTF16(const ReadCharFunc & get) + { + int byte0 = (unsigned char)get(0); + int byte1 = (unsigned char)get(1); + int word0 = byte0 + (byte1 << 8); + if (word0 >= 0xD800 && word0 <= 0xDFFF) + { + int byte2 = (unsigned char)get(2); + int byte3 = (unsigned char)get(3); + int word1 = byte2 + (byte3 << 8); + return ((word0 & 0x3FF) << 10) + (word1 & 0x3FF) + 0x10000; + } + else + return word0; + } + + template + int GetUnicodePointFromUTF16Reversed(const ReadCharFunc & get) + { + int byte0 = (unsigned char)get(0); + int byte1 = (unsigned char)get(1); + int word0 = (byte0 << 8) + byte1; + if (word0 >= 0xD800 && word0 <= 0xDFFF) + { + int byte2 = (unsigned char)get(2); + int byte3 = (unsigned char)get(3); + int word1 = (byte2 << 8) + byte3; + return ((word0 & 0x3FF) << 10) + (word1 & 0x3FF); + } + else + return word0; + } + + template + int GetUnicodePointFromUTF32(const ReadCharFunc & get) + { + int byte0 = (unsigned char)get(0); + int byte1 = (unsigned char)get(1); + int byte2 = (unsigned char)get(2); + int byte3 = (unsigned char)get(3); + return byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24); + } + + inline int EncodeUnicodePointToUTF8(char * buffer, int codePoint) + { + int count = 0; + if (codePoint <= 0x7F) + buffer[count++] = ((char)codePoint); + else if (codePoint <= 0x7FF) + { + unsigned char byte = (unsigned char)(0xC0 + (codePoint >> 6)); + buffer[count++] = ((char)byte); + byte = 0x80 + (codePoint & 0x3F); + buffer[count++] = ((char)byte); + } + else if (codePoint <= 0xFFFF) + { + unsigned char byte = (unsigned char)(0xE0 + (codePoint >> 12)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + ((codePoint >> 6) & (0x3F))); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + (codePoint & 0x3F)); + buffer[count++] = ((char)byte); + } + else + { + unsigned char byte = (unsigned char)(0xF0 + (codePoint >> 18)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + ((codePoint >> 12) & 0x3F)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + ((codePoint >> 6) & 0x3F)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + (codePoint & 0x3F)); + buffer[count++] = ((char)byte); + } + return count; + } + + inline int EncodeUnicodePointToUTF16(unsigned short * buffer, int codePoint) + { + int count = 0; + if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) + buffer[count++] = (unsigned short)codePoint; + else + { + int sub = codePoint - 0x10000; + int high = (sub >> 10) + 0xD800; + int low = (sub & 0x3FF) + 0xDC00; + buffer[count++] = (unsigned short)high; + buffer[count++] = (unsigned short)low; + } + return count; + } + + inline unsigned short ReverseBitOrder(unsigned short val) + { + int byte0 = val & 0xFF; + int byte1 = val >> 8; + return (unsigned short)(byte1 + (byte0 << 8)); + } + + inline int EncodeUnicodePointToUTF16Reversed(unsigned short * buffer, int codePoint) + { + int count = 0; + if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) + buffer[count++] = ReverseBitOrder((unsigned short)codePoint); + else + { + int sub = codePoint - 0x10000; + int high = (sub >> 10) + 0xD800; + int low = (sub & 0x3FF) + 0xDC00; + buffer[count++] = ReverseBitOrder((unsigned short)high); + buffer[count++] = ReverseBitOrder((unsigned short)low); + } + return count; + } + + class Encoding + { + public: + static Encoding * UTF8, * UTF16, *UTF16Reversed, * UTF32; + virtual void GetBytes(List& buffer, const String & str) = 0; + virtual String ToString(const char * buffer, int length) = 0; + virtual ~Encoding() + {} + }; + + class StreamWriter : public TextWriter + { + private: + List encodingBuffer; + RefPtr stream; + Encoding * encoding; + public: + StreamWriter(const String & path, Encoding * encoding = Encoding::UTF8); + StreamWriter(RefPtr stream, Encoding * encoding = Encoding::UTF8); + virtual void Write(const String & str); + virtual void Write(const char * str); + virtual void Close() + { + stream->Close(); + } + void ReleaseStream() + { + stream = 0; + } + }; + + class StreamReader : public TextReader + { + private: + RefPtr stream; + List buffer; + Encoding * encoding; + Index ptr; + char ReadBufferChar(); + void ReadBuffer(); + + Encoding * DetermineEncoding(); + protected: + virtual void ReadChar() + { + decodedCharPtr = 0; + int codePoint = 0; + if (encoding == Encoding::UTF8) + codePoint = GetUnicodePointFromUTF8([&](int) {return ReadBufferChar(); }); + else if (encoding == Encoding::UTF16) + codePoint = GetUnicodePointFromUTF16([&](int) {return ReadBufferChar(); }); + else if (encoding == Encoding::UTF16Reversed) + codePoint = GetUnicodePointFromUTF16Reversed([&](int) {return ReadBufferChar(); }); + else if (encoding == Encoding::UTF32) + codePoint = GetUnicodePointFromUTF32([&](int) {return ReadBufferChar(); }); + decodedCharSize = EncodeUnicodePointToUTF8(decodedChar, codePoint); + } + public: + StreamReader(const String & path); + StreamReader(RefPtr stream, Encoding * encoding = nullptr); + virtual String ReadLine(); + virtual String ReadToEnd(); + virtual bool IsEnd() + { + return ptr == buffer.getCount() && stream->IsEnd(); + } + virtual void Close() + { + stream->Close(); + } + void ReleaseStream() + { + stream = 0; + } + }; +} + +#endif diff --git a/source/core/slang-token-reader.cpp b/source/core/slang-token-reader.cpp new file mode 100644 index 000000000..a15dcda9c --- /dev/null +++ b/source/core/slang-token-reader.cpp @@ -0,0 +1,768 @@ +#include "slang-token-reader.h" + +namespace Slang +{ + enum class TokenizeErrorType + { + InvalidCharacter, InvalidEscapeSequence + }; + + enum class State + { + Start, Identifier, Operator, Int, Hex, Fixed, Double, Char, String, MultiComment, SingleComment + }; + + enum class LexDerivative + { + None, Line, File + }; + + 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 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'); + } + + void ParseOperators(const String & str, List & tokens, TokenFlags& tokenFlags, int line, int col, int startPos, String fileName) + { + 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) + { + 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 == '=') + { + InsertToken(TokenType::OpEql, "=="); + pos += 2; + } + else + { + InsertToken(TokenType::OpAssign, "="); + pos++; + } + break; + case '!': + if (nextChar == '=') + { + InsertToken(TokenType::OpNeq, "!="); + pos += 2; + } + else + { + InsertToken(TokenType::OpNot, "!"); + pos++; + } + 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++; + } + 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 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 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) + { + 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; + } + }; + while (pos <= text.getLength()) + { + char curChar = (pos < text.getLength() ? text[pos] : ' '); + char nextChar = (pos < text.getLength() - 1) ? text[pos + 1] : '\0'; + if (lastPos != pos) + { + if (curChar == '\n') + { + line++; + col = 0; + } + else + col++; + lastPos = pos; + } + + switch (state) + { + 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 == -62 || curChar == -96) // -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#") + { + line = 0; + col = 0; + tokenBuilder.Clear(); + } + else if (tokenStr == "#line") + { + derivative = LexDerivative::Line; + tokenBuilder.Clear(); + } + else if (tokenStr == "#file") + { + derivative = LexDerivative::File; + tokenBuilder.Clear(); + line = 0; + col = 0; + } + else +#endif + 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(nextChar); + pos++; + } + 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) + { + 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')) + { + 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 == '+') + { + tokenBuilder.Append(nextChar); + pos++; + } + pos++; + } + else + { + if (curChar == 'f') + pos++; + InsertToken(TokenType::DoubleLiteral); + state = State::Start; + } + break; + case State::Double: + if (IsDigit(curChar)) + { + tokenBuilder.Append(curChar); + 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; + } + } + return tokenList; + } + List TokenizeText(const String & text) + { + return TokenizeText("", text); + } + + String EscapeStringLiteral(String str) + { + StringBuilder sb; + sb << "\""; + const Index length = str.getLength(); + const char*const data = str.getBuffer(); + for (Index i = 0; i < length; i++) + { + switch (data[i]) + { + case ' ': + sb << "\\s"; + break; + case '\n': + sb << "\\n"; + break; + case '\r': + sb << "\\r"; + break; + case '\t': + sb << "\\t"; + break; + case '\v': + sb << "\\v"; + break; + case '\'': + sb << "\\\'"; + break; + case '\"': + sb << "\\\""; + break; + case '\\': + sb << "\\\\"; + break; + default: + sb << data[i]; + break; + } + } + sb << "\""; + return sb.ProduceString(); + } + + String UnescapeStringLiteral(String str) + { + StringBuilder sb; + const Index length = str.getLength(); + const char*const data = str.getBuffer(); + for (Index i = 0; i < length; i++) + { + if (data[i] == '\\' && i < length - 1) + { + switch (data[i + 1]) + { + case 's': + sb << " "; + break; + case 't': + sb << '\t'; + break; + case 'n': + sb << '\n'; + break; + case 'r': + sb << '\r'; + break; + case 'v': + sb << '\v'; + break; + case '\'': + sb << '\''; + break; + case '\"': + sb << "\""; + break; + case '\\': + sb << "\\"; + break; + default: + i = i - 1; + sb << data[i]; + } + i++; + } + else + sb << data[i]; + } + return sb.ProduceString(); + } + + TokenReader::TokenReader(String text) + { + this->tokens = TokenizeText("", text); + tokenPtr = 0; + } +} diff --git a/source/core/slang-token-reader.h b/source/core/slang-token-reader.h new file mode 100644 index 000000000..f8a455452 --- /dev/null +++ b/source/core/slang-token-reader.h @@ -0,0 +1,260 @@ +#ifndef SLANG_CORE_TOKEN_READER_H +#define SLANG_CORE_TOKEN_READER_H + +#include "slang-basic.h" + +namespace Slang +{ + /* 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, + + QuestionMark, Colon, RightArrow, At, Pound, PoundPound, Scope, + }; + + class CodePosition + { + 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 + { + AtStartOfLine = 1 << 0, + AfterWhitespace = 1 << 1, + }; + typedef unsigned int TokenFlags; + + class Token + { + public: + TokenType Type = TokenType::Unknown; + String Content; + CodePosition Position; + TokenFlags flags; + 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); + } + }; + + class TextFormatException : public Exception + { + public: + TextFormatException(String message) + : Exception(message) + {} + }; + + class TokenReader + { + private: + bool legal; + List tokens; + int tokenPtr; + public: + TokenReader(String text); + int ReadInt() + { + auto token = ReadToken(); + bool neg = false; + if (token.Content == '-') + { + 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."); + } + unsigned int ReadUInt() + { + auto token = ReadToken(); + if (token.Type == TokenType::IntLiteral) + { + return StringToUInt(token.Content); + } + throw TextFormatException("Text parsing error: int expected."); + } + double ReadDouble() + { + auto token = ReadToken(); + bool neg = false; + if (token.Content == '-') + { + 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."); + } + float ReadFloat() + { + return (float)ReadDouble(); + } + String ReadWord() + { + auto token = ReadToken(); + if (token.Type == TokenType::Identifier) + { + return token.Content; + } + throw TextFormatException("Text parsing error: identifier expected."); + } + String Read(const char * expectedStr) + { + auto token = ReadToken(); + if (token.Content == expectedStr) + { + return token.Content; + } + throw TextFormatException("Text parsing error: \'" + String(expectedStr) + "\' expected."); + } + String Read(String expectedStr) + { + auto token = ReadToken(); + if (token.Content == expectedStr) + { + return token.Content; + } + throw TextFormatException("Text parsing error: \'" + expectedStr + "\' expected."); + } + + String ReadStringLiteral() + { + auto token = ReadToken(); + if (token.Type == TokenType::StringLiteral) + { + return token.Content; + } + throw TextFormatException("Text parsing error: string literal expected."); + } + void Back(int count) + { + tokenPtr -= count; + } + Token ReadToken() + { + if (tokenPtr < (int)tokens.getCount()) + { + auto &rs = tokens[tokenPtr]; + tokenPtr++; + return rs; + } + throw TextFormatException("Unexpected ending."); + } + Token NextToken(int offset = 0) + { + if (tokenPtr + offset < (int)tokens.getCount()) + return tokens[tokenPtr + offset]; + else + { + Token rs; + rs.Type = TokenType::Unknown; + return rs; + } + } + bool LookAhead(String token) + { + if (tokenPtr < (int)tokens.getCount()) + { + auto next = NextToken(); + return next.Content == token; + } + else + { + return false; + } + } + bool IsEnd() + { + return tokenPtr == (int)tokens.getCount(); + } + public: + bool IsLegalText() + { + return legal; + } + }; + + inline List Split(String text, char c) + { + List result; + StringBuilder sb; + for (Index i = 0; i < text.getLength(); i++) + { + if (text[i] == c) + { + auto str = sb.ToString(); + if (str.getLength() != 0) + result.add(str); + sb.Clear(); + } + else + sb << text[i]; + } + auto lastStr = sb.ToString(); + if (lastStr.getLength()) + result.add(lastStr); + return result; + } +} + + +#endif diff --git a/source/core/slang-type-traits.h b/source/core/slang-type-traits.h new file mode 100644 index 000000000..ccd1fb29c --- /dev/null +++ b/source/core/slang-type-traits.h @@ -0,0 +1,46 @@ +#ifndef SLANG_CORE_TYPE_TRAITS_H +#define SLANG_CORE_TYPE_TRAITS_H + +namespace Slang +{ + struct TraitResultYes + { + char x; + }; + struct TraitResultNo + { + char x[2]; + }; + + template + struct IsBaseOfTraitHost + { + operator B*() const { return nullptr; } + operator D*() { return nullptr; } + }; + + template + struct IsBaseOf + { + template + static TraitResultYes Check(D*, T) { return TraitResultYes(); } + static TraitResultNo Check(B*, int) { return TraitResultNo(); } + enum { Value = sizeof(Check(IsBaseOfTraitHost(), int())) == sizeof(TraitResultYes) }; + }; + + template + struct EnableIf {}; + + template + struct EnableIf { typedef T type; }; + + template + struct IsConvertible + { + static TraitResultYes Use(B) { return TraitResultYes(); }; + static TraitResultNo Use(...) { return TraitResultNo(); }; + enum { Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) }; + }; +} + +#endif diff --git a/source/core/slang-uint-set.h b/source/core/slang-uint-set.h index 25f0c9269..77930ba0d 100644 --- a/source/core/slang-uint-set.h +++ b/source/core/slang-uint-set.h @@ -1,9 +1,9 @@ -#ifndef SLANG_UINT_SET_H -#define SLANG_UINT_SET_H +#ifndef SLANG_CORE_UINT_SET_H +#define SLANG_CORE_UINT_SET_H -#include "list.h" +#include "slang-list.h" #include "slang-math.h" -#include "common.h" +#include "slang-common.h" #include diff --git a/source/core/slang-writer.cpp b/source/core/slang-writer.cpp index 2c6f99bf9..5b643fff8 100644 --- a/source/core/slang-writer.cpp +++ b/source/core/slang-writer.cpp @@ -1,6 +1,6 @@ #include "slang-writer.h" -#include "platform.h" +#include "slang-platform.h" #include "slang-string-util.h" // Includes to allow us to control console diff --git a/source/core/slang-writer.h b/source/core/slang-writer.h index 463450ac9..6e26d6750 100644 --- a/source/core/slang-writer.h +++ b/source/core/slang-writer.h @@ -1,10 +1,10 @@ -#ifndef SLANG_WRITER_H -#define SLANG_WRITER_H +#ifndef SLANG_CORE_WRITER_H +#define SLANG_CORE_WRITER_H #include "slang-string.h" #include "../../slang-com-helper.h" -#include "../../source/core/list.h" +#include "slang-list.h" namespace Slang { diff --git a/source/core/smart-pointer.h b/source/core/smart-pointer.h deleted file mode 100644 index aa5c06e02..000000000 --- a/source/core/smart-pointer.h +++ /dev/null @@ -1,250 +0,0 @@ -#ifndef FUNDAMENTAL_LIB_SMART_POINTER_H -#define FUNDAMENTAL_LIB_SMART_POINTER_H - -#include "common.h" -#include "hash.h" -#include "type-traits.h" - -#include "../../slang.h" - -namespace Slang -{ - // Base class for all reference-counted objects - class RefObject - { - private: - UInt referenceCount; - - public: - RefObject() - : referenceCount(0) - {} - - RefObject(const RefObject &) - : referenceCount(0) - {} - - virtual ~RefObject() - {} - - UInt addReference() - { - return ++referenceCount; - } - - UInt decreaseReference() - { - 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; - } - - UInt debugGetReferenceCount() - { - return referenceCount; - } - }; - - SLANG_FORCE_INLINE void addReference(RefObject* obj) - { - if(obj) obj->addReference(); - } - - 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 - SLANG_FORCE_INLINE T* dynamicCast(RefObject* obj) { return dynamic_cast(obj); } - template - SLANG_FORCE_INLINE const T* dynamicCast(const RefObject* obj) { return dynamic_cast(obj); } - - // Like a dynamicCast, but allows a type to implement a specific implementation that is suitable for it - template - SLANG_FORCE_INLINE T* as(RefObject* obj) { return dynamicCast(obj); } - template - SLANG_FORCE_INLINE const T* as(const RefObject* obj) { return dynamicCast(obj); } - - // "Smart" pointer to a reference-counted object - template - struct RefPtr - { - RefPtr() - : pointer(nullptr) - {} - - RefPtr(T* p) - : pointer(p) - { - addReference(p); - } - - RefPtr(RefPtr const& p) - : pointer(p.pointer) - { - addReference(p.pointer); - } - - RefPtr(RefPtr&& p) - : pointer(p.pointer) - { - p.pointer = nullptr; - } - - template - RefPtr(RefPtr const& p, - typename EnableIf::Value, void>::type * = 0) - : pointer((U*) p) - { - addReference((U*) p); - } - -#if 0 - void operator=(T* p) - { - T* old = pointer; - addReference(p); - pointer = p; - releaseReference(old); - } -#endif - - void operator=(RefPtr const& p) - { - T* old = pointer; - addReference(p.pointer); - pointer = p.pointer; - releaseReference(old); - } - - void operator=(RefPtr&& p) - { - T* old = pointer; - pointer = p.pointer; - p.pointer = old; - } - - template - typename EnableIf::value, void>::type - operator=(RefPtr const& p) - { - T* old = pointer; - addReference(p.pointer); - pointer = p.pointer; - releaseReference(old); - } - - int GetHashCode() - { - // Note: We need a `RefPtr` to hash the same as a `T*`, - // so that a `T*` can be used as a key in a dictionary with - // `RefPtr` 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==(RefPtr const& ptr) const - { - return pointer == ptr.pointer; - } - - bool operator!=(RefPtr const& ptr) const - { - return pointer != ptr.pointer; - } - - template - RefPtr dynamicCast() const - { - return RefPtr(Slang::dynamicCast(pointer)); - } - - template - RefPtr as() const - { - return RefPtr(Slang::as(pointer)); - } - - template - bool is() const { return Slang::as(pointer) != nullptr; } - - ~RefPtr() - { - releaseReference((Slang::RefObject*) pointer); - } - - T& operator*() const - { - return *pointer; - } - - T* operator->() const - { - return pointer; - } - - T * Ptr() const - { - return pointer; - } - - operator T*() const - { - return pointer; - } - - void attach(T* p) - { - T* old = pointer; - pointer = p; - releaseReference(old); - } - - T* detach() - { - auto rs = pointer; - pointer = nullptr; - return rs; - } - - /// 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; } - - private: - T* pointer; - - }; -} - -#endif diff --git a/source/core/stream.cpp b/source/core/stream.cpp deleted file mode 100644 index de0a8b8f3..000000000 --- a/source/core/stream.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include "stream.h" -#ifdef _WIN32 -#include -#endif -#include "slang-io.h" - -namespace Slang -{ - FileStream::FileStream(const Slang::String & fileName, FileMode fileMode) - { - Init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None); - } - FileStream::FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share) - { - Init(fileName, fileMode, access, share); - } - void FileStream::Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share) - { - const wchar_t * mode = L"rt"; - const char* modeMBCS = "rt"; - switch (fileMode) - { - case Slang::FileMode::Create: - if (access == FileAccess::Read) - throw ArgumentException("Read-only access is incompatible with Create mode."); - else if (access == FileAccess::ReadWrite) - { - mode = L"w+b"; - modeMBCS = "w+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"wb"; - modeMBCS = "wb"; - this->fileAccess = FileAccess::Write; - } - break; - case Slang::FileMode::Open: - if (access == FileAccess::Read) - { - mode = L"rb"; - modeMBCS = "rb"; - this->fileAccess = FileAccess::Read; - } - else if (access == FileAccess::ReadWrite) - { - mode = L"r+b"; - modeMBCS = "r+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"wb"; - modeMBCS = "wb"; - this->fileAccess = FileAccess::Write; - } - break; - case Slang::FileMode::CreateNew: - if (File::exists(fileName)) - { - throw IOException("Failed opening '" + fileName + "', file already exists."); - } - if (access == FileAccess::Read) - throw ArgumentException("Read-only access is incompatible with Create mode."); - else if (access == FileAccess::ReadWrite) - { - mode = L"w+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"wb"; - this->fileAccess = FileAccess::Write; - } - break; - case Slang::FileMode::Append: - if (access == FileAccess::Read) - throw ArgumentException("Read-only access is incompatible with Append mode."); - else if (access == FileAccess::ReadWrite) - { - mode = L"a+b"; - this->fileAccess = FileAccess::ReadWrite; - } - else - { - mode = L"ab"; - this->fileAccess = FileAccess::Write; - } - break; - default: - break; - } -#ifdef _WIN32 - int shFlag = _SH_DENYRW; - switch (share) - { - case Slang::FileShare::None: - shFlag = _SH_DENYRW; - break; - case Slang::FileShare::ReadOnly: - shFlag = _SH_DENYWR; - break; - case Slang::FileShare::WriteOnly: - shFlag = _SH_DENYRD; - break; - case Slang::FileShare::ReadWrite: - shFlag = _SH_DENYNO; - break; - default: - throw ArgumentException("Invalid file share mode."); - break; - } - if (share == Slang::FileShare::None) -#pragma warning(suppress:4996) - handle = _wfopen(fileName.toWString(), mode); - else - handle = _wfsopen(fileName.toWString(), mode, shFlag); -#else - handle = fopen(fileName.getBuffer(), modeMBCS); -#endif - if (!handle) - { - throw IOException("Cannot open file '" + fileName + "'"); - } - } - FileStream::~FileStream() - { - Close(); - } - Int64 FileStream::GetPosition() - { -#if defined(_WIN32) || defined(__CYGWIN__) - fpos_t pos; - fgetpos(handle, &pos); - return pos; -#elif defined(__APPLE__) - return ftell(handle); -#else - fpos64_t pos; - fgetpos64(handle, &pos); - return *(Int64*)(&pos); -#endif - } - void FileStream::Seek(SeekOrigin origin, Int64 offset) - { - int _origin; - switch (origin) - { - case Slang::SeekOrigin::Start: - _origin = SEEK_SET; - endReached = false; - break; - case Slang::SeekOrigin::End: - _origin = SEEK_END; - // JS TODO: This doesn't seem right, the offset can mean it's not at the end - endReached = true; - break; - case Slang::SeekOrigin::Current: - _origin = SEEK_CUR; - endReached = false; - break; - default: - throw NotSupportedException("Unsupported seek origin."); - break; - } -#ifdef _WIN32 - int rs = _fseeki64(handle, offset, _origin); -#else - int rs = fseek(handle, (int)offset, _origin); -#endif - if (rs != 0) - { - throw IOException("FileStream seek failed."); - } - } - Int64 FileStream::Read(void * buffer, Int64 length) - { - auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle); - if (bytes == 0 && length > 0) - { - if (!feof(handle)) - throw IOException("FileStream read failed."); - else if (endReached) - throw EndOfStreamException("End of file is reached."); - endReached = true; - } - return (int)bytes; - } - Int64 FileStream::Write(const void * buffer, Int64 length) - { - auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle); - if (bytes < length) - { - throw IOException("FileStream write failed."); - } - return bytes; - } - bool FileStream::CanRead() - { - return ((int)fileAccess & (int)FileAccess::Read) != 0; - } - bool FileStream::CanWrite() - { - return ((int)fileAccess & (int)FileAccess::Write) != 0; - } - void FileStream::Close() - { - if (handle) - { - fclose(handle); - handle = 0; - } - } - bool FileStream::IsEnd() - { - return endReached; - } - - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MemoryStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - void MemoryStream::Seek(SeekOrigin origin, Int64 offset) - { - Int64 pos = 0; - switch (origin) - { - case Slang::SeekOrigin::Start: - pos = offset; - break; - case Slang::SeekOrigin::End: - pos = Int64(m_contents.getCount()) + offset; - break; - case Slang::SeekOrigin::Current: - pos = Int64(m_position) + offset; - break; - default: - throw NotSupportedException("Unsupported seek origin."); - break; - } - - m_atEnd = false; - - // Clamp to the valid range - pos = (pos < 0) ? 0 : pos; - pos = (pos > Int64(m_contents.getCount())) ? Int64(m_contents.getCount()) : pos; - - m_position = UInt(pos); - } - - Int64 MemoryStream::Read(void * buffer, Int64 length) - { - if (!CanRead()) - { - throw IOException("Cannot read this stream."); - } - - const Int64 maxRead = Int64(m_contents.getCount() - m_position); - - if (maxRead == 0 && length > 0) - { - m_atEnd = true; - throw EndOfStreamException("End of file is reached."); - } - - length = length > maxRead ? maxRead : length; - - ::memcpy(buffer, m_contents.begin() + m_position, size_t(length)); - m_position += UInt(length); - return maxRead; - } - - Int64 MemoryStream::Write(const void * buffer, Int64 length) - { - if (!CanWrite()) - { - throw IOException("Cannot write this stream."); - } - - if (m_position == m_contents.getCount()) - { - m_contents.addRange((const uint8_t*)buffer, UInt(length)); - } - else - { - m_contents.insertRange(m_position, (const uint8_t*)buffer, UInt(length)); - } - - m_atEnd = false; - - m_position += UInt(length); - return length; - } - -} diff --git a/source/core/stream.h b/source/core/stream.h deleted file mode 100644 index 618aadbd4..000000000 --- a/source/core/stream.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef CORE_LIB_STREAM_H -#define CORE_LIB_STREAM_H - -#include "basic.h" - -namespace Slang -{ - class IOException : public Exception - { - public: - IOException() - {} - IOException(const String & message) - : Slang::Exception(message) - { - } - }; - - class EndOfStreamException : public IOException - { - public: - EndOfStreamException() - {} - EndOfStreamException(const String & message) - : IOException(message) - { - } - }; - - enum class SeekOrigin - { - Start, End, Current - }; - - class Stream : public RefObject - { - public: - virtual ~Stream() {} - virtual Int64 GetPosition()=0; - virtual void Seek(SeekOrigin origin, Int64 offset)=0; - virtual Int64 Read(void * buffer, Int64 length) = 0; - virtual Int64 Write(const void * buffer, Int64 length) = 0; - virtual bool IsEnd() = 0; - virtual bool CanRead() = 0; - virtual bool CanWrite() = 0; - virtual void Close() = 0; - }; - - enum class FileMode - { - Create, Open, CreateNew, Append - }; - - enum class FileAccess - { - None = 0, Read = 1, Write = 2, ReadWrite = 3 - }; - - enum class FileShare - { - None, ReadOnly, WriteOnly, ReadWrite - }; - - class MemoryStream : public Stream - { - public: - virtual Int64 GetPosition() SLANG_OVERRIDE { return m_position; } - virtual void Seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE; - virtual Int64 Read(void * buffer, Int64 length) SLANG_OVERRIDE; - virtual Int64 Write(const void * buffer, Int64 length) SLANG_OVERRIDE; - 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; } - - MemoryStream(FileAccess access) : - m_access(access), - m_position(0), - m_atEnd(false) - {} - - Index m_position; - - bool m_atEnd; ///< Happens when a read is done and nothing can be returned because already at end - - FileAccess m_access; - List m_contents; - }; - - class FileStream : public Stream - { - private: - FILE * handle; - FileAccess fileAccess; - bool endReached = false; - void Init(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share); - public: - FileStream(const Slang::String & fileName, FileMode fileMode = FileMode::Open); - FileStream(const Slang::String & fileName, FileMode fileMode, FileAccess access, FileShare share); - ~FileStream(); - public: - virtual Int64 GetPosition(); - virtual void Seek(SeekOrigin origin, Int64 offset); - virtual Int64 Read(void * buffer, Int64 length); - virtual Int64 Write(const void * buffer, Int64 length); - virtual bool CanRead(); - virtual bool CanWrite(); - virtual void Close(); - virtual bool IsEnd(); - }; -} - -#endif diff --git a/source/core/text-io.cpp b/source/core/text-io.cpp deleted file mode 100644 index 1f6b44c92..000000000 --- a/source/core/text-io.cpp +++ /dev/null @@ -1,343 +0,0 @@ -#include "text-io.h" -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX -#define CONVERT_END_OF_LINE -#endif - -namespace Slang -{ - class Utf8Encoding : public Encoding - { - public: - virtual void GetBytes(List & result, const String & str) override - { - result.addRange(str.getBuffer(), str.getLength()); - } - virtual String ToString(const char * bytes, int /*length*/) override - { - return String(bytes); - } - }; - - class Utf32Encoding : public Encoding - { - public: - virtual void GetBytes(List & result, const String & str) override - { - Index ptr = 0; - while (ptr < str.getLength()) - { - int codePoint = GetUnicodePointFromUTF8([&](int) - { - if (ptr < str.getLength()) - return str[ptr++]; - else - return '\0'; - }); - result.addRange((char*)&codePoint, 4); - } - } - virtual String ToString(const char * bytes, int length) override - { - StringBuilder sb; - int * content = (int*)bytes; - for (int i = 0; i < (length >> 2); i++) - { - char buf[5]; - int count = EncodeUnicodePointToUTF8(buf, content[i]); - for (int j = 0; j < count; j++) - sb.Append(buf[j]); - } - return sb.ProduceString(); - } - }; - - class Utf16Encoding : public Encoding //UTF16 - { - private: - bool reverseOrder = false; - public: - Utf16Encoding(bool pReverseOrder) - : reverseOrder(pReverseOrder) - {} - virtual void GetBytes(List & result, const String & str) override - { - Index ptr = 0; - while (ptr < str.getLength()) - { - int codePoint = GetUnicodePointFromUTF8([&](int) - { - if (ptr < str.getLength()) - return str[ptr++]; - else - return '\0'; - }); - unsigned short buffer[2]; - int count; - if (!reverseOrder) - count = EncodeUnicodePointToUTF16(buffer, codePoint); - else - count = EncodeUnicodePointToUTF16Reversed(buffer, codePoint); - result.addRange((char*)buffer, count * 2); - } - } - virtual String ToString(const char * bytes, int length) override - { - int ptr = 0; - StringBuilder sb; - while (ptr < length) - { - int codePoint = GetUnicodePointFromUTF16([&](int) - { - if (ptr < length) - return bytes[ptr++]; - else - return '\0'; - }); - char buf[5]; - int count = EncodeUnicodePointToUTF8(buf, codePoint); - for (int i = 0; i < count; i++) - sb.Append(buf[i]); - } - return sb.ProduceString(); - } - }; - - Utf8Encoding __utf8Encoding; - Utf16Encoding __utf16Encoding(false); - Utf16Encoding __utf16EncodingReversed(true); - Utf32Encoding __utf32Encoding; - - Encoding * Encoding::UTF8 = &__utf8Encoding; - Encoding * Encoding::UTF16 = &__utf16Encoding; - Encoding * Encoding::UTF16Reversed = &__utf16EncodingReversed; - Encoding * Encoding::UTF32 = &__utf32Encoding; - - const unsigned short Utf16Header = 0xFEFF; - const unsigned short Utf16ReversedHeader = 0xFFFE; - - StreamWriter::StreamWriter(const String & path, Encoding * encoding) - { - this->stream = new FileStream(path, FileMode::Create); - this->encoding = encoding; - if (encoding == Encoding::UTF16) - { - this->stream->Write(&Utf16Header, 2); - } - else if (encoding == Encoding::UTF16Reversed) - { - this->stream->Write(&Utf16ReversedHeader, 2); - } - } - StreamWriter::StreamWriter(RefPtr stream, Encoding * encoding) - { - this->stream = stream; - this->encoding = encoding; - if (encoding == Encoding::UTF16) - { - this->stream->Write(&Utf16Header, 2); - } - else if (encoding == Encoding::UTF16Reversed) - { - this->stream->Write(&Utf16ReversedHeader, 2); - } - } - void StreamWriter::Write(const String & str) - { - encodingBuffer.clear(); - StringBuilder sb; - String newLine; -#ifdef _WIN32 - newLine = "\r\n"; -#else - newLine = "\n"; -#endif - for (Index i = 0; i < str.getLength(); i++) - { - if (str[i] == '\r') - sb << newLine; - else if (str[i] == '\n') - { - if (i > 0 && str[i - 1] != '\r') - sb << newLine; - } - else - sb << str[i]; - } - encoding->GetBytes(encodingBuffer, sb.ProduceString()); - stream->Write(encodingBuffer.getBuffer(), encodingBuffer.getCount()); - } - void StreamWriter::Write(const char * str) - { - Write(String(str)); - } - - StreamReader::StreamReader(const String & path) - { - stream = new FileStream(path, FileMode::Open); - ReadBuffer(); - encoding = DetermineEncoding(); - if (encoding == 0) - encoding = Encoding::UTF8; - } - StreamReader::StreamReader(RefPtr stream, Encoding * encoding) - { - this->stream = stream; - this->encoding = encoding; - ReadBuffer(); - auto determinedEncoding = DetermineEncoding(); - if (this->encoding == nullptr) - this->encoding = determinedEncoding; - } - - bool HasNullBytes(char * str, int len) - { - bool hasSeenNull = false; - for (int i = 0; i < len - 1; i++) - if (str[i] == 0) - hasSeenNull = true; - else if (hasSeenNull) - return true; - return false; - } - - Encoding * StreamReader::DetermineEncoding() - { - if (buffer.getCount() >= 3 && (unsigned char)(buffer[0]) == 0xEF && (unsigned char)(buffer[1]) == 0xBB && (unsigned char)(buffer[2]) == 0xBF) - { - ptr += 3; - return Encoding::UTF8; - } - else if (*((unsigned short*)(buffer.getBuffer())) == 0xFEFF) - { - ptr += 2; - return Encoding::UTF16; - } - else if (*((unsigned short*)(buffer.getBuffer())) == 0xFFFE) - { - ptr += 2; - return Encoding::UTF16Reversed; - } - else - { - // find null bytes - if (HasNullBytes(buffer.getBuffer(), (int)buffer.getCount())) - { - return Encoding::UTF16; - } - return Encoding::UTF8; - } - } - - void StreamReader::ReadBuffer() - { - buffer.setCount(4096); - memset(buffer.getBuffer(), 0, buffer.getCount() * sizeof(buffer[0])); - auto len = stream->Read(buffer.getBuffer(), buffer.getCount()); - buffer.setCount((int)len); - ptr = 0; - } - - char StreamReader::ReadBufferChar() - { - if (ptrIsEnd()) - ReadBuffer(); - if (ptr - 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) - { - Write(value); - return *this; - } - TextWriter & operator << (const String & val) - { - Write(val); - return *this; - } - TextWriter & operator << (const _EndLine &) - { -#ifdef _WIN32 - Write("\r\n"); -#else - Write("\n"); -#endif - return *this; - } - }; - - template - int GetUnicodePointFromUTF8(const ReadCharFunc & get) - { - int codePoint = 0; - int leading = get(0); - int mask = 0x80; - int count = 0; - while (leading & mask) - { - count++; - mask >>= 1; - } - codePoint = (leading & (mask - 1)); - for (int i = 1; i <= count - 1; i++) - { - codePoint <<= 6; - codePoint += (get(i) & 0x3F); - } - return codePoint; - } - - template - int GetUnicodePointFromUTF16(const ReadCharFunc & get) - { - int byte0 = (unsigned char)get(0); - int byte1 = (unsigned char)get(1); - int word0 = byte0 + (byte1 << 8); - if (word0 >= 0xD800 && word0 <= 0xDFFF) - { - int byte2 = (unsigned char)get(2); - int byte3 = (unsigned char)get(3); - int word1 = byte2 + (byte3 << 8); - return ((word0 & 0x3FF) << 10) + (word1 & 0x3FF) + 0x10000; - } - else - return word0; - } - - template - int GetUnicodePointFromUTF16Reversed(const ReadCharFunc & get) - { - int byte0 = (unsigned char)get(0); - int byte1 = (unsigned char)get(1); - int word0 = (byte0 << 8) + byte1; - if (word0 >= 0xD800 && word0 <= 0xDFFF) - { - int byte2 = (unsigned char)get(2); - int byte3 = (unsigned char)get(3); - int word1 = (byte2 << 8) + byte3; - return ((word0 & 0x3FF) << 10) + (word1 & 0x3FF); - } - else - return word0; - } - - template - int GetUnicodePointFromUTF32(const ReadCharFunc & get) - { - int byte0 = (unsigned char)get(0); - int byte1 = (unsigned char)get(1); - int byte2 = (unsigned char)get(2); - int byte3 = (unsigned char)get(3); - return byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24); - } - - inline int EncodeUnicodePointToUTF8(char * buffer, int codePoint) - { - int count = 0; - if (codePoint <= 0x7F) - buffer[count++] = ((char)codePoint); - else if (codePoint <= 0x7FF) - { - unsigned char byte = (unsigned char)(0xC0 + (codePoint >> 6)); - buffer[count++] = ((char)byte); - byte = 0x80 + (codePoint & 0x3F); - buffer[count++] = ((char)byte); - } - else if (codePoint <= 0xFFFF) - { - unsigned char byte = (unsigned char)(0xE0 + (codePoint >> 12)); - buffer[count++] = ((char)byte); - byte = (unsigned char)(0x80 + ((codePoint >> 6) & (0x3F))); - buffer[count++] = ((char)byte); - byte = (unsigned char)(0x80 + (codePoint & 0x3F)); - buffer[count++] = ((char)byte); - } - else - { - unsigned char byte = (unsigned char)(0xF0 + (codePoint >> 18)); - buffer[count++] = ((char)byte); - byte = (unsigned char)(0x80 + ((codePoint >> 12) & 0x3F)); - buffer[count++] = ((char)byte); - byte = (unsigned char)(0x80 + ((codePoint >> 6) & 0x3F)); - buffer[count++] = ((char)byte); - byte = (unsigned char)(0x80 + (codePoint & 0x3F)); - buffer[count++] = ((char)byte); - } - return count; - } - - inline int EncodeUnicodePointToUTF16(unsigned short * buffer, int codePoint) - { - int count = 0; - if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) - buffer[count++] = (unsigned short)codePoint; - else - { - int sub = codePoint - 0x10000; - int high = (sub >> 10) + 0xD800; - int low = (sub & 0x3FF) + 0xDC00; - buffer[count++] = (unsigned short)high; - buffer[count++] = (unsigned short)low; - } - return count; - } - - inline unsigned short ReverseBitOrder(unsigned short val) - { - int byte0 = val & 0xFF; - int byte1 = val >> 8; - return (unsigned short)(byte1 + (byte0 << 8)); - } - - inline int EncodeUnicodePointToUTF16Reversed(unsigned short * buffer, int codePoint) - { - int count = 0; - if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) - buffer[count++] = ReverseBitOrder((unsigned short)codePoint); - else - { - int sub = codePoint - 0x10000; - int high = (sub >> 10) + 0xD800; - int low = (sub & 0x3FF) + 0xDC00; - buffer[count++] = ReverseBitOrder((unsigned short)high); - buffer[count++] = ReverseBitOrder((unsigned short)low); - } - return count; - } - - class Encoding - { - public: - static Encoding * UTF8, * UTF16, *UTF16Reversed, * UTF32; - virtual void GetBytes(List& buffer, const String & str) = 0; - virtual String ToString(const char * buffer, int length) = 0; - virtual ~Encoding() - {} - }; - - class StreamWriter : public TextWriter - { - private: - List encodingBuffer; - RefPtr stream; - Encoding * encoding; - public: - StreamWriter(const String & path, Encoding * encoding = Encoding::UTF8); - StreamWriter(RefPtr stream, Encoding * encoding = Encoding::UTF8); - virtual void Write(const String & str); - virtual void Write(const char * str); - virtual void Close() - { - stream->Close(); - } - void ReleaseStream() - { - stream = 0; - } - }; - - class StreamReader : public TextReader - { - private: - RefPtr stream; - List buffer; - Encoding * encoding; - Index ptr; - char ReadBufferChar(); - void ReadBuffer(); - - Encoding * DetermineEncoding(); - protected: - virtual void ReadChar() - { - decodedCharPtr = 0; - int codePoint = 0; - if (encoding == Encoding::UTF8) - codePoint = GetUnicodePointFromUTF8([&](int) {return ReadBufferChar(); }); - else if (encoding == Encoding::UTF16) - codePoint = GetUnicodePointFromUTF16([&](int) {return ReadBufferChar(); }); - else if (encoding == Encoding::UTF16Reversed) - codePoint = GetUnicodePointFromUTF16Reversed([&](int) {return ReadBufferChar(); }); - else if (encoding == Encoding::UTF32) - codePoint = GetUnicodePointFromUTF32([&](int) {return ReadBufferChar(); }); - decodedCharSize = EncodeUnicodePointToUTF8(decodedChar, codePoint); - } - public: - StreamReader(const String & path); - StreamReader(RefPtr stream, Encoding * encoding = nullptr); - virtual String ReadLine(); - virtual String ReadToEnd(); - virtual bool IsEnd() - { - return ptr == buffer.getCount() && stream->IsEnd(); - } - virtual void Close() - { - stream->Close(); - } - void ReleaseStream() - { - stream = 0; - } - }; -} - -#endif diff --git a/source/core/token-reader.cpp b/source/core/token-reader.cpp deleted file mode 100644 index ea40c9ed9..000000000 --- a/source/core/token-reader.cpp +++ /dev/null @@ -1,768 +0,0 @@ -#include "token-reader.h" - -namespace Slang -{ - enum class TokenizeErrorType - { - InvalidCharacter, InvalidEscapeSequence - }; - - enum class State - { - Start, Identifier, Operator, Int, Hex, Fixed, Double, Char, String, MultiComment, SingleComment - }; - - enum class LexDerivative - { - None, Line, File - }; - - 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 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'); - } - - void ParseOperators(const String & str, List & tokens, TokenFlags& tokenFlags, int line, int col, int startPos, String fileName) - { - 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) - { - 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 == '=') - { - InsertToken(TokenType::OpEql, "=="); - pos += 2; - } - else - { - InsertToken(TokenType::OpAssign, "="); - pos++; - } - break; - case '!': - if (nextChar == '=') - { - InsertToken(TokenType::OpNeq, "!="); - pos += 2; - } - else - { - InsertToken(TokenType::OpNot, "!"); - pos++; - } - 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++; - } - 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 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 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) - { - 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; - } - }; - while (pos <= text.getLength()) - { - char curChar = (pos < text.getLength() ? text[pos] : ' '); - char nextChar = (pos < text.getLength() - 1) ? text[pos + 1] : '\0'; - if (lastPos != pos) - { - if (curChar == '\n') - { - line++; - col = 0; - } - else - col++; - lastPos = pos; - } - - switch (state) - { - 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 == -62 || curChar == -96) // -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#") - { - line = 0; - col = 0; - tokenBuilder.Clear(); - } - else if (tokenStr == "#line") - { - derivative = LexDerivative::Line; - tokenBuilder.Clear(); - } - else if (tokenStr == "#file") - { - derivative = LexDerivative::File; - tokenBuilder.Clear(); - line = 0; - col = 0; - } - else -#endif - 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(nextChar); - pos++; - } - 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) - { - 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')) - { - 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 == '+') - { - tokenBuilder.Append(nextChar); - pos++; - } - pos++; - } - else - { - if (curChar == 'f') - pos++; - InsertToken(TokenType::DoubleLiteral); - state = State::Start; - } - break; - case State::Double: - if (IsDigit(curChar)) - { - tokenBuilder.Append(curChar); - 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; - } - } - return tokenList; - } - List TokenizeText(const String & text) - { - return TokenizeText("", text); - } - - String EscapeStringLiteral(String str) - { - StringBuilder sb; - sb << "\""; - const Index length = str.getLength(); - const char*const data = str.getBuffer(); - for (Index i = 0; i < length; i++) - { - switch (data[i]) - { - case ' ': - sb << "\\s"; - break; - case '\n': - sb << "\\n"; - break; - case '\r': - sb << "\\r"; - break; - case '\t': - sb << "\\t"; - break; - case '\v': - sb << "\\v"; - break; - case '\'': - sb << "\\\'"; - break; - case '\"': - sb << "\\\""; - break; - case '\\': - sb << "\\\\"; - break; - default: - sb << data[i]; - break; - } - } - sb << "\""; - return sb.ProduceString(); - } - - String UnescapeStringLiteral(String str) - { - StringBuilder sb; - const Index length = str.getLength(); - const char*const data = str.getBuffer(); - for (Index i = 0; i < length; i++) - { - if (data[i] == '\\' && i < length - 1) - { - switch (data[i + 1]) - { - case 's': - sb << " "; - break; - case 't': - sb << '\t'; - break; - case 'n': - sb << '\n'; - break; - case 'r': - sb << '\r'; - break; - case 'v': - sb << '\v'; - break; - case '\'': - sb << '\''; - break; - case '\"': - sb << "\""; - break; - case '\\': - sb << "\\"; - break; - default: - i = i - 1; - sb << data[i]; - } - i++; - } - else - sb << data[i]; - } - return sb.ProduceString(); - } - - TokenReader::TokenReader(String text) - { - this->tokens = TokenizeText("", text); - tokenPtr = 0; - } -} diff --git a/source/core/token-reader.h b/source/core/token-reader.h deleted file mode 100644 index a5b9b3694..000000000 --- a/source/core/token-reader.h +++ /dev/null @@ -1,258 +0,0 @@ -#ifndef CORE_TOKEN_READER_H -#define CORE_TOKEN_READER_H - -#include "basic.h" - -namespace Slang -{ - 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, - }; - - class CodePosition - { - 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 - { - AtStartOfLine = 1 << 0, - AfterWhitespace = 1 << 1, - }; - typedef unsigned int TokenFlags; - - class Token - { - public: - TokenType Type = TokenType::Unknown; - String Content; - CodePosition Position; - TokenFlags flags; - 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); - } - }; - - class TextFormatException : public Exception - { - public: - TextFormatException(String message) - : Exception(message) - {} - }; - - class TokenReader - { - private: - bool legal; - List tokens; - int tokenPtr; - public: - TokenReader(String text); - int ReadInt() - { - auto token = ReadToken(); - bool neg = false; - if (token.Content == '-') - { - 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."); - } - unsigned int ReadUInt() - { - auto token = ReadToken(); - if (token.Type == TokenType::IntLiteral) - { - return StringToUInt(token.Content); - } - throw TextFormatException("Text parsing error: int expected."); - } - double ReadDouble() - { - auto token = ReadToken(); - bool neg = false; - if (token.Content == '-') - { - 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."); - } - float ReadFloat() - { - return (float)ReadDouble(); - } - String ReadWord() - { - auto token = ReadToken(); - if (token.Type == TokenType::Identifier) - { - return token.Content; - } - throw TextFormatException("Text parsing error: identifier expected."); - } - String Read(const char * expectedStr) - { - auto token = ReadToken(); - if (token.Content == expectedStr) - { - return token.Content; - } - throw TextFormatException("Text parsing error: \'" + String(expectedStr) + "\' expected."); - } - String Read(String expectedStr) - { - auto token = ReadToken(); - if (token.Content == expectedStr) - { - return token.Content; - } - throw TextFormatException("Text parsing error: \'" + expectedStr + "\' expected."); - } - - String ReadStringLiteral() - { - auto token = ReadToken(); - if (token.Type == TokenType::StringLiteral) - { - return token.Content; - } - throw TextFormatException("Text parsing error: string literal expected."); - } - void Back(int count) - { - tokenPtr -= count; - } - Token ReadToken() - { - if (tokenPtr < (int)tokens.getCount()) - { - auto &rs = tokens[tokenPtr]; - tokenPtr++; - return rs; - } - throw TextFormatException("Unexpected ending."); - } - Token NextToken(int offset = 0) - { - if (tokenPtr + offset < (int)tokens.getCount()) - return tokens[tokenPtr + offset]; - else - { - Token rs; - rs.Type = TokenType::Unknown; - return rs; - } - } - bool LookAhead(String token) - { - if (tokenPtr < (int)tokens.getCount()) - { - auto next = NextToken(); - return next.Content == token; - } - else - { - return false; - } - } - bool IsEnd() - { - return tokenPtr == (int)tokens.getCount(); - } - public: - bool IsLegalText() - { - return legal; - } - }; - - inline List Split(String text, char c) - { - List result; - StringBuilder sb; - for (Index i = 0; i < text.getLength(); i++) - { - if (text[i] == c) - { - auto str = sb.ToString(); - if (str.getLength() != 0) - result.add(str); - sb.Clear(); - } - else - sb << text[i]; - } - auto lastStr = sb.ToString(); - if (lastStr.getLength()) - result.add(lastStr); - return result; - } -} - - -#endif diff --git a/source/core/type-traits.h b/source/core/type-traits.h deleted file mode 100644 index 804b4d3fe..000000000 --- a/source/core/type-traits.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef CORELIB_TYPETRAITS_H -#define CORELIB_TYPETRAITS_H - -namespace Slang -{ - struct TraitResultYes - { - char x; - }; - struct TraitResultNo - { - char x[2]; - }; - - template - struct IsBaseOfTraitHost - { - operator B*() const { return nullptr; } - operator D*() { return nullptr; } - }; - - template - struct IsBaseOf - { - template - static TraitResultYes Check(D*, T) { return TraitResultYes(); } - static TraitResultNo Check(B*, int) { return TraitResultNo(); } - enum { Value = sizeof(Check(IsBaseOfTraitHost(), int())) == sizeof(TraitResultYes) }; - }; - - template - struct EnableIf {}; - - template - struct EnableIf { typedef T type; }; - - template - struct IsConvertible - { - static TraitResultYes Use(B) { return TraitResultYes(); }; - static TraitResultNo Use(...) { return TraitResultNo(); }; - enum { Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) }; - }; -} - -#endif -- cgit v1.2.3