summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-diagnostic-sink.cpp8
-rw-r--r--source/compiler-core/slang-downstream-compiler.cpp39
-rw-r--r--source/core/slang-char-encode.cpp181
-rw-r--r--source/core/slang-char-encode.h200
-rw-r--r--source/core/slang-common.h50
-rw-r--r--source/core/slang-dictionary.h27
-rw-r--r--source/core/slang-exception.h87
-rw-r--r--source/core/slang-file-system.cpp22
-rw-r--r--source/core/slang-io.cpp130
-rw-r--r--source/core/slang-io.h6
-rw-r--r--source/core/slang-riff.cpp185
-rw-r--r--source/core/slang-signal.cpp69
-rw-r--r--source/core/slang-signal.h44
-rw-r--r--source/core/slang-stream.cpp139
-rw-r--r--source/core/slang-stream.h87
-rw-r--r--source/core/slang-string-escape-util.cpp5
-rw-r--r--source/core/slang-string.cpp48
-rw-r--r--source/core/slang-string.h13
-rw-r--r--source/core/slang-text-io.cpp438
-rw-r--r--source/core/slang-text-io.h434
-rw-r--r--source/slang/slang-api.cpp19
-rw-r--r--source/slang/slang-compiler.cpp13
-rw-r--r--source/slang/slang-options.cpp3
-rw-r--r--source/slang/slang-repro.cpp26
-rw-r--r--source/slang/slang-serialize-types.cpp20
-rw-r--r--source/slang/slang-serialize.cpp17
-rw-r--r--source/slang/slang.cpp7
27 files changed, 1191 insertions, 1126 deletions
diff --git a/source/compiler-core/slang-diagnostic-sink.cpp b/source/compiler-core/slang-diagnostic-sink.cpp
index a6502abc9..c92610e85 100644
--- a/source/compiler-core/slang-diagnostic-sink.cpp
+++ b/source/compiler-core/slang-diagnostic-sink.cpp
@@ -112,7 +112,7 @@ static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int a
if (index >= argCount)
{
// TODO(tfoley): figure out what a good policy will be for "panic" situations like this
- throw InvalidOperationException("too few arguments for diagnostic message");
+ SLANG_INVALID_OPERATION("too few arguments for diagnostic message");
}
else
{
@@ -123,7 +123,7 @@ static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int a
break;
default:
- throw InvalidOperationException("invalid diagnostic message format");
+ SLANG_INVALID_OPERATION("invalid diagnostic message format");
break;
}
@@ -512,7 +512,7 @@ void DiagnosticSink::diagnoseImpl(DiagnosticInfo const& info, const UnownedStrin
if (info.severity >= Severity::Fatal)
{
// TODO: figure out a better policy for aborting compilation
- throw AbortCompilationException();
+ SLANG_ABORT_COMPILATION("");
}
}
@@ -573,7 +573,7 @@ void DiagnosticSink::diagnoseRaw(
if (severity >= Severity::Fatal)
{
// TODO: figure out a better policy for aborting compilation
- throw InvalidOperationException();
+ SLANG_ABORT_COMPILATION("");
}
}
diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp
index 2a172eb3a..9312554ae 100644
--- a/source/compiler-core/slang-downstream-compiler.cpp
+++ b/source/compiler-core/slang-downstream-compiler.cpp
@@ -391,20 +391,14 @@ SlangResult CommandLineDownstreamCompileResult::getBinary(ComPtr<ISlangBlob>& ou
return SLANG_OK;
}
+ List<uint8_t> contents;
// Read the binary
- try
- {
// Read the contents of the binary
- List<uint8_t> contents = File::readAllBytes(m_moduleFilePath);
+ SLANG_RETURN_ON_FAIL(File::readAllBytes(m_moduleFilePath, contents));
- m_binaryBlob = new ScopeRefObjectBlob(ListBlob::moveCreate(contents), m_temporaryFiles);
- outBlob = m_binaryBlob;
- return SLANG_OK;
- }
- catch (const Slang::IOException&)
- {
- return SLANG_FAIL;
- }
+ m_binaryBlob = new ScopeRefObjectBlob(ListBlob::moveCreate(contents), m_temporaryFiles);
+ outBlob = m_binaryBlob;
+ return SLANG_OK;
}
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/
@@ -428,15 +422,12 @@ static bool _isContentsInFile(const DownstreamCompiler::CompileOptions& options)
// file either from some specialized ISlangFileSystem, so this is probably as good as it gets
// until we can integrate directly to a C/C++ compiler through say a shared library where we can control
// file system access.
- try
+ String readContents;
+
+ if (SLANG_SUCCEEDED(File::readAllText(options.sourceContentsPath, readContents)))
{
- String readContents = File::readAllText(options.sourceContentsPath);
- // We should see if they are the same
return options.sourceContents == readContents.getUnownedSlice();
}
- catch (const Slang::IOException&)
- {
- }
}
return false;
}
@@ -484,17 +475,9 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio
}
// Write it out
- try
- {
- productFileSet->add(compileSourcePath);
-
- File::writeAllText(compileSourcePath, options.sourceContents);
- }
- catch (...)
- {
- return SLANG_FAIL;
- }
-
+ productFileSet->add(compileSourcePath);
+ SLANG_RETURN_ON_FAIL(File::writeAllText(compileSourcePath, options.sourceContents));
+
// Add it as a source file
options.sourceFiles.add(compileSourcePath);
}
diff --git a/source/core/slang-char-encode.cpp b/source/core/slang-char-encode.cpp
new file mode 100644
index 000000000..d061e34ba
--- /dev/null
+++ b/source/core/slang-char-encode.cpp
@@ -0,0 +1,181 @@
+#include "slang-char-encode.h"
+
+namespace Slang
+{
+
+class Utf8CharEncoding : public CharEncoding
+{
+public:
+ typedef CharEncoding Super;
+
+ virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override
+ {
+ ioBuffer.addRange((const Byte*)slice.begin(), slice.getLength());
+ }
+ virtual void decode(const Byte* bytes, int length, List<char>& ioChars) override
+ {
+ ioChars.addRange((const char*)bytes, length);
+ }
+ Utf8CharEncoding() : Super(CharEncodeType::UTF8) {}
+};
+
+class Utf32CharEncoding : public CharEncoding
+{
+public:
+ typedef CharEncoding Super;
+
+ virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override
+ {
+ Index ptr = 0;
+ while (ptr < slice.getLength())
+ {
+ const Char32 codePoint = getUnicodePointFromUTF8([&]() -> Byte
+ {
+ if (ptr < slice.getLength())
+ return slice[ptr++];
+ else
+ return '\0';
+ });
+ // Note: Assumes byte order is same as arch byte order
+ ioBuffer.addRange((const Byte*)&codePoint, 4);
+ }
+ }
+ virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override
+ {
+ // Note: Assumes bytes is Char32 aligned
+ SLANG_ASSERT((size_t(bytes) & 3) == 0);
+ const Char32* content = (const Char32*)bytes;
+ for (int i = 0; i < (length >> 2); i++)
+ {
+ char buf[5];
+ int count = encodeUnicodePointToUTF8(content[i], buf);
+ for (int j = 0; j < count; j++)
+ ioBuffer.addRange(buf, count);
+ }
+ }
+
+ Utf32CharEncoding() : Super(CharEncodeType::UTF32) {}
+};
+
+class Utf16CharEncoding : public CharEncoding //UTF16
+{
+public:
+ typedef CharEncoding Super;
+ Utf16CharEncoding(bool reverseOrder):
+ Super(reverseOrder ? CharEncodeType::UTF16Reversed : CharEncodeType::UTF16),
+ m_reverseOrder(reverseOrder)
+ {}
+ virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override
+ {
+ Index index = 0;
+ while (index < slice.getLength())
+ {
+ const Char32 codePoint = getUnicodePointFromUTF8([&]() -> Byte
+ {
+ if (index < slice.getLength())
+ return slice[index++];
+ else
+ return '\0';
+ });
+
+ Char16 buffer[2];
+ int count;
+ if (!m_reverseOrder)
+ count = encodeUnicodePointToUTF16(codePoint, buffer);
+ else
+ count = encodeUnicodePointToUTF16Reversed(codePoint, buffer);
+ ioBuffer.addRange((const Byte*)buffer, count * 2);
+ }
+ }
+ virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override
+ {
+ Index index = 0;
+ while (index < length)
+ {
+ const Char32 codePoint = getUnicodePointFromUTF16([&]() -> Byte
+ {
+ if (index < length)
+ return bytes[index++];
+ else
+ return Byte(0);
+ });
+
+ char buf[5];
+ int count = encodeUnicodePointToUTF8(codePoint, buf);
+ ioBuffer.addRange((const char*)buf, count);
+ }
+ }
+
+private:
+ bool m_reverseOrder = false;
+};
+
+/* static */CharEncodeType CharEncoding::determineEncoding(const Byte* bytes, size_t bytesCount, size_t& outOffset)
+{
+ // TODO(JS): Assumes the bytes are suitably aligned
+
+ if (bytesCount >= 3 && bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf)
+ {
+ outOffset = 3;
+ return CharEncodeType::UTF8;
+ }
+ else if (bytesCount >= 2)
+ {
+ Char16 c;
+ ::memcpy(&c, bytes, 2);
+
+ if (c == kUTF16Header)
+ {
+ outOffset = 2;
+ return CharEncodeType::UTF16;
+ }
+ else if (c == kUTF16ReversedHeader)
+ {
+ outOffset = 2;
+ return CharEncodeType::UTF16Reversed;
+ }
+ }
+ else
+ {
+ // If we don't have a 'mark' byte then we are bit stumped. We'll look for a null bytes and assume they mean we have a 16 bit encoding
+ for (size_t i = 0; i < bytesCount; i += 2)
+ {
+#if SLANG_LITTLE_ENDIAN
+ const auto low = bytes[i];
+ const auto high = bytes[i + 1];
+#else
+ const auto low = bytes[i + 1];
+ const auto high = bytes[i];
+#endif
+ if ((low == 0) ^ (high == 0))
+ {
+ outOffset = 2;
+ return (high == 0) ? CharEncodeType::UTF16 : CharEncodeType::UTF16Reversed;
+ }
+ }
+ }
+
+ // Assume it's UTF8 or 7 bit ascii which UTF8 is a superset of
+ outOffset = 0;
+ return CharEncodeType::UTF8;
+}
+
+static Utf8CharEncoding _utf8Encoding;
+static Utf16CharEncoding _utf16Encoding(false);
+static Utf16CharEncoding _utf16EncodingReversed(true);
+static Utf32CharEncoding _utf32Encoding;
+
+/* static */CharEncoding* const CharEncoding::g_encoding[Index(CharEncodeType::CountOf)]
+{
+ &_utf8Encoding, // UTF8,
+ &_utf16Encoding, // UTF16,
+ &_utf16EncodingReversed, // UTF16Reversed,
+ &_utf32Encoding, // UTF32,
+};
+
+CharEncoding* CharEncoding::UTF8 = &_utf8Encoding;
+CharEncoding* CharEncoding::UTF16 = &_utf16Encoding;
+CharEncoding* CharEncoding::UTF16Reversed = &_utf16EncodingReversed;
+CharEncoding* CharEncoding::UTF32 = &_utf32Encoding;
+
+} // namespace Slang
diff --git a/source/core/slang-char-encode.h b/source/core/slang-char-encode.h
new file mode 100644
index 000000000..a778cc3c9
--- /dev/null
+++ b/source/core/slang-char-encode.h
@@ -0,0 +1,200 @@
+#ifndef SLANG_CORE_CHAR_ENCODE_H
+#define SLANG_CORE_CHAR_ENCODE_H
+
+#include "slang-secure-crt.h"
+#include "slang-basic.h"
+
+namespace Slang
+{
+
+// NOTE! Order must be kept the same to match up with
+enum class CharEncodeType
+{
+ UTF8,
+ UTF16,
+ UTF16Reversed,
+ UTF32,
+ CountOf,
+};
+
+template <typename ReadByteFunc>
+Char32 getUnicodePointFromUTF8(const ReadByteFunc& readByte)
+{
+ Char32 codePoint = 0;
+ uint32_t leading = Byte(readByte());
+ uint32_t mask = 0x80;
+ Index count = 0;
+ while (leading & mask)
+ {
+ count++;
+ mask >>= 1;
+ }
+ codePoint = (leading & (mask - 1));
+ for (Index i = 1; i <= count - 1; i++)
+ {
+ codePoint <<= 6;
+ codePoint += (readByte() & 0x3F);
+ }
+ return codePoint;
+}
+
+template <typename ReadByteFunc>
+Char32 getUnicodePointFromUTF16(const ReadByteFunc& readByte)
+{
+ uint32_t byte0 = Byte(readByte());
+ uint32_t byte1 = Byte(readByte());
+ uint32_t word0 = byte0 + (byte1 << 8);
+ if (word0 >= 0xD800 && word0 <= 0xDFFF)
+ {
+ uint32_t byte2 = Byte(readByte());
+ uint32_t byte3 = Byte(readByte());
+ uint32_t word1 = byte2 + (byte3 << 8);
+ return Char32(((word0 & 0x3FF) << 10) + (word1 & 0x3FF) + 0x10000);
+ }
+ else
+ return Char32(word0);
+}
+
+template <typename ReadByteFunc>
+Char32 getUnicodePointFromUTF16Reversed(const ReadByteFunc& readByte)
+{
+ uint32_t byte0 = Byte(readByte());
+ uint32_t byte1 = Byte(readByte());
+ uint32_t word0 = (byte0 << 8) + byte1;
+ if (word0 >= 0xD800 && word0 <= 0xDFFF)
+ {
+ uint32_t byte2 = Byte(readByte());
+ uint32_t byte3 = Byte(readByte());
+ uint32_t word1 = (byte2 << 8) + byte3;
+ return Char32(((word0 & 0x3FF) << 10) + (word1 & 0x3FF));
+ }
+ else
+ return Char32(word0);
+}
+
+template <typename ReadByteFunc>
+Char32 getUnicodePointFromUTF32(const ReadByteFunc& readByte)
+{
+ uint32_t byte0 = Byte(readByte());
+ uint32_t byte1 = Byte(readByte());
+ uint32_t byte2 = Byte(readByte());
+ uint32_t byte3 = Byte(readByte());
+ return Char32(byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24));
+}
+
+// Encode functions return the amount of elements output to the buffer
+inline int encodeUnicodePointToUTF8(Char32 codePoint, char* outBuffer)
+{
+ char* const dst = outBuffer;
+ // TODO(JS): This supports 4 + 6 * 3 = 22 bits.
+ // The standard allows up to 0x10FFFF.
+ if (codePoint <= 0x7F)
+ {
+ dst[0] = char(codePoint);
+ return 1;
+ }
+ else if (codePoint <= 0x7FF)
+ {
+ dst[0] = char(0xC0 + (codePoint >> 6));
+ dst[1] = char(0x80 + (codePoint & 0x3F));
+ return 2;
+ }
+ else if (codePoint <= 0xFFFF)
+ {
+ dst[0] = char(0xE0 + (codePoint >> 12));
+ dst[1] = char(0x80 + ((codePoint >> 6) & (0x3F)));
+ dst[2] = char(0x80 + (codePoint & 0x3F));
+ return 3;
+ }
+ else
+ {
+ dst[0] = char(0xF0 + (codePoint >> 18));
+ dst[1] = char(0x80 + ((codePoint >> 12) & 0x3F));
+ dst[2] = char(0x80 + ((codePoint >> 6) & 0x3F));
+ dst[3] = char(0x80 + (codePoint & 0x3F));
+ return 4;
+ }
+}
+
+inline int encodeUnicodePointToUTF16(Char32 codePoint, Char16* outBuffer)
+{
+ Char16* const dst = outBuffer;
+ if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF))
+ {
+ dst[0] = Char16(codePoint);
+ return 1;
+ }
+ else
+ {
+ const uint32_t sub = codePoint - 0x10000;
+ dst[0] = Char16((sub >> 10) + 0xD800);
+ dst[1] = Char16((sub & 0x3FF) + 0xDC00);
+ return 2;
+ }
+}
+
+SLANG_FORCE_INLINE Char16 reverseByteOrder(Char16 val)
+{
+ return (val >> 8) | (val << 8);
+}
+
+inline int encodeUnicodePointToUTF16Reversed(Char32 codePoint, Char16* outBuffer)
+{
+ Char16* const dst = outBuffer;
+ if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF))
+ {
+ dst[0] = reverseByteOrder(Char16(codePoint));
+ return 1;
+ }
+ else
+ {
+ const uint32_t sub = codePoint - 0x10000;
+ const uint32_t high = (sub >> 10) + 0xD800;
+ const uint32_t low = (sub & 0x3FF) + 0xDC00;
+ dst[0] = reverseByteOrder(Char16(high));
+ dst[1] = reverseByteOrder(Char16(low));
+ return 2;
+ }
+}
+
+static const Char16 kUTF16Header = 0xFEFF;
+static const Char16 kUTF16ReversedHeader = 0xFFFE;
+
+class CharEncoding
+{
+public:
+ static CharEncoding* UTF8,* UTF16,* UTF16Reversed,* UTF32;
+
+ /// Encode Utf8 held in slice append into ioBuffer
+ virtual void encode(const UnownedStringSlice& str, List<Byte>& ioBuffer) = 0;
+ /// Decode buffer into Utf8 held in ioBuffer
+ virtual void decode(const Byte* buffer, int length, List<char>& ioBuffer) = 0;
+
+ virtual ~CharEncoding() {}
+
+ /// Get the encoding type
+ CharEncodeType getEncodingType() const { return m_encodingType; }
+
+ /// Given some bytes determines a character encoding type, based on the initial bytes.
+ /// If can't be determined will assume UTF8.
+ /// Outputs the offset to the first non mark in outOffset
+ static CharEncodeType determineEncoding(const Byte* bytes, size_t bytesCount, size_t& outOffset);
+
+ /// Get the
+ static CharEncoding* getEncoding(CharEncodeType type) { return g_encoding[Index(type)]; }
+
+ CharEncoding(CharEncodeType encodingType) :
+ m_encodingType(encodingType)
+ {
+ }
+
+protected:
+
+ CharEncodeType m_encodingType;
+
+ static CharEncoding*const g_encoding[Index(CharEncodeType::CountOf)];
+};
+
+}
+
+#endif
diff --git a/source/core/slang-common.h b/source/core/slang-common.h
index 717b63740..eb6502b41 100644
--- a/source/core/slang-common.h
+++ b/source/core/slang-common.h
@@ -7,11 +7,7 @@
#include <stdint.h>
-#ifdef __GNUC__
-#define CORE_LIB_ALIGN_16(x) x __attribute__((aligned(16)))
-#else
-#define CORE_LIB_ALIGN_16(x) __declspec(align(16)) x
-#endif
+#include "slang-signal.h"
#define VARIADIC_TEMPLATE
@@ -27,13 +23,33 @@ namespace Slang
typedef SlangUInt UInt;
typedef SlangInt Int;
+ static const UInt kMaxUInt = ~UInt(0);
+ static const Int kMaxInt = Int(kMaxUInt >> 1);
+
// typedef unsigned short Word;
typedef intptr_t PtrInt;
+ // TODO(JS): It looks like Index is actually 64 bit on 64 bit targets(!)
+ // Previous discussions landed on Index being int32_t.
+
// Type used for indexing, in arrays/views etc
typedef Int Index;
+ static const Index kMaxIndex = kMaxInt;
+
+ typedef uint8_t Byte;
+
+ // TODO(JS):
+ // Perhaps these should be named Utf8, Utf16 and UnicodePoint/Rune/etc? For now, just keep it simple
+ //
+ typedef char Char8;
+ // 16 bit character. Note much like in utf8, a character may or may not represent a code point (it can be part of a code point).
+ typedef uint16_t Char16;
+
+ // Can always hold a unicode code point.
+ typedef uint32_t Char32;
+
template <typename T>
inline T&& _Move(T & obj)
{
@@ -48,15 +64,7 @@ namespace Slang
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
-
+// TODO: Shouldn't these be SLANG_ prefixed?
#ifdef _MSC_VER
#define UNREACHABLE_RETURN(x)
#define UNREACHABLE(x)
@@ -65,27 +73,17 @@ namespace Slang
#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_EXPECT(VALUE, MSG) if(VALUE) {} else SLANG_ASSERT_FAILURE(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_ASSERT(VALUE) if(VALUE) {} else SLANG_ASSERT_FAILURE(#VALUE)
#define SLANG_RELEASE_EXPECT(VALUE, WHAT) if(VALUE) {} else SLANG_UNEXPECTED(WHAT)
template<typename T> void slang_use_obj(T&) {}
diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h
index 51b61de60..eef7d6908 100644
--- a/source/core/slang-dictionary.h
+++ b/source/core/slang-dictionary.h
@@ -171,7 +171,7 @@ namespace Slang
}
if (insertPos != -1)
return FindPositionResult(-1, insertPos);
- throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::getHashCode.");
+ SLANG_ASSERT_FAILURE("Hash map is full. This indicates an error in Key::Equal or Key::getHashCode.");
}
TValue & _Insert(KeyValuePair<TKey, TValue>&& kvPair, int pos)
{
@@ -217,12 +217,12 @@ namespace Slang
return true;
}
else
- throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
void Add(KeyValuePair<TKey, TValue>&& kvPair)
{
if (!AddIfNotExists(_Move(kvPair)))
- throw KeyExistsException("The key already exists in Dictionary.");
+ SLANG_ASSERT_FAILURE("The key already exists in Dictionary.");
}
TValue& Set(KeyValuePair<TKey, TValue>&& kvPair)
{
@@ -236,7 +236,7 @@ namespace Slang
return _Insert(_Move(kvPair), pos.InsertionPosition);
}
else
- throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
public:
class Iterator
@@ -358,7 +358,7 @@ namespace Slang
return nullptr;
}
else
- throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
/// This differs from TryGetValueOrAdd, in that it always returns the Value held in the Dictionary.
@@ -379,7 +379,7 @@ namespace Slang
return _Insert(_Move(kvPair), pos.InsertionPosition);
}
else
- throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
template<typename KeyType>
@@ -440,7 +440,7 @@ namespace Slang
return dict->hashMap[pos.ObjectPosition].Value;
}
else
- throw KeyNotFoundException("The key does not exists in dictionary.");
+ SLANG_ASSERT_FAILURE("The key does not exists in dictionary.");
}
inline TValue & operator()() const
{
@@ -742,8 +742,7 @@ namespace Slang
}
if (insertPos != -1)
return FindPositionResult(-1, insertPos);
- throw InvalidOperationException(
- "Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode.");
+ SLANG_ASSERT_FAILURE("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode.");
}
TValue& _Insert(KeyValuePair<TKey, TValue>&& kvPair, int pos)
{
@@ -791,13 +790,12 @@ namespace Slang
return true;
}
else
- throw InvalidOperationException("Inconsistent find result returned. This is a "
- "bug in Dictionary implementation.");
+ SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
void Add(KeyValuePair<TKey, TValue>&& kvPair)
{
if (!AddIfNotExists(_Move(kvPair)))
- throw KeyExistsException("The key already exists in Dictionary.");
+ SLANG_ASSERT_FAILURE("The key already exists in Dictionary.");
}
TValue& Set(KeyValuePair<TKey, TValue>&& kvPair)
{
@@ -814,8 +812,7 @@ namespace Slang
return _Insert(_Move(kvPair), pos.InsertionPosition);
}
else
- throw InvalidOperationException("Inconsistent find result returned. This is a "
- "bug in Dictionary implementation.");
+ SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation.");
}
public:
@@ -923,7 +920,7 @@ namespace Slang
}
else
{
- throw KeyNotFoundException("The key does not exists in dictionary.");
+ SLANG_ASSERT_FAILURE("The key does not exists in dictionary.");
}
}
inline TValue& operator()() const { return GetValue(); }
diff --git a/source/core/slang-exception.h b/source/core/slang-exception.h
index 91139e298..3c5621d7f 100644
--- a/source/core/slang-exception.h
+++ b/source/core/slang-exception.h
@@ -6,6 +6,13 @@
namespace Slang
{
+ // NOTE!
+ // Exceptions should not generally be used in core/compiler-core, use the 'signal' mechanism
+ // ideally using the macros in the slang-signal.h such as `SLANG_UNEXPECTED`
+ //
+ // If core/compiler-core libraries are compiled with SLANG_DISABLE_EXCEPTIONS,
+ // these classes will *never* be thrown.
+
class Exception
{
public:
@@ -21,18 +28,6 @@ namespace Slang
{}
};
- class IndexOutofRangeException : public Exception
- {
- public:
- IndexOutofRangeException()
- {}
- IndexOutofRangeException(const String & message)
- : Exception(message)
- {
- }
-
- };
-
class InvalidOperationException : public Exception
{
public:
@@ -44,73 +39,7 @@ namespace Slang
}
};
-
- 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:
diff --git a/source/core/slang-file-system.cpp b/source/core/slang-file-system.cpp
index 8dd01ebf0..52ec40c07 100644
--- a/source/core/slang-file-system.cpp
+++ b/source/core/slang-file-system.cpp
@@ -201,26 +201,10 @@ SlangResult OSFileSystem::enumeratePathContents(const char* path, FileSystemCont
SlangResult OSFileSystem::saveFile(const char* pathIn, const void* data, size_t size)
{
SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
-
const String path = _fixPathDelimiters(pathIn);
-
- try
- {
- FileStream stream(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite);
-
- int64_t numWritten = stream.write(data, size);
-
- if (numWritten != int64_t(size))
- {
- return SLANG_FAIL;
- }
-
- }
- catch (const IOException&)
- {
- return SLANG_E_CANNOT_OPEN;
- }
-
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
+ SLANG_RETURN_ON_FAIL(stream.write(data, size));
return SLANG_OK;
}
diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp
index 0755a6a2f..162e49980 100644
--- a/source/core/slang-io.cpp
+++ b/source/core/slang-io.cpp
@@ -825,94 +825,98 @@ namespace Slang
return _getExecutablePath();
}
- Slang::String File::readAllText(const Slang::String& fileName)
+ SlangResult File::readAllText(const Slang::String& fileName, String& outText)
{
- StreamReader reader(new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
- return reader.ReadToEnd();
+ RefPtr<FileStream> stream(new FileStream);
+ SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
+
+ StreamReader reader;
+ SLANG_RETURN_ON_FAIL(reader.init(stream));
+ SLANG_RETURN_ON_FAIL(reader.readToEnd(outText));
+
+ return SLANG_OK;
}
- Slang::List<unsigned char> File::readAllBytes(const Slang::String& fileName)
+ SlangResult File::readAllBytes(const Slang::String& path, Slang::List<unsigned char>& out)
{
- RefPtr<FileStream> fs = new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
- List<unsigned char> buffer;
- while (!fs->isEnd())
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
+
+ const Int64 start = stream.getPosition();
+ stream.seek(SeekOrigin::End, 0);
+ const Int64 end = stream.getPosition();
+ stream.seek(SeekOrigin::Start, start);
+
+ const Int64 positionSizeInBytes = end - start;
+
+ if (UInt64(positionSizeInBytes) > UInt64(kMaxIndex))
{
- unsigned char ch;
- int read = (int)fs->read(&ch, 1);
- if (read)
- buffer.add(ch);
- else
- break;
+ // It's too large to fit in memory.
+ return SLANG_FAIL;
}
- return _Move(buffer);
+
+ const Index sizeInBytes = Index(positionSizeInBytes);
+
+ out.setCount(sizeInBytes);
+
+ size_t readSizeInBytes;
+ SLANG_RETURN_ON_FAIL(stream.read(out.getBuffer(), sizeInBytes, readSizeInBytes));
+
+ // If not all read just return an error
+ return (size_t(sizeInBytes) == readSizeInBytes) ? SLANG_OK : SLANG_FAIL;
}
SlangResult File::readAllBytes(const String& path, ScopedAllocation& out)
{
- try
- {
- FileStream stream(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
-
- const Int64 start = stream.getPosition();
- stream.seek(SeekOrigin::End, 0);
- const Int64 end = stream.getPosition();
- stream.seek(SeekOrigin::Start, start);
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
- const Int64 positionSizeInBytes = end - start;
+ const Int64 start = stream.getPosition();
+ stream.seek(SeekOrigin::End, 0);
+ const Int64 end = stream.getPosition();
+ stream.seek(SeekOrigin::Start, start);
- if (UInt64(positionSizeInBytes) > UInt64(~size_t(0)))
- {
- // It's too large to fit in memory.
- return SLANG_FAIL;
- }
+ const Int64 positionSizeInBytes = end - start;
- const size_t sizeInBytes = size_t(positionSizeInBytes);
- void* data = out.allocate(sizeInBytes);
- if (!data)
- {
- return SLANG_E_OUT_OF_MEMORY;
- }
+ if (UInt64(positionSizeInBytes) > UInt64(~size_t(0)))
+ {
+ // It's too large to fit in memory.
+ return SLANG_FAIL;
+ }
- const size_t readSizeInBytes = stream.read(data, sizeInBytes);
+ const size_t sizeInBytes = size_t(positionSizeInBytes);
- // If not all read just return an error
- if (sizeInBytes != readSizeInBytes)
- {
- return SLANG_FAIL;
- }
- }
- catch (const IOException&)
+ void* data = out.allocate(sizeInBytes);
+ if (!data)
{
- return SLANG_FAIL;
+ return SLANG_E_OUT_OF_MEMORY;
}
- return SLANG_OK;
+
+ size_t readSizeInBytes;
+ SLANG_RETURN_ON_FAIL(stream.read(data, sizeInBytes, readSizeInBytes));
+
+ // If not all read just return an error
+ return (sizeInBytes == readSizeInBytes) ? SLANG_OK : SLANG_FAIL;
}
SlangResult File::writeAllBytes(const String& path, const void* data, size_t size)
{
- try
- {
- FileStream stream(path, FileMode::Create, FileAccess::Write, FileShare::ReadWrite);
-
- const size_t writeSizeInBytes = stream.write(data, size);
-
- // If not all written just return an error
- if (size != writeSizeInBytes)
- {
- return SLANG_FAIL;
- }
- }
- catch (const IOException&)
- {
- return SLANG_FAIL;
- }
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
+ SLANG_RETURN_ON_FAIL(stream.write(data, size));
return SLANG_OK;
}
- void File::writeAllText(const Slang::String& fileName, const Slang::String& text)
+ SlangResult File::writeAllText(const Slang::String& fileName, const Slang::String& text)
{
- StreamWriter writer(new FileStream(fileName, FileMode::Create));
- writer.Write(text);
+ RefPtr<FileStream> stream = new FileStream;
+ SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create));
+
+ StreamWriter writer;
+ SLANG_RETURN_ON_FAIL(writer.init(stream));
+ SLANG_RETURN_ON_FAIL(writer.write(text));
+
+ return SLANG_OK;
}
diff --git a/source/core/slang-io.h b/source/core/slang-io.h
index a077d416b..50ce67784 100644
--- a/source/core/slang-io.h
+++ b/source/core/slang-io.h
@@ -14,12 +14,12 @@ namespace Slang
public:
static bool exists(const String& fileName);
- static String readAllText(const String& fileName);
+ static SlangResult readAllText(const String& fileName, String& outString);
- static List<unsigned char> readAllBytes(const String& fileName);
+ static SlangResult readAllBytes(const String& fileName, List<unsigned char>& out);
static SlangResult readAllBytes(const String& fileName, ScopedAllocation& out);
- static void writeAllText(const String& fileName, const String& text);
+ static SlangResult writeAllText(const String& fileName, const String& text);
static SlangResult writeAllBytes(const String& fileName, const void* data, size_t size);
diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp
index 482c35e81..670fed7a2 100644
--- a/source/core/slang-riff.cpp
+++ b/source/core/slang-riff.cpp
@@ -22,27 +22,18 @@ namespace Slang
}
// Skip the payload (we don't need to skip the Chunk because that was already read
- stream->seek(SeekOrigin::Current, chunkSize - sizeof(RiffHeader));
+ SLANG_RETURN_ON_FAIL(stream->seek(SeekOrigin::Current, chunkSize - sizeof(RiffHeader)));
return SLANG_OK;
}
/* static */SlangResult RiffUtil::readChunk(Stream* stream, RiffHeader& outChunk)
{
- try
- {
- stream->read(&outChunk, sizeof(RiffHeader));
- }
- catch (const IOException&)
- {
- return SLANG_FAIL;
- }
-
+ size_t readBytes;
+ SLANG_RETURN_ON_FAIL(stream->read(&outChunk, sizeof(RiffHeader), readBytes));
// TODO(JS): Could handle endianness issues here...
-
- return SLANG_OK;
+ return (readBytes == sizeof(RiffHeader)) ? SLANG_OK : SLANG_FAIL;
}
-
/* static */SlangResult RiffUtil::writeData(const RiffHeader* header, size_t headerSize, const void* payload, size_t payloadSize, Stream* out)
{
SLANG_ASSERT(uint64_t(payloadSize) <= uint64_t(0xfffffffff));
@@ -54,56 +45,43 @@ namespace Slang
chunk.type = header->type;
chunk.size = uint32_t(headerSize - sizeof(RiffHeader) + payloadSize);
- try
- {
- // The chunk
- out->write(&chunk, sizeof(RiffHeader));
+ // The chunk
+ SLANG_RETURN_ON_FAIL(out->write(&chunk, sizeof(RiffHeader)));
- // Remainder of header
- if (headerSize > sizeof(RiffHeader))
- {
- // The rest of the header
- out->write(header + 1, headerSize - sizeof(RiffHeader));
- }
+ // Remainder of header
+ if (headerSize > sizeof(RiffHeader))
+ {
+ // The rest of the header
+ SLANG_RETURN_ON_FAIL(out->write(header + 1, headerSize - sizeof(RiffHeader)));
+ }
- // Write the payload
- out->write(payload, payloadSize);
+ // Write the payload
+ SLANG_RETURN_ON_FAIL(out->write(payload, payloadSize));
- // The riff spec requires all chunks are 4 byte aligned (even if size is not)
- size_t padSize = getPadSize(payloadSize);
- if (padSize - payloadSize)
- {
- uint8_t end[kRiffPadSize] = { 0 };
- out->write(end, padSize - payloadSize);
- }
- }
- catch (const IOException&)
+ // The riff spec requires all chunks are 4 byte aligned (even if size is not)
+ size_t padSize = getPadSize(payloadSize);
+ if (padSize - payloadSize)
{
- return SLANG_FAIL;
+ uint8_t end[kRiffPadSize] = { 0 };
+ SLANG_RETURN_ON_FAIL(out->write(end, padSize - payloadSize));
}
-
+
return SLANG_OK;
}
/* static */SlangResult RiffUtil::readPayload(Stream* stream, size_t size, void* outData, size_t& outReadSize)
{
outReadSize = 0;
- try
- {
- stream->read(outData, size);
- const size_t alignedSize = getPadSize(size);
- // Skip to the alignment
- if (alignedSize > size)
- {
- stream->seek(SeekOrigin::Current, alignedSize - size);
- }
- outReadSize = alignedSize;
- }
- catch (const IOException&)
+
+ SLANG_RETURN_ON_FAIL(stream->readExactly(outData, size));
+
+ const size_t alignedSize = getPadSize(size);
+ // Skip to the alignment
+ if (alignedSize > size)
{
- return SLANG_FAIL;
+ SLANG_RETURN_ON_FAIL(stream->seek(SeekOrigin::Current, alignedSize - size));
}
-
+ outReadSize = alignedSize;
return SLANG_OK;
}
@@ -118,19 +96,12 @@ namespace Slang
*outHeader = chunk;
- try
- {
- // Read the header
- if (headerSize > sizeof(RiffHeader))
- {
- stream->read(outHeader + 1, headerSize - sizeof(RiffHeader));
- }
- }
- catch (const IOException&)
+ // Read the header
+ if (headerSize > sizeof(RiffHeader))
{
- return SLANG_FAIL;
+ SLANG_RETURN_ON_FAIL(stream->readExactly(outHeader + 1, headerSize - sizeof(RiffHeader)));
}
-
+
const size_t payloadSize = chunk.size - (headerSize - sizeof(RiffHeader));
size_t readSize;
data.setCount(payloadSize);
@@ -146,14 +117,7 @@ namespace Slang
if (isListType(outHeader.chunk.type))
{
// Read the sub type
- try
- {
- stream->read(&outHeader.subType, sizeof(RiffListHeader) - sizeof(RiffHeader));
- }
- catch (const IOException&)
- {
- return SLANG_FAIL;
- }
+ SLANG_RETURN_ON_FAIL(stream->readExactly(&outHeader.subType, sizeof(RiffListHeader) - sizeof(RiffHeader)));
}
return SLANG_OK;
@@ -251,65 +215,58 @@ struct DumpVisitor : public RiffContainer::Visitor
listHeader.chunk.size = uint32_t(list->m_payloadSize);
listHeader.subType = list->getSubType();
- try
- {
- // Write the header
- stream->write(&listHeader, sizeof(listHeader));
+ // Write the header
+ SLANG_RETURN_ON_FAIL(stream->write(&listHeader, sizeof(listHeader)));
// Write the contained chunks
- Chunk* chunk = list->m_containedChunks;
- while (chunk)
+ Chunk* chunk = list->m_containedChunks;
+ while (chunk)
+ {
+ switch (chunk->m_kind)
{
- switch (chunk->m_kind)
+ case Chunk::Kind::List:
{
- case Chunk::Kind::List:
- {
- auto listChunk = static_cast<ListChunk*>(chunk);
- // It's a container
- SLANG_RETURN_ON_FAIL(write(listChunk, false, stream));
- break;
- }
- case Chunk::Kind::Data:
- {
- auto dataChunk = static_cast<DataChunk*>(chunk);
+ auto listChunk = static_cast<ListChunk*>(chunk);
+ // It's a container
+ SLANG_RETURN_ON_FAIL(write(listChunk, false, stream));
+ break;
+ }
+ case Chunk::Kind::Data:
+ {
+ auto dataChunk = static_cast<DataChunk*>(chunk);
- // Must be a regular chunk with data
- RiffHeader chunkHeader;
- chunkHeader.type = dataChunk->m_fourCC;
- chunkHeader.size = uint32_t(dataChunk->m_payloadSize);
+ // Must be a regular chunk with data
+ RiffHeader chunkHeader;
+ chunkHeader.type = dataChunk->m_fourCC;
+ chunkHeader.size = uint32_t(dataChunk->m_payloadSize);
- stream->write(&chunkHeader, sizeof(chunkHeader));
+ SLANG_RETURN_ON_FAIL(stream->write(&chunkHeader, sizeof(chunkHeader)));
- RiffContainer::Data* data = dataChunk->m_dataList;
- while (data)
- {
- stream->write(data->getPayload(), data->getSize());
+ RiffContainer::Data* data = dataChunk->m_dataList;
+ while (data)
+ {
+ SLANG_RETURN_ON_FAIL(stream->write(data->getPayload(), data->getSize()));
- // Next but of data
- data = data->m_next;
- }
+ // Next but of data
+ data = data->m_next;
+ }
- // Need to write for alignment
- const size_t remainingSize = getPadSize(dataChunk->m_payloadSize) - dataChunk->m_payloadSize;
+ // Need to write for alignment
+ const size_t remainingSize = getPadSize(dataChunk->m_payloadSize) - dataChunk->m_payloadSize;
- if (remainingSize)
- {
- static const uint8_t trailing[kRiffPadSize] = { 0 };
- stream->write(trailing, remainingSize);
- }
+ if (remainingSize)
+ {
+ static const uint8_t trailing[kRiffPadSize] = { 0 };
+ SLANG_RETURN_ON_FAIL(stream->write(trailing, remainingSize));
}
- default: break;
}
-
- // Next
- chunk = chunk->m_next;
+ default: break;
}
- }
- catch (const IOException&)
- {
- return SLANG_FAIL;
- }
+ // Next
+ chunk = chunk->m_next;
+ }
+
return SLANG_OK;
}
diff --git a/source/core/slang-signal.cpp b/source/core/slang-signal.cpp
new file mode 100644
index 000000000..9641fe5f7
--- /dev/null
+++ b/source/core/slang-signal.cpp
@@ -0,0 +1,69 @@
+#include "slang-signal.h"
+
+#include "slang-exception.h"
+
+#include "stdio.h"
+
+namespace Slang
+{
+
+static const char* _getSignalTypeAsText(SignalType type)
+{
+ switch (type)
+ {
+ case SignalType::AssertFailure: return "assert failure";
+ case SignalType::Unimplemented: return "unimplemented";
+ case SignalType::Unreachable: return "hit unreachable code";
+ case SignalType::Unexpected: return "unexpected";
+ case SignalType::InvalidOperation: return "invalid operation";
+ case SignalType::AbortCompilation: return "abort compilation";
+ default: return "unhandled";
+ }
+}
+
+String _getMessage(SignalType type, char const* message)
+{
+ StringBuilder buf;
+ const char* const typeText = _getSignalTypeAsText(type);
+ buf << typeText;
+ if (message)
+ {
+ buf << ": " << message;
+ }
+
+ return buf.ProduceString();
+}
+
+// One point of having as a single function is a choke point both for handling (allowing different
+// handling scenarios) as well as a choke point to set a breakpoint to catch 'signal' types
+SLANG_RETURN_NEVER void handleSignal(SignalType type, char const* message)
+{
+ StringBuilder buf;
+ const char*const typeText = _getSignalTypeAsText(type);
+ buf << typeText << ": " << message;
+
+ // Can be useful to enable during debug when problem is on CI
+ if (false)
+ {
+ printf("%s\n", _getMessage(type, message).getBuffer());
+ }
+
+#if SLANG_HAS_EXCEPTIONS
+ switch (type)
+ {
+ case SignalType::InvalidOperation: throw InvalidOperationException(_getMessage(type, message));
+ case SignalType::AbortCompilation: throw AbortCompilationException();
+ default: throw InternalError(_getMessage(type, message));
+ }
+#else
+ // Attempt to drop out into the debugger. If a debugger isn't attached this will likely crash - which is probably the best
+ // we can do.
+
+ SLANG_BREAKPOINT(0);
+
+ // 'panic'. Exit with an error code as we can't throw or catch.
+ exit(-1);
+#endif
+}
+
+}
diff --git a/source/core/slang-signal.h b/source/core/slang-signal.h
new file mode 100644
index 000000000..2151bdcfe
--- /dev/null
+++ b/source/core/slang-signal.h
@@ -0,0 +1,44 @@
+#ifndef SLANG_CORE_SIGNAL_H
+#define SLANG_CORE_SIGNAL_H
+
+#include "slang-common.h"
+
+namespace Slang
+{
+
+enum class SignalType
+{
+ Unexpected,
+ Unimplemented,
+ AssertFailure,
+ Unreachable,
+ InvalidOperation,
+ AbortCompilation,
+};
+
+
+// Note that message can be passed as nullptr for no message.
+SLANG_RETURN_NEVER void handleSignal(SignalType type, char const* message);
+
+#define SLANG_UNEXPECTED(reason) \
+ ::Slang::handleSignal(::Slang::SignalType::Unexpected, reason)
+
+#define SLANG_UNIMPLEMENTED_X(what) \
+ ::Slang::handleSignal(::Slang::SignalType::Unimplemented, what)
+
+#define SLANG_UNREACHABLE(msg) \
+ ::Slang::handleSignal(::Slang::SignalType::Unreachable, msg)
+
+#define SLANG_ASSERT_FAILURE(msg) \
+ ::Slang::handleSignal(::Slang::SignalType::AssertFailure, msg)
+
+#define SLANG_INVALID_OPERATION(msg) \
+ ::Slang::handleSignal(::Slang::SignalType::InvalidOperation, msg)
+
+#define SLANG_ABORT_COMPILATION(msg) \
+ ::Slang::handleSignal(::Slang::SignalType::AbortCompilation, msg)
+
+
+}
+
+#endif
diff --git a/source/core/slang-stream.cpp b/source/core/slang-stream.cpp
index c4ba27927..f938eb886 100644
--- a/source/core/slang-stream.cpp
+++ b/source/core/slang-stream.cpp
@@ -9,33 +9,53 @@ namespace Slang
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-FileStream::FileStream(const String& fileName, FileMode fileMode)
+SlangResult Stream::readExactly(void* buffer, size_t length)
+{
+ size_t readBytes;
+ SLANG_RETURN_ON_FAIL(read(buffer, length, readBytes));
+ return (readBytes == length) ? SLANG_OK : SLANG_FAIL;
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+FileStream::FileStream() :
+ m_handle(nullptr),
+ m_fileAccess(FileAccess::None),
+ m_endReached(false)
+{
+}
+
+SlangResult FileStream::init(const String& fileName, FileMode fileMode)
{
const FileAccess access = (fileMode == FileMode::Open) ? FileAccess::Read : FileAccess::Write;
- _init(fileName, fileMode, access, FileShare::None);
+ return _init(fileName, fileMode, access, FileShare::None);
}
-FileStream::FileStream(const String& fileName, FileMode fileMode, FileAccess access, FileShare share)
+SlangResult FileStream::init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share)
{
- _init(fileName, fileMode, access, share);
+ return _init(fileName, fileMode, access, share);
}
-void FileStream::_init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share)
+SlangResult FileStream::_init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share)
{
+ // Make sure it's closed to start with
+ close();
+
if (access == FileAccess::None)
{
- throw ArgumentException("FileAccess::None not valid to create a FileStream.");
+ SLANG_ASSERT(!"FileAccess::None not valid to create a FileStream.");
+ return SLANG_E_INVALID_ARG;
}
- // Default to no access, until stream is fully constructed
- m_fileAccess = FileAccess::None;
-
const char* mode = "rt";
switch (fileMode)
{
case FileMode::Create:
if (access == FileAccess::Read)
- throw ArgumentException("Read-only access is incompatible with Create mode.");
+ {
+ SLANG_ASSERT(!"Read-only access is incompatible with Create mode.");
+ return SLANG_E_INVALID_ARG;
+ }
else if (access == FileAccess::ReadWrite)
{
mode = "w+b";
@@ -62,10 +82,13 @@ void FileStream::_init(const String& fileName, FileMode fileMode, FileAccess acc
case FileMode::CreateNew:
if (File::exists(fileName))
{
- throw IOException("Failed opening '" + fileName + "', file already exists.");
+ return SLANG_E_CANNOT_OPEN;
}
if (access == FileAccess::Read)
- throw ArgumentException("Read-only access is incompatible with Create mode.");
+ {
+ SLANG_ASSERT(!"Read-only access is incompatible with Create mode.");
+ return SLANG_E_INVALID_ARG;
+ }
else if (access == FileAccess::ReadWrite)
{
mode = "w+b";
@@ -77,7 +100,10 @@ void FileStream::_init(const String& fileName, FileMode fileMode, FileAccess acc
break;
case FileMode::Append:
if (access == FileAccess::Read)
- throw ArgumentException("Read-only access is incompatible with Append mode.");
+ {
+ SLANG_ASSERT(!"Read-only access is incompatible with Append mode.");
+ return SLANG_E_INVALID_ARG;
+ }
else if (access == FileAccess::ReadWrite)
{
mode = "a+b";
@@ -122,8 +148,8 @@ void FileStream::_init(const String& fileName, FileMode fileMode, FileAccess acc
shFlag = _SH_DENYNO;
break;
default:
- throw ArgumentException("Invalid file share mode.");
- break;
+ SLANG_ASSERT(!"Invalid file share mode.");
+ return SLANG_FAIL;
}
if (share == FileShare::None)
#pragma warning(suppress:4996)
@@ -135,11 +161,12 @@ void FileStream::_init(const String& fileName, FileMode fileMode, FileAccess acc
#endif
if (!m_handle)
{
- throw IOException("Cannot open file '" + fileName + "'");
+ return SLANG_E_CANNOT_OPEN;
}
// Just set the access specified
m_fileAccess = access;
+ return SLANG_OK;
}
FileStream::~FileStream()
@@ -162,7 +189,7 @@ Int64 FileStream::getPosition()
#endif
}
-void FileStream::seek(SeekOrigin seekOrigin, Int64 offset)
+SlangResult FileStream::seek(SeekOrigin seekOrigin, Int64 offset)
{
int fseekOrigin;
switch (seekOrigin)
@@ -177,8 +204,8 @@ void FileStream::seek(SeekOrigin seekOrigin, Int64 offset)
fseekOrigin = SEEK_CUR;
break;
default:
- throw NotSupportedException("Unsupported seek origin.");
- break;
+ SLANG_ASSERT(!"Unsupported seek origin.");
+ return SLANG_FAIL;
}
// If endReached is intended to be like feof - then doing a seek will reset it
@@ -190,34 +217,37 @@ void FileStream::seek(SeekOrigin seekOrigin, Int64 offset)
int rs = fseek(m_handle, (long int)offset, fseekOrigin);
#endif
- if (rs != 0)
- {
- throw IOException("FileStream seek failed.");
- }
+ // If rs != 0 then the the seek failed
+ SLANG_ASSERT(rs == 0);
+
+ return (rs == 0) ? SLANG_OK : SLANG_FAIL;
}
-size_t FileStream::read(void* buffer, size_t length)
+SlangResult FileStream::read(void* buffer, size_t length, size_t& outBytesRead)
{
- auto bytes = fread_s(buffer, length, 1, length, m_handle);
- if (bytes == 0 && length > 0)
+ auto bytesRead = fread_s(buffer, length, 1, length, m_handle);
+
+ outBytesRead = bytesRead;
+ if (bytesRead == 0 && length > 0)
{
- if (!feof(m_handle))
- throw IOException("FileStream read failed.");
- else if (m_endReached)
- throw EndOfStreamException("End of file is reached.");
- m_endReached = true;
+ // If we have reached the end, then reading nothing is ok.
+ if (!m_endReached)
+ {
+ // If we are not at the end of the file we should be able to read some bytes
+ if (!feof(m_handle))
+ {
+ return SLANG_FAIL;
+ }
+ m_endReached = true;
+ }
}
- return bytes;
+ return SLANG_OK;
}
-size_t FileStream::write(const void* buffer, size_t length)
+SlangResult FileStream::write(const void* buffer, size_t length)
{
- auto bytes = fwrite(buffer, 1, length, m_handle);
- if (bytes < length)
- {
- throw IOException("FileStream write failed.");
- }
- return bytes;
+ auto bytesWritten = fwrite(buffer, 1, length, m_handle);
+ return (bytesWritten == length) ? SLANG_OK : SLANG_FAIL;
}
bool FileStream::canRead()
@@ -235,7 +265,7 @@ void FileStream::close()
if (m_handle)
{
fclose(m_handle);
- m_handle = 0;
+ m_handle = nullptr;
// If closed, can neither read or write
m_fileAccess = FileAccess::None;
@@ -249,7 +279,7 @@ bool FileStream::isEnd()
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MemoryStreamBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-void MemoryStreamBase::seek(SeekOrigin origin, Int64 offset)
+SlangResult MemoryStreamBase::seek(SeekOrigin origin, Int64 offset)
{
Int64 pos = 0;
switch (origin)
@@ -264,8 +294,8 @@ void MemoryStreamBase::seek(SeekOrigin origin, Int64 offset)
pos = Int64(m_position) + offset;
break;
default:
- throw NotSupportedException("Unsupported seek origin.");
- break;
+ SLANG_ASSERT(!"Unsupported seek origin.");
+ return SLANG_E_NOT_IMPLEMENTED;
}
m_atEnd = false;
@@ -275,36 +305,43 @@ void MemoryStreamBase::seek(SeekOrigin origin, Int64 offset)
pos = (pos > Int64(m_contentsSize)) ? Int64(m_contentsSize) : pos;
m_position = ptrdiff_t(pos);
+ return SLANG_OK;
}
-size_t MemoryStreamBase::read(void* buffer, size_t length)
+SlangResult MemoryStreamBase::read(void* buffer, size_t length, size_t& outReadBytes)
{
+ outReadBytes = 0;
if (!canRead())
{
- throw IOException("Cannot read this stream.");
+ SLANG_ASSERT(!"Cannot read this stream.");
+ return SLANG_FAIL;
}
const size_t maxRead = size_t(m_contentsSize - m_position);
if (maxRead == 0 && length > 0)
{
- m_atEnd = true;
- throw EndOfStreamException("End of file is reached.");
+ // At end of stream
+ m_atEnd = true;
+ return SLANG_OK;
}
length = length > maxRead ? maxRead : length;
::memcpy(buffer, m_contents + m_position, length);
m_position += ptrdiff_t(length);
- return maxRead;
+ outReadBytes = length;
+
+ return SLANG_OK;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! OwnedMemoryStream !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-size_t OwnedMemoryStream::write(const void * buffer, size_t length)
+SlangResult OwnedMemoryStream::write(const void * buffer, size_t length)
{
if (!canWrite())
{
- throw IOException("Cannot write this stream.");
+ SLANG_ASSERT(!"Cannot write this stream.");
+ return SLANG_FAIL;
}
if (m_position == m_ownedContents.getCount())
@@ -322,7 +359,7 @@ size_t OwnedMemoryStream::write(const void * buffer, size_t length)
m_atEnd = false;
m_position += ptrdiff_t(length);
- return length;
+ return SLANG_OK;
}
} // namespace Slang
diff --git a/source/core/slang-stream.h b/source/core/slang-stream.h
index 730ce70be..e33e1c601 100644
--- a/source/core/slang-stream.h
+++ b/source/core/slang-stream.h
@@ -6,45 +6,45 @@
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
+ Start, ///< Seek from the start of the stream
+ End, ///< Seek from the end of the stream
+ Current, ///< Seek from the current cursor position
};
class Stream : public RefObject
{
public:
virtual ~Stream() {}
+ /// Get the current 'cursor' position in the stream
virtual Int64 getPosition()=0;
- virtual void seek(SeekOrigin origin, Int64 offset)=0;
- virtual size_t read(void * buffer, size_t length) = 0;
- virtual size_t write(const void * buffer, size_t length) = 0;
+ /// Seek the cursor to a position. How the seek is performed is dependent on the 'origin' and the offset required.
+ /// NOTE that *any* seek will reset the 'end of stream' status. See 'read' for requirements for 'isEnd' to be reached.
+ virtual SlangResult seek(SeekOrigin origin, Int64 offset)=0;
+ /// Read from the current position into buffer.
+ /// If there are less bytes available than requested only the amount available will be read. outReadBytes holds the actual amount of bytes read.
+ /// It is valid (and not an error) for read to return 0 bytes read - even if the end of the stream.
+ ///
+ /// 'isEnd' only becomes true when a read is performed *past* the end of a stream.
+ /// If a non zero read is performed from the end then isEnd must be true.
+ ///
+ /// Will return an error if there is a reading failure.
+ virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) = 0;
+ /// Write to the stream from current position
+ virtual SlangResult write(const void* buffer, size_t length) = 0;
+ /// True if the of the stream has been hit. The 'read' method has more discussion as to when this can occur.
virtual bool isEnd() = 0;
+ /// Returns true if it's possible to read from the stream.
virtual bool canRead() = 0;
+ /// Returns true when it's possible to write to the stream.
virtual bool canWrite() = 0;
+ /// Close the stream. Once closed no more operations can be performed on the stream.
+ /// Implies any pending data is flushed.
virtual void close() = 0;
+
+ /// Helper function that will also *fail* if the specified amount of bytes aren't read.
+ SlangResult readExactly(void* buffer, size_t length);
};
enum class FileMode
@@ -69,9 +69,9 @@ public:
typedef Stream Super;
virtual Int64 getPosition() SLANG_OVERRIDE { return m_position; }
- virtual void seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE;
- virtual size_t read(void * buffer, size_t length) SLANG_OVERRIDE;
- virtual size_t write(const void * buffer, size_t length) SLANG_OVERRIDE { SLANG_UNUSED(buffer); SLANG_UNUSED(length); return 0; }
+ virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE;
+ virtual SlangResult read(void * buffer, size_t length, size_t& outReadByts) SLANG_OVERRIDE;
+ virtual SlangResult write(const void * buffer, size_t length) SLANG_OVERRIDE { SLANG_UNUSED(buffer); SLANG_UNUSED(length); return SLANG_E_NOT_IMPLEMENTED; }
virtual 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; }
@@ -120,7 +120,7 @@ class OwnedMemoryStream : public MemoryStreamBase
public:
typedef MemoryStreamBase Super;
- virtual size_t write(const void* buffer, size_t length) SLANG_OVERRIDE;
+ virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE;
/// Set the contents
void setContent(const void* contents, size_t contentsSize)
@@ -151,21 +151,24 @@ public:
typedef Stream Super;
// Stream interface
- virtual Int64 getPosition();
- virtual void seek(SeekOrigin origin, Int64 offset);
- virtual size_t read(void* buffer, size_t length);
- virtual size_t write(const void* buffer, size_t length);
- virtual bool canRead();
- virtual bool canWrite();
- virtual void close();
- virtual bool isEnd();
-
- FileStream(const String& fileName, FileMode fileMode = FileMode::Open);
- FileStream(const String& fileName, FileMode fileMode, FileAccess access, FileShare share);
+ virtual Int64 getPosition() SLANG_OVERRIDE;
+ virtual SlangResult seek(SeekOrigin origin, Int64 offset) SLANG_OVERRIDE;
+ virtual SlangResult read(void* buffer, size_t length, size_t& outReadBytes) SLANG_OVERRIDE;
+ virtual SlangResult write(const void* buffer, size_t length) SLANG_OVERRIDE;
+ virtual bool canRead() SLANG_OVERRIDE;
+ virtual bool canWrite() SLANG_OVERRIDE;
+ virtual void close() SLANG_OVERRIDE;
+ virtual bool isEnd() SLANG_OVERRIDE;
+
+ FileStream();
+
+ SlangResult init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share);
+ SlangResult init(const String& fileName, FileMode fileMode = FileMode::Open);
+
~FileStream();
private:
- void _init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share);
+ SlangResult _init(const String& fileName, FileMode fileMode, FileAccess access, FileShare share);
FILE* m_handle;
FileAccess m_fileAccess;
diff --git a/source/core/slang-string-escape-util.cpp b/source/core/slang-string-escape-util.cpp
index ffc43a7cb..513908c4c 100644
--- a/source/core/slang-string-escape-util.cpp
+++ b/source/core/slang-string-escape-util.cpp
@@ -351,8 +351,7 @@ SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& sl
const Index maxUtf8EncodeCount = 6;
char* chars = out.prepareForAppend(maxUtf8EncodeCount);
-
- int numChars = EncodeUnicodePointToUTF8(chars, int(value));
+ int numChars = encodeUnicodePointToUTF8(Char32(value), chars);
out.appendInPlace(chars, numChars);
start = cur;
@@ -812,7 +811,7 @@ SlangResult JSONStringEscapeHandler::appendUnescaped(const UnownedStringSlice& s
// Need to encode in UTF8 to concat
char buf[8];
- int len = EncodeUnicodePointToUTF8(buf, value);
+ int len = encodeUnicodePointToUTF8(Char32(value), buf);
out.append(buf, buf + len);
diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp
index 0a5b7d260..e21333809 100644
--- a/source/core/slang-string.cpp
+++ b/source/core/slang-string.cpp
@@ -11,15 +11,6 @@ namespace Slang
// for anything that uses core
static const auto s_charUtilLink = CharUtil::_ensureLink();
- // TODO: this belongs in a different file:
-
- SLANG_RETURN_NEVER void signalUnexpectedError(char const* message)
- {
- // Can be useful to uncomment during debug when problem is on CI
- // printf("Unexpected: %s\n", message);
- throw InternalError(message);
- }
-
// OSString
OSString::OSString()
@@ -120,6 +111,14 @@ namespace Slang
return UnownedStringSlice(start, end);
}
+ UnownedStringSlice UnownedStringSlice::trimStart() const
+ {
+ const char* start = m_begin;
+
+ while (start < m_end && CharUtil::isHorizontalWhitespace(*start)) start++;
+ return UnownedStringSlice(start, m_end);
+ }
+
UnownedStringSlice UnownedStringSlice::trim(char c) const
{
const char* start = m_begin;
@@ -217,37 +216,42 @@ namespace Slang
String String::fromWString(const wchar_t * wstr)
{
+ List<char> buf;
#ifdef _WIN32
- return Slang::Encoding::UTF16->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)));
+ Slang::CharEncoding::UTF16->decode((const Byte*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)), buf);
#else
- return Slang::Encoding::UTF32->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)));
+ Slang::CharEncoding::UTF32->decode((const Byte*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)), buf);
#endif
+ return String(buf.begin(), buf.end());
}
String String::fromWString(const wchar_t * wstr, const wchar_t * wend)
{
+ List<char> buf;
#ifdef _WIN32
- return Slang::Encoding::UTF16->ToString((const char*)wstr, (int)((wend - wstr) * sizeof(wchar_t)));
+ Slang::CharEncoding::UTF16->decode((const Byte*)wstr, (int)((wend - wstr) * sizeof(wchar_t)), buf);
#else
- return Slang::Encoding::UTF32->ToString((const char*)wstr, (int)((wend - wstr) * sizeof(wchar_t)));
+ Slang::CharEncoding::UTF32->decode((const Byte*)wstr, (int)((wend - wstr) * sizeof(wchar_t)), buf);
#endif
+ return String(buf.begin(), buf.end());
}
String String::fromWChar(const wchar_t ch)
{
+ List<char> buf;
#ifdef _WIN32
- return Slang::Encoding::UTF16->ToString((const char*)&ch, (int)(sizeof(wchar_t)));
+ Slang::CharEncoding::UTF16->decode((const Byte*)&ch, (int)(sizeof(wchar_t)), buf);
#else
- return Slang::Encoding::UTF32->ToString((const char*)&ch, (int)(sizeof(wchar_t)));
+ Slang::CharEncoding::UTF32->decode((const Byte*)&ch, (int)(sizeof(wchar_t)), buf);
#endif
+ return String(buf.begin(), buf.end());
}
- String String::fromUnicodePoint(unsigned int codePoint)
+ /* static */String String::fromUnicodePoint(Char32 codePoint)
{
char buf[6];
- int len = Slang::EncodeUnicodePointToUTF8(buf, (int)codePoint);
- buf[len] = 0;
- return String(buf);
+ int len = Slang::encodeUnicodePointToUTF8(codePoint, buf);
+ return String(buf, buf + len);
}
OSString String::toWString(Index* outLength) const
@@ -258,15 +262,15 @@ namespace Slang
}
else
{
- List<char> buf;
+ List<Byte> buf;
switch(sizeof(wchar_t))
{
case 2:
- Slang::Encoding::UTF16->GetBytes(buf, *this);
+ Slang::CharEncoding::UTF16->encode(getUnownedSlice(), buf);
break;
case 4:
- Slang::Encoding::UTF32->GetBytes(buf, *this);
+ Slang::CharEncoding::UTF32->encode(getUnownedSlice(), buf);
break;
default:
diff --git a/source/core/slang-string.h b/source/core/slang-string.h
index 6b9a73bcb..85f7b894f 100644
--- a/source/core/slang-string.h
+++ b/source/core/slang-string.h
@@ -168,6 +168,9 @@ namespace Slang
/// Trims any 'c' from the start or the end, and returns as a substring
UnownedStringSlice trim(char c) const;
+ /// Trims any horizonatl whitespace from start and returns as a substring
+ UnownedStringSlice trimStart() const;
+
HashCode getHashCode() const
{
return Slang::getHashCode(m_begin, size_t(m_end - m_begin));
@@ -409,7 +412,7 @@ namespace Slang
static String fromWString(const wchar_t * wstr);
static String fromWString(const wchar_t * wstr, const wchar_t * wend);
static String fromWChar(const wchar_t ch);
- static String fromUnicodePoint(unsigned int codePoint);
+ static String fromUnicodePoint(Char32 codePoint);
String()
{
}
@@ -619,9 +622,9 @@ namespace Slang
len = getLength() - id;
#if _DEBUG
if (id < 0 || id >= getLength() || (id + len) > getLength())
- throw "SubString: index out of range.";
+ SLANG_ASSERT_FAILURE("SubString: index out of range.");
if (len < 0)
- throw "SubString: length less than zero.";
+ SLANG_ASSERT_FAILURE("SubString: length less than zero.");
#endif
return StringSlice(m_buffer, id, id + len);
}
@@ -997,9 +1000,9 @@ namespace Slang
{
#if _DEBUG
if (id >= length || id < 0)
- throw "Remove: Index out of range.";
+ SLANG_ASSERT_FAILURE("Remove: Index out of range.");
if (len < 0)
- throw "Remove: remove length smaller than zero.";
+ SLANG_ASSERT_FAILURE("Remove: remove length smaller than zero.");
#endif
int actualDelLength = ((id + len) >= length) ? (length - id) : len;
for (int i = id + actualDelLength; i <= length; i++)
diff --git a/source/core/slang-text-io.cpp b/source/core/slang-text-io.cpp
index ca3b9447c..3f5d739d9 100644
--- a/source/core/slang-text-io.cpp
+++ b/source/core/slang-text-io.cpp
@@ -1,343 +1,163 @@
#include "slang-text-io.h"
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#define NOMINMAX
-#include <Windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#undef NOMINMAX
-#define CONVERT_END_OF_LINE
-#endif
+
+#include "../../slang-com-helper.h"
namespace Slang
{
- class Utf8Encoding : public Encoding
- {
- public:
- virtual void GetBytes(List<char> & 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<char> & 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();
- }
- };
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StreamWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- class Utf16Encoding : public Encoding //UTF16
- {
- private:
- bool reverseOrder = false;
- public:
- Utf16Encoding(bool pReverseOrder)
- : reverseOrder(pReverseOrder)
- {}
- virtual void GetBytes(List<char> & 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;
+SlangResult StreamWriter::init(const String& path, CharEncoding* encoding)
+{
+ RefPtr<FileStream> fileStream = new FileStream;
+ SLANG_RETURN_ON_FAIL(fileStream->init(path, FileMode::Create));
+ return init(fileStream, encoding);
+}
- StreamWriter::StreamWriter(const String & path, Encoding * encoding)
+SlangResult StreamWriter::init(RefPtr<Stream> stream, CharEncoding* encoding)
+{
+ m_stream = stream;
+ m_encoding = encoding;
+ if (encoding == CharEncoding::UTF16)
{
- 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);
- }
+ SLANG_RETURN_ON_FAIL(m_stream->write(&kUTF16Header, 2));
}
- StreamWriter::StreamWriter(RefPtr<Stream> stream, Encoding * encoding)
+ else if (encoding == CharEncoding::UTF16Reversed)
{
- 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);
- }
+ SLANG_RETURN_ON_FAIL(m_stream->write(&kUTF16ReversedHeader, 2));
}
- void StreamWriter::Write(const String & str)
- {
- encodingBuffer.clear();
- StringBuilder sb;
- String newLine;
+
+ return SLANG_OK;
+}
+
+SlangResult StreamWriter::writeSlice(const UnownedStringSlice& slice)
+{
+ // TODO(JS):
+ // We can do better here. On Linux, this is a no-op and can just write directly (assuming slice only contains \n)
+
+ m_encodingBuffer.clear();
+
+ StringBuilder sb;
#ifdef _WIN32
- newLine = "\r\n";
+ const char newLine[] = "\r\n";
#else
- newLine = "\n";
+ const char newLine[] = "\n";
#endif
- for (Index i = 0; i < str.getLength(); i++)
+ const Index length = slice.getLength();
+
+ for (Index i = 0; i < length; i++)
+ {
+ if (slice[i] == '\r')
+ sb << newLine;
+ else if (slice[i] == '\n')
{
- if (str[i] == '\r')
+ if (i > 0 && slice[i - 1] != '\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));
+ else
+ sb << slice[i];
}
- StreamReader::StreamReader(const String & path)
- {
- stream = new FileStream(path, FileMode::Open);
- ReadBuffer();
- encoding = DetermineEncoding();
- if (encoding == 0)
- encoding = Encoding::UTF8;
- }
- StreamReader::StreamReader(RefPtr<Stream> stream, Encoding * encoding)
- {
- this->stream = stream;
- this->encoding = encoding;
- ReadBuffer();
- auto determinedEncoding = DetermineEncoding();
- if (this->encoding == nullptr)
- this->encoding = determinedEncoding;
- }
+ // NOTE! This assumes that sb contains *complete* utf8 code points, which it might not, as encoder is only able to handle complete code points.
+ m_encodingBuffer.clear();
+ m_encoding->encode(sb.getUnownedSlice(), m_encodingBuffer);
+ return m_stream->write(m_encodingBuffer.getBuffer(), m_encodingBuffer.getCount());
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StreamReader !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+StreamReader::StreamReader()
+{
+}
+
+SlangResult StreamReader::init(const String& path)
+{
+ RefPtr<FileStream> fileStream = new FileStream;
+ SLANG_RETURN_ON_FAIL(fileStream->init(path, FileMode::Open));
+ return init(fileStream);
+}
- bool HasNullBytes(char * str, int len)
+SlangResult StreamReader::init(RefPtr<Stream> stream, CharEncoding* encoding)
+{
+ m_stream = stream;
+ m_encoding = encoding;
+ SLANG_RETURN_ON_FAIL(readBuffer());
+
+ if (encoding == nullptr)
{
- bool hasSeenNull = false;
- for (int i = 0; i < len - 1; i++)
- if (str[i] == 0)
- hasSeenNull = true;
- else if (hasSeenNull)
- return true;
- return false;
+ size_t offset;
+ m_encodingType = CharEncoding::determineEncoding((const Byte*)m_buffer.getBuffer(), m_buffer.getCount(), offset);
+ m_encoding = CharEncoding::getEncoding(m_encodingType);
+ m_index = Index(offset);
+ }
+ else
+ {
+ m_encodingType = encoding->getEncodingType();
+ m_encoding = encoding;
}
- 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;
- }
- }
+ return SLANG_OK;
+}
- 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;
- }
+SlangResult StreamReader::readBuffer()
+{
+ m_buffer.setCount(0);
+ m_index = 0;
- char StreamReader::ReadBufferChar()
- {
- if (ptr<buffer.getCount())
- {
- return buffer[ptr++];
- }
- if (!stream->isEnd())
- ReadBuffer();
- if (ptr<buffer.getCount())
- {
- return buffer[ptr++];
- }
- return 0;
- }
- int TextReader::Read(char * destBuffer, int length)
+ if (m_stream->isEnd())
+ {
+ return SLANG_OK;
+ }
+
+ m_buffer.setCount(4096);
+
+ // TODO(JS): Not clear this is necessary
+ memset(m_buffer.getBuffer(), 0, m_buffer.getCount() * sizeof(m_buffer[0]));
+
+ size_t readBytes;
+ SLANG_RETURN_ON_FAIL(m_stream->read(m_buffer.getBuffer(), m_buffer.getCount(), readBytes));
+
+ m_buffer.setCount(Index(readBytes));
+ m_index = 0;
+ return SLANG_OK;
+}
+
+char StreamReader::readBufferChar()
+{
+ if (m_index < m_buffer.getCount())
{
- int i = 0;
- for (i = 0; i<length; i++)
- {
- try
- {
- auto ch = Read();
- if (IsEnd())
- break;
- if (ch == '\r')
- {
- if (Peak() == '\n')
- Read();
- break;
- }
- else if (ch == '\n')
- {
- break;
- }
- destBuffer[i] = ch;
- }
- catch (const EndOfStreamException& )
- {
- break;
- }
- }
- return i;
+ return m_buffer[m_index++];
}
- String StreamReader::ReadLine()
+
+ readBuffer();
+
+ if (m_index < m_buffer.getCount())
{
- StringBuilder sb(256);
- while (!IsEnd())
- {
- try
- {
- auto ch = Read();
- if (IsEnd())
- break;
- if (ch == '\r')
- {
- if (Peak() == '\n')
- Read();
- break;
- }
- else if (ch == '\n')
- {
- break;
- }
- sb.Append(ch);
- }
- catch (const EndOfStreamException&)
- {
- break;
- }
- }
- return sb.ProduceString();
+ return m_buffer[m_index++];
}
- String StreamReader::ReadToEnd()
+ return 0;
+}
+
+SlangResult StreamReader::readToEnd(String& outString)
+{
+ StringBuilder sb(16384);
+ while (!isEnd())
{
- StringBuilder sb(16384);
- while (!IsEnd())
+ auto ch = read();
+ if (isEnd())
+ break;
+ if (ch == '\r')
{
- try
- {
- auto ch = Read();
- if (IsEnd())
- break;
- if (ch == '\r')
- {
- sb.Append('\n');
- if (Peak() == '\n')
- Read();
- }
- else
- sb.Append(ch);
- }
- catch (const EndOfStreamException&)
- {
- break;
- }
+ sb.Append('\n');
+ if (peek() == '\n')
+ read();
}
- return sb.ProduceString();
+ else
+ sb.Append(ch);
}
+
+ outString = sb.ProduceString();
+ return SLANG_OK;
}
+
+} // namespace Slang
diff --git a/source/core/slang-text-io.h b/source/core/slang-text-io.h
index b5a9ad0e1..0ee381c46 100644
--- a/source/core/slang-text-io.h
+++ b/source/core/slang-text-io.h
@@ -3,314 +3,184 @@
#include "slang-secure-crt.h"
#include "slang-stream.h"
+#include "slang-char-encode.h"
namespace Slang
{
- using Slang::List;
- using Slang::_EndLine;
+using Slang::List;
+using Slang::_EndLine;
- class TextReader
- {
- protected:
- char decodedChar[5];
- int decodedCharPtr = 0, decodedCharSize = 0;
- virtual void ReadChar() = 0;
- public:
- virtual ~TextReader()
- {
- Close();
- }
- virtual void Close(){}
- virtual String ReadLine()=0;
- virtual String ReadToEnd()=0;
- virtual bool IsEnd() = 0;
- int Read(char * buffer, int count);
- char Read()
- {
- if (decodedCharPtr == decodedCharSize)
- ReadChar();
- if (decodedCharPtr < decodedCharSize)
- return decodedChar[decodedCharPtr++];
- else
- return 0;
- }
- char Peak()
- {
- if (decodedCharPtr == decodedCharSize)
- ReadChar();
- if (decodedCharPtr < decodedCharSize)
- return decodedChar[decodedCharPtr];
- else
- return 0;
- }
- };
-
- class TextWriter
- {
- public:
- virtual ~TextWriter()
- {
- Close();
- }
- virtual void Write(const String & str)=0;
- virtual void Write(const char * str)=0;
- virtual void Close(){}
- template<typename T>
- TextWriter & operator << (const T& val)
- {
- Write(val.ToString());
- return *this;
- }
- TextWriter & operator << (int value)
- {
- Write(String(value));
- return *this;
- }
- TextWriter & operator << (float value)
- {
- Write(String(value));
- return *this;
- }
- TextWriter & operator << (double value)
- {
- Write(String(value));
- return *this;
- }
- TextWriter & operator << (const char* value)
- {
- 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;
- }
- };
+class TextReader
+{
+public:
+ virtual void close(){}
+ virtual SlangResult readToEnd(String& outString) = 0;
+ virtual bool isEnd() = 0;
- template <typename ReadCharFunc>
- int GetUnicodePointFromUTF8(const ReadCharFunc & get)
+ char read()
{
- 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;
+ if (m_decodedCharIndex == m_decodedCharSize)
+ readChar();
+ if (m_decodedCharIndex < m_decodedCharSize)
+ return m_decodedChar[m_decodedCharIndex++];
+ else
+ return 0;
}
-
- template <typename ReadCharFunc>
- int GetUnicodePointFromUTF16(const ReadCharFunc & get)
+ char peek()
{
- 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;
- }
+ if (m_decodedCharIndex == m_decodedCharSize)
+ readChar();
+ if (m_decodedCharIndex < m_decodedCharSize)
+ return m_decodedChar[m_decodedCharIndex];
else
- return word0;
+ return 0;
}
- template <typename ReadCharFunc>
- int GetUnicodePointFromUTF16Reversed(const ReadCharFunc & get)
+ virtual ~TextReader() { close(); }
+
+protected:
+ char m_decodedChar[5];
+ Index m_decodedCharIndex = 0;
+ Index m_decodedCharSize = 0;
+
+ virtual void readChar() = 0;
+};
+
+
+class StreamReader : public TextReader
+{
+public:
+ virtual SlangResult readToEnd(String& outString) SLANG_OVERRIDE;
+ virtual bool isEnd() SLANG_OVERRIDE { return m_index == m_buffer.getCount() && m_stream->isEnd(); }
+ virtual void close() SLANG_OVERRIDE { m_stream->close(); }
+
+ void releaseStream() { m_stream.setNull(); }
+
+ StreamReader();
+
+ SlangResult init(const String& path);
+ SlangResult init(RefPtr<Stream> stream, CharEncoding* encoding = nullptr);
+
+protected:
+ virtual void readChar() SLANG_OVERRIDE
+ {
+ m_decodedCharIndex = 0;
+
+ Char32 codePoint = 0;
+ switch (m_encodingType)
+ {
+ case CharEncodeType::UTF8:
+ {
+ codePoint = getUnicodePointFromUTF8([&]() -> Byte {return readBufferChar(); });
+ break;
+ }
+ case CharEncodeType::UTF16:
+ {
+ codePoint = getUnicodePointFromUTF16([&]() -> Byte {return readBufferChar(); });
+ break;
+ }
+ case CharEncodeType::UTF16Reversed:
+ {
+ codePoint = getUnicodePointFromUTF16Reversed([&]() -> Byte {return readBufferChar(); });
+ break;
+ }
+ case CharEncodeType::UTF32:
+ {
+ codePoint = getUnicodePointFromUTF32([&]() -> Byte {return readBufferChar(); });
+ break;
+ }
+ }
+
+ m_decodedCharSize = encodeUnicodePointToUTF8(codePoint, m_decodedChar);
+ }
+
+private:
+ char readBufferChar();
+ SlangResult readBuffer();
+
+ RefPtr<Stream> m_stream;
+ List<char> m_buffer;
+
+ CharEncodeType m_encodingType = CharEncodeType::UTF8;
+ CharEncoding* m_encoding = nullptr;
+ Index m_index = 0; ///< Index into buffer
+};
+
+class TextWriter
+{
+public:
+
+ virtual SlangResult writeSlice(const UnownedStringSlice& slice) = 0;
+ virtual void close(){}
+
+ SlangResult write(const UnownedStringSlice& slice) { return writeSlice(slice); }
+ SlangResult write(const char* str) { return writeSlice(UnownedStringSlice(str)); }
+ SlangResult write(const String& str) { return writeSlice(str.getUnownedSlice()); }
+
+ virtual ~TextWriter() { close(); }
+
+ template<typename T>
+ TextWriter& operator << (const T& val)
{
- 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;
+ write(val.ToString());
+ return *this;
}
-
- template <typename ReadCharFunc>
- int GetUnicodePointFromUTF32(const ReadCharFunc & get)
+ TextWriter& operator << (int value)
{
- 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);
+ write(String(value));
+ return *this;
}
-
- inline int EncodeUnicodePointToUTF8(char * buffer, int codePoint)
+ TextWriter& operator << (float value)
{
- 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;
+ write(String(value));
+ return *this;
}
-
- inline int EncodeUnicodePointToUTF16(unsigned short * buffer, int codePoint)
+ TextWriter& operator << (double value)
{
- 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;
+ write(String(value));
+ return *this;
}
-
- inline unsigned short ReverseBitOrder(unsigned short val)
+ TextWriter& operator << (const char* value)
{
- int byte0 = val & 0xFF;
- int byte1 = val >> 8;
- return (unsigned short)(byte1 + (byte0 << 8));
+ writeSlice(UnownedStringSlice(value));
+ return *this;
}
-
- inline int EncodeUnicodePointToUTF16Reversed(unsigned short * buffer, int codePoint)
+ TextWriter& operator << (const String & val)
{
- 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;
+ writeSlice(val.getUnownedSlice());
+ return *this;
}
-
- class Encoding
+ TextWriter& operator << (const _EndLine &)
{
- public:
- static Encoding * UTF8, * UTF16, *UTF16Reversed, * UTF32;
- virtual void GetBytes(List<char>& buffer, const String & str) = 0;
- virtual String ToString(const char * buffer, int length) = 0;
- virtual ~Encoding()
- {}
- };
+#ifdef _WIN32
+ writeSlice(UnownedStringSlice::fromLiteral("\r\n"));
+#else
+ writeSlice(UnownedStringSlice::fromLiteral("\n"));
+#endif
+ return *this;
+ }
+};
+
+class StreamWriter : public TextWriter
+{
+public:
+ // TextWriter
+ virtual SlangResult writeSlice(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+ virtual void close() SLANG_OVERRIDE { m_stream->close(); }
- class StreamWriter : public TextWriter
- {
- private:
- List<char> encodingBuffer;
- RefPtr<Stream> stream;
- Encoding * encoding;
- public:
- StreamWriter(const String & path, Encoding * encoding = Encoding::UTF8);
- StreamWriter(RefPtr<Stream> 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;
- }
- };
+ void releaseStream() { m_stream.setNull(); }
+
+ StreamWriter() {}
+
+ SlangResult init(const String& path, CharEncoding* encoding = CharEncoding::UTF8);
+ SlangResult init(RefPtr<Stream> stream, CharEncoding* encoding = CharEncoding::UTF8);
+
+private:
+ List<Byte> m_encodingBuffer;
+ RefPtr<Stream> m_stream;
+ CharEncoding* m_encoding = nullptr;
+};
- class StreamReader : public TextReader
- {
- private:
- RefPtr<Stream> stream;
- List<char> 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> 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/slang/slang-api.cpp b/source/slang/slang-api.cpp
index a00d993e3..5ee384e4a 100644
--- a/source/slang/slang-api.cpp
+++ b/source/slang/slang-api.cpp
@@ -64,18 +64,15 @@ SlangResult trySaveStdLibToCache(
Slang::ComPtr<ISlangBlob> stdLibBlobPtr;
SLANG_RETURN_ON_FAIL(
globalSession->saveStdLib(SLANG_ARCHIVE_TYPE_RIFF_LZ4, stdLibBlobPtr.writeRef()));
- try
- {
- Slang::FileStream fileStream(cacheFilename, Slang::FileMode::Create);
- fileStream.write(&dllTimestamp, sizeof(dllTimestamp));
- fileStream.write(stdLibBlobPtr->getBufferPointer(), stdLibBlobPtr->getBufferSize());
- return SLANG_OK;
- }
- catch (...)
- {
- }
+
+ Slang::FileStream fileStream;
+ SLANG_RETURN_ON_FAIL(fileStream.init(cacheFilename, Slang::FileMode::Create));
+
+ SLANG_RETURN_ON_FAIL(fileStream.write(&dllTimestamp, sizeof(dllTimestamp)));
+ SLANG_RETURN_ON_FAIL(fileStream.write(stdLibBlobPtr->getBufferPointer(), stdLibBlobPtr->getBufferSize()))
}
- return SLANG_FAIL;
+
+ return SLANG_OK;
}
SLANG_API SlangResult slang_createGlobalSession(
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index c6c41b099..a73289852 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -2176,16 +2176,9 @@ namespace Slang
return SLANG_OK;
}
- FileStream stream(fileName, FileMode::Create, FileAccess::Write, FileShare::ReadWrite);
- try
- {
- stream.write(m_containerBlob->getBufferPointer(), m_containerBlob->getBufferSize());
- }
- catch (const IOException&)
- {
- // Unable to write
- return SLANG_FAIL;
- }
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(fileName, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
+ SLANG_RETURN_ON_FAIL(stream.write(m_containerBlob->getBufferPointer(), m_containerBlob->getBufferSize()));
return SLANG_OK;
}
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 90c5a3896..1c7d8fbc2 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -1151,7 +1151,8 @@ struct OptionsParser
SLANG_RETURN_ON_FAIL(reader.expectArg(referenceModuleName));
// We need to deserialize and add the modules
- FileStream fileStream(referenceModuleName.value, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
+ FileStream fileStream;
+ SLANG_RETURN_ON_FAIL(fileStream.init(referenceModuleName.value, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
// TODO: probably near an error when we can't open the file?
diff --git a/source/slang/slang-repro.cpp b/source/slang/slang-repro.cpp
index 4b3148278..67feebe43 100644
--- a/source/slang/slang-repro.cpp
+++ b/source/slang/slang-repro.cpp
@@ -1082,22 +1082,15 @@ struct LoadContext
/* static */SlangResult ReproUtil::saveState(EndToEndCompileRequest* request, const String& filename)
{
- RefPtr<Stream> stream(new FileStream(filename, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
+ RefPtr<FileStream> stream(new FileStream);
+ SLANG_RETURN_ON_FAIL(stream->init(filename, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
return saveState(request, stream);
}
/* static */ SlangResult ReproUtil::loadState(const String& filename, List<uint8_t>& outBuffer)
{
- RefPtr<Stream> stream;
- try
- {
- stream = new FileStream(filename, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
- }
- catch (const IOException&)
- {
- return SLANG_FAIL;
- }
-
+ RefPtr<FileStream> stream = new FileStream;
+ SLANG_RETURN_ON_FAIL(stream->init(filename, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
return loadState(stream, outBuffer);
}
@@ -1564,6 +1557,8 @@ static SlangResult _findFirstSourcePath(EndToEndCompileRequest* request, String&
String sourceFileName = Path::getFileName(sourcePath);
String sourceBaseName = Path::getFileNameWithoutExt(sourceFileName);
+ RefPtr<FileStream> stream = new FileStream;
+
// Okay we need a unique number to make sure the name is unique
const int maxTries = 100;
for (int triesCount = 0; triesCount < maxTries; ++triesCount)
@@ -1578,15 +1573,12 @@ static SlangResult _findFirstSourcePath(EndToEndCompileRequest* request, String&
outFileName = builder;
// We could have clashes, as we use ticks, we should get to a point where the clashes stop
- try
+ if (SLANG_SUCCEEDED(stream->init(builder, FileMode::CreateNew, FileAccess::Write, FileShare::WriteOnly)))
{
- outStream = new FileStream(builder, FileMode::CreateNew, FileAccess::Write, FileShare::WriteOnly);
+ outStream = stream;
return SLANG_OK;
}
- catch (const IOException&)
- {
- }
-
+
// TODO(JS):
// Might make sense to sleep here - but don't seem to have cross platform func for that yet.
}
diff --git a/source/slang/slang-serialize-types.cpp b/source/slang/slang-serialize-types.cpp
index fc839afc1..6c4512b1d 100644
--- a/source/slang/slang-serialize-types.cpp
+++ b/source/slang/slang-serialize-types.cpp
@@ -14,10 +14,10 @@ namespace Slang {
namespace { // anonymous
-struct CharReader
+struct ByteReader
{
- char operator()(int pos) const { SLANG_UNUSED(pos); return *m_pos++; }
- CharReader(const char* pos) :m_pos(pos) {}
+ Byte operator()() const { return Byte(*m_pos++); }
+ ByteReader(const char* pos) :m_pos(pos) {}
mutable const char* m_pos;
};
@@ -37,11 +37,15 @@ struct CharReader
stringTable.clear();
for (const auto& slice : slices)
{
+ // TODO(JS):
+ // This is a bit of a hack. We need to store the string length, along with the string contents. We don't want to write
+ // the size as (say) uint32, because most strings are short. So we just save off the length as a utf8 encoding.
+ // As it stands this *does* have an arguable problem because encoding isn't of the full 32 bits.
const int len = int(slice.getLength());
// We need to write into the the string array
char prefixBytes[6];
- const int numPrefixBytes = EncodeUnicodePointToUTF8(prefixBytes, len);
+ const int numPrefixBytes = encodeUnicodePointToUTF8(len, prefixBytes);
const Index baseIndex = stringTable.getCount();
stringTable.setCount(baseIndex + numPrefixBytes + len);
@@ -61,8 +65,8 @@ struct CharReader
while (cur < end)
{
- CharReader reader(cur);
- const int len = GetUnicodePointFromUTF8(reader);
+ ByteReader reader(cur);
+ const int len = getUnicodePointFromUTF8(reader);
slicesOut.add(UnownedStringSlice(reader.m_pos, len));
cur = reader.m_pos + len;
}
@@ -87,8 +91,8 @@ struct CharReader
while (cur < end)
{
- CharReader reader(cur);
- const int len = GetUnicodePointFromUTF8(reader);
+ ByteReader reader(cur);
+ const int len = getUnicodePointFromUTF8(reader);
outPool.add(UnownedStringSlice(reader.m_pos, len));
cur = reader.m_pos + len;
}
diff --git a/source/slang/slang-serialize.cpp b/source/slang/slang-serialize.cpp
index 4f8fdc546..a7074df1c 100644
--- a/source/slang/slang-serialize.cpp
+++ b/source/slang/slang-serialize.cpp
@@ -506,20 +506,13 @@ SlangResult SerialWriter::write(Stream* stream)
// MAX_ALIGNMENT, and so < MAX_ALIGNMENT is the most extra bytes we can write
SLANG_ASSERT( alignmentFixSize < SerialInfo::MAX_ALIGNMENT);
- try
+ SLANG_RETURN_ON_FAIL(stream->write(entry, entrySize));
+ // If we needed to fix so that subsequent alignment is right, write out extra bytes here
+ if (alignmentFixSize)
{
- stream->write(entry, entrySize);
- // If we needed to fix so that subsequent alignment is right, write out extra bytes here
- if (alignmentFixSize)
- {
- stream->write(s_fixBuffer, alignmentFixSize);
- }
+ SLANG_RETURN_ON_FAIL(stream->write(s_fixBuffer, alignmentFixSize));
}
- catch (const IOException&)
- {
- return SLANG_FAIL;
- }
-
+
// Onto next
offset = nextOffset;
entry = next;
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 0fc5f6122..6fe778435 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -269,11 +269,14 @@ SlangResult Session::compileStdLib(slang::CompileStdLibFlags compileFlags)
{
String fileName("stdlib-doc.md");
- StreamWriter writer(new FileStream(fileName, FileMode::Create));
+ RefPtr<FileStream> stream = new FileStream;
+ SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create));
+ StreamWriter writer;
+ SLANG_RETURN_ON_FAIL(writer.init(stream));
for (auto& docString : docStrings)
{
- writer.Write(docString);
+ SLANG_RETURN_ON_FAIL(writer.write(docString));
}
}
}