├── .editorconfig
├── .gitignore
├── Examples
└── hello
│ ├── README.md
│ ├── hello.cpp
│ ├── hello.sln
│ ├── hello.spire
│ ├── hello.vcxproj
│ └── hello.vcxproj.filters
├── LICENSE.txt
├── README.md
├── Source
├── CoreLib
│ ├── Allocator.h
│ ├── Array.h
│ ├── ArrayView.h
│ ├── Basic.h
│ ├── CMakeLists.txt
│ ├── CommandLineParser.cpp
│ ├── CommandLineParser.h
│ ├── Common.h
│ ├── CoreLibBasic.vcxproj
│ ├── Dictionary.h
│ ├── Exception.h
│ ├── Func.h
│ ├── Hash.h
│ ├── IntSet.h
│ ├── LibIO.cpp
│ ├── LibIO.h
│ ├── LibMath.cpp
│ ├── LibMath.h
│ ├── LibString.cpp
│ ├── LibString.h
│ ├── Link.h
│ ├── Linq.h
│ ├── List.h
│ ├── MemoryPool.cpp
│ ├── MemoryPool.h
│ ├── SecureCRT.h
│ ├── SmartPointer.h
│ ├── Stream.cpp
│ ├── Stream.h
│ ├── TextIO.cpp
│ ├── TextIO.h
│ ├── Tokenizer.cpp
│ ├── Tokenizer.h
│ ├── TypeTraits.h
│ ├── VectorMath.cpp
│ ├── VectorMath.h
│ └── corelib.natvis
├── Spire.sln
├── SpireCompiler
│ ├── D3DCompiler.cpp
│ ├── D3DCompiler.h
│ ├── ShaderCompilerShell.cpp
│ ├── SpireCompiler.vcxproj
│ └── SpireCompiler.vcxproj.filters
├── SpireCore
│ ├── CLikeCodeGen.cpp
│ ├── CLikeCodeGen.h
│ ├── Closure.cpp
│ ├── Closure.h
│ ├── CodeGenBackend.h
│ ├── CodeGenerator.cpp
│ ├── CodeWriter.h
│ ├── CompiledProgram.cpp
│ ├── CompiledProgram.h
│ ├── ConstantPool.cpp
│ ├── DiagnosticDefs.h
│ ├── Diagnostics.cpp
│ ├── Diagnostics.h
│ ├── GLSLCodeGen.cpp
│ ├── GetDependencyVisitor.cpp
│ ├── GetDependencyVisitor.h
│ ├── HLSLCodeGen.cpp
│ ├── IL.cpp
│ ├── IL.h
│ ├── InsertImplicitImportOperator.cpp
│ ├── KeyHoleMatching.cpp
│ ├── Lexer.cpp
│ ├── Lexer.h
│ ├── Naming.cpp
│ ├── Naming.h
│ ├── NatvisFile.natvis
│ ├── NewSpirVCodeGen.cpp
│ ├── Parser.cpp
│ ├── Parser.h
│ ├── Preprocessor.cpp
│ ├── Preprocessor.h
│ ├── SamplerUsageAnalysis.cpp
│ ├── SamplerUsageAnalysis.h
│ ├── Schedule.cpp
│ ├── Schedule.h
│ ├── ScopeDictionary.h
│ ├── SemanticsVisitor.cpp
│ ├── ShaderCompiler.cpp
│ ├── ShaderCompiler.h
│ ├── SpirVCodeGen.cpp
│ ├── SpireCore.vcxproj
│ ├── SpireCore.vcxproj.filters
│ ├── StdInclude.cpp
│ ├── StdInclude.h
│ ├── StringObject.h
│ ├── SymbolTable.cpp
│ ├── SymbolTable.h
│ ├── Syntax.cpp
│ ├── Syntax.h
│ ├── SyntaxVisitors.h
│ ├── TypeLayout.cpp
│ ├── TypeLayout.h
│ ├── TypeTranslation.cpp
│ ├── TypeTranslation.h
│ ├── VariantIR.cpp
│ └── VariantIR.h
└── SpireLib
│ ├── SpireLib.cpp
│ ├── SpireLib.h
│ ├── SpireLib.vcxproj
│ └── SpireLib.vcxproj.filters
├── Spire.h
├── SpireAllSource.h
├── Tests
├── Diagnostics
│ ├── break-outside-loop.spire
│ ├── break-outside-loop.spire.expected
│ ├── call-argument-type.spire
│ ├── call-argument-type.spire.expected
│ ├── continue-outside-loop.spire
│ ├── continue-outside-loop.spire.expected
│ ├── expected-token-eof.spire
│ ├── expected-token-eof.spire.expected
│ ├── expected-token.spire
│ ├── expected-token.spire.expected
│ ├── function-redefinition.spire
│ ├── function-redefinition.spire.expected
│ ├── hull-shader-invalid-domain.spire
│ ├── hull-shader-invalid-domain.spire.expected
│ ├── hull-shader-no-domain.spire
│ ├── hull-shader-no-domain.spire.expected
│ ├── illegal-character.spire
│ ├── illegal-character.spire.expected
│ ├── missing-file.spire
│ ├── missing-file.spire.expected
│ ├── parameter-already-defined.spire
│ ├── parameter-already-defined.spire.expected
│ ├── undefined-identifier.spire
│ ├── undefined-identifier.spire.expected
│ ├── variable-void-type.spire
│ ├── variable-void-type.spire.expected
│ ├── while-predicate-type.spire
│ └── while-predicate-type.spire.expected
├── FrontEnd
│ ├── lexer-comments.spire
│ ├── parser-decls.spire
│ ├── parser-empty.spire
│ ├── parser-error-unclosed-curly.spire
│ ├── parser-error-unclosed-curly.spire.expected
│ ├── parser-using-file-a.spireh
│ ├── parser-using-file.spire
│ ├── pipeline-simple.spireh
│ ├── struct.spire
│ └── typedef.spire
├── HLSLCodeGen
│ ├── DeferredLighting.fs.hlsl
│ ├── DeferredLighting.vs.hlsl
│ ├── StandardPipeline.spire
│ ├── Utils.spire
│ └── shader1.spire
├── Preprocessor
│ ├── define-function-like.spire
│ ├── define-function-like.spire.expected
│ ├── define-simple.spire
│ ├── if.spire
│ ├── ifdef.spire
│ ├── include-a.spireh
│ └── include.spire
└── SpireTestTool
│ ├── SpireTestTool.vcxproj
│ ├── SpireTestTool.vcxproj.filters
│ ├── main.cpp
│ ├── os.cpp
│ └── os.h
└── test.bat
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_style = tab
3 | indent_size = 4
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | DebugClang/
2 | *.user
3 | autotuneLog.txt
4 | LibraryRelease/CodePack.exe
5 | *.exe
6 | *.exe.config
7 | *.exe.manifest
8 | *.pdb
9 | .vs
10 | *.VC.opendb
11 | *.VC.db
12 | *.spire.actual
13 | LibraryRelease/Spire.cpp
14 | *.sdf
15 | Debug/
16 | Release/
17 | x64/
18 | *.TMP
19 | *.cse
20 |
--------------------------------------------------------------------------------
/Examples/hello/README.md:
--------------------------------------------------------------------------------
1 | Spire "Hello World" Example
2 | ===========================
3 |
4 | The goal of this example is to demonstrate an almost minimal application that uses Spire for shading, and D3D11 for rendering.
5 |
6 | The `hello.spire` file contains a simple declaration of a Spire *shader module*, along with a *pipeline declaration* that will be used for mapping shader code to the capabilities of the "engine" (in this case, just vertex and fragment shaders).
7 | The `hello.cpp` file contains the C++ application code, showing how to use the Spire C API to load and compile the shader code, and construct a (trivial) executable shader from Spire modules.
8 |
9 | Note that this example is not intended to demonstrate good practices for integrating Spire into a production engine; the goal is merely to use the minimum amount of code possible to demonstrate a complete applicaiton that uses Spire.
10 |
--------------------------------------------------------------------------------
/Examples/hello/hello.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hello", "hello.vcxproj", "{E6385042-1649-4803-9EBD-168F8B7EF131}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x64.ActiveCfg = Debug|x64
17 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x64.Build.0 = Debug|x64
18 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x86.ActiveCfg = Debug|Win32
19 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Debug|x86.Build.0 = Debug|Win32
20 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x64.ActiveCfg = Release|x64
21 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x64.Build.0 = Release|x64
22 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x86.ActiveCfg = Release|Win32
23 | {E6385042-1649-4803-9EBD-168F8B7EF131}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/Examples/hello/hello.spire:
--------------------------------------------------------------------------------
1 | // shaders.spire
2 |
3 | // TODO(tfoley): strip this down to a minimal pipeline
4 |
5 | pipeline StandardPipeline
6 | {
7 | [Pinned]
8 | input world MeshVertex;
9 |
10 | world CoarseVertex;// : "glsl(vertex:projCoord)" using projCoord export standardExport;
11 | world Fragment;// : "glsl" export fragmentExport;
12 |
13 | require @CoarseVertex vec4 projCoord;
14 |
15 | [VertexInput]
16 | extern @CoarseVertex MeshVertex vertAttribIn;
17 | import(MeshVertex->CoarseVertex) vertexImport()
18 | {
19 | return project(vertAttribIn);
20 | }
21 |
22 | extern @Fragment CoarseVertex CoarseVertexIn;
23 | import(CoarseVertex->Fragment) standardImport()
24 | // TODO(tfoley): this trait doesn't seem to be implemented on `vec3`
25 | // require trait IsTriviallyPassable(CoarseVertex)
26 | {
27 | return project(CoarseVertexIn);
28 | }
29 |
30 | stage vs : VertexShader
31 | {
32 | World: CoarseVertex;
33 | Position: projCoord;
34 | }
35 |
36 | stage fs : FragmentShader
37 | {
38 | World: Fragment;
39 | }
40 | }
41 |
42 | module HelloModule
43 | {
44 | @MeshVertex vec3 position;
45 | @MeshVertex vec3 color;
46 |
47 | param mat4 modelViewProjection;
48 |
49 | public vec4 projCoord = modelViewProjection * vec4(position, 1.0);
50 |
51 | out @Fragment vec4 colorTarget = vec4(color,1);
52 | }
53 |
--------------------------------------------------------------------------------
/Examples/hello/hello.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Spire - The MIT License (MIT)
3 | Copyright (c) 2016, Carnegie Mellon University
4 |
5 | Developers: Yong He, Haomin Long, Teguh Hofstee
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a
8 | copy of this software and associated documentation files (the "Software"),
9 | to deal in the Software without restriction, including without limitation
10 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | and/or sell copies of the Software, and to permit persons to whom the
12 | Software is furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | DEALINGS IN THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Spire
3 | Spire is a shading language and compiler framework that facilitates modular shader authoring and rapid exploration of shader optimization choices (such as frequency reduction and algorithmic approximation) afforded by modern real-time graphics engines. The current implementation of the Spire compiler can generate either GLSL or SPIR-V output for use with OpenGL and Vulkan based engines.
4 |
5 | For an example of intergrating Spire into a game engine, head to this repository:
6 | https://github.com/csyonghe/GameEngine
7 |
8 | Note: This repository is no longer being updated. Code here is used to produce the work of our SIGGRAPH 2017 publication. Please check out our latest development of the Spire shading language at https://github.com/shader-slang/slang.
9 |
10 | # Publications
11 |
12 | [Shader Components: Modular and High Performance Shader Development](http://graphics.cs.cmu.edu/projects/shadercomp/) SIGGRAPH 2017
13 |
14 | [A System for Rapid Exploration of Shader Optimization Choices](http://graphics.cs.cmu.edu/projects/spire/) SIGGRAPH 2016
15 |
--------------------------------------------------------------------------------
/Source/CoreLib/Allocator.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_ALLOCATOR_H
2 | #define CORE_LIB_ALLOCATOR_H
3 |
4 | #include
5 |
6 | namespace CoreLib
7 | {
8 | namespace Basic
9 | {
10 | inline void * AlignedAlloc(size_t size, size_t alignment)
11 | {
12 | #ifdef _MSC_VER
13 | return _aligned_malloc(size, alignment);
14 | #else
15 | void * rs = 0;
16 | int succ = posix_memalign(&rs, alignment, size);
17 | if (succ!=0)
18 | rs = 0;
19 | return rs;
20 | #endif
21 | }
22 |
23 | inline void AlignedFree(void * ptr)
24 | {
25 | #ifdef _MSC_VER
26 | _aligned_free(ptr);
27 | #else
28 | free(ptr);
29 | #endif
30 | }
31 |
32 | class StandardAllocator
33 | {
34 | public:
35 | // not really called
36 | void * Alloc(size_t size)
37 | {
38 | return malloc(size);
39 | }
40 | void Free(void * ptr)
41 | {
42 | return free(ptr);
43 | }
44 | };
45 |
46 | template
47 | class AlignedAllocator
48 | {
49 | public:
50 | void * Alloc(size_t size)
51 | {
52 | return AlignedAlloc(size, alignment);
53 | }
54 | void Free(void * ptr)
55 | {
56 | return AlignedFree(ptr);
57 | }
58 | };
59 | }
60 | }
61 |
62 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/Array.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_ARRAY_H
2 | #define CORE_LIB_ARRAY_H
3 |
4 | #include "Exception.h"
5 | #include "ArrayView.h"
6 |
7 | namespace CoreLib
8 | {
9 | namespace Basic
10 | {
11 | template
12 | class Array
13 | {
14 | private:
15 | T _buffer[size];
16 | int _count = 0;
17 | public:
18 | T* begin() const
19 | {
20 | return (T*)_buffer;
21 | }
22 | T* end() const
23 | {
24 | return (T*)_buffer + _count;
25 | }
26 | public:
27 | inline int GetCapacity() const
28 | {
29 | return size;
30 | }
31 | inline int Count() const
32 | {
33 | return _count;
34 | }
35 | inline T & First() const
36 | {
37 | return const_cast(_buffer[0]);
38 | }
39 | inline T & Last() const
40 | {
41 | return const_cast(_buffer[_count - 1]);
42 | }
43 | inline void SetSize(int newSize)
44 | {
45 | #ifdef _DEBUG
46 | if (newSize > size)
47 | throw IndexOutofRangeException("size too large.");
48 | #endif
49 | _count = newSize;
50 | }
51 | inline void Add(const T & item)
52 | {
53 | #ifdef _DEBUG
54 | if (_count == size)
55 | throw IndexOutofRangeException("out of range access to static array.");
56 | #endif
57 | _buffer[_count++] = item;
58 | }
59 | inline void Add(T && item)
60 | {
61 | #ifdef _DEBUG
62 | if (_count == size)
63 | throw IndexOutofRangeException("out of range access to static array.");
64 | #endif
65 | _buffer[_count++] = _Move(item);
66 | }
67 |
68 | inline T & operator [](int id) const
69 | {
70 | #if _DEBUG
71 | if (id >= _count || id < 0)
72 | throw IndexOutofRangeException("Operator[]: Index out of Range.");
73 | #endif
74 | return ((T*)_buffer)[id];
75 | }
76 |
77 | inline T* Buffer() const
78 | {
79 | return (T*)_buffer;
80 | }
81 |
82 | inline void Clear()
83 | {
84 | _count = 0;
85 | }
86 |
87 | template
88 | int IndexOf(const T2 & val) const
89 | {
90 | for (int i = 0; i < _count; i++)
91 | {
92 | if (_buffer[i] == val)
93 | return i;
94 | }
95 | return -1;
96 | }
97 |
98 | template
99 | int LastIndexOf(const T2 & val) const
100 | {
101 | for (int i = _count - 1; i >= 0; i--)
102 | {
103 | if (_buffer[i] == val)
104 | return i;
105 | }
106 | return -1;
107 | }
108 |
109 | inline ArrayView GetArrayView() const
110 | {
111 | return ArrayView((T*)_buffer, _count);
112 | }
113 | inline ArrayView GetArrayView(int start, int count) const
114 | {
115 | return ArrayView((T*)_buffer + start, count);
116 | }
117 | };
118 |
119 | template
120 | struct FirstType
121 | {
122 | typedef T type;
123 | };
124 |
125 |
126 | template
127 | void InsertArray(Array &) {}
128 |
129 | template
130 | void InsertArray(Array & arr, const T & val, TArgs... args)
131 | {
132 | arr.Add(val);
133 | InsertArray(arr, args...);
134 | }
135 |
136 | template
137 | auto MakeArray(TArgs ...args)
138 | {
139 | Array::type, sizeof...(args)> rs;
140 | InsertArray(rs, args...);
141 | return rs;
142 | }
143 | }
144 | }
145 |
146 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/ArrayView.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_ARRAY_VIEW_H
2 | #define CORE_LIB_ARRAY_VIEW_H
3 |
4 | #include "Exception.h"
5 |
6 | namespace CoreLib
7 | {
8 | namespace Basic
9 | {
10 | template
11 | class ArrayView
12 | {
13 | private:
14 | T * _buffer;
15 | int _count;
16 | int stride;
17 | public:
18 | T* begin() const
19 | {
20 | return _buffer;
21 | }
22 | T* end() const
23 | {
24 | return (T*)((char*)_buffer + _count*stride);
25 | }
26 | public:
27 | ArrayView()
28 | {
29 | _buffer = 0;
30 | _count = 0;
31 | }
32 | ArrayView(const T & singleObj)
33 | {
34 | SetData((T*)&singleObj, 1, sizeof(T));
35 | }
36 | ArrayView(T * buffer, int count)
37 | {
38 | SetData(buffer, count, sizeof(T));
39 | }
40 | ArrayView(void * buffer, int count, int _stride)
41 | {
42 | SetData(buffer, count, _stride);
43 | }
44 | void SetData(void * buffer, int count, int _stride)
45 | {
46 | this->_buffer = (T*)buffer;
47 | this->_count = count;
48 | this->stride = _stride;
49 | }
50 | inline int GetCapacity() const
51 | {
52 | return _count;
53 | }
54 | inline int Count() const
55 | {
56 | return _count;
57 | }
58 |
59 | inline T & operator [](int id) const
60 | {
61 | #if _DEBUG
62 | if (id >= _count || id < 0)
63 | throw IndexOutofRangeException("Operator[]: Index out of Range.");
64 | #endif
65 | return *(T*)((char*)_buffer+id*stride);
66 | }
67 |
68 | inline T* Buffer() const
69 | {
70 | return _buffer;
71 | }
72 |
73 | template
74 | int IndexOf(const T2 & val) const
75 | {
76 | for (int i = 0; i < _count; i++)
77 | {
78 | if (*(T*)((char*)_buffer + i*stride) == val)
79 | return i;
80 | }
81 | return -1;
82 | }
83 |
84 | template
85 | int LastIndexOf(const T2 & val) const
86 | {
87 | for (int i = _count - 1; i >= 0; i--)
88 | {
89 | if (*(T*)((char*)_buffer + i*stride) == val)
90 | return i;
91 | }
92 | return -1;
93 | }
94 |
95 | template
96 | int FindFirst(const Func & predicate) const
97 | {
98 | for (int i = 0; i < _count; i++)
99 | {
100 | if (predicate(_buffer[i]))
101 | return i;
102 | }
103 | return -1;
104 | }
105 |
106 | template
107 | int FindLast(const Func & predicate) const
108 | {
109 | for (int i = _count - 1; i >= 0; i--)
110 | {
111 | if (predicate(_buffer[i]))
112 | return i;
113 | }
114 | return -1;
115 | }
116 | };
117 |
118 | template
119 | ArrayView MakeArrayView(const T & obj)
120 | {
121 | return ArrayView(obj);
122 | }
123 |
124 | template
125 | ArrayView MakeArrayView(T * buffer, int count)
126 | {
127 | return ArrayView(buffer, count);
128 | }
129 | }
130 | }
131 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/Basic.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_BASIC_H
2 | #define CORE_LIB_BASIC_H
3 |
4 | #include "Common.h"
5 | #include "LibMath.h"
6 | #include "LibString.h"
7 | #include "Array.h"
8 | #include "List.h"
9 | #include "Link.h"
10 | #include "SmartPointer.h"
11 | #include "Exception.h"
12 | #include "Dictionary.h"
13 | #include "Func.h"
14 | #include "Linq.h"
15 |
16 | namespace CoreLib
17 | {
18 | using namespace Basic;
19 | }
20 |
21 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 2.6)
2 | project (CoreLib)
3 |
4 | add_library(CoreLib_Basic STATIC
5 | Basic.h
6 | Common.h
7 | Dictionary.h
8 | Exception.h
9 | IntSet.h
10 | LibIO.cpp
11 | LibIO.h
12 | LibMath.cpp
13 | LibMath.h
14 | LibString.cpp
15 | LibString.h
16 | Link.h
17 | List.h
18 | Parser.cpp
19 | Parser.h
20 | PerformanceCounter.cpp
21 | PerformanceCounter.h
22 | SmartPointer.h
23 | Stream.cpp
24 | Stream.h
25 | TextIO.cpp
26 | TextIO.h
27 | Threading.h
28 | VectorMath.cpp
29 | VectorMath.h
30 | WideChar.cpp
31 | WideChar.h
32 | SecureCRT.h
33 | )
34 | add_subdirectory (Graphics)
35 | add_subdirectory (Imaging)
36 | add_subdirectory (Regex)
37 |
--------------------------------------------------------------------------------
/Source/CoreLib/CommandLineParser.cpp:
--------------------------------------------------------------------------------
1 | #include "CommandLineParser.h"
2 |
3 | namespace CoreLib
4 | {
5 | namespace Text
6 | {
7 | CommandLineParser::CommandLineParser(const String & cmdLine)
8 | {
9 | stream = Split(cmdLine, L' ');
10 | }
11 |
12 | String CommandLineParser::GetFileName()
13 | {
14 | if (stream.Count())
15 | return stream.First();
16 | else
17 | return "";
18 | }
19 |
20 | bool CommandLineParser::OptionExists(const String & opt)
21 | {
22 | for (auto & token : stream)
23 | {
24 | if (token.Equals(opt, false))
25 | {
26 | return true;
27 | }
28 | }
29 | return false;
30 | }
31 |
32 | String CommandLineParser::GetOptionValue(const String & opt)
33 | {
34 | for (int i = 0; i < stream.Count(); i++)
35 | {
36 | if (stream[i].Equals(opt, false))
37 | {
38 | if (i < stream.Count() - 1)
39 | return stream[i+1];
40 | return "";
41 | }
42 | }
43 | return "";
44 | }
45 |
46 | String CommandLineParser::GetToken(int id)
47 | {
48 | return stream[id];
49 | }
50 |
51 | int CommandLineParser::GetTokenCount()
52 | {
53 | return stream.Count();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Source/CoreLib/CommandLineParser.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_COMMANDLINE_PARSER
2 | #define CORE_LIB_COMMANDLINE_PARSER
3 |
4 | #include "Tokenizer.h"
5 |
6 | namespace CoreLib
7 | {
8 | namespace Text
9 | {
10 | class CommandLineParser : public Object
11 | {
12 | private:
13 | List stream;
14 | public:
15 | CommandLineParser(const String & cmdLine);
16 | String GetFileName();
17 | bool OptionExists(const String & opt);
18 | String GetOptionValue(const String & opt);
19 | String GetToken(int id);
20 | int GetTokenCount();
21 | };
22 | }
23 | }
24 |
25 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/Common.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_COMMON_H
2 | #define CORE_LIB_COMMON_H
3 |
4 | #include
5 |
6 | #ifdef __GNUC__
7 | #define CORE_LIB_ALIGN_16(x) x __attribute__((aligned(16)))
8 | #else
9 | #define CORE_LIB_ALIGN_16(x) __declspec(align(16)) x
10 | #endif
11 |
12 | #define VARIADIC_TEMPLATE
13 |
14 | namespace CoreLib
15 | {
16 | typedef int64_t Int64;
17 | typedef unsigned short Word;
18 | #ifdef _M_X64
19 | typedef int64_t PtrInt;
20 | #else
21 | typedef int PtrInt;
22 | #endif
23 | namespace Basic
24 | {
25 | class Object
26 | {
27 | public:
28 | virtual ~Object()
29 | {}
30 | };
31 |
32 | template
33 | inline T&& _Move(T & obj)
34 | {
35 | return static_cast(obj);
36 | }
37 |
38 | template
39 | inline void Swap(T & v0, T & v1)
40 | {
41 | T tmp = _Move(v0);
42 | v0 = _Move(v1);
43 | v1 = _Move(tmp);
44 | }
45 | }
46 | }
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/Source/CoreLib/Exception.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_EXCEPTION_H
2 | #define CORE_LIB_EXCEPTION_H
3 |
4 | #include "Common.h"
5 | #include "LibString.h"
6 |
7 | namespace CoreLib
8 | {
9 | namespace Basic
10 | {
11 | class Exception : public Object
12 | {
13 | public:
14 | String Message;
15 | Exception()
16 | {}
17 | Exception(const String & message)
18 | : Message(message)
19 | {
20 | }
21 | };
22 |
23 | class IndexOutofRangeException : public Exception
24 | {
25 | public:
26 | IndexOutofRangeException()
27 | {}
28 | IndexOutofRangeException(const String & message)
29 | : Exception(message)
30 | {
31 | }
32 |
33 | };
34 |
35 | class InvalidOperationException : public Exception
36 | {
37 | public:
38 | InvalidOperationException()
39 | {}
40 | InvalidOperationException(const String & message)
41 | : Exception(message)
42 | {
43 | }
44 |
45 | };
46 |
47 | class ArgumentException : public Exception
48 | {
49 | public:
50 | ArgumentException()
51 | {}
52 | ArgumentException(const String & message)
53 | : Exception(message)
54 | {
55 | }
56 |
57 | };
58 |
59 | class KeyNotFoundException : public Exception
60 | {
61 | public:
62 | KeyNotFoundException()
63 | {}
64 | KeyNotFoundException(const String & message)
65 | : Exception(message)
66 | {
67 | }
68 | };
69 | class KeyExistsException : public Exception
70 | {
71 | public:
72 | KeyExistsException()
73 | {}
74 | KeyExistsException(const String & message)
75 | : Exception(message)
76 | {
77 | }
78 | };
79 |
80 | class NotSupportedException : public Exception
81 | {
82 | public:
83 | NotSupportedException()
84 | {}
85 | NotSupportedException(const String & message)
86 | : Exception(message)
87 | {
88 | }
89 | };
90 |
91 | class NotImplementedException : public Exception
92 | {
93 | public:
94 | NotImplementedException()
95 | {}
96 | NotImplementedException(const String & message)
97 | : Exception(message)
98 | {
99 | }
100 | };
101 |
102 | class InvalidProgramException : public Exception
103 | {
104 | public:
105 | InvalidProgramException()
106 | {}
107 | InvalidProgramException(const String & message)
108 | : Exception(message)
109 | {
110 | }
111 | };
112 | }
113 | }
114 |
115 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/Func.h:
--------------------------------------------------------------------------------
1 | #ifndef CORELIB_FUNC_H
2 | #define CORELIB_FUNC_H
3 |
4 | #include "SmartPointer.h"
5 |
6 | namespace CoreLib
7 | {
8 | namespace Basic
9 | {
10 | template
11 | class FuncPtr
12 | {
13 | public:
14 | virtual TResult operator()(Arguments...) = 0;
15 | virtual bool operator == (const FuncPtr *)
16 | {
17 | return false;
18 | }
19 | virtual ~FuncPtr() {}
20 | };
21 |
22 | template
23 | class CdeclFuncPtr : public FuncPtr
24 | {
25 | public:
26 | typedef TResult (*FuncType)(Arguments...);
27 | private:
28 | FuncType funcPtr;
29 | public:
30 | CdeclFuncPtr(FuncType func)
31 | :funcPtr(func)
32 | {
33 | }
34 |
35 | virtual TResult operator()(Arguments... params) override
36 | {
37 | return funcPtr(params...);
38 | }
39 |
40 | virtual bool operator == (const FuncPtr * ptr) override
41 | {
42 | auto cptr = dynamic_cast*>(ptr);
43 | if (cptr)
44 | return funcPtr == cptr->funcPtr;
45 | else
46 | return false;
47 | }
48 | };
49 |
50 | template
51 | class MemberFuncPtr : public FuncPtr
52 | {
53 | public:
54 | typedef TResult (Class::*FuncType)(Arguments...);
55 | private:
56 | FuncType funcPtr;
57 | Class * object;
58 | public:
59 | MemberFuncPtr(Class * obj, FuncType func)
60 | : funcPtr(func), object(obj)
61 | {
62 | }
63 |
64 | virtual TResult operator()(Arguments... params) override
65 | {
66 | return (object->*funcPtr)(params...);
67 | }
68 |
69 | virtual bool operator == (const FuncPtr * ptr) override
70 | {
71 | auto cptr = dynamic_cast*>(ptr);
72 | if (cptr)
73 | return funcPtr == cptr->funcPtr && object == cptr->object;
74 | else
75 | return false;
76 | }
77 | };
78 |
79 | template
80 | class LambdaFuncPtr : public FuncPtr
81 | {
82 | private:
83 | F func;
84 | public:
85 | LambdaFuncPtr(const F & _func)
86 | : func(_func)
87 | {}
88 | virtual TResult operator()(Arguments... params) override
89 | {
90 | return func(params...);
91 | }
92 | virtual bool operator == (const FuncPtr * /*ptr*/) override
93 | {
94 | return false;
95 | }
96 | };
97 |
98 | template
99 | class Func
100 | {
101 | private:
102 | RefPtr> funcPtr;
103 | public:
104 | Func(){}
105 | Func(typename CdeclFuncPtr::FuncType func)
106 | {
107 | funcPtr = new CdeclFuncPtr(func);
108 | }
109 | template
110 | Func(Class * object, typename MemberFuncPtr::FuncType func)
111 | {
112 | funcPtr = new MemberFuncPtr(object, func);
113 | }
114 | template
115 | Func(const TFuncObj & func)
116 | {
117 | funcPtr = new LambdaFuncPtr(func);
118 | }
119 | Func & operator = (typename CdeclFuncPtr::FuncType func)
120 | {
121 | funcPtr = new CdeclFuncPtr(func);
122 | return *this;
123 | }
124 | template
125 | Func & operator = (const MemberFuncPtr & func)
126 | {
127 | funcPtr = new MemberFuncPtr(func);
128 | return *this;
129 | }
130 | template
131 | Func & operator = (const TFuncObj & func)
132 | {
133 | funcPtr = new LambdaFuncPtr(func);
134 | return *this;
135 | }
136 | bool operator == (const Func & f)
137 | {
138 | return *funcPtr == f.funcPtr.Ptr();
139 | }
140 | bool operator != (const Func & f)
141 | {
142 | return !(*this == f);
143 | }
144 | TResult operator()(Arguments... params)
145 | {
146 | return (*funcPtr)(params...);
147 | }
148 | };
149 |
150 | // template
151 | // using Procedure = Func;
152 |
153 | template
154 | class Procedure : public Func
155 | {
156 | private:
157 | RefPtr> funcPtr;
158 | public:
159 | Procedure(){}
160 | Procedure(const Procedure & proc)
161 | {
162 | funcPtr = proc.funcPtr;
163 | }
164 | Procedure(typename CdeclFuncPtr::FuncType func)
165 | {
166 | funcPtr = new CdeclFuncPtr(func);
167 | }
168 | template
169 | Procedure(Class * object, typename MemberFuncPtr::FuncType func)
170 | {
171 | funcPtr = new MemberFuncPtr(object, func);
172 | }
173 | template
174 | Procedure(const TFuncObj & func)
175 | {
176 | funcPtr = new LambdaFuncPtr(func);
177 | }
178 | Procedure & operator = (typename CdeclFuncPtr::FuncType func)
179 | {
180 | funcPtr = new CdeclFuncPtr(func);
181 | return *this;
182 | }
183 | template
184 | Procedure & operator = (const MemberFuncPtr & func)
185 | {
186 | funcPtr = new MemberFuncPtr(func);
187 | return *this;
188 | }
189 | template
190 | Procedure & operator = (const TFuncObj & func)
191 | {
192 | funcPtr = new LambdaFuncPtr(func);
193 | return *this;
194 | }
195 | Procedure & operator = (const Procedure & proc)
196 | {
197 | funcPtr = proc.funcPtr;
198 | }
199 | void Clear()
200 | {
201 | funcPtr = nullptr;
202 | }
203 | void operator()(Arguments... params)
204 | {
205 | if (funcPtr)
206 | (*funcPtr)(params...);
207 | }
208 | };
209 | }
210 | }
211 |
212 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/Hash.h:
--------------------------------------------------------------------------------
1 | #ifndef CORELIB_HASH_H
2 | #define CORELIB_HASH_H
3 |
4 | #include "LibMath.h"
5 | #include
6 |
7 | namespace CoreLib
8 | {
9 | namespace Basic
10 | {
11 |
12 | inline int GetHashCode(double key)
13 | {
14 | return FloatAsInt((float)key);
15 | }
16 | inline int GetHashCode(float key)
17 | {
18 | return FloatAsInt(key);
19 | }
20 | inline int GetHashCode(const char * buffer)
21 | {
22 | if (!buffer)
23 | return 0;
24 | int hash = 0;
25 | int c;
26 | auto str = buffer;
27 | c = *str++;
28 | while (c)
29 | {
30 | hash = c + (hash << 6) + (hash << 16) - hash;
31 | c = *str++;
32 | }
33 | return hash;
34 | }
35 | inline int GetHashCode(char * buffer)
36 | {
37 | return GetHashCode(const_cast(buffer));
38 | }
39 |
40 | template
41 | class Hash
42 | {
43 | public:
44 | };
45 | template<>
46 | class Hash<1>
47 | {
48 | public:
49 | template
50 | static int GetHashCode(TKey & key)
51 | {
52 | return (int)key;
53 | }
54 | };
55 | template<>
56 | class Hash<0>
57 | {
58 | public:
59 | template
60 | static int GetHashCode(TKey & key)
61 | {
62 | return key.GetHashCode();
63 | }
64 | };
65 | template
66 | class PointerHash
67 | {};
68 | template<>
69 | class PointerHash<1>
70 | {
71 | public:
72 | template
73 | static int GetHashCode(TKey & key)
74 | {
75 | return (int)((CoreLib::PtrInt)key) / sizeof(typename std::remove_pointer::type);
76 | }
77 | };
78 | template<>
79 | class PointerHash<0>
80 | {
81 | public:
82 | template
83 | static int GetHashCode(TKey & key)
84 | {
85 | return Hash::value || std::is_enum::value>::GetHashCode(key);
86 | }
87 | };
88 |
89 | template
90 | int GetHashCode(const TKey & key)
91 | {
92 | return PointerHash::value>::GetHashCode(key);
93 | }
94 |
95 | template
96 | int GetHashCode(TKey & key)
97 | {
98 | return PointerHash::value>::GetHashCode(key);
99 | }
100 |
101 |
102 | }
103 | }
104 |
105 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/IntSet.h:
--------------------------------------------------------------------------------
1 | #ifndef BIT_VECTOR_INT_SET_H
2 | #define BIT_VECTOR_INT_SET_H
3 |
4 | #include
5 | #include "List.h"
6 | #include "LibMath.h"
7 | #include "Common.h"
8 | #include "Exception.h"
9 |
10 | namespace CoreLib
11 | {
12 | namespace Basic
13 | {
14 | class IntSet
15 | {
16 | private:
17 | List buffer;
18 | public:
19 | IntSet()
20 | {}
21 | IntSet(const IntSet & other)
22 | {
23 | buffer = other.buffer;
24 | }
25 | IntSet(IntSet && other)
26 | {
27 | *this = (_Move(other));
28 | }
29 | IntSet & operator = (IntSet && other)
30 | {
31 | buffer = _Move(other.buffer);
32 | return *this;
33 | }
34 | IntSet & operator = (const IntSet & other)
35 | {
36 | buffer = other.buffer;
37 | return *this;
38 | }
39 | int GetHashCode()
40 | {
41 | int rs = 0;
42 | for (auto val : buffer)
43 | rs ^= val;
44 | return rs;
45 | }
46 | IntSet(int maxVal)
47 | {
48 | SetMax(maxVal);
49 | }
50 | int Size() const
51 | {
52 | return buffer.Count()*32;
53 | }
54 | void SetMax(int val)
55 | {
56 | Resize(val);
57 | Clear();
58 | }
59 | void SetAll()
60 | {
61 | for (int i = 0; i>5);
68 | if (buffer.Count() > oldBufferSize)
69 | memset(buffer.Buffer()+oldBufferSize, 0, (buffer.Count()-oldBufferSize) * sizeof(int));
70 | }
71 | void Clear()
72 | {
73 | for (int i = 0; i>5;
79 | if (id < buffer.Count())
80 | buffer[id] |= (1<<(val&31));
81 | else
82 | {
83 | int oldSize = buffer.Count();
84 | buffer.SetSize(id+1);
85 | memset(buffer.Buffer() + oldSize, 0, (buffer.Count()-oldSize)*sizeof(int));
86 | buffer[id] |= (1<<(val&31));
87 | }
88 | }
89 | void Remove(int val)
90 | {
91 | if ((val>>5) < buffer.Count())
92 | buffer[(val>>5)] &= ~(1<<(val&31));
93 | }
94 | bool Contains(int val) const
95 | {
96 | if ((val>>5) >= buffer.Count())
97 | return false;
98 | return (buffer[(val>>5)] & (1<<(val&31))) != 0;
99 | }
100 | void UnionWith(const IntSet & set)
101 | {
102 | for (int i = 0; i buffer.Count())
107 | buffer.AddRange(set.buffer.Buffer()+buffer.Count(), set.buffer.Count()-buffer.Count());
108 | }
109 | bool operator == (const IntSet & set)
110 | {
111 | if (buffer.Count() != set.buffer.Count())
112 | return false;
113 | for (int i = 0; i
7 | #ifdef _WIN32
8 | #include
9 | #endif
10 | namespace CoreLib
11 | {
12 | namespace IO
13 | {
14 | using namespace CoreLib::Basic;
15 |
16 | CommandLineWriter * currentCommandWriter = nullptr;
17 |
18 | void SetCommandLineWriter(CommandLineWriter * writer)
19 | {
20 | currentCommandWriter = writer;
21 | }
22 |
23 | bool File::Exists(const String & fileName)
24 | {
25 | #ifdef _WIN32
26 | struct _stat32 statVar;
27 | return ::_wstat32(((String)fileName).ToWString(), &statVar) != -1;
28 | #else
29 | struct stat statVar;
30 | return ::stat(fileName.Buffer(), &statVar) == 0;
31 | #endif
32 | }
33 |
34 | String Path::TruncateExt(const String & path)
35 | {
36 | int dotPos = path.LastIndexOf('.');
37 | if (dotPos != -1)
38 | return path.SubString(0, dotPos);
39 | else
40 | return path;
41 | }
42 | String Path::ReplaceExt(const String & path, const char * newExt)
43 | {
44 | StringBuilder sb(path.Length()+10);
45 | int dotPos = path.LastIndexOf('.');
46 | if (dotPos == -1)
47 | dotPos = path.Length();
48 | sb.Append(path.Buffer(), dotPos);
49 | sb.Append('.');
50 | sb.Append(newExt);
51 | return sb.ProduceString();
52 | }
53 | String Path::GetFileName(const String & path)
54 | {
55 | int pos = path.LastIndexOf('/');
56 | pos = Math::Max(path.LastIndexOf('\\'), pos) + 1;
57 | return path.SubString(pos, path.Length()-pos);
58 | }
59 | String Path::GetFileNameWithoutEXT(const String & path)
60 | {
61 | int pos = path.LastIndexOf('/');
62 | pos = Math::Max(path.LastIndexOf('\\'), pos) + 1;
63 | int dotPos = path.LastIndexOf('.');
64 | if (dotPos <= pos)
65 | dotPos = path.Length();
66 | return path.SubString(pos, dotPos - pos);
67 | }
68 | String Path::GetFileExt(const String & path)
69 | {
70 | int dotPos = path.LastIndexOf('.');
71 | if (dotPos != -1)
72 | return path.SubString(dotPos+1, path.Length()-dotPos-1);
73 | else
74 | return "";
75 | }
76 | String Path::GetDirectoryName(const String & path)
77 | {
78 | int pos = path.LastIndexOf('/');
79 | pos = Math::Max(path.LastIndexOf('\\'), pos);
80 | if (pos != -1)
81 | return path.SubString(0, pos);
82 | else
83 | return "";
84 | }
85 | String Path::Combine(const String & path1, const String & path2)
86 | {
87 | if (path1.Length() == 0) return path2;
88 | StringBuilder sb(path1.Length()+path2.Length()+2);
89 | sb.Append(path1);
90 | if (!path1.EndsWith('\\') && !path1.EndsWith('/'))
91 | sb.Append(PathDelimiter);
92 | sb.Append(path2);
93 | return sb.ProduceString();
94 | }
95 | String Path::Combine(const String & path1, const String & path2, const String & path3)
96 | {
97 | StringBuilder sb(path1.Length()+path2.Length()+path3.Length()+3);
98 | sb.Append(path1);
99 | if (!path1.EndsWith('\\') && !path1.EndsWith('/'))
100 | sb.Append(PathDelimiter);
101 | sb.Append(path2);
102 | if (!path2.EndsWith('\\') && !path2.EndsWith('/'))
103 | sb.Append(PathDelimiter);
104 | sb.Append(path3);
105 | return sb.ProduceString();
106 | }
107 |
108 | bool Path::CreateDir(const String & path)
109 | {
110 | #if defined(_WIN32)
111 | return _wmkdir(path.ToWString()) == 0;
112 | #else
113 | return mkdir(path.Buffer(), 0777) == 0;
114 | #endif
115 | }
116 |
117 | CoreLib::Basic::String File::ReadAllText(const CoreLib::Basic::String & fileName)
118 | {
119 | StreamReader reader(new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
120 | return reader.ReadToEnd();
121 | }
122 |
123 | CoreLib::Basic::List File::ReadAllBytes(const CoreLib::Basic::String & fileName)
124 | {
125 | RefPtr fs = new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
126 | List buffer;
127 | while (!fs->IsEnd())
128 | {
129 | unsigned char ch;
130 | int read = (int)fs->Read(&ch, 1);
131 | if (read)
132 | buffer.Add(ch);
133 | else
134 | break;
135 | }
136 | return _Move(buffer);
137 | }
138 |
139 | void File::WriteAllText(const CoreLib::Basic::String & fileName, const CoreLib::Basic::String & text)
140 | {
141 | StreamWriter writer(new FileStream(fileName, FileMode::Create));
142 | writer.Write(text);
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/Source/CoreLib/LibIO.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_IO_H
2 | #define CORE_LIB_IO_H
3 |
4 | #include "LibString.h"
5 | #include "Stream.h"
6 | #include "TextIO.h"
7 | #include "SecureCRT.h"
8 |
9 | namespace CoreLib
10 | {
11 | namespace IO
12 | {
13 | class File
14 | {
15 | public:
16 | static bool Exists(const CoreLib::Basic::String & fileName);
17 | static CoreLib::Basic::String ReadAllText(const CoreLib::Basic::String & fileName);
18 | static CoreLib::Basic::List ReadAllBytes(const CoreLib::Basic::String & fileName);
19 | static void WriteAllText(const CoreLib::Basic::String & fileName, const CoreLib::Basic::String & text);
20 | };
21 |
22 | class Path
23 | {
24 | public:
25 | #ifdef _WIN32
26 | static const char PathDelimiter = '\\';
27 | #else
28 | static const char PathDelimiter = '/';
29 | #endif
30 | static String TruncateExt(const String & path);
31 | static String ReplaceExt(const String & path, const char * newExt);
32 | static String GetFileName(const String & path);
33 | static String GetFileNameWithoutEXT(const String & path);
34 | static String GetFileExt(const String & path);
35 | static String GetDirectoryName(const String & path);
36 | static String Combine(const String & path1, const String & path2);
37 | static String Combine(const String & path1, const String & path2, const String & path3);
38 | static bool CreateDir(const String & path);
39 | };
40 |
41 | class CommandLineWriter : public Object
42 | {
43 | public:
44 | virtual void Write(const String & text) = 0;
45 | };
46 |
47 | void SetCommandLineWriter(CommandLineWriter * writer);
48 |
49 | extern CommandLineWriter * currentCommandWriter;
50 | template
51 | void uiprintf(const wchar_t * format, Args... args)
52 | {
53 | if (currentCommandWriter)
54 | {
55 | char buffer[1024];
56 | snprintf(buffer, 1024, format, args...);
57 | currentCommandWriter->Write(buffer);
58 | }
59 | }
60 | }
61 | }
62 |
63 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/LibMath.cpp:
--------------------------------------------------------------------------------
1 | #include "LibMath.h"
2 |
3 | namespace CoreLib
4 | {
5 | namespace Basic
6 | {
7 | const float Math::Pi = 3.141592654f;
8 | }
9 | }
--------------------------------------------------------------------------------
/Source/CoreLib/LibMath.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_MATH_H
2 | #define CORE_LIB_MATH_H
3 |
4 | #include
5 |
6 | namespace CoreLib
7 | {
8 | namespace Basic
9 | {
10 | class Math
11 | {
12 | public:
13 | static const float Pi;
14 | template
15 | static T Min(const T& v1, const T&v2)
16 | {
17 | return v1
20 | static T Max(const T& v1, const T&v2)
21 | {
22 | return v1>v2?v1:v2;
23 | }
24 | template
25 | static T Min(const T& v1, const T&v2, const T&v3)
26 | {
27 | return Min(v1, Min(v2, v3));
28 | }
29 | template
30 | static T Max(const T& v1, const T&v2, const T&v3)
31 | {
32 | return Max(v1, Max(v2, v3));
33 | }
34 | template
35 | static T Clamp(const T& val, const T& vmin, const T&vmax)
36 | {
37 | if (val < vmin) return vmin;
38 | else if (val > vmax) return vmax;
39 | else return val;
40 | }
41 |
42 | static inline int FastFloor(float x)
43 | {
44 | int i = (int)x;
45 | return i - (i > x);
46 | }
47 |
48 | static inline int FastFloor(double x)
49 | {
50 | int i = (int)x;
51 | return i - (i > x);
52 | }
53 |
54 | static inline int IsNaN(float x)
55 | {
56 | #ifdef _M_X64
57 | return _isnanf(x);
58 | #else
59 | return isnan(x);
60 | #endif
61 | }
62 |
63 | static inline int IsInf(float x)
64 | {
65 | return isinf(x);
66 | }
67 |
68 | static inline unsigned int Ones32(register unsigned int x)
69 | {
70 | /* 32-bit recursive reduction using SWAR...
71 | but first step is mapping 2-bit values
72 | into sum of 2 1-bit values in sneaky way
73 | */
74 | x -= ((x >> 1) & 0x55555555);
75 | x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
76 | x = (((x >> 4) + x) & 0x0f0f0f0f);
77 | x += (x >> 8);
78 | x += (x >> 16);
79 | return(x & 0x0000003f);
80 | }
81 |
82 | static inline unsigned int Log2Floor(register unsigned int x)
83 | {
84 | x |= (x >> 1);
85 | x |= (x >> 2);
86 | x |= (x >> 4);
87 | x |= (x >> 8);
88 | x |= (x >> 16);
89 | return(Ones32(x >> 1));
90 | }
91 |
92 | static inline unsigned int Log2Ceil(register unsigned int x)
93 | {
94 | int y = (x & (x - 1));
95 | y |= -y;
96 | y >>= (32 - 1);
97 | x |= (x >> 1);
98 | x |= (x >> 2);
99 | x |= (x >> 4);
100 | x |= (x >> 8);
101 | x |= (x >> 16);
102 | return(Ones32(x >> 1) - y);
103 | }
104 | /*
105 | static inline int Log2(float x)
106 | {
107 | unsigned int ix = (unsigned int&)x;
108 | unsigned int exp = (ix >> 23) & 0xFF;
109 | int log2 = (unsigned int)(exp) - 127;
110 |
111 | return log2;
112 | }
113 | */
114 | };
115 | inline int FloatAsInt(float val)
116 | {
117 | union InterCast
118 | {
119 | float fvalue;
120 | int ivalue;
121 | } cast;
122 | cast.fvalue = val;
123 | return cast.ivalue;
124 | }
125 | inline float IntAsFloat(int val)
126 | {
127 | union InterCast
128 | {
129 | float fvalue;
130 | int ivalue;
131 | } cast;
132 | cast.ivalue = val;
133 | return cast.fvalue;
134 | }
135 |
136 | inline unsigned short FloatToHalf(float val)
137 | {
138 | int x = *(int*)&val;
139 | unsigned short bits = (x >> 16) & 0x8000;
140 | unsigned short m = (x >> 12) & 0x07ff;
141 | unsigned int e = (x >> 23) & 0xff;
142 | if (e < 103)
143 | return bits;
144 | if (e > 142)
145 | {
146 | bits |= 0x7c00u;
147 | bits |= e == 255 && (x & 0x007fffffu);
148 | return bits;
149 | }
150 | if (e < 113)
151 | {
152 | m |= 0x0800u;
153 | bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
154 | return bits;
155 | }
156 | bits |= ((e - 112) << 10) | (m >> 1);
157 | bits += m & 1;
158 | return bits;
159 | }
160 |
161 | inline float HalfToFloat(unsigned short input)
162 | {
163 | union InterCast
164 | {
165 | float fvalue;
166 | int ivalue;
167 | InterCast() = default;
168 | InterCast(int ival)
169 | {
170 | ivalue = ival;
171 | }
172 | };
173 | static const InterCast magic = InterCast((127 + (127 - 15)) << 23);
174 | static const InterCast was_infnan = InterCast((127 + 16) << 23);
175 | InterCast o;
176 | o.ivalue = (input & 0x7fff) << 13; // exponent/mantissa bits
177 | o.fvalue *= magic.fvalue; // exponent adjust
178 | if (o.fvalue >= was_infnan.fvalue) // make sure Inf/NaN survive
179 | o.ivalue |= 255 << 23;
180 | o.ivalue |= (input & 0x8000) << 16; // sign bit
181 | return o.fvalue;
182 | }
183 |
184 | class Random
185 | {
186 | private:
187 | unsigned int seed;
188 | public:
189 | Random(int seed)
190 | {
191 | this->seed = seed;
192 | }
193 | int Next() // random between 0 and RandMax (currently 0x7fff)
194 | {
195 | return (((seed = seed * 214013L + 2531011L) >> 16) & 0x7fff);
196 | }
197 | int Next(int min, int max) // inclusive min, exclusive max
198 | {
199 | unsigned int a = ((seed = seed * 214013L + 2531011L) & 0xFFFF0000);
200 | unsigned int b = ((seed = seed * 214013L + 2531011L) >> 16);
201 | unsigned int r = a + b;
202 | return min + r % (max - min);
203 | }
204 | float NextFloat()
205 | {
206 | return ((Next() << 15) + Next()) / ((float)(1 << 30));
207 | }
208 | float NextFloat(float valMin, float valMax)
209 | {
210 | return valMin + (valMax - valMin) * NextFloat();
211 | }
212 | static int RandMax()
213 | {
214 | return 0x7fff;
215 | }
216 | };
217 | }
218 | }
219 |
220 | #endif
221 |
--------------------------------------------------------------------------------
/Source/CoreLib/LibString.cpp:
--------------------------------------------------------------------------------
1 | #include "LibString.h"
2 | #include "TextIO.h"
3 |
4 | namespace CoreLib
5 | {
6 | namespace Basic
7 | {
8 | _EndLine EndLine;
9 | String StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen)
10 | {
11 | String res;
12 | res.length = leftLen + rightLen;
13 | res.buffer = new char[res.length + 1];
14 | strcpy_s(res.buffer.Ptr(), res.length + 1, lhs);
15 | strcpy_s(res.buffer + leftLen, res.length + 1 - leftLen, rhs);
16 | return res;
17 | }
18 | String operator+(const char * op1, const String & op2)
19 | {
20 | if(!op2.buffer) // no string 2 - return first
21 | return String(op1);
22 |
23 | if (!op1) // no base string?! return the second string
24 | return op2;
25 |
26 | return StringConcat(op1, (int)strlen(op1), op2.buffer.Ptr(), op2.length);
27 | }
28 |
29 | String operator+(const String & op1, const char * op2)
30 | {
31 | if(!op1.buffer)
32 | return String(op2);
33 |
34 | return StringConcat(op1.buffer.Ptr(), op1.length, op2, (int)strlen(op2));
35 | }
36 |
37 | String operator+(const String & op1, const String & op2)
38 | {
39 | if(!op1.buffer && !op2.buffer)
40 | return String();
41 | else if(!op1.buffer)
42 | return String(op2);
43 | else if(!op2.buffer)
44 | return String(op1);
45 |
46 | return StringConcat(op1.buffer.Ptr(), op1.length, op2.buffer.Ptr(), op2.length);
47 | }
48 |
49 | int StringToInt(const String & str, int radix)
50 | {
51 | if (str.StartsWith("0x"))
52 | return (int)strtoll(str.Buffer(), NULL, 16);
53 | else
54 | return (int)strtoll(str.Buffer(), NULL, radix);
55 | }
56 | unsigned int StringToUInt(const String & str, int radix)
57 | {
58 | if (str.StartsWith("0x"))
59 | return (unsigned int)strtoull(str.Buffer(), NULL, 16);
60 | else
61 | return (unsigned int)strtoull(str.Buffer(), NULL, radix);
62 | }
63 | double StringToDouble(const String & str)
64 | {
65 | return (double)strtod(str.Buffer(), NULL);
66 | }
67 | float StringToFloat(const String & str)
68 | {
69 | return strtof(str.Buffer(), NULL);
70 | }
71 |
72 | String String::ReplaceAll(String src, String dst) const
73 | {
74 | String rs = *this;
75 | int index = 0;
76 | int srcLen = src.length;
77 | int len = rs.length;
78 | while ((index = rs.IndexOf(src, index)) != -1)
79 | {
80 | rs = rs.SubString(0, index) + dst + rs.SubString(index + srcLen, len - index - srcLen);
81 | len = rs.length;
82 | }
83 | return rs;
84 | }
85 |
86 | String String::FromWString(const wchar_t * wstr)
87 | {
88 | #ifdef _WIN32
89 | return CoreLib::IO::Encoding::UTF16->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)));
90 | #else
91 | return CoreLib::IO::Encoding::UTF32->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t)));
92 | #endif
93 | }
94 |
95 | String String::FromWChar(const wchar_t ch)
96 | {
97 | #ifdef _WIN32
98 | return CoreLib::IO::Encoding::UTF16->ToString((const char*)&ch, (int)(sizeof(wchar_t)));
99 | #else
100 | return CoreLib::IO::Encoding::UTF32->ToString((const char*)&ch, (int)(sizeof(wchar_t)));
101 | #endif
102 | }
103 |
104 | String String::FromUnicodePoint(unsigned int codePoint)
105 | {
106 | char buf[6];
107 | int len = CoreLib::IO::EncodeUnicodePointToUTF8(buf, (int)codePoint);
108 | buf[len] = 0;
109 | return String(buf);
110 | }
111 |
112 | const wchar_t * String::ToWString(int * len) const
113 | {
114 | if (!buffer)
115 | {
116 | if (len)
117 | *len = 0;
118 | return L"";
119 | }
120 | else
121 | {
122 | if (wcharBuffer)
123 | {
124 | if (len)
125 | *len = (int)wcslen(wcharBuffer);
126 | return wcharBuffer;
127 | }
128 | List buf;
129 | CoreLib::IO::Encoding::UTF16->GetBytes(buf, *this);
130 | if (len)
131 | *len = buf.Count() / sizeof(wchar_t);
132 | buf.Add(0);
133 | buf.Add(0);
134 | const_cast(this)->wcharBuffer = (wchar_t*)buf.Buffer();
135 | buf.ReleaseBuffer();
136 | return wcharBuffer;
137 | }
138 | }
139 |
140 | String String::PadLeft(char ch, int pLen)
141 | {
142 | StringBuilder sb;
143 | for (int i = 0; i < pLen - this->length; i++)
144 | sb << ch;
145 | for (int i = 0; i < this->length; i++)
146 | sb << buffer[i];
147 | return sb.ProduceString();
148 | }
149 |
150 | String String::PadRight(char ch, int pLen)
151 | {
152 | StringBuilder sb;
153 | for (int i = 0; i < this->length; i++)
154 | sb << buffer[i];
155 | for (int i = 0; i < pLen - this->length; i++)
156 | sb << ch;
157 | return sb.ProduceString();
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/Source/CoreLib/Link.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_LINK_H
2 | #define CORE_LIB_LINK_H
3 |
4 | #include "Common.h"
5 | #include "Exception.h"
6 |
7 | namespace CoreLib
8 | {
9 | namespace Basic
10 | {
11 | template
12 | class LinkedList;
13 |
14 | template
15 | class LinkedNode
16 | {
17 | template
18 | friend class LinkedList;
19 | private:
20 | LinkedNode *pPrev, *pNext;
21 | LinkedList * FLink;
22 | public:
23 | T Value;
24 | LinkedNode (LinkedList * lnk):FLink(lnk)
25 | {
26 | pPrev = pNext = 0;
27 | };
28 | LinkedNode * GetPrevious()
29 | {
30 | return pPrev;
31 | };
32 | LinkedNode * GetNext()
33 | {
34 | return pNext;
35 | };
36 | LinkedNode * InsertAfter(const T & nData)
37 | {
38 | LinkedNode * n = new LinkedNode(FLink);
39 | n->Value = nData;
40 | n->pPrev = this;
41 | n->pNext = this->pNext;
42 | LinkedNode *npp = n->pNext;
43 | if (npp)
44 | {
45 | npp->pPrev = n;
46 | }
47 | pNext = n;
48 | if (!n->pNext)
49 | FLink->FTail = n;
50 | FLink->FCount ++;
51 | return n;
52 | };
53 | LinkedNode * InsertBefore(const T & nData)
54 | {
55 | LinkedNode * n = new LinkedNode(FLink);
56 | n->Value = nData;
57 | n->pPrev = pPrev;
58 | n->pNext = this;
59 | pPrev = n;
60 | LinkedNode *npp = n->pPrev;
61 | if (npp)
62 | npp->pNext = n;
63 | if (!n->pPrev)
64 | FLink->FHead = n;
65 | FLink->FCount ++;
66 | return n;
67 | };
68 | void Delete()
69 | {
70 | if (pPrev)
71 | pPrev->pNext = pNext;
72 | if (pNext)
73 | pNext->pPrev = pPrev;
74 | FLink->FCount --;
75 | if (FLink->FHead == this)
76 | {
77 | FLink->FHead = pNext;
78 | }
79 | if (FLink->FTail == this)
80 | {
81 | FLink->FTail = pPrev;
82 | }
83 | delete this;
84 | }
85 | };
86 | template
87 | class LinkedList
88 | {
89 | template
90 | friend class LinkedNode;
91 | private:
92 | LinkedNode * FHead, *FTail;
93 | int FCount;
94 | public:
95 | class Iterator
96 | {
97 | public:
98 | LinkedNode * Current, *Next;
99 | void SetCurrent(LinkedNode * cur)
100 | {
101 | Current = cur;
102 | if (Current)
103 | Next = Current->GetNext();
104 | else
105 | Next = 0;
106 | }
107 | Iterator()
108 | {
109 | Current = Next = 0;
110 | }
111 | Iterator(LinkedNode * cur)
112 | {
113 | SetCurrent(cur);
114 | }
115 | T & operator *() const
116 | {
117 | return Current->Value;
118 | }
119 | Iterator& operator ++()
120 | {
121 | SetCurrent(Next);
122 | return *this;
123 | }
124 | Iterator operator ++(int)
125 | {
126 | Iterator rs = *this;
127 | SetCurrent(Next);
128 | return rs;
129 | }
130 | bool operator != (const Iterator & iter) const
131 | {
132 | return Current != iter.Current;
133 | }
134 | bool operator == (const Iterator & iter) const
135 | {
136 | return Current == iter.Current;
137 | }
138 | };
139 | Iterator begin() const
140 | {
141 | return Iterator(FHead);
142 | }
143 | Iterator end() const
144 | {
145 | return Iterator(0);
146 | }
147 | public:
148 | LinkedList() : FHead(0), FTail(0), FCount(0)
149 | {
150 | }
151 | ~LinkedList()
152 | {
153 | Clear();
154 | }
155 | LinkedList(const LinkedList & link) : FHead(0), FTail(0), FCount(0)
156 | {
157 | this->operator=(link);
158 | }
159 | LinkedList(LinkedList && link) : FHead(0), FTail(0), FCount(0)
160 | {
161 | this->operator=(_Move(link));
162 | }
163 | LinkedList & operator = (LinkedList && link)
164 | {
165 | if (FHead != 0)
166 | Clear();
167 | FHead = link.FHead;
168 | FTail = link.FTail;
169 | FCount = link.FCount;
170 | link.FHead = 0;
171 | link.FTail = 0;
172 | link.FCount = 0;
173 | for (auto node = FHead; node; node = node->GetNext())
174 | node->FLink = this;
175 | return *this;
176 | }
177 | LinkedList & operator = (const LinkedList & link)
178 | {
179 | if (FHead != 0)
180 | Clear();
181 | auto p = link.FHead;
182 | while (p)
183 | {
184 | AddLast(p->Value);
185 | p = p->GetNext();
186 | }
187 | return *this;
188 | }
189 | template
190 | void ForEach(const IteratorFunc & f)
191 | {
192 | auto p = FHead;
193 | while (p)
194 | {
195 | f(p->Value);
196 | p = p->GetNext();
197 | }
198 | }
199 | LinkedNode * GetNode(int x)
200 | {
201 | LinkedNode *pCur = FHead;
202 | for (int i=0;ipNext;
206 | else
207 | throw "Index out of range";
208 | }
209 | return pCur;
210 | };
211 | LinkedNode * Find(const T& fData)
212 | {
213 | for (LinkedNode * pCur = FHead; pCur; pCur = pCur->pNext)
214 | {
215 | if (pCur->Value == fData)
216 | return pCur;
217 | }
218 | return 0;
219 | };
220 | LinkedNode * FirstNode() const
221 | {
222 | return FHead;
223 | };
224 | T & First() const
225 | {
226 | if (!FHead)
227 | throw IndexOutofRangeException("LinkedList: index out of range.");
228 | return FHead->Value;
229 | }
230 | T & Last() const
231 | {
232 | if (!FTail)
233 | throw IndexOutofRangeException("LinkedList: index out of range.");
234 | return FTail->Value;
235 | }
236 | LinkedNode * LastNode() const
237 | {
238 | return FTail;
239 | };
240 | LinkedNode * AddLast(const T & nData)
241 | {
242 | LinkedNode * n = new LinkedNode(this);
243 | n->Value = nData;
244 | n->pPrev = FTail;
245 | if (FTail)
246 | FTail->pNext = n;
247 | n->pNext = 0;
248 | FTail = n;
249 | if (!FHead)
250 | FHead = n;
251 | FCount ++;
252 | return n;
253 | };
254 | // Insert a blank node
255 | LinkedNode * AddLast()
256 | {
257 | LinkedNode * n = new LinkedNode(this);
258 | n->pPrev = FTail;
259 | if (FTail)
260 | FTail->pNext = n;
261 | n->pNext = 0;
262 | FTail = n;
263 | if (!FHead)
264 | FHead = n;
265 | FCount ++;
266 | return n;
267 | };
268 | LinkedNode * AddFirst(const T& nData)
269 | {
270 | LinkedNode *n = new LinkedNode(this);
271 | n->Value = nData;
272 | n->pPrev = 0;
273 | n->pNext = FHead;
274 | if (FHead)
275 | FHead->pPrev = n;
276 | FHead = n;
277 | if (!FTail)
278 | FTail = n;
279 | FCount ++;
280 | return n;
281 | };
282 | void Delete(LinkedNode*n, int Count = 1)
283 | {
284 | LinkedNode *n1,*n2 = 0, *tn;
285 | n1 = n->pPrev;
286 | tn = n;
287 | int numDeleted = 0;
288 | for (int i=0; ipNext;
291 | delete tn;
292 | tn = n2;
293 | numDeleted++;
294 | if (tn == 0)
295 | break;
296 | }
297 | if (n1)
298 | n1->pNext = n2;
299 | else
300 | FHead = n2;
301 | if (n2)
302 | n2->pPrev = n1;
303 | else
304 | FTail = n1;
305 | FCount -= numDeleted;
306 | }
307 | void Clear()
308 | {
309 | for (LinkedNode *n = FHead; n; )
310 | {
311 | LinkedNode * tmp = n->pNext;
312 | delete n;
313 | n = tmp;
314 | }
315 | FHead = 0;
316 | FTail = 0;
317 | FCount = 0;
318 | }
319 | List ToList() const
320 | {
321 | List rs;
322 | rs.Reserve(FCount);
323 | for (auto & item : *this)
324 | {
325 | rs.Add(item);
326 | }
327 | return rs;
328 | }
329 | int Count()
330 | {
331 | return FCount;
332 | }
333 | };
334 | }
335 | }
336 | #endif
337 |
--------------------------------------------------------------------------------
/Source/CoreLib/MemoryPool.cpp:
--------------------------------------------------------------------------------
1 | #include "MemoryPool.h"
2 | #include
3 |
4 | namespace CoreLib
5 | {
6 | namespace Basic
7 | {
8 | MemoryPool::MemoryPool(unsigned char * pBuffer, int pLog2BlockSize, int numBlocks)
9 | {
10 | Init(pBuffer, pLog2BlockSize, numBlocks);
11 | }
12 | void MemoryPool::Init(unsigned char * pBuffer, int pLog2BlockSize, int numBlocks)
13 | {
14 | assert(pLog2BlockSize >= 1 && pLog2BlockSize <= 30);
15 | assert(numBlocks >= 4);
16 | buffer = pBuffer;
17 | blockSize = 1 << pLog2BlockSize;
18 | log2BlockSize = pLog2BlockSize;
19 | numLevels = Math::Log2Floor(numBlocks);
20 | freeList[0] = (FreeListNode*)buffer;
21 | freeList[0]->NextPtr = nullptr;
22 | freeList[0]->PrevPtr = nullptr;
23 | used.SetMax(1 << (numLevels));
24 | for (int i = 1; i < MaxLevels; i++)
25 | {
26 | freeList[i] = nullptr;
27 | }
28 | }
29 | int MemoryPool::AllocBlock(int level)
30 | {
31 | if (level < 0)
32 | return -1;
33 | if (freeList[level] == nullptr)
34 | {
35 | auto largeBlockAddr = AllocBlock(level - 1);
36 | if (largeBlockAddr != -1)
37 | {
38 | auto block1 = (FreeListNode*)(buffer + ((largeBlockAddr ^ (1 << (numLevels - level))) << log2BlockSize));
39 | block1->NextPtr = nullptr;
40 | block1->PrevPtr = nullptr;
41 | freeList[level] = block1;
42 |
43 | int blockIndex = (1 << level) + (largeBlockAddr >> (numLevels-level)) - 1;
44 | used.Add(blockIndex);
45 | return largeBlockAddr;
46 | }
47 | else
48 | return -1;
49 | }
50 | else
51 | {
52 | auto node = freeList[level];
53 | if (node->NextPtr)
54 | {
55 | node->NextPtr->PrevPtr = node->PrevPtr;
56 | }
57 | freeList[level] = freeList[level]->NextPtr;
58 | int rs = (int)((unsigned char *)node - buffer) >> log2BlockSize;
59 | int blockIndex = (1 << level) + (rs >> (numLevels - level)) - 1;
60 | used.Add(blockIndex);
61 | return rs;
62 | }
63 | }
64 | unsigned char * MemoryPool::Alloc(int size)
65 | {
66 | if (size == 0)
67 | return nullptr;
68 | int originalSize = size;
69 | if (size < blockSize)
70 | size = blockSize;
71 | int order = numLevels - (Math::Log2Ceil(size) - log2BlockSize);
72 | assert(order >= 0 && order < MaxLevels);
73 |
74 | bytesAllocated += (1 << ((numLevels-order) + log2BlockSize));
75 | bytesWasted += (1 << ((numLevels - order) + log2BlockSize)) - originalSize;
76 |
77 | int blockId = AllocBlock(order);
78 | if (blockId != -1)
79 | return buffer + (blockId << log2BlockSize);
80 | else
81 | return nullptr;
82 | }
83 | void MemoryPool::FreeBlock(unsigned char * ptr, int level)
84 | {
85 | int indexInLevel = (int)(ptr - buffer) >> (numLevels - level + log2BlockSize);
86 | int blockIndex = (1 << level) + indexInLevel - 1;
87 | assert(used.Contains(blockIndex));
88 | int buddyIndex = (blockIndex & 1) ? blockIndex + 1 : blockIndex - 1;
89 | used.Remove(blockIndex);
90 | if (level > 0 && !used.Contains(buddyIndex))
91 | {
92 | auto buddyPtr = (FreeListNode *)(buffer + ((((int)(ptr - buffer) >> log2BlockSize) ^ (1 << (numLevels - level))) << log2BlockSize));
93 | if (buddyPtr->PrevPtr)
94 | {
95 | buddyPtr->PrevPtr->NextPtr = buddyPtr->NextPtr;
96 | }
97 | if (buddyPtr->NextPtr)
98 | {
99 | buddyPtr->NextPtr->PrevPtr = buddyPtr->PrevPtr;
100 | }
101 | if (freeList[level] == buddyPtr)
102 | {
103 | freeList[level] = buddyPtr->NextPtr;
104 | }
105 | // recursively free parent blocks
106 | auto parentPtr = Math::Min(buddyPtr, (FreeListNode*)ptr);
107 | if (level > 0)
108 | FreeBlock((unsigned char*)parentPtr, level - 1);
109 | }
110 | else
111 | {
112 | // insert to freelist
113 | auto freeNode = (FreeListNode *)ptr;
114 | freeNode->NextPtr = freeList[level];
115 | freeNode->PrevPtr = nullptr;
116 | if (freeList[level])
117 | freeList[level]->PrevPtr = freeNode;
118 | freeList[level] = freeNode;
119 | }
120 | }
121 | void MemoryPool::Free(unsigned char * ptr, int size)
122 | {
123 | if (size == 0)
124 | return;
125 | int originalSize = size;
126 | if (size < blockSize)
127 | size = blockSize;
128 | int level = numLevels - (Math::Log2Ceil(size) - log2BlockSize);
129 | bytesAllocated -= (1 << ((numLevels-level) + log2BlockSize));
130 | bytesWasted -= (1 << ((numLevels - level) + log2BlockSize)) - originalSize;
131 | FreeBlock(ptr, level);
132 | }
133 | }
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/Source/CoreLib/MemoryPool.h:
--------------------------------------------------------------------------------
1 | #ifndef CORE_LIB_MEMORY_POOL_H
2 | #define CORE_LIB_MEMORY_POOL_H
3 |
4 | #include "Basic.h"
5 | #include "IntSet.h"
6 |
7 | namespace CoreLib
8 | {
9 | namespace Basic
10 | {
11 | struct MemoryBlockFields
12 | {
13 | unsigned int Occupied : 1;
14 | unsigned int Order : 31;
15 | };
16 | struct FreeListNode
17 | {
18 | FreeListNode * PrevPtr = nullptr, *NextPtr = nullptr;
19 | };
20 | class MemoryPool
21 | {
22 | private:
23 | static const int MaxLevels = 32;
24 | int blockSize = 0, log2BlockSize = 0;
25 | int numLevels = 0;
26 | int bytesAllocated = 0;
27 | int bytesWasted = 0;
28 | unsigned char * buffer = nullptr;
29 | FreeListNode * freeList[MaxLevels];
30 | IntSet used;
31 | int AllocBlock(int level);
32 | void FreeBlock(unsigned char * ptr, int level);
33 | public:
34 | MemoryPool(unsigned char * buffer, int log2BlockSize, int numBlocks);
35 | MemoryPool() = default;
36 | void Init(unsigned char * buffer, int log2BlockSize, int numBlocks);
37 | unsigned char * Alloc(int size);
38 | void Free(unsigned char * ptr, int size);
39 | };
40 |
41 | class OutofPoolMemoryException : public Exception
42 | {};
43 |
44 | template
45 | class ObjectPool
46 | {
47 | static const int ObjectSize = sizeof(T) < 8 ? 8 : sizeof(T);
48 | private:
49 | struct FreeList
50 | {
51 | FreeList* Next;
52 | };
53 | FreeList * freeList = nullptr;
54 | int allocPtr = 0;
55 | int poolSize = 0;
56 | void * buffer = 0;
57 | T * GetFreeObject()
58 | {
59 | if (freeList)
60 | {
61 | auto rs = (T*)freeList;
62 | freeList = freeList->Next;
63 | return rs;
64 | }
65 | return nullptr;
66 | }
67 | public:
68 | ObjectPool()
69 | {
70 | freeList = nullptr;
71 | allocPtr = 0;
72 | buffer = malloc(PoolSize * ObjectSize);
73 | }
74 |
75 | void Close()
76 | {
77 | free(buffer);
78 | }
79 |
80 | void Free(T * obj)
81 | {
82 | auto newList = (FreeList*)obj;
83 | newList->Next = freeList;
84 | freeList = newList;
85 | }
86 |
87 | void * Buffer()
88 | {
89 | return buffer;
90 | }
91 |
92 | T * Alloc()
93 | {
94 | auto rs = GetFreeObject();
95 | if (!rs)
96 | {
97 | if (allocPtr < PoolSize)
98 | {
99 | rs = (T*)buffer + allocPtr;
100 | allocPtr++;
101 | }
102 | }
103 | if (!rs)
104 | {
105 | throw OutofPoolMemoryException();
106 | }
107 | return rs;
108 | }
109 | };
110 | };
111 |
112 | #define USE_POOL_ALLOCATOR(T, PoolSize) \
113 | private:\
114 | static CoreLib::ObjectPool _pool;\
115 | public:\
116 | void * operator new(std::size_t) { return _pool.Alloc(); } \
117 | void operator delete(void * ptr) {_pool.Free((T*)ptr); }\
118 | int GetObjectId() { return (int)(this - (T*)_pool.Buffer()); }\
119 | static void ClosePool();
120 | #define IMPL_POOL_ALLOCATOR(T, PoolSize) \
121 | CoreLib::ObjectPool T::_pool;\
122 | void T::ClosePool() { _pool.Close(); }
123 |
124 | }
125 |
126 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/SecureCRT.h:
--------------------------------------------------------------------------------
1 | #ifndef _MSC_VER
2 | #ifndef CORE_LIB_SECURE_CRT_H
3 | #define CORE_LIB_SECURE_CRT_H
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | inline void memcpy_s(void *dest, size_t numberOfElements, const void * src, size_t count)
10 | {
11 | memcpy(dest, src, count);
12 | }
13 |
14 | #define _TRUNCATE ((size_t)-1)
15 | #define _stricmp strcasecmp
16 |
17 | inline void fopen_s(FILE**f, const char * fileName, const char * mode)
18 | {
19 | *f = fopen(fileName, mode);
20 | }
21 |
22 | inline size_t fread_s(void * buffer, size_t bufferSize, size_t elementSize, size_t count, FILE * stream)
23 | {
24 | return fread(buffer, elementSize, count, stream);
25 | }
26 |
27 | inline size_t wcsnlen_s(const wchar_t * str, size_t /*numberofElements*/)
28 | {
29 | return wcslen(str);
30 | }
31 |
32 | inline size_t strnlen_s(const char * str, size_t numberofElements)
33 | {
34 | return strnlen(str, numberofElements);
35 | }
36 |
37 | inline int sprintf_s(char * buffer, size_t sizeOfBuffer, const char * format, ...)
38 | {
39 | va_list argptr;
40 | va_start(argptr, format);
41 | int rs = snprintf(buffer, sizeOfBuffer, format, argptr);
42 | va_end(argptr);
43 | return rs;
44 | }
45 |
46 | inline int swprintf_s(wchar_t * buffer, size_t sizeOfBuffer, const wchar_t * format, ...)
47 | {
48 | va_list argptr;
49 | va_start(argptr, format);
50 | int rs = swprintf(buffer, sizeOfBuffer, format, argptr);
51 | va_end(argptr);
52 | return rs;
53 | }
54 |
55 | inline void wcscpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource)
56 | {
57 | wcscpy(strDestination, strSource);
58 | }
59 | inline void strcpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource)
60 | {
61 | strcpy(strDestination, strSource);
62 | }
63 |
64 | inline void wcsncpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource, size_t count)
65 | {
66 | wcscpy(strDestination, strSource);
67 | //wcsncpy(strDestination, strSource, count);
68 | }
69 | inline void strncpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource, size_t count)
70 | {
71 | strncpy(strDestination, strSource, count);
72 | //wcsncpy(strDestination, strSource, count);
73 | }
74 | #endif
75 | #endif
76 |
--------------------------------------------------------------------------------
/Source/CoreLib/Stream.cpp:
--------------------------------------------------------------------------------
1 | #include "Stream.h"
2 | #ifdef _WIN32
3 | #include
4 | #endif
5 | #include "LibIO.h"
6 |
7 | namespace CoreLib
8 | {
9 | namespace IO
10 | {
11 | using namespace CoreLib::Basic;
12 | FileStream::FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode)
13 | {
14 | Init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None);
15 | }
16 | FileStream::FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share)
17 | {
18 | Init(fileName, fileMode, access, share);
19 | }
20 | void FileStream::Init(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share)
21 | {
22 | const wchar_t * mode = L"rt";
23 | const char* modeMBCS = "rt";
24 | switch (fileMode)
25 | {
26 | case CoreLib::IO::FileMode::Create:
27 | if (access == FileAccess::Read)
28 | throw ArgumentException("Read-only access is incompatible with Create mode.");
29 | else if (access == FileAccess::ReadWrite)
30 | {
31 | mode = L"w+b";
32 | modeMBCS = "w+b";
33 | this->fileAccess = FileAccess::ReadWrite;
34 | }
35 | else
36 | {
37 | mode = L"wb";
38 | modeMBCS = "wb";
39 | this->fileAccess = FileAccess::Write;
40 | }
41 | break;
42 | case CoreLib::IO::FileMode::Open:
43 | if (access == FileAccess::Read)
44 | {
45 | mode = L"rb";
46 | modeMBCS = "rb";
47 | this->fileAccess = FileAccess::Read;
48 | }
49 | else if (access == FileAccess::ReadWrite)
50 | {
51 | mode = L"r+b";
52 | modeMBCS = "r+b";
53 | this->fileAccess = FileAccess::ReadWrite;
54 | }
55 | else
56 | {
57 | mode = L"wb";
58 | modeMBCS = "wb";
59 | this->fileAccess = FileAccess::Write;
60 | }
61 | break;
62 | case CoreLib::IO::FileMode::CreateNew:
63 | if (File::Exists(fileName))
64 | {
65 | throw IOException("Failed opening '" + fileName + "', file already exists.");
66 | }
67 | if (access == FileAccess::Read)
68 | throw ArgumentException("Read-only access is incompatible with Create mode.");
69 | else if (access == FileAccess::ReadWrite)
70 | {
71 | mode = L"w+b";
72 | this->fileAccess = FileAccess::ReadWrite;
73 | }
74 | else
75 | {
76 | mode = L"wb";
77 | this->fileAccess = FileAccess::Write;
78 | }
79 | break;
80 | case CoreLib::IO::FileMode::Append:
81 | if (access == FileAccess::Read)
82 | throw ArgumentException("Read-only access is incompatible with Append mode.");
83 | else if (access == FileAccess::ReadWrite)
84 | {
85 | mode = L"a+b";
86 | this->fileAccess = FileAccess::ReadWrite;
87 | }
88 | else
89 | {
90 | mode = L"ab";
91 | this->fileAccess = FileAccess::Write;
92 | }
93 | break;
94 | default:
95 | break;
96 | }
97 | int shFlag;
98 | #ifdef _WIN32
99 | switch (share)
100 | {
101 | case CoreLib::IO::FileShare::None:
102 | shFlag = _SH_DENYRW;
103 | break;
104 | case CoreLib::IO::FileShare::ReadOnly:
105 | shFlag = _SH_DENYWR;
106 | break;
107 | case CoreLib::IO::FileShare::WriteOnly:
108 | shFlag = _SH_DENYRD;
109 | break;
110 | case CoreLib::IO::FileShare::ReadWrite:
111 | shFlag = _SH_DENYNO;
112 | break;
113 | default:
114 | throw ArgumentException("Invalid file share mode.");
115 | break;
116 | }
117 | handle = _wfsopen(fileName.ToWString(), mode, shFlag);
118 | #else
119 | handle = fopen(fileName.Buffer(), modeMBCS);
120 | #endif
121 | if (!handle)
122 | {
123 | throw IOException("Cannot open file '" + fileName + "'");
124 | }
125 | }
126 | FileStream::~FileStream()
127 | {
128 | Close();
129 | }
130 | Int64 FileStream::GetPosition()
131 | {
132 | #ifdef _WIN32
133 | fpos_t pos;
134 | fgetpos(handle, &pos);
135 | return pos;
136 | #else
137 | fpos64_t pos;
138 | fgetpos64(handle, &pos);
139 | return *(Int64*)(&pos);
140 | #endif
141 | }
142 | void FileStream::Seek(SeekOrigin origin, Int64 offset)
143 | {
144 | int _origin;
145 | switch (origin)
146 | {
147 | case CoreLib::IO::SeekOrigin::Start:
148 | _origin = SEEK_SET;
149 | endReached = false;
150 | break;
151 | case CoreLib::IO::SeekOrigin::End:
152 | _origin = SEEK_END;
153 | endReached = true;
154 | break;
155 | case CoreLib::IO::SeekOrigin::Current:
156 | _origin = SEEK_CUR;
157 | endReached = false;
158 | break;
159 | default:
160 | throw NotSupportedException("Unsupported seek origin.");
161 | break;
162 | }
163 | #ifdef _WIN32
164 | int rs = _fseeki64(handle, offset, _origin);
165 | #else
166 | int rs = fseek(handle, (int)offset, _origin);
167 | #endif
168 | if (rs != 0)
169 | {
170 | throw IOException("FileStream seek failed.");
171 | }
172 | }
173 | Int64 FileStream::Read(void * buffer, Int64 length)
174 | {
175 | auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle);
176 | if (bytes == 0 && length > 0)
177 | {
178 | if (!feof(handle))
179 | throw IOException("FileStream read failed.");
180 | else if (endReached)
181 | throw EndOfStreamException("End of file is reached.");
182 | endReached = true;
183 | }
184 | return (int)bytes;
185 | }
186 | Int64 FileStream::Write(const void * buffer, Int64 length)
187 | {
188 | auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle);
189 | if (bytes < length)
190 | {
191 | throw IOException("FileStream write failed.");
192 | }
193 | return bytes;
194 | }
195 | bool FileStream::CanRead()
196 | {
197 | return ((int)fileAccess & (int)FileAccess::Read) != 0;
198 | }
199 | bool FileStream::CanWrite()
200 | {
201 | return ((int)fileAccess & (int)FileAccess::Write) != 0;
202 | }
203 | void FileStream::Close()
204 | {
205 | if (handle)
206 | {
207 | fclose(handle);
208 | handle = 0;
209 | }
210 | }
211 | bool FileStream::IsEnd()
212 | {
213 | return endReached;
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/Source/CoreLib/Tokenizer.h:
--------------------------------------------------------------------------------
1 | #ifndef CORELIB_TEXT_PARSER_H
2 | #define CORELIB_TEXT_PARSER_H
3 |
4 | #include "Basic.h"
5 |
6 | namespace CoreLib
7 | {
8 | namespace Text
9 | {
10 | class TextFormatException : public Exception
11 | {
12 | public:
13 | TextFormatException(String message)
14 | : Exception(message)
15 | {}
16 | };
17 |
18 | inline bool IsLetter(char ch)
19 | {
20 | return ((ch >= 'a' && ch <= 'z') ||
21 | (ch >= 'A' && ch <= 'Z') || ch == '_');
22 | }
23 |
24 | inline bool IsDigit(char ch)
25 | {
26 | return ch >= '0' && ch <= '9';
27 | }
28 |
29 | inline bool IsPunctuation(char ch)
30 | {
31 | return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||
32 | ch == '!' || ch == '^' || ch == '&' || ch == '(' || ch == ')' ||
33 | ch == '=' || ch == '{' || ch == '}' || ch == '[' || ch == ']' ||
34 | ch == '|' || ch == ';' || ch == ',' || ch == '.' || ch == '<' ||
35 | ch == '>' || ch == '~' || ch == '@' || ch == ':' || ch == '?' || ch == '#';
36 | }
37 |
38 | inline bool IsWhiteSpace(char ch)
39 | {
40 | return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v');
41 | }
42 |
43 | class CodePosition
44 | {
45 | public:
46 | int Line = -1, Col = -1, Pos = -1;
47 | String FileName;
48 | String ToString()
49 | {
50 | StringBuilder sb(100);
51 | sb << FileName;
52 | if (Line != -1)
53 | sb << "(" << Line << ")";
54 | return sb.ProduceString();
55 | }
56 | CodePosition() = default;
57 | CodePosition(int line, int col, int pos, String fileName)
58 | {
59 | Line = line;
60 | Col = col;
61 | Pos = pos;
62 | this->FileName = fileName;
63 | }
64 | bool operator < (const CodePosition & pos) const
65 | {
66 | return FileName < pos.FileName || (FileName == pos.FileName && Line < pos.Line) ||
67 | (FileName == pos.FileName && Line == pos.Line && Col < pos.Col);
68 | }
69 | bool operator == (const CodePosition & pos) const
70 | {
71 | return FileName == pos.FileName && Line == pos.Line && Col == pos.Col;
72 | }
73 | };
74 |
75 | enum class TokenType
76 | {
77 | EndOfFile = -1,
78 | // illegal
79 | Unknown,
80 | // identifier
81 | Identifier,
82 | // constant
83 | IntLiterial, DoubleLiterial, StringLiterial, CharLiterial,
84 | // operators
85 | Semicolon, Comma, Dot, LBrace, RBrace, LBracket, RBracket, LParent, RParent,
86 | OpAssign, OpAdd, OpSub, OpMul, OpDiv, OpMod, OpNot, OpBitNot, OpLsh, OpRsh,
87 | OpEql, OpNeq, OpGreater, OpLess, OpGeq, OpLeq,
88 | OpAnd, OpOr, OpBitXor, OpBitAnd, OpBitOr,
89 | OpInc, OpDec, OpAddAssign, OpSubAssign, OpMulAssign, OpDivAssign, OpModAssign,
90 | OpShlAssign, OpShrAssign, OpOrAssign, OpAndAssign, OpXorAssign,
91 |
92 | QuestionMark, Colon, RightArrow, At, Pound, PoundPound,
93 | };
94 |
95 | String TokenTypeToString(TokenType type);
96 |
97 | enum TokenFlag : unsigned int
98 | {
99 | AtStartOfLine = 1 << 0,
100 | AfterWhitespace = 1 << 1,
101 | };
102 | typedef unsigned int TokenFlags;
103 |
104 | class Token
105 | {
106 | public:
107 | TokenType Type = TokenType::Unknown;
108 | String Content;
109 | CodePosition Position;
110 | TokenFlags flags = 0;
111 | Token() = default;
112 | Token(TokenType type, const String & content, int line, int col, int pos, String fileName, TokenFlags flags = 0)
113 | : flags(flags)
114 | {
115 | Type = type;
116 | Content = content;
117 | Position = CodePosition(line, col, pos, fileName);
118 | }
119 | };
120 |
121 | enum class TokenizeErrorType
122 | {
123 | InvalidCharacter, InvalidEscapeSequence
124 | };
125 |
126 | List TokenizeText(const String & fileName, const String & text, Procedure errorHandler);
127 | List TokenizeText(const String & fileName, const String & text);
128 | List TokenizeText(const String & text);
129 |
130 | String EscapeStringLiteral(String str);
131 | String UnescapeStringLiteral(String str);
132 |
133 | class TokenReader
134 | {
135 | private:
136 | bool legal;
137 | List tokens;
138 | int tokenPtr;
139 | public:
140 | TokenReader(Basic::String text);
141 | int ReadInt()
142 | {
143 | auto token = ReadToken();
144 | bool neg = false;
145 | if (token.Content == '-')
146 | {
147 | neg = true;
148 | token = ReadToken();
149 | }
150 | if (token.Type == TokenType::IntLiterial)
151 | {
152 | if (neg)
153 | return -StringToInt(token.Content);
154 | else
155 | return StringToInt(token.Content);
156 | }
157 | throw TextFormatException("Text parsing error: int expected.");
158 | }
159 | unsigned int ReadUInt()
160 | {
161 | auto token = ReadToken();
162 | if (token.Type == TokenType::IntLiterial)
163 | {
164 | return StringToUInt(token.Content);
165 | }
166 | throw TextFormatException("Text parsing error: int expected.");
167 | }
168 | double ReadDouble()
169 | {
170 | auto token = ReadToken();
171 | bool neg = false;
172 | if (token.Content == '-')
173 | {
174 | neg = true;
175 | token = ReadToken();
176 | }
177 | if (token.Type == TokenType::DoubleLiterial || token.Type == TokenType::IntLiterial)
178 | {
179 | if (neg)
180 | return -StringToDouble(token.Content);
181 | else
182 | return StringToDouble(token.Content);
183 | }
184 | throw TextFormatException("Text parsing error: floating point value expected.");
185 | }
186 | float ReadFloat()
187 | {
188 | return (float)ReadDouble();
189 | }
190 | String ReadWord()
191 | {
192 | auto token = ReadToken();
193 | if (token.Type == TokenType::Identifier)
194 | {
195 | return token.Content;
196 | }
197 | throw TextFormatException("Text parsing error: identifier expected.");
198 | }
199 | String Read(const char * expectedStr)
200 | {
201 | auto token = ReadToken();
202 | if (token.Content == expectedStr)
203 | {
204 | return token.Content;
205 | }
206 | throw TextFormatException("Text parsing error: \'" + String(expectedStr) + "\' expected.");
207 | }
208 | String Read(String expectedStr)
209 | {
210 | auto token = ReadToken();
211 | if (token.Content == expectedStr)
212 | {
213 | return token.Content;
214 | }
215 | throw TextFormatException("Text parsing error: \'" + expectedStr + "\' expected.");
216 | }
217 |
218 | String ReadStringLiteral()
219 | {
220 | auto token = ReadToken();
221 | if (token.Type == TokenType::StringLiterial)
222 | {
223 | return token.Content;
224 | }
225 | throw TextFormatException("Text parsing error: string literal expected.");
226 | }
227 | void Back(int count)
228 | {
229 | tokenPtr -= count;
230 | }
231 | Token ReadToken()
232 | {
233 | if (tokenPtr < tokens.Count())
234 | {
235 | auto &rs = tokens[tokenPtr];
236 | tokenPtr++;
237 | return rs;
238 | }
239 | throw TextFormatException("Unexpected ending.");
240 | }
241 | Token NextToken(int offset = 0)
242 | {
243 | if (tokenPtr + offset < tokens.Count())
244 | return tokens[tokenPtr + offset];
245 | else
246 | {
247 | Token rs;
248 | rs.Type = TokenType::Unknown;
249 | return rs;
250 | }
251 | }
252 | bool LookAhead(String token)
253 | {
254 | if (tokenPtr < tokens.Count())
255 | {
256 | auto next = NextToken();
257 | return next.Content == token;
258 | }
259 | else
260 | {
261 | return false;
262 | }
263 | }
264 | bool IsEnd()
265 | {
266 | return tokenPtr == tokens.Count();
267 | }
268 | public:
269 | bool IsLegalText()
270 | {
271 | return legal;
272 | }
273 | };
274 |
275 | List Split(String str, char c);
276 | }
277 | }
278 |
279 | #endif
--------------------------------------------------------------------------------
/Source/CoreLib/TypeTraits.h:
--------------------------------------------------------------------------------
1 | #ifndef CORELIB_TYPETRAITS_H
2 | #define CORELIB_TYPETRAITS_H
3 |
4 | namespace CoreLib
5 | {
6 | namespace Basic
7 | {
8 | struct TraitResultYes
9 | {
10 | char x;
11 | };
12 | struct TraitResultNo
13 | {
14 | char x[2];
15 | };
16 |
17 | template
18 | struct IsBaseOfTraitHost
19 | {
20 | operator B*() const { return nullptr; }
21 | operator D*() { return nullptr; }
22 | };
23 |
24 | template
25 | struct IsBaseOf
26 | {
27 | template
28 | static TraitResultYes Check(D*, T) { return TraitResultYes(); }
29 | static TraitResultNo Check(B*, int) { return TraitResultNo(); }
30 | enum { Value = sizeof(Check(IsBaseOfTraitHost(), int())) == sizeof(TraitResultYes) };
31 | };
32 |
33 | template
34 | struct EnableIf {};
35 |
36 | template
37 | struct EnableIf { typedef T type; };
38 |
39 | template
40 | struct IsConvertible
41 | {
42 | static TraitResultYes Use(B) {};
43 | static TraitResultNo Use(...) {};
44 | enum { Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) };
45 | };
46 | }
47 | }
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/Source/CoreLib/corelib.natvis:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {buffer.pointer,s}
7 | buffer.pointer,s
8 |
9 |
10 |
11 | {{ size={_count} }}
12 |
13 | - _count
14 |
15 | _count
16 | _buffer
17 |
18 |
19 |
20 |
21 |
22 | {{ size={_count} }}
23 |
24 | - _count
25 | - bufferSize
26 |
27 | _count
28 | buffer
29 |
30 |
31 |
32 |
33 |
34 |
35 | {{ size={_count} }}
36 |
37 | - _count
38 |
39 | _count
40 | _buffer
41 |
42 |
43 |
44 |
45 |
46 | {{ size={FCount} }}
47 |
48 |
49 | FCount
50 | FHead
51 | pNext
52 | Value
53 |
54 |
55 |
56 |
57 |
58 | {{ size={_count} }}
59 |
60 | - _count
61 | - bucketSizeMinusOne + 1
62 |
63 | bucketSizeMinusOne + 1
64 | hashMap
65 |
66 |
67 |
68 |
69 |
70 | {{ size={_count} }}
71 |
72 | - _count
73 | - bucketSizeMinusOne + 1
74 |
75 | kvPairs.FCount
76 | kvPairs.FHead
77 | pNext
78 | Value
79 |
80 |
81 |
82 |
83 |
84 | {{ size={dict._count} }}
85 |
86 | - dict._count
87 | - dict.bucketSizeMinusOne + 1
88 |
89 | dict.kvPairs.FCount
90 | dict.kvPairs.FHead
91 | pNext
92 | Value
93 |
94 |
95 |
96 |
97 |
98 | pointer
99 | empty
100 | RefPtr {*pointer}
101 |
102 | pointer
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/Source/SpireCompiler/D3DCompiler.cpp:
--------------------------------------------------------------------------------
1 | #include "D3DCompiler.h"
2 | #ifdef _WIN32
3 |
4 | #include
5 |
6 | using namespace CoreLib::Basic;
7 |
8 | typedef HRESULT (WINAPI *D3DCompile2Func)(
9 | LPCVOID pSrcData,
10 | SIZE_T SrcDataSize,
11 | LPCSTR pSourceName,
12 | D3D_SHADER_MACRO * pDefines,
13 | ID3DInclude * pInclude,
14 | LPCSTR pEntrypoint,
15 | LPCSTR pTarget,
16 | UINT Flags1,
17 | UINT Flags2,
18 | UINT SecondaryDataFlags,
19 | LPCVOID pSecondaryData,
20 | SIZE_T SecondaryDataSize,
21 | ID3DBlob **ppCode,
22 | ID3DBlob **ppErrorMsgs
23 | );
24 | typedef HRESULT (WINAPI *D3DCreateBlobFunc)(
25 | SIZE_T Size,
26 | ID3DBlob **ppBlob
27 | );
28 |
29 |
30 | class D3DCompilerImpl : public D3DCompiler
31 | {
32 | public:
33 | D3DCompile2Func D3DCompile2;
34 | D3DCreateBlobFunc D3DCreateBlob;
35 | HMODULE Lib;
36 | virtual bool Compile(CoreLib::String input, CoreLib::String stageName, CoreLib::String & errMsg) override
37 | {
38 | auto entryPoint = "main";
39 | char * profile = "ps_5_0";
40 | if (stageName == "vs")
41 | profile = "vs_5_0";
42 | else if (stageName == "tes")
43 | profile = "hs_5_0";
44 | else if (stageName == "tcs")
45 | profile = "ds_5_0";
46 | ID3DBlob *code, *err = nullptr;
47 | D3DCompile2(input.Buffer(), input.Length(), "", nullptr, nullptr, entryPoint, profile, 0, 0, 0, 0, 0, &code, &err);
48 | if (err != nullptr)
49 | {
50 | errMsg = (char*)err->GetBufferPointer();
51 | return false;
52 | }
53 | return true;
54 | }
55 | };
56 |
57 | D3DCompiler * LoadD3DCompiler()
58 | {
59 | auto d3dLib = LoadLibraryW(L"D3DCompiler_47.dll");
60 | if (d3dLib)
61 | {
62 | auto compileFunc = (D3DCompile2Func)GetProcAddress(d3dLib, "D3DCompile2");
63 | auto createBlobFunc = (D3DCreateBlobFunc)GetProcAddress(d3dLib, "D3DCreateBlob");
64 | if (compileFunc && createBlobFunc)
65 | {
66 | D3DCompilerImpl* result = new D3DCompilerImpl();
67 | result->D3DCompile2 = compileFunc;
68 | result->D3DCreateBlob = createBlobFunc;
69 | result->Lib = d3dLib;
70 | return result;
71 | }
72 | else
73 | FreeLibrary(d3dLib);
74 | }
75 | return nullptr;
76 | }
77 |
78 | #else
79 |
80 | D3DCompiler * LoadD3DCompiler()
81 | {
82 | return nullptr;
83 | }
84 |
85 | #endif
86 |
--------------------------------------------------------------------------------
/Source/SpireCompiler/D3DCompiler.h:
--------------------------------------------------------------------------------
1 | #ifndef SPIRE_D3D_COMPILER_H
2 | #define SPIRE_D3D_COMPILER_H
3 |
4 | #include "CoreLib/Basic.h"
5 |
6 | class D3DCompiler : public CoreLib::Object
7 | {
8 | public:
9 | virtual bool Compile(CoreLib::String input, CoreLib::String stageName, CoreLib::String & errMsg) = 0;
10 | };
11 |
12 | D3DCompiler * LoadD3DCompiler();
13 |
14 | #endif
--------------------------------------------------------------------------------
/Source/SpireCompiler/ShaderCompilerShell.cpp:
--------------------------------------------------------------------------------
1 | #include "CoreLib/LibIO.h"
2 | #include "SpireLib.h"
3 | #include "D3DCompiler.h"
4 |
5 | using namespace CoreLib::Basic;
6 | using namespace CoreLib::IO;
7 | using namespace Spire::Compiler;
8 |
9 | // Try to read an argument for a command-line option.
10 | String tryReadCommandLineArgument(wchar_t const* option, wchar_t***ioCursor, wchar_t**end)
11 | {
12 | wchar_t**& cursor = *ioCursor;
13 | if (cursor == end)
14 | {
15 | fprintf(stderr, "expected an argument for command-line option '%S'", option);
16 | exit(1);
17 | }
18 | else
19 | {
20 | return String::FromWString(*cursor++);
21 | }
22 | }
23 |
24 | int wmain(int argc, wchar_t* argv[])
25 | {
26 | int returnValue = -1;
27 | {
28 | // We need to parse any command-line arguments.
29 | String outputDir;
30 | CompileOptions options;
31 |
32 | // As we parse the command line, we will rewrite the
33 | // entries in `argv` to collect any "ordinary" arguments.
34 | wchar_t const** inputPaths = (wchar_t const**)&argv[1];
35 | wchar_t const** inputPathCursor = inputPaths;
36 |
37 | wchar_t** argCursor = &argv[1];
38 | wchar_t** argEnd = &argv[argc];
39 | while (argCursor != argEnd)
40 | {
41 | wchar_t const* arg = *argCursor++;
42 | if (arg[0] == '-')
43 | {
44 | String argStr = String::FromWString(arg);
45 |
46 | // The argument looks like an option, so try to parse it.
47 | if (argStr == "-out")
48 | outputDir = tryReadCommandLineArgument(arg, &argCursor, argEnd);
49 | else if (argStr == "-symbo")
50 | options.SymbolToCompile = tryReadCommandLineArgument(arg, &argCursor, argEnd);
51 | else if (argStr == "-schedule")
52 | options.ScheduleFileName = tryReadCommandLineArgument(arg, &argCursor, argEnd);
53 | else if (argStr == "-backend")
54 | {
55 | String name = tryReadCommandLineArgument(arg, &argCursor, argEnd);
56 | if (name == "glsl")
57 | {
58 | options.Target = CodeGenTarget::GLSL;
59 | }
60 | else if (name == "glsl_vk")
61 | {
62 | options.Target = CodeGenTarget::GLSL_Vulkan;
63 | }
64 | else if (name == "glsl_vk_onedesc")
65 | {
66 | options.Target = CodeGenTarget::GLSL_Vulkan_OneDesc;
67 | }
68 | else if (name == "hlsl")
69 | {
70 | options.Target = CodeGenTarget::HLSL;
71 | }
72 | else if (name == "spriv")
73 | {
74 | options.Target = CodeGenTarget::SPIRV;
75 | }
76 | else
77 | {
78 | fprintf(stderr, "unknown code generation target '%S'\n", name.ToWString());
79 | }
80 | }
81 | else if (argStr == "-genchoice")
82 | options.Mode = CompilerMode::GenerateChoice;
83 | else if (argStr == "--")
84 | {
85 | // The `--` option causes us to stop trying to parse options,
86 | // and treat the rest of the command line as input file names:
87 | while (argCursor != argEnd)
88 | {
89 | *inputPathCursor++ = *argCursor++;
90 | }
91 | break;
92 | }
93 | else
94 | {
95 | fprintf(stderr, "unknown command-line option '%S'\n", argStr.ToWString());
96 | // TODO: print a usage message
97 | exit(1);
98 | }
99 | }
100 | else
101 | {
102 | *inputPathCursor++ = arg;
103 | }
104 | }
105 |
106 | int inputPathCount = (int)(inputPathCursor - inputPaths);
107 | if (inputPathCount == 0)
108 | {
109 | fprintf(stderr, "error: no input file specified\n");
110 | exit(1);
111 | }
112 | else if (inputPathCount > 1)
113 | {
114 | fprintf(stderr, "error: multiple input files specified\n");
115 | exit(1);
116 | }
117 |
118 | String fileName = String::FromWString(inputPaths[0]);
119 |
120 | // Output directory defaults to the path of the input file
121 | if (outputDir.Length() == 0)
122 | {
123 | outputDir = Path::GetDirectoryName(fileName);
124 | }
125 |
126 | auto sourceDir = Path::GetDirectoryName(fileName);
127 | String schedule;
128 | if (options.ScheduleFileName.Length())
129 | {
130 | try
131 | {
132 | schedule = File::ReadAllText(options.ScheduleFileName);
133 | options.ScheduleSource = schedule;
134 | }
135 | catch (IOException)
136 | {
137 | printf("Cannot open schedule file '%S'.\n", options.ScheduleFileName.ToWString());
138 | goto end;
139 | }
140 | }
141 | CompileResult result;
142 | try
143 | {
144 | auto files = SpireLib::CompileShaderSourceFromFile(result, fileName, options);
145 | for (auto & f : files)
146 | {
147 |
148 | try
149 | {
150 | f.SaveToFile(Path::Combine(outputDir, f.MetaData.ShaderName + ".cse"));
151 | }
152 | catch (Exception &)
153 | {
154 | result.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, ""), Diagnostics::cannotWriteOutputFile, Path::Combine(outputDir, f.MetaData.ShaderName + ".cse"));
155 | }
156 | }
157 |
158 | if (options.Target == CodeGenTarget::HLSL)
159 | {
160 | // verify shader using D3DCompileShaderFromFile
161 | RefPtr d3dCompiler = LoadD3DCompiler();
162 | if (d3dCompiler)
163 | {
164 | for (auto & f : files)
165 | {
166 | for (auto & stage : f.Sources)
167 | {
168 | String errMsg;
169 | d3dCompiler->Compile(stage.Value.MainCode, stage.Key, errMsg);
170 | if (errMsg.Length())
171 | {
172 | auto dumpFileName = f.MetaData.ShaderName + "." + stage.Key + ".hlsl";
173 | result.GetErrorWriter()->diagnose(CodePosition(0, 0, 0, dumpFileName), Diagnostics::d3dCompileInfo, errMsg);
174 | File::WriteAllText(Path::Combine(Path::GetDirectoryName(fileName), dumpFileName), stage.Value.MainCode);
175 | }
176 | }
177 | }
178 | }
179 | else
180 | {
181 | printf("failed to load d3d compiler for verification.\n");
182 | }
183 | }
184 | }
185 | catch (Exception & e)
186 | {
187 | printf("internal compiler error: %S\n", e.Message.ToWString());
188 | }
189 | result.PrintDiagnostics();
190 | if (result.GetErrorCount() == 0)
191 | returnValue = 0;
192 |
193 | }
194 | end:;
195 | #ifdef _MSC_VER
196 | _CrtDumpMemoryLeaks();
197 | #endif
198 | return returnValue;
199 | }
--------------------------------------------------------------------------------
/Source/SpireCompiler/SpireCompiler.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 |
26 |
27 | Header Files
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Source/SpireCore/Closure.h:
--------------------------------------------------------------------------------
1 | #ifndef BAKERSL_SHADER_CLOSURE_H
2 | #define BAKERSL_SHADER_CLOSURE_H
3 | #include "SymbolTable.h"
4 |
5 | namespace Spire
6 | {
7 | namespace Compiler
8 | {
9 | RefPtr CreateShaderClosure(DiagnosticSink * sink, SymbolTable * symTable, ShaderSymbol * shader);
10 | void FlattenShaderClosure(DiagnosticSink * sink, SymbolTable * symTable, ShaderClosure * shader);
11 | void InsertImplicitImportOperators(DiagnosticSink * sink, ShaderIR * shader);
12 | }
13 | }
14 |
15 | #endif
--------------------------------------------------------------------------------
/Source/SpireCore/CodeGenBackend.h:
--------------------------------------------------------------------------------
1 | #ifndef CODE_GEN_BACKEND_H
2 | #define CODE_GEN_BACKEND_H
3 |
4 | #include "../CoreLib/Basic.h"
5 | #include "CompiledProgram.h"
6 | #include "SymbolTable.h"
7 | #include "TypeLayout.h"
8 |
9 | namespace Spire
10 | {
11 | namespace Compiler
12 | {
13 | class CodeGenBackend : public CoreLib::Basic::Object
14 | {
15 | public:
16 | virtual CompiledShaderSource GenerateShader(CompileResult & result, SymbolTable * symbols, ILShader * shader, DiagnosticSink * err) = 0;
17 | virtual LayoutRule GetDefaultLayoutRule() = 0;
18 | };
19 |
20 | CodeGenBackend * CreateGLSLCodeGen();
21 | CodeGenBackend * CreateGLSL_VulkanCodeGen();
22 | CodeGenBackend * CreateGLSL_VulkanOneDescCodeGen();
23 | CodeGenBackend * CreateHLSLCodeGen();
24 | CodeGenBackend * CreateSpirVCodeGen();
25 | }
26 | }
27 |
28 | #endif
--------------------------------------------------------------------------------
/Source/SpireCore/CodeWriter.h:
--------------------------------------------------------------------------------
1 | #ifndef IL_CODE_WRITER_H
2 | #define IL_CODE_WRITER_H
3 |
4 | #include "IL.h"
5 | #include "ShaderCompiler.h"
6 |
7 | namespace Spire
8 | {
9 | namespace Compiler
10 | {
11 | class CodeWriter
12 | {
13 | private:
14 | List> cfgNode;
15 | ConstantPool * constantPool = nullptr;
16 | public:
17 | void SetConstantPool(ConstantPool * pool)
18 | {
19 | constantPool = pool;
20 | }
21 | CFGNode * GetCurrentNode()
22 | {
23 | return cfgNode.Last().Ptr();
24 | }
25 | void PushNode()
26 | {
27 | RefPtr n = new CFGNode();
28 | cfgNode.Add(n);
29 | }
30 | RefPtr PopNode()
31 | {
32 | auto rs = cfgNode.Last();
33 | cfgNode.SetSize(cfgNode.Count() - 1);
34 | return rs;
35 | }
36 | void Assign(ILType * type, ILOperand * dest, ILOperand * src) // handles base type and ILArrayType assignment
37 | {
38 | auto arrType = dynamic_cast(type);
39 | if (arrType)
40 | {
41 | for (int i = 0; i < arrType->ArrayLength; i++)
42 | {
43 | auto srcAddr = Add(src, i);
44 | auto destAddr = Add(dest, i);
45 | Store(destAddr, Load(srcAddr));
46 | }
47 | }
48 | else
49 | Store(dest, Load(src));
50 | }
51 | ILOperand * Select(ILOperand * cond, ILOperand * v0, ILOperand * v1)
52 | {
53 | auto rs = new SelectInstruction(cond, v0, v1);
54 | cfgNode.Last()->InsertTail(rs);
55 | return rs;
56 | }
57 | ILOperand * BitAnd(ILOperand * v0, ILOperand * v1)
58 | {
59 | auto instr = new BitAndInstruction(v0, v1);
60 | cfgNode.Last()->InsertTail(instr);
61 | return instr;
62 | }
63 | ILOperand * BitAnd(ILOperand * v0, int c)
64 | {
65 | auto instr = new BitAndInstruction(v0, constantPool->CreateConstant(c));
66 | cfgNode.Last()->InsertTail(instr);
67 | return instr;
68 | }
69 | ILOperand * Add(ILOperand * v0, ILOperand * v1)
70 | {
71 | auto instr = new AddInstruction(v0, v1);
72 | cfgNode.Last()->InsertTail(instr);
73 | return instr;
74 | }
75 | ILOperand * Add(ILOperand * v0, int v1)
76 | {
77 | auto instr = new AddInstruction(v0, constantPool->CreateConstant(v1));
78 | cfgNode.Last()->InsertTail(instr);
79 | return instr;
80 | }
81 | ILOperand * Mul(ILOperand * v0, ILOperand * v1)
82 | {
83 | auto instr = new MulInstruction(v0, v1);
84 | cfgNode.Last()->InsertTail(instr);
85 | return instr;
86 | }
87 | ILOperand * Copy(ILOperand * src)
88 | {
89 | auto rs = new CopyInstruction(src);
90 | cfgNode.Last()->InsertTail(rs);
91 | return rs;
92 | }
93 | ILOperand * Load(ILOperand * src, int offset)
94 | {
95 | if (offset == 0)
96 | {
97 | auto instr = new LoadInstruction(src);
98 | cfgNode.Last()->InsertTail(instr);
99 | return instr;
100 | }
101 | else
102 | {
103 | auto dest = new AddInstruction(src, constantPool->CreateConstant(offset));
104 | cfgNode.Last()->InsertTail(dest);
105 | auto instr = new LoadInstruction(dest);
106 | cfgNode.Last()->InsertTail(instr);
107 | return instr;
108 | }
109 | }
110 | ILOperand * Load(ILOperand * src)
111 | {
112 | auto instr = new LoadInstruction(src);
113 | cfgNode.Last()->InsertTail(instr);
114 | return instr;
115 | }
116 | ILOperand * Load(ILOperand * src, ILOperand * offset)
117 | {
118 | auto dest = new AddInstruction(src, offset);
119 | cfgNode.Last()->InsertTail(dest);
120 | return Load(dest);
121 | }
122 | StoreInstruction * Store(ILOperand * dest, ILOperand * value)
123 | {
124 | auto instr = new StoreInstruction(dest, value);
125 | cfgNode.Last()->InsertTail(instr);
126 | return instr;
127 | }
128 | DiscardInstruction * Discard()
129 | {
130 | auto instr = new DiscardInstruction();
131 | cfgNode.Last()->InsertTail(instr);
132 | return instr;
133 | }
134 | MemberUpdateInstruction * Update(ILOperand * dest, ILOperand * offset, ILOperand * value)
135 | {
136 | auto instr = new MemberUpdateInstruction(dest, offset, value);
137 | cfgNode.Last()->InsertTail(instr);
138 | return instr;
139 | }
140 | MemberLoadInstruction * Retrieve(ILOperand * dest, ILOperand * offset)
141 | {
142 | auto instr = new MemberLoadInstruction(dest, offset);
143 | cfgNode.Last()->InsertTail(instr);
144 | return instr;
145 | }
146 | //AllocVarInstruction * AllocVar(ILType * type, ILOperand * size)
147 | //{
148 | // auto arrType = dynamic_cast(type);
149 | // if (arrType)
150 | // {
151 | // // check: size must be constant 1. Do not support array of array in IL level.
152 | // auto s = dynamic_cast(size);
153 | // if (!s || s->IntValues[0] != 1)
154 | // throw ArgumentException("AllocVar(arrayType, size): size must be constant 1.");
155 | // auto instr = new AllocVarInstruction(arrType->BaseType, program.CreateConstant(arrType->ArrayLength));
156 | // cfgNode->InsertTail(instr);
157 | // return instr;
158 | // }
159 | // else
160 | // {
161 | // auto instr = new AllocVarInstruction(type, size);
162 | // cfgNode->InsertTail(instr);
163 | // return instr;
164 | // }
165 | //}
166 | AllocVarInstruction * AllocVar(RefPtr & type, ILOperand * size)
167 | {
168 | auto arrType = dynamic_cast(type.Ptr());
169 | if (arrType)
170 | {
171 | // check: size must be constant 1. Do not support array of array in IL level.
172 | auto s = dynamic_cast(size);
173 | if (!s || s->IntValues[0] != 1)
174 | throw ArgumentException("AllocVar(arrayType, size): size must be constant 1.");
175 | auto instr = new AllocVarInstruction(arrType->BaseType, constantPool->CreateConstant(arrType->ArrayLength));
176 | cfgNode.Last()->InsertTail(instr);
177 | return instr;
178 | }
179 | else
180 | {
181 | auto instr = new AllocVarInstruction(type, size);
182 | cfgNode.Last()->InsertTail(instr);
183 | return instr;
184 | }
185 | }
186 | /*GLeaInstruction * GLea(ILType * type, const String & name)
187 | {
188 | auto arrType = dynamic_cast(type);
189 | auto instr = new GLeaInstruction();
190 | if (arrType)
191 | instr->Type = new ILPointerType(arrType->BaseType);
192 | else
193 | instr->Type = new ILPointerType(type);
194 | instr->Name = name;
195 | instr->VariableName = name;
196 | cfgNode->InsertTail(instr);
197 | return instr;
198 | }*/
199 | FetchArgInstruction * FetchArg(RefPtr type, int argId)
200 | {
201 | auto instr = new FetchArgInstruction(type);
202 | cfgNode.Last()->InsertTail(instr);
203 | instr->ArgId = argId;
204 | return instr;
205 | }
206 |
207 | void Insert(ILInstruction * instr)
208 | {
209 | cfgNode.Last()->InsertTail(instr);
210 | }
211 | };
212 | }
213 | }
214 |
215 | #endif
--------------------------------------------------------------------------------
/Source/SpireCore/CompiledProgram.cpp:
--------------------------------------------------------------------------------
1 | #include "CompiledProgram.h"
2 |
3 | namespace Spire
4 | {
5 | namespace Compiler
6 | {
7 | void IndentString(StringBuilder & sb, String src)
8 | {
9 | int indent = 0;
10 | bool beginTrim = true;
11 | for (int c = 0; c < src.Length(); c++)
12 | {
13 | auto ch = src[c];
14 | if (ch == '\n')
15 | {
16 | sb << "\n";
17 |
18 | beginTrim = true;
19 | }
20 | else
21 | {
22 | if (beginTrim)
23 | {
24 | while (c < src.Length() - 1 && (src[c] == '\t' || src[c] == '\n' || src[c] == '\r' || src[c] == ' '))
25 | {
26 | c++;
27 | ch = src[c];
28 | }
29 | for (int i = 0; i < indent - 1; i++)
30 | sb << '\t';
31 | if (ch != '}' && indent > 0)
32 | sb << '\t';
33 | beginTrim = false;
34 | }
35 |
36 | if (ch == '{')
37 | indent++;
38 | else if (ch == '}')
39 | indent--;
40 | if (indent < 0)
41 | indent = 0;
42 |
43 | sb << ch;
44 | }
45 | }
46 | }
47 | ShaderChoiceValue ShaderChoiceValue::Parse(String str)
48 | {
49 | return ShaderChoiceValue(str);
50 | }
51 |
52 | }
53 | }
--------------------------------------------------------------------------------
/Source/SpireCore/CompiledProgram.h:
--------------------------------------------------------------------------------
1 | #ifndef BAKER_SL_COMPILED_PROGRAM_H
2 | #define BAKER_SL_COMPILED_PROGRAM_H
3 |
4 | #include "../CoreLib/Basic.h"
5 | #include "Diagnostics.h"
6 | #include "IL.h"
7 | #include "Syntax.h"
8 |
9 | namespace Spire
10 | {
11 | namespace Compiler
12 | {
13 | class ConstantPoolImpl;
14 |
15 | class ConstantPool
16 | {
17 | private:
18 | ConstantPoolImpl * impl;
19 | public:
20 | ILConstOperand * CreateConstant(ILConstOperand * c);
21 | ILConstOperand * CreateConstantIntVec(int val0, int val1);
22 | ILConstOperand * CreateConstantIntVec(int val0, int val1, int val2);
23 | ILConstOperand * CreateConstantIntVec(int val0, int val1, int val3, int val4);
24 | ILConstOperand * CreateConstant(int val, int vectorSize = 0);
25 | ILConstOperand * CreateConstant(float val, int vectorSize = 0);
26 | ILConstOperand * CreateConstant(float val, float val1);
27 | ILConstOperand * CreateConstant(float val, float val1, float val2);
28 | ILConstOperand * CreateConstant(float val, float val1, float val2, float val3);
29 | ILConstOperand * CreateConstant(bool b);
30 | ILConstOperand * CreateConstantU(unsigned int u);
31 |
32 | ILOperand * CreateDefaultValue(ILType * type);
33 | ILUndefinedOperand * GetUndefinedOperand();
34 | ConstantPool();
35 | ~ConstantPool();
36 | };
37 |
38 | class ILShader;
39 |
40 | class ILWorld : public Object
41 | {
42 | public:
43 | String Name;
44 | CodePosition Position;
45 | RefPtr OutputType;
46 | List Inputs;
47 | RefPtr Code;
48 | EnumerableDictionary Components;
49 | bool IsAbstract = false;
50 | EnumerableDictionary Attributes;
51 | EnumerableHashSet ReferencedFunctions; // internal names of referenced functions
52 | ILShader * Shader = nullptr;
53 | };
54 |
55 | class StageAttribute
56 | {
57 | public:
58 | String Name;
59 | String Value;
60 | CodePosition Position;
61 | };
62 |
63 | class ILStage : public Object
64 | {
65 | public:
66 | CodePosition Position;
67 | String Name;
68 | String StageType;
69 | EnumerableDictionary Attributes;
70 | };
71 |
72 | class ILModuleParameterSet;
73 |
74 | class ILModuleParameterInstance : public ILOperand
75 | {
76 | public:
77 | ILModuleParameterSet * Module = nullptr;
78 | int BufferOffset = -1;
79 | int Size = 0;
80 | List BindingPoints; // for legacy API, usually one item. Samplers may have multiple binding points in OpenGL.
81 | virtual String ToString()
82 | {
83 | return "moduleParam<" + Name + ">";
84 | }
85 | };
86 |
87 | class ILModuleParameterSet : public RefObject
88 | {
89 | public:
90 | int BufferSize = 0;
91 | String BindingName;
92 | int DescriptorSetId = -1;
93 | int UniformBufferLegacyBindingPoint = -1;
94 | bool IsTopLevel = false;
95 |
96 | // for sub parameter sets: these are starting indices for each type of resource (for vk they should be the same)
97 | int TextureBindingStartIndex = 0, SamplerBindingStartIndex = 0, StorageBufferBindingStartIndex = 0, UniformBindingStartIndex = 0;
98 |
99 | // for sub parameter sets: this is the offset into parent's uniform buffer where fields of this parameter set started.
100 | int UniformBufferOffset = 0;
101 | EnumerableDictionary> Parameters;
102 | List> SubModules;
103 | };
104 |
105 | class ILShader
106 | {
107 | public:
108 | CodePosition Position;
109 | String Name;
110 | EnumerableDictionary> ModuleParamSets;
111 | EnumerableDictionary> Worlds;
112 | EnumerableDictionary> Stages;
113 | };
114 |
115 | class ILParameter
116 | {
117 | public:
118 | RefPtr Type;
119 | ParameterQualifier Qualifier;
120 | ILParameter() = default;
121 | ILParameter(RefPtr type, ParameterQualifier qualifier = ParameterQualifier::In)
122 | : Type(type), Qualifier(qualifier)
123 | {}
124 | };
125 |
126 | class ILFunction
127 | {
128 | public:
129 | EnumerableDictionary Parameters;
130 | RefPtr ReturnType;
131 | RefPtr Code;
132 | String Name;
133 | };
134 |
135 | class ILProgram
136 | {
137 | public:
138 | RefPtr ConstantPool = new Compiler::ConstantPool();
139 | List> Shaders;
140 | EnumerableDictionary> Functions;
141 | List> Structs;
142 | };
143 |
144 | class ShaderChoiceValue
145 | {
146 | public:
147 | String WorldName;
148 | ShaderChoiceValue() = default;
149 | ShaderChoiceValue(String world)
150 | {
151 | WorldName = world;
152 | }
153 | static ShaderChoiceValue Parse(String str);
154 | String ToString()
155 | {
156 | return WorldName;
157 | }
158 | bool operator == (const ShaderChoiceValue & val)
159 | {
160 | return WorldName == val.WorldName;
161 | }
162 | bool operator != (const ShaderChoiceValue & val)
163 | {
164 | return WorldName != val.WorldName;
165 | }
166 | int GetHashCode()
167 | {
168 | return WorldName.GetHashCode();
169 | }
170 | };
171 |
172 | class ShaderChoice
173 | {
174 | public:
175 | String ChoiceName;
176 | String DefaultValue;
177 | List Options;
178 | };
179 |
180 | class ShaderMetaData
181 | {
182 | public:
183 | CoreLib::String ShaderName;
184 | CoreLib::EnumerableDictionary> ParameterSets; // bindingName->DescSet
185 | };
186 |
187 | class StageSource
188 | {
189 | public:
190 | String MainCode;
191 | List BinaryCode;
192 | };
193 |
194 | class CompiledShaderSource
195 | {
196 | public:
197 | EnumerableDictionary Stages;
198 | ShaderMetaData MetaData;
199 | };
200 |
201 | void IndentString(StringBuilder & sb, String src);
202 |
203 | class CompileResult
204 | {
205 | public:
206 | DiagnosticSink sink;
207 | String ScheduleFile;
208 | RefPtr Program;
209 | List Choices;
210 | EnumerableDictionary CompiledSource; // shader -> stage -> code
211 | void PrintDiagnostics()
212 | {
213 | for (int i = 0; i < sink.diagnostics.Count(); i++)
214 | {
215 | fprintf(stderr, "%S(%d): %s %d: %S\n",
216 | sink.diagnostics[i].Position.FileName.ToWString(),
217 | sink.diagnostics[i].Position.Line,
218 | getSeverityName(sink.diagnostics[i].severity),
219 | sink.diagnostics[i].ErrorID,
220 | sink.diagnostics[i].Message.ToWString());
221 | }
222 | }
223 | CompileResult()
224 | {}
225 | DiagnosticSink * GetErrorWriter()
226 | {
227 | return &sink;
228 | }
229 | int GetErrorCount()
230 | {
231 | return sink.GetErrorCount();
232 | }
233 | };
234 |
235 | }
236 | }
237 |
238 | #endif
--------------------------------------------------------------------------------
/Source/SpireCore/Diagnostics.cpp:
--------------------------------------------------------------------------------
1 | // Diagnostics.cpp
2 | #include "Diagnostics.h"
3 |
4 | #include "CompiledProgram.h"
5 | #include "SymbolTable.h"
6 | #include "Syntax.h"
7 |
8 | #include
9 |
10 | namespace Spire {
11 | namespace Compiler {
12 |
13 | void printDiagnosticArg(StringBuilder& sb, char const* str)
14 | {
15 | sb << str;
16 | }
17 |
18 | void printDiagnosticArg(StringBuilder& sb, int str)
19 | {
20 | sb << str;
21 | }
22 |
23 | void printDiagnosticArg(StringBuilder& sb, CoreLib::Basic::String const& str)
24 | {
25 | sb << str;
26 | }
27 |
28 | void printDiagnosticArg(StringBuilder& sb, Decl* decl)
29 | {
30 | sb << decl->Name.Content;
31 | }
32 |
33 | void printDiagnosticArg(StringBuilder& sb, Type* type)
34 | {
35 | sb << type->DataType->ToString();
36 | }
37 |
38 | void printDiagnosticArg(StringBuilder& sb, ExpressionType* type)
39 | {
40 | sb << type->ToString();
41 | }
42 |
43 | void printDiagnosticArg(StringBuilder& sb, ILType* type)
44 | {
45 | sb << type->ToString();
46 | }
47 |
48 | void printDiagnosticArg(StringBuilder& sb, CoreLib::Text::TokenType tokenType)
49 | {
50 | sb << TokenTypeToString(tokenType);
51 | }
52 |
53 | void printDiagnosticArg(StringBuilder& sb, Token const& token)
54 | {
55 | sb << token.Content;
56 | }
57 |
58 | void printDiagnosticArg(StringBuilder& sb, StageAttribute const& attr)
59 | {
60 | sb << attr.Value;
61 | }
62 |
63 | CodePosition const& getDiagnosticPos(SyntaxNode const* syntax)
64 | {
65 | return syntax->Position;
66 | }
67 |
68 | CodePosition const& getDiagnosticPos(CoreLib::Text::Token const& token)
69 | {
70 | return token.Position;
71 | }
72 |
73 | CodePosition const& getDiagnosticPos(ShaderClosure* shader)
74 | {
75 | return shader->Position;
76 | }
77 |
78 | // Take the format string for a diagnostic message, along with its arguments, and turn it into a
79 | static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int argCount, DiagnosticArg const* const* args)
80 | {
81 | char const* spanBegin = format;
82 | for(;;)
83 | {
84 | char const* spanEnd = spanBegin;
85 | while (int c = *spanEnd)
86 | {
87 | if (c == '$')
88 | break;
89 | spanEnd++;
90 | }
91 |
92 | sb.Append(spanBegin, int(spanEnd - spanBegin));
93 | if (!*spanEnd)
94 | return;
95 |
96 | assert(*spanEnd == '$');
97 | spanEnd++;
98 | int d = *spanEnd++;
99 | switch (d)
100 | {
101 | // A double dollar sign `$$` is used to emit a single `$`
102 | case '$':
103 | sb.Append('$');
104 | break;
105 |
106 | // A single digit means to emit the corresponding argument.
107 | // TODO: support more than 10 arguments, and add options
108 | // to control formatting, etc.
109 | case '0': case '1': case '2': case '3': case '4':
110 | case '5': case '6': case '7': case '8': case '9':
111 | {
112 | int index = d - '0';
113 | if (index >= argCount)
114 | {
115 | // TODO(tfoley): figure out what a good policy will be for "panic" situations like this
116 | throw InvalidOperationException("too few arguments for diagnostic message");
117 | }
118 | else
119 | {
120 | DiagnosticArg const* arg = args[index];
121 | arg->printFunc(sb, arg->data);
122 | }
123 | }
124 | break;
125 |
126 | default:
127 | throw InvalidOperationException("invalid diagnostic message format");
128 | break;
129 | }
130 |
131 | spanBegin = spanEnd;
132 | }
133 | }
134 |
135 | void DiagnosticSink::diagnoseImpl(CodePosition const& pos, DiagnosticInfo const& info, int argCount, DiagnosticArg const* const* args)
136 | {
137 | StringBuilder sb;
138 | formatDiagnosticMessage(sb, info.messageFormat, argCount, args);
139 |
140 | Diagnostic diagnostic;
141 | diagnostic.ErrorID = info.id;
142 | diagnostic.Message = sb.ProduceString();
143 | diagnostic.Position = pos;
144 | diagnostic.severity = info.severity;
145 |
146 | diagnostics.Add(diagnostic);
147 | if (diagnostic.severity >= Severity::Error)
148 | {
149 | errorCount++;
150 | }
151 | if (diagnostic.severity >= Severity::Fatal)
152 | {
153 | // TODO: figure out a better policy for aborting compilation
154 | throw InvalidOperationException();
155 | }
156 | }
157 |
158 | namespace Diagnostics
159 | {
160 | #define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, messageFormat };
161 | #include "DiagnosticDefs.h"
162 | }
163 |
164 |
165 | }} // namespace Spire::Compiler
166 |
--------------------------------------------------------------------------------
/Source/SpireCore/GetDependencyVisitor.cpp:
--------------------------------------------------------------------------------
1 | #include "GetDependencyVisitor.h"
2 |
3 | namespace Spire
4 | {
5 | namespace Compiler
6 | {
7 | EnumerableHashSet GetDependentComponents(SyntaxNode * tree)
8 | {
9 | GetDependencyVisitor visitor;
10 | tree->Accept(&visitor);
11 | return visitor.Result;
12 | }
13 |
14 | RefPtr GetDependencyVisitor::VisitImportExpression(ImportExpressionSyntaxNode * syntax)
15 | {
16 | for (auto & comp : syntax->ImportOperatorDef->Usings)
17 | Result.Add(ComponentDependency(comp, nullptr));
18 | Result.Add(ComponentDependency(syntax->ComponentUniqueName, syntax->ImportOperatorDef.Ptr()));
19 | return SyntaxVisitor::VisitImportExpression(syntax);
20 | }
21 | RefPtr GetDependencyVisitor::VisitMemberExpression(MemberExpressionSyntaxNode * member)
22 | {
23 | RefPtr