diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-09 11:34:21 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-09 13:44:59 -0700 |
| commit | fcf83dbf9effab3bd98bad2b83b2468b7eb05cfd (patch) | |
| tree | 41047c94883b86ec085a81597391ce3ef557cd43 /source/core | |
| parent | 52e8d4b9a27ab0060f874c3a63ab531847be35c0 (diff) | |
Initial import of code.
Diffstat (limited to 'source/core')
30 files changed, 8027 insertions, 0 deletions
diff --git a/source/core/allocator.h b/source/core/allocator.h new file mode 100644 index 000000000..d4dfcf5a9 --- /dev/null +++ b/source/core/allocator.h @@ -0,0 +1,62 @@ +#ifndef CORE_LIB_ALLOCATOR_H +#define CORE_LIB_ALLOCATOR_H + +#include <stdlib.h> + +namespace CoreLib +{ + namespace Basic + { + inline void * AlignedAlloc(size_t size, size_t alignment) + { +#ifdef _MSC_VER + return _aligned_malloc(size, alignment); +#else + void * rs = 0; + int succ = posix_memalign(&rs, alignment, size); + if (succ!=0) + rs = 0; + return rs; +#endif + } + + inline void AlignedFree(void * ptr) + { +#ifdef _MSC_VER + _aligned_free(ptr); +#else + free(ptr); +#endif + } + + class StandardAllocator + { + public: + // not really called + void * Alloc(size_t size) + { + return malloc(size); + } + void Free(void * ptr) + { + return free(ptr); + } + }; + + template<int alignment> + class AlignedAllocator + { + public: + void * Alloc(size_t size) + { + return AlignedAlloc(size, alignment); + } + void Free(void * ptr) + { + return AlignedFree(ptr); + } + }; + } +} + +#endif
\ No newline at end of file diff --git a/source/core/array-view.h b/source/core/array-view.h new file mode 100644 index 000000000..201ef2a79 --- /dev/null +++ b/source/core/array-view.h @@ -0,0 +1,131 @@ +#ifndef CORE_LIB_ARRAY_VIEW_H +#define CORE_LIB_ARRAY_VIEW_H + +#include "Exception.h" + +namespace CoreLib +{ + namespace Basic + { + template<typename T> + class ArrayView + { + private: + T * _buffer; + int _count; + int stride; + public: + T* begin() const + { + return _buffer; + } + T* end() const + { + return (T*)((char*)_buffer + _count*stride); + } + public: + ArrayView() + { + _buffer = 0; + _count = 0; + } + ArrayView(const T & singleObj) + { + SetData((T*)&singleObj, 1, sizeof(T)); + } + ArrayView(T * buffer, int count) + { + SetData(buffer, count, sizeof(T)); + } + ArrayView(void * buffer, int count, int _stride) + { + SetData(buffer, count, _stride); + } + void SetData(void * buffer, int count, int _stride) + { + this->_buffer = (T*)buffer; + this->_count = count; + this->stride = _stride; + } + inline int GetCapacity() const + { + return _count; + } + inline int Count() const + { + return _count; + } + + inline T & operator [](int id) const + { +#if _DEBUG + if (id >= _count || id < 0) + throw IndexOutofRangeException("Operator[]: Index out of Range."); +#endif + return *(T*)((char*)_buffer+id*stride); + } + + inline T* Buffer() const + { + return _buffer; + } + + template<typename T2> + int IndexOf(const T2 & val) const + { + for (int i = 0; i < _count; i++) + { + if (*(T*)((char*)_buffer + i*stride) == val) + return i; + } + return -1; + } + + template<typename T2> + int LastIndexOf(const T2 & val) const + { + for (int i = _count - 1; i >= 0; i--) + { + if (*(T*)((char*)_buffer + i*stride) == val) + return i; + } + return -1; + } + + template<typename Func> + int FindFirst(const Func & predicate) const + { + for (int i = 0; i < _count; i++) + { + if (predicate(_buffer[i])) + return i; + } + return -1; + } + + template<typename Func> + int FindLast(const Func & predicate) const + { + for (int i = _count - 1; i >= 0; i--) + { + if (predicate(_buffer[i])) + return i; + } + return -1; + } + }; + + template<typename T> + ArrayView<T> MakeArrayView(const T & obj) + { + return ArrayView<T>(obj); + } + + template<typename T> + ArrayView<T> MakeArrayView(T * buffer, int count) + { + return ArrayView<T>(buffer, count); + } + } +} +#endif
\ No newline at end of file diff --git a/source/core/array.h b/source/core/array.h new file mode 100644 index 000000000..b6dbeab07 --- /dev/null +++ b/source/core/array.h @@ -0,0 +1,146 @@ +#ifndef CORE_LIB_ARRAY_H +#define CORE_LIB_ARRAY_H + +#include "exception.h" +#include "array-view.h" + +namespace CoreLib +{ + namespace Basic + { + template<typename T, int size> + class Array + { + private: + T _buffer[size]; + int _count = 0; + public: + T* begin() const + { + return (T*)_buffer; + } + T* end() const + { + return (T*)_buffer + _count; + } + public: + inline int GetCapacity() const + { + return size; + } + inline int Count() const + { + return _count; + } + inline T & First() const + { + return const_cast<T&>(_buffer[0]); + } + inline T & Last() const + { + return const_cast<T&>(_buffer[_count - 1]); + } + inline void SetSize(int newSize) + { +#ifdef _DEBUG + if (newSize > size) + throw IndexOutofRangeException("size too large."); +#endif + _count = newSize; + } + inline void Add(const T & item) + { +#ifdef _DEBUG + if (_count == size) + throw IndexOutofRangeException("out of range access to static array."); +#endif + _buffer[_count++] = item; + } + inline void Add(T && item) + { +#ifdef _DEBUG + if (_count == size) + throw IndexOutofRangeException("out of range access to static array."); +#endif + _buffer[_count++] = _Move(item); + } + + inline T & operator [](int id) const + { +#if _DEBUG + if (id >= _count || id < 0) + throw IndexOutofRangeException("Operator[]: Index out of Range."); +#endif + return ((T*)_buffer)[id]; + } + + inline T* Buffer() const + { + return (T*)_buffer; + } + + inline void Clear() + { + _count = 0; + } + + template<typename T2> + int IndexOf(const T2 & val) const + { + for (int i = 0; i < _count; i++) + { + if (_buffer[i] == val) + return i; + } + return -1; + } + + template<typename T2> + int LastIndexOf(const T2 & val) const + { + for (int i = _count - 1; i >= 0; i--) + { + if (_buffer[i] == val) + return i; + } + return -1; + } + + inline ArrayView<T> GetArrayView() const + { + return ArrayView<T>((T*)_buffer, _count); + } + inline ArrayView<T> GetArrayView(int start, int count) const + { + return ArrayView<T>((T*)_buffer + start, count); + } + }; + + template<typename T, typename ...TArgs> + struct FirstType + { + typedef T type; + }; + + + template<typename T, int size> + void InsertArray(Array<T, size> &) {} + + template<typename T, typename ...TArgs, int size> + void InsertArray(Array<T, size> & arr, const T & val, TArgs... args) + { + arr.Add(val); + InsertArray(arr, args...); + } + + template<typename ...TArgs> + auto MakeArray(TArgs ...args) -> Array<typename FirstType<TArgs...>::type, sizeof...(args)> + { + Array<typename FirstType<TArgs...>::type, sizeof...(args)> rs; + InsertArray(rs, args...); + return rs; + } + } +} + +#endif
\ No newline at end of file diff --git a/source/core/basic.h b/source/core/basic.h new file mode 100644 index 000000000..5b0e05e7b --- /dev/null +++ b/source/core/basic.h @@ -0,0 +1,21 @@ +#ifndef CORE_LIB_BASIC_H +#define CORE_LIB_BASIC_H + +#include "common.h" +#include "slang-math.h" +#include "slang-string.h" +#include "array.h" +#include "list.h" +#include "link.h" +#include "smart-pointer.h" +#include "exception.h" +#include "dictionary.h" +#include "func.h" +#include "linq.h" + +namespace CoreLib +{ + using namespace Basic; +} + +#endif
\ No newline at end of file diff --git a/source/core/common.h b/source/core/common.h new file mode 100644 index 000000000..517b018a7 --- /dev/null +++ b/source/core/common.h @@ -0,0 +1,48 @@ +#ifndef CORE_LIB_COMMON_H +#define CORE_LIB_COMMON_H + +#include <cstdint> + +#ifdef __GNUC__ +#define CORE_LIB_ALIGN_16(x) x __attribute__((aligned(16))) +#else +#define CORE_LIB_ALIGN_16(x) __declspec(align(16)) x +#endif + +#define VARIADIC_TEMPLATE + +namespace CoreLib +{ + typedef int64_t Int64; + typedef unsigned short Word; +#ifdef _M_X64 + typedef int64_t PtrInt; +#else + typedef int PtrInt; +#endif + namespace Basic + { + class Object + { + public: + virtual ~Object() + {} + }; + + template <typename T> + inline T&& _Move(T & obj) + { + return static_cast<T&&>(obj); + } + + template <typename T> + inline void Swap(T & v0, T & v1) + { + T tmp = _Move(v0); + v0 = _Move(v1); + v1 = _Move(tmp); + } + } +} + +#endif diff --git a/source/core/core.natvis b/source/core/core.natvis new file mode 100644 index 000000000..b856d31db --- /dev/null +++ b/source/core/core.natvis @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="utf-8"?> + +<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + +<Type Name="CoreLib::Basic::String"> + <DisplayString>{buffer.pointer,s}</DisplayString> + <StringView>buffer.pointer,s</StringView> +</Type> + +<Type Name="CoreLib::Basic::ArrayView<*>"> + <DisplayString>{{ size={_count} }}</DisplayString> + <Expand> + <Item Name="[size]">_count</Item> + <ArrayItems> + <Size>_count</Size> + <ValuePointer>_buffer</ValuePointer> + </ArrayItems> + </Expand> +</Type> + +<Type Name="CoreLib::Basic::List<*>"> + <DisplayString>{{ size={_count} }}</DisplayString> + <Expand> + <Item Name="[size]">_count</Item> + <Item Name="[capacity]">bufferSize</Item> + <ArrayItems> + <Size>_count</Size> + <ValuePointer>buffer</ValuePointer> + </ArrayItems> + </Expand> +</Type> + + +<Type Name="CoreLib::Basic::Array<*,*>"> + <DisplayString>{{ size={_count} }}</DisplayString> + <Expand> + <Item Name="[size]">_count</Item> + <ArrayItems> + <Size>_count</Size> + <ValuePointer>_buffer</ValuePointer> + </ArrayItems> + </Expand> +</Type> + +<Type Name="CoreLib::Basic::LinkedList<*>"> + <DisplayString>{{ size={FCount} }}</DisplayString> + <Expand> + <LinkedListItems> + <Size>FCount</Size> + <HeadPointer>FHead</HeadPointer> + <NextPointer>pNext</NextPointer> + <ValueNode>Value</ValueNode> + </LinkedListItems> + </Expand> +</Type> + +<Type Name="CoreLib::Basic::Dictionary<*,*>"> + <DisplayString>{{ size={_count} }}</DisplayString> + <Expand> + <Item Name="[size]">_count</Item> + <Item Name="[capacity]">bucketSizeMinusOne + 1</Item> + <ArrayItems> + <Size>bucketSizeMinusOne + 1</Size> + <ValuePointer>hashMap</ValuePointer> + </ArrayItems> + </Expand> +</Type> + +<Type Name="CoreLib::Basic::EnumerableDictionary<*,*>"> + <DisplayString>{{ size={_count} }}</DisplayString> + <Expand> + <Item Name="[size]">_count</Item> + <Item Name="[capacity]">bucketSizeMinusOne + 1</Item> + <LinkedListItems> + <Size>kvPairs.FCount</Size> + <HeadPointer>kvPairs.FHead</HeadPointer> + <NextPointer>pNext</NextPointer> + <ValueNode>Value</ValueNode> + </LinkedListItems> + </Expand> +</Type> + +<Type Name="CoreLib::Basic::EnumerableHashSet<*,*>"> + <DisplayString>{{ size={dict._count} }}</DisplayString> + <Expand> + <Item Name="[size]">dict._count</Item> + <Item Name="[capacity]">dict.bucketSizeMinusOne + 1</Item> + <LinkedListItems> + <Size>dict.kvPairs.FCount</Size> + <HeadPointer>dict.kvPairs.FHead</HeadPointer> + <NextPointer>pNext</NextPointer> + <ValueNode>Value</ValueNode> + </LinkedListItems> + </Expand> +</Type> + +<Type Name="CoreLib::Basic::RefPtrImpl<*,*,*>"> + <SmartPointer Usage="Minimal">pointer</SmartPointer> + <DisplayString Condition="pointer == 0">empty</DisplayString> + <DisplayString Condition="pointer != 0">RefPtr {*pointer}</DisplayString> + <Expand> + <ExpandedItem>pointer</ExpandedItem> + </Expand> +</Type> +</AutoVisualizer> diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj new file mode 100644 index 000000000..6b8496080 --- /dev/null +++ b/source/core/core.vcxproj @@ -0,0 +1,802 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="DebugClang|ARM"> + <Configuration>DebugClang</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="DebugClang|Win32"> + <Configuration>DebugClang</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="DebugClang|x64"> + <Configuration>DebugClang</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_VS2013|ARM"> + <Configuration>Debug_VS2013</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_VS2013|Win32"> + <Configuration>Debug_VS2013</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_VS2013|x64"> + <Configuration>Debug_VS2013</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_VS2013|ARM"> + <Configuration>Release_VS2013</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_VS2013|Win32"> + <Configuration>Release_VS2013</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_VS2013|x64"> + <Configuration>Release_VS2013</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="TracingDebug|ARM"> + <Configuration>TracingDebug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="TracingDebug|Win32"> + <Configuration>TracingDebug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="TracingDebug|x64"> + <Configuration>TracingDebug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="TracingRelease|ARM"> + <Configuration>TracingRelease</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="TracingRelease|Win32"> + <Configuration>TracingRelease</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="TracingRelease|x64"> + <Configuration>TracingRelease</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClInclude Include="allocator.h" /> + <ClInclude Include="array-view.h" /> + <ClInclude Include="array.h" /> + <ClInclude Include="basic.h" /> + <ClInclude Include="common.h" /> + <ClInclude Include="dictionary.h" /> + <ClInclude Include="exception.h" /> + <ClInclude Include="func.h" /> + <ClInclude Include="hash.h" /> + <ClInclude Include="int-set.h" /> + <ClInclude Include="link.h" /> + <ClInclude Include="linq.h" /> + <ClInclude Include="list.h" /> + <ClInclude Include="memory-pool.h" /> + <ClInclude Include="secure-crt.h" /> + <ClInclude Include="slang-io.h" /> + <ClInclude Include="slang-math.h" /> + <ClInclude Include="slang-string.h" /> + <ClInclude Include="smart-pointer.h" /> + <ClInclude Include="stream.h" /> + <ClInclude Include="text-io.h" /> + <ClInclude Include="type-traits.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="memory-pool.cpp" /> + <ClCompile Include="slang-io.cpp" /> + <ClCompile Include="slang-math.cpp" /> + <ClCompile Include="slang-string.cpp" /> + <ClCompile Include="stream.cpp" /> + <ClCompile Include="text-io.cpp" /> + </ItemGroup> + <ItemGroup> + <Natvis Include="core.natvis" /> + </ItemGroup> + <PropertyGroup Label="Globals" /> + <PropertyGroup Label="Globals"> + </PropertyGroup> + <PropertyGroup Label="Globals"> + </PropertyGroup> + <PropertyGroup Label="Globals"> + </PropertyGroup> + <PropertyGroup Label="Globals"> + <Keyword>Win32Proj</Keyword> + <RootNamespace>CoreLib</RootNamespace> + <ProjectGuid>{F9BE7957-8399-899E-0C49-E714FDDD4B65}</ProjectGuid> + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140_clang_3_7</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140_Clang_3_7</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140_clang_3_7</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|ARM'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>EnableAllWarnings</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + <RuntimeTypeInfo>true</RuntimeTypeInfo> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <BrowseInformation>true</BrowseInformation> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + <Bscmake> + <PreserveSbr>true</PreserveSbr> + </Bscmake> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <BrowseInformation>true</BrowseInformation> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + <Bscmake> + <PreserveSbr>true</PreserveSbr> + </Bscmake> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <BrowseInformation>true</BrowseInformation> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + <Bscmake> + <PreserveSbr>true</PreserveSbr> + </Bscmake> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_VS2013|ARM'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugClang|ARM'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='TracingDebug|ARM'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <FloatingPointExceptions>false</FloatingPointExceptions> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_VS2013|ARM'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='TracingRelease|ARM'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WINDOWS_PLATFORM;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <MultiProcessorCompilation>false</MultiProcessorCompilation> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + <Lib> + <AdditionalDependencies>Shlwapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/source/core/dictionary.h b/source/core/dictionary.h new file mode 100644 index 000000000..77f0df515 --- /dev/null +++ b/source/core/dictionary.h @@ -0,0 +1,1018 @@ +#ifndef CORE_LIB_DICTIONARY_H +#define CORE_LIB_DICTIONARY_H +#include "list.h" +#include "common.h" +#include "int-set.h" +#include "exception.h" +#include "slang-math.h" +#include "hash.h" + +namespace CoreLib +{ + namespace Basic + { + template<typename TKey, typename TValue> + class KeyValuePair + { + public: + TKey Key; + TValue Value; + KeyValuePair() + {} + KeyValuePair(const TKey & key, const TValue & value) + { + Key = key; + Value = value; + } + KeyValuePair(TKey && key, TValue && value) + { + Key = _Move(key); + Value = _Move(value); + } + KeyValuePair(TKey && key, const TValue & value) + { + Key = _Move(key); + Value = value; + } + KeyValuePair(const KeyValuePair<TKey, TValue> & _that) + { + Key = _that.Key; + Value = _that.Value; + } + KeyValuePair(KeyValuePair<TKey, TValue> && _that) + { + operator=(_Move(_that)); + } + KeyValuePair & operator=(KeyValuePair<TKey, TValue> && that) + { + Key = _Move(that.Key); + Value = _Move(that.Value); + return *this; + } + KeyValuePair & operator=(const KeyValuePair<TKey, TValue> & that) + { + Key = that.Key; + Value = that.Value; + return *this; + } + int GetHashCode() + { + return GetHashCode(Key); + } + }; + + template<typename TKey, typename TValue> + inline KeyValuePair<TKey, TValue> KVPair(const TKey & k, const TValue & v) + { + return KeyValuePair<TKey, TValue>(k, v); + } + + const float MaxLoadFactor = 0.7f; + + template<typename TKey, typename TValue> + class Dictionary + { + friend class Iterator; + friend class ItemProxy; + private: + inline int GetProbeOffset(int /*probeId*/) const + { + // quadratic probing + return 1; + } + private: + int bucketSizeMinusOne, shiftBits; + int _count; + IntSet marks; + KeyValuePair<TKey, TValue>* hashMap; + void Free() + { + if (hashMap) + delete[] hashMap; + hashMap = 0; + } + inline bool IsDeleted(int pos) const + { + return marks.Contains((pos << 1) + 1); + } + inline bool IsEmpty(int pos) const + { + return !marks.Contains((pos << 1)); + } + inline void SetDeleted(int pos, bool val) + { + if (val) + marks.Add((pos << 1) + 1); + else + marks.Remove((pos << 1) + 1); + } + inline void SetEmpty(int pos, bool val) + { + if (val) + marks.Remove((pos << 1)); + else + marks.Add((pos << 1)); + } + struct FindPositionResult + { + int ObjectPosition; + int InsertionPosition; + FindPositionResult() + { + ObjectPosition = -1; + InsertionPosition = -1; + } + FindPositionResult(int objPos, int insertPos) + { + ObjectPosition = objPos; + InsertionPosition = insertPos; + } + + }; + template<typename T> + inline int GetHashPos(T & key) const + { + return ((unsigned int)(GetHashCode(key) * 2654435761)) >> shiftBits; + } + template<typename T> + FindPositionResult FindPosition(const T & key) const + { + int hashPos = GetHashPos((T&)key); + int insertPos = -1; + int numProbes = 0; + while (numProbes <= bucketSizeMinusOne) + { + if (IsEmpty(hashPos)) + { + if (insertPos == -1) + return FindPositionResult(-1, hashPos); + else + return FindPositionResult(-1, insertPos); + } + else if (IsDeleted(hashPos)) + { + if (insertPos == -1) + insertPos = hashPos; + } + else if (hashMap[hashPos].Key == key) + { + return FindPositionResult(hashPos, -1); + } + numProbes++; + hashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne; + } + if (insertPos != -1) + return FindPositionResult(-1, insertPos); + throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode."); + } + TValue & _Insert(KeyValuePair<TKey, TValue> && kvPair, int pos) + { + hashMap[pos] = _Move(kvPair); + SetEmpty(pos, false); + SetDeleted(pos, false); + return hashMap[pos].Value; + } + void Rehash() + { + if (bucketSizeMinusOne == -1 || _count / (float)bucketSizeMinusOne >= MaxLoadFactor) + { + int newSize = (bucketSizeMinusOne + 1) * 2; + int newShiftBits = shiftBits - 1; + if (newSize == 0) + { + newSize = 16; + newShiftBits = 28; + } + Dictionary<TKey, TValue> newDict; + newDict.shiftBits = newShiftBits; + newDict.bucketSizeMinusOne = newSize - 1; + newDict.hashMap = new KeyValuePair<TKey, TValue>[newSize]; + newDict.marks.SetMax(newSize * 2); + if (hashMap) + { + for (auto & kvPair : *this) + { + newDict.Add(_Move(kvPair)); + } + } + *this = _Move(newDict); + } + } + + bool AddIfNotExists(KeyValuePair<TKey, TValue> && kvPair) + { + Rehash(); + auto pos = FindPosition(kvPair.Key); + if (pos.ObjectPosition != -1) + return false; + else if (pos.InsertionPosition != -1) + { + _count++; + _Insert(_Move(kvPair), pos.InsertionPosition); + return true; + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + void Add(KeyValuePair<TKey, TValue> && kvPair) + { + if (!AddIfNotExists(_Move(kvPair))) + throw KeyExistsException("The key already exists in Dictionary."); + } + TValue & Set(KeyValuePair<TKey, TValue> && kvPair) + { + Rehash(); + auto pos = FindPosition(kvPair.Key); + if (pos.ObjectPosition != -1) + return _Insert(_Move(kvPair), pos.ObjectPosition); + else if (pos.InsertionPosition != -1) + { + _count++; + return _Insert(_Move(kvPair), pos.InsertionPosition); + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + public: + class Iterator + { + private: + const Dictionary<TKey, TValue> * dict; + int pos; + public: + KeyValuePair<TKey, TValue> & operator *() const + { + return dict->hashMap[pos]; + } + KeyValuePair<TKey, TValue> * operator ->() const + { + return dict->hashMap + pos; + } + Iterator & operator ++() + { + if (pos > dict->bucketSizeMinusOne) + return *this; + pos++; + while (pos <= dict->bucketSizeMinusOne && (dict->IsDeleted(pos) || dict->IsEmpty(pos))) + { + pos++; + } + return *this; + } + Iterator operator ++(int) + { + Iterator rs = *this; + operator++(); + return rs; + } + bool operator != (const Iterator & _that) const + { + return pos != _that.pos || dict != _that.dict; + } + bool operator == (const Iterator & _that) const + { + return pos == _that.pos && dict == _that.dict; + } + Iterator(const Dictionary<TKey, TValue> * _dict, int _pos) + { + this->dict = _dict; + this->pos = _pos; + } + Iterator() + { + this->dict = 0; + this->pos = 0; + } + }; + + Iterator begin() const + { + int pos = 0; + while (pos < bucketSizeMinusOne + 1) + { + if (IsEmpty(pos) || IsDeleted(pos)) + pos++; + else + break; + } + return Iterator(this, pos); + } + Iterator end() const + { + return Iterator(this, bucketSizeMinusOne + 1); + } + public: + void Add(const TKey & key, const TValue & value) + { + Add(KeyValuePair<TKey, TValue>(key, value)); + } + void Add(TKey && key, TValue && value) + { + Add(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); + } + bool AddIfNotExists(const TKey & key, const TValue & value) + { + return AddIfNotExists(KeyValuePair<TKey, TValue>(key, value)); + } + bool AddIfNotExists(TKey && key, TValue && value) + { + return AddIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); + } + void Remove(const TKey & key) + { + if (_count == 0) + return; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + SetDeleted(pos.ObjectPosition, true); + _count--; + } + } + void Clear() + { + _count = 0; + + marks.Clear(); + } + + template<typename T> + bool ContainsKey(const T & key) const + { + if (bucketSizeMinusOne == -1) + return false; + auto pos = FindPosition(key); + return pos.ObjectPosition != -1; + } + template<typename T> + bool TryGetValue(const T & key, TValue & value) const + { + if (bucketSizeMinusOne == -1) + return false; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + value = hashMap[pos.ObjectPosition].Value; + return true; + } + return false; + } + template<typename T> + TValue * TryGetValue(const T & key) const + { + if (bucketSizeMinusOne == -1) + return nullptr; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + return &hashMap[pos.ObjectPosition].Value; + } + return nullptr; + } + class ItemProxy + { + private: + const Dictionary<TKey, TValue> * dict; + TKey key; + public: + ItemProxy(const TKey & _key, const Dictionary<TKey, TValue> * _dict) + { + this->dict = _dict; + this->key = _key; + } + ItemProxy(TKey && _key, const Dictionary<TKey, TValue> * _dict) + { + this->dict = _dict; + this->key = _Move(_key); + } + TValue & GetValue() const + { + auto pos = dict->FindPosition(key); + if (pos.ObjectPosition != -1) + { + return dict->hashMap[pos.ObjectPosition].Value; + } + else + throw KeyNotFoundException("The key does not exists in dictionary."); + } + inline TValue & operator()() const + { + return GetValue(); + } + operator TValue&() const + { + return GetValue(); + } + TValue & operator = (const TValue & val) const + { + return ((Dictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), val)); + } + TValue & operator = (TValue && val) const + { + return ((Dictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val))); + } + }; + ItemProxy operator [](const TKey & key) const + { + return ItemProxy(key, this); + } + ItemProxy operator [](TKey && key) const + { + return ItemProxy(_Move(key), this); + } + int Count() const + { + return _count; + } + private: + template<typename... Args> + void Init(const KeyValuePair<TKey, TValue> & kvPair, Args... args) + { + Add(kvPair); + Init(args...); + } + public: + Dictionary() + { + bucketSizeMinusOne = -1; + shiftBits = 32; + _count = 0; + hashMap = 0; + } + template<typename Arg, typename... Args> + Dictionary(Arg arg, Args... args) + { + Init(arg, args...); + } + Dictionary(const Dictionary<TKey, TValue> & other) + : bucketSizeMinusOne(-1), _count(0), hashMap(0) + { + *this = other; + } + Dictionary(Dictionary<TKey, TValue> && other) + : bucketSizeMinusOne(-1), _count(0), hashMap(0) + { + *this = (_Move(other)); + } + Dictionary<TKey, TValue> & operator = (const Dictionary<TKey, TValue> & other) + { + if (this == &other) + return *this; + Free(); + bucketSizeMinusOne = other.bucketSizeMinusOne; + _count = other._count; + shiftBits = other.shiftBits; + hashMap = new KeyValuePair<TKey, TValue>[other.bucketSizeMinusOne + 1]; + marks = other.marks; + for (int i = 0; i <= bucketSizeMinusOne; i++) + hashMap[i] = other.hashMap[i]; + return *this; + } + Dictionary<TKey, TValue> & operator = (Dictionary<TKey, TValue> && other) + { + if (this == &other) + return *this; + Free(); + bucketSizeMinusOne = other.bucketSizeMinusOne; + _count = other._count; + hashMap = other.hashMap; + shiftBits = other.shiftBits; + marks = _Move(other.marks); + other.hashMap = 0; + other._count = 0; + other.bucketSizeMinusOne = -1; + return *this; + } + ~Dictionary() + { + Free(); + } + }; + + template<typename TKey, typename TValue> + class EnumerableDictionary + { + friend class Iterator; + friend class ItemProxy; + private: + inline int GetProbeOffset(int /*probeIdx*/) const + { + // quadratic probing + return 1; + } + private: + int bucketSizeMinusOne, shiftBits; + int _count; + IntSet marks; + + // debug op + struct Op + { + TKey key; + int opType; + Op() + {} + Op(const TKey & key, int t) + { + this->key = key; + opType = t; + } + }; + LinkedList<KeyValuePair<TKey, TValue>> kvPairs; + LinkedNode<KeyValuePair<TKey, TValue>>** hashMap; + void Free() + { + if (hashMap) + delete[] hashMap; + hashMap = 0; + kvPairs.Clear(); + } + inline bool IsDeleted(int pos) const + { + return marks.Contains((pos << 1) + 1); + } + inline bool IsEmpty(int pos) const + { + return !marks.Contains((pos << 1)); + } + inline void SetDeleted(int pos, bool val) + { + if (val) + marks.Add((pos << 1) + 1); + else + marks.Remove((pos << 1) + 1); + } + inline void SetEmpty(int pos, bool val) + { + if (val) + marks.Remove((pos << 1)); + else + marks.Add((pos << 1)); + } + struct FindPositionResult + { + int ObjectPosition; + int InsertionPosition; + FindPositionResult() + { + ObjectPosition = -1; + InsertionPosition = -1; + } + FindPositionResult(int objPos, int insertPos) + { + ObjectPosition = objPos; + InsertionPosition = insertPos; + } + + }; + template<typename T> + inline int GetHashPos(T & key) const + { + return ((unsigned int)(GetHashCode(key) * 2654435761)) >> shiftBits; + } + template<typename T> + FindPositionResult FindPosition(const T & key) const + { + int hashPos = GetHashPos((T&)key); + int insertPos = -1; + int numProbes = 0; + while (numProbes <= bucketSizeMinusOne) + { + if (IsEmpty(hashPos)) + { + if (insertPos == -1) + return FindPositionResult(-1, hashPos); + else + return FindPositionResult(-1, insertPos); + } + else if (IsDeleted(hashPos)) + { + if (insertPos == -1) + insertPos = hashPos; + } + else if (hashMap[hashPos]->Value.Key == key) + { + return FindPositionResult(hashPos, -1); + } + numProbes++; + hashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne; + } + if (insertPos != -1) + return FindPositionResult(-1, insertPos); + throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode."); + } + TValue & _Insert(KeyValuePair<TKey, TValue> && kvPair, int pos) + { + auto node = kvPairs.AddLast(); + node->Value = _Move(kvPair); + hashMap[pos] = node; + SetEmpty(pos, false); + SetDeleted(pos, false); + return node->Value.Value; + } + void Rehash() + { + if (bucketSizeMinusOne == -1 || _count / (float)bucketSizeMinusOne >= MaxLoadFactor) + { + int newSize = (bucketSizeMinusOne + 1) * 2; + int newShiftBits = shiftBits - 1; + if (newSize == 0) + { + newSize = 16; + newShiftBits = 28; + } + EnumerableDictionary<TKey, TValue> newDict; + newDict.shiftBits = newShiftBits; + newDict.bucketSizeMinusOne = newSize - 1; + newDict.hashMap = new LinkedNode<KeyValuePair<TKey, TValue>>*[newSize]; + newDict.marks.SetMax(newSize * 2); + if (hashMap) + { + for (auto & kvPair : *this) + { + newDict.Add(_Move(kvPair)); + } + } + *this = _Move(newDict); + } + } + + bool AddIfNotExists(KeyValuePair<TKey, TValue> && kvPair) + { + Rehash(); + auto pos = FindPosition(kvPair.Key); + if (pos.ObjectPosition != -1) + return false; + else if (pos.InsertionPosition != -1) + { + _count++; + _Insert(_Move(kvPair), pos.InsertionPosition); + return true; + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + void Add(KeyValuePair<TKey, TValue> && kvPair) + { + if (!AddIfNotExists(_Move(kvPair))) + throw KeyExistsException("The key already exists in Dictionary."); + } + TValue & Set(KeyValuePair<TKey, TValue> && kvPair) + { + Rehash(); + auto pos = FindPosition(kvPair.Key); + if (pos.ObjectPosition != -1) + { + hashMap[pos.ObjectPosition]->Delete(); + return _Insert(_Move(kvPair), pos.ObjectPosition); + } + else if (pos.InsertionPosition != -1) + { + _count++; + return _Insert(_Move(kvPair), pos.InsertionPosition); + } + else + throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation."); + } + public: + typedef typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator Iterator; + + typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator begin() const + { + return kvPairs.begin(); + } + typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator end() const + { + return kvPairs.end(); + } + public: + void Add(const TKey & key, const TValue & value) + { + Add(KeyValuePair<TKey, TValue>(key, value)); + } + void Add(TKey && key, TValue && value) + { + Add(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); + } + bool AddIfNotExists(const TKey & key, const TValue & value) + { + return AddIfNotExists(KeyValuePair<TKey, TValue>(key, value)); + } + bool AddIfNotExists(TKey && key, TValue && value) + { + return AddIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value))); + } + void Remove(const TKey & key) + { + if (_count > 0) + { + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + kvPairs.Delete(hashMap[pos.ObjectPosition]); + hashMap[pos.ObjectPosition] = 0; + SetDeleted(pos.ObjectPosition, true); + _count--; + } + } + } + void Clear() + { + _count = 0; + kvPairs.Clear(); + marks.Clear(); + } + template<typename T> + bool ContainsKey(const T & key) const + { + if (bucketSizeMinusOne == -1) + return false; + auto pos = FindPosition(key); + return pos.ObjectPosition != -1; + } + template<typename T> + TValue * TryGetValue(const T & key) const + { + if (bucketSizeMinusOne == -1) + return nullptr; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + return &(hashMap[pos.ObjectPosition]->Value.Value); + } + return nullptr; + } + template<typename T> + bool TryGetValue(const T & key, TValue & value) const + { + if (bucketSizeMinusOne == -1) + return false; + auto pos = FindPosition(key); + if (pos.ObjectPosition != -1) + { + value = hashMap[pos.ObjectPosition]->Value.Value; + return true; + } + return false; + } + class ItemProxy + { + private: + const EnumerableDictionary<TKey, TValue> * dict; + TKey key; + public: + ItemProxy(const TKey & _key, const EnumerableDictionary<TKey, TValue> * _dict) + { + this->dict = _dict; + this->key = _key; + } + ItemProxy(TKey && _key, const EnumerableDictionary<TKey, TValue> * _dict) + { + this->dict = _dict; + this->key = _Move(_key); + } + TValue & GetValue() const + { + auto pos = dict->FindPosition(key); + if (pos.ObjectPosition != -1) + { + return dict->hashMap[pos.ObjectPosition]->Value.Value; + } + else + { + throw KeyNotFoundException("The key does not exists in dictionary."); + } + } + inline TValue & operator()() const + { + return GetValue(); + } + operator TValue&() const + { + return GetValue(); + } + TValue & operator = (const TValue & val) + { + return ((EnumerableDictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), val)); + } + TValue & operator = (TValue && val) + { + return ((EnumerableDictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val))); + } + }; + ItemProxy operator [](const TKey & key) const + { + return ItemProxy(key, this); + } + ItemProxy operator [](TKey && key) const + { + return ItemProxy(_Move(key), this); + } + int Count() const + { + return _count; + } + KeyValuePair<TKey, TValue> & First() const + { + return kvPairs.First(); + } + KeyValuePair<TKey, TValue> & Last() const + { + return kvPairs.Last(); + } + private: + template<typename... Args> + void Init(const KeyValuePair<TKey, TValue> & kvPair, Args... args) + { + Add(kvPair); + Init(args...); + } + public: + EnumerableDictionary() + { + bucketSizeMinusOne = -1; + shiftBits = 32; + _count = 0; + hashMap = 0; + } + template<typename Arg, typename... Args> + EnumerableDictionary(Arg arg, Args... args) + { + Init(arg, args...); + } + EnumerableDictionary(const EnumerableDictionary<TKey, TValue> & other) + : bucketSizeMinusOne(-1), _count(0), hashMap(0) + { + *this = other; + } + EnumerableDictionary(EnumerableDictionary<TKey, TValue> && other) + : bucketSizeMinusOne(-1), _count(0), hashMap(0) + { + *this = (_Move(other)); + } + EnumerableDictionary<TKey, TValue> & operator = (const EnumerableDictionary<TKey, TValue> & other) + { + if (this == &other) + return *this; + Clear(); + for (auto & item : other) + Add(item.Key, item.Value); + return *this; + } + EnumerableDictionary<TKey, TValue> & operator = (EnumerableDictionary<TKey, TValue> && other) + { + if (this == &other) + return *this; + Free(); + bucketSizeMinusOne = other.bucketSizeMinusOne; + _count = other._count; + hashMap = other.hashMap; + shiftBits = other.shiftBits; + marks = _Move(other.marks); + other.hashMap = 0; + other._count = 0; + other.bucketSizeMinusOne = -1; + kvPairs = _Move(other.kvPairs); + return *this; + } + ~EnumerableDictionary() + { + Free(); + } + }; + + class _DummyClass + {}; + + template<typename T, typename DictionaryType> + class HashSetBase + { + protected: + DictionaryType dict; + private: + template<typename... Args> + void Init(const T & v, Args... args) + { + Add(v); + Init(args...); + } + public: + HashSetBase() + {} + template<typename Arg, typename... Args> + HashSetBase(Arg arg, Args... args) + { + Init(arg, args...); + } + HashSetBase(const HashSetBase & set) + { + operator=(set); + } + HashSetBase(HashSetBase && set) + { + operator=(_Move(set)); + } + HashSetBase & operator = (const HashSetBase & set) + { + dict = set.dict; + return *this; + } + HashSetBase & operator = (HashSetBase && set) + { + dict = _Move(set.dict); + return *this; + } + public: + class Iterator + { + private: + typename DictionaryType::Iterator iter; + public: + Iterator() = default; + T & operator *() const + { + return (*iter).Key; + } + T * operator ->() const + { + return &(*iter).Key; + } + Iterator & operator ++() + { + ++iter; + return *this; + } + Iterator operator ++(int) + { + Iterator rs = *this; + operator++(); + return rs; + } + bool operator != (const Iterator & _that) const + { + return iter != _that.iter; + } + bool operator == (const Iterator & _that) const + { + return iter == _that.iter; + } + Iterator(const typename DictionaryType::Iterator & _iter) + { + this->iter = _iter; + } + }; + Iterator begin() const + { + return Iterator(dict.begin()); + } + Iterator end() const + { + return Iterator(dict.end()); + } + public: + int Count() const + { + return dict.Count(); + } + void Clear() + { + dict.Clear(); + } + bool Add(const T& obj) + { + return dict.AddIfNotExists(obj, _DummyClass()); + } + bool Add(T && obj) + { + return dict.AddIfNotExists(_Move(obj), _DummyClass()); + } + void Remove(const T & obj) + { + dict.Remove(obj); + } + bool Contains(const T & obj) const + { + return dict.ContainsKey(obj); + } + }; + template <typename T> + class HashSet : public HashSetBase<T, Dictionary<T, _DummyClass>> + {}; + + template <typename T> + class EnumerableHashSet : public HashSetBase<T, EnumerableDictionary<T, _DummyClass>> + { + public: + T & First() const + { + return this->dict.First().Key; + } + T & Last() const + { + return this->dict.Last().Key; + } + }; + } +} + +#endif diff --git a/source/core/exception.h b/source/core/exception.h new file mode 100644 index 000000000..652cafca7 --- /dev/null +++ b/source/core/exception.h @@ -0,0 +1,115 @@ +#ifndef CORE_LIB_EXCEPTION_H +#define CORE_LIB_EXCEPTION_H + +#include "common.h" +#include "slang-string.h" + +namespace CoreLib +{ + namespace Basic + { + class Exception : public Object + { + public: + String Message; + Exception() + {} + Exception(const String & message) + : Message(message) + { + } + }; + + class IndexOutofRangeException : public Exception + { + public: + IndexOutofRangeException() + {} + IndexOutofRangeException(const String & message) + : Exception(message) + { + } + + }; + + class InvalidOperationException : public Exception + { + public: + InvalidOperationException() + {} + InvalidOperationException(const String & message) + : Exception(message) + { + } + + }; + + class ArgumentException : public Exception + { + public: + ArgumentException() + {} + ArgumentException(const String & message) + : Exception(message) + { + } + + }; + + class KeyNotFoundException : public Exception + { + public: + KeyNotFoundException() + {} + KeyNotFoundException(const String & message) + : Exception(message) + { + } + }; + class KeyExistsException : public Exception + { + public: + KeyExistsException() + {} + KeyExistsException(const String & message) + : Exception(message) + { + } + }; + + class NotSupportedException : public Exception + { + public: + NotSupportedException() + {} + NotSupportedException(const String & message) + : Exception(message) + { + } + }; + + class NotImplementedException : public Exception + { + public: + NotImplementedException() + {} + NotImplementedException(const String & message) + : Exception(message) + { + } + }; + + class InvalidProgramException : public Exception + { + public: + InvalidProgramException() + {} + InvalidProgramException(const String & message) + : Exception(message) + { + } + }; + } +} + +#endif
\ No newline at end of file diff --git a/source/core/func.h b/source/core/func.h new file mode 100644 index 000000000..8ec2ba8a5 --- /dev/null +++ b/source/core/func.h @@ -0,0 +1,216 @@ +#ifndef CORELIB_FUNC_H +#define CORELIB_FUNC_H + +#if 0 + +#include "SmartPointer.h" + +namespace CoreLib +{ + namespace Basic + { + template<typename TResult, typename... Arguments> + class FuncPtr + { + public: + virtual TResult operator()(Arguments...) = 0; + virtual bool operator == (const FuncPtr<TResult, Arguments...> *) + { + return false; + } + virtual ~FuncPtr() {} + }; + + template<typename TResult, typename... Arguments> + class CdeclFuncPtr : public FuncPtr<TResult, Arguments...> + { + public: + typedef TResult (*FuncType)(Arguments...); + private: + FuncType funcPtr; + public: + CdeclFuncPtr(FuncType func) + :funcPtr(func) + { + } + + virtual TResult operator()(Arguments... params) override + { + return funcPtr(params...); + } + + virtual bool operator == (const FuncPtr<TResult, Arguments...> * ptr) override + { + auto cptr = dynamic_cast<const CdeclFuncPtr<TResult, Arguments...>*>(ptr); + if (cptr) + return funcPtr == cptr->funcPtr; + else + return false; + } + }; + + template<typename Class, typename TResult, typename... Arguments> + class MemberFuncPtr : public FuncPtr<TResult, Arguments...> + { + public: + typedef TResult (Class::*FuncType)(Arguments...); + private: + FuncType funcPtr; + Class * object; + public: + MemberFuncPtr(Class * obj, FuncType func) + : funcPtr(func), object(obj) + { + } + + virtual TResult operator()(Arguments... params) override + { + return (object->*funcPtr)(params...); + } + + virtual bool operator == (const FuncPtr<TResult, Arguments...> * ptr) override + { + auto cptr = dynamic_cast<const MemberFuncPtr<Class, TResult, Arguments...>*>(ptr); + if (cptr) + return funcPtr == cptr->funcPtr && object == cptr->object; + else + return false; + } + }; + + template<typename F, typename TResult, typename... Arguments> + class LambdaFuncPtr : public FuncPtr<TResult, Arguments...> + { + private: + F func; + public: + LambdaFuncPtr(const F & _func) + : func(_func) + {} + virtual TResult operator()(Arguments... params) override + { + return func(params...); + } + virtual bool operator == (const FuncPtr<TResult, Arguments...> * /*ptr*/) override + { + return false; + } + }; + + template<typename TResult, typename... Arguments> + class Func + { + private: + RefPtr<FuncPtr<TResult, Arguments...>> funcPtr; + public: + Func(){} + Func(typename CdeclFuncPtr<TResult, Arguments...>::FuncType func) + { + funcPtr = new CdeclFuncPtr<TResult, Arguments...>(func); + } + template<typename Class> + Func(Class * object, typename MemberFuncPtr<Class, TResult, Arguments...>::FuncType func) + { + funcPtr = new MemberFuncPtr<Class, TResult, Arguments...>(object, func); + } + template<typename TFuncObj> + Func(const TFuncObj & func) + { + funcPtr = new LambdaFuncPtr<TFuncObj, TResult, Arguments...>(func); + } + Func & operator = (typename CdeclFuncPtr<TResult, Arguments...>::FuncType func) + { + funcPtr = new CdeclFuncPtr<TResult, Arguments...>(func); + return *this; + } + template<typename Class> + Func & operator = (const MemberFuncPtr<Class, TResult, Arguments...> & func) + { + funcPtr = new MemberFuncPtr<Class, TResult, Arguments...>(func); + return *this; + } + template<typename TFuncObj> + Func & operator = (const TFuncObj & func) + { + funcPtr = new LambdaFuncPtr<TFuncObj, TResult, Arguments...>(func); + return *this; + } + bool operator == (const Func & f) + { + return *funcPtr == f.funcPtr.Ptr(); + } + bool operator != (const Func & f) + { + return !(*this == f); + } + TResult operator()(Arguments... params) + { + return (*funcPtr)(params...); + } + }; + + // template<typename... Arguments> + // using Procedure = Func<void, Arguments...>; + + template<typename... Arguments> + class Procedure : public Func<void, Arguments...> + { + private: + RefPtr<FuncPtr<void, Arguments...>> funcPtr; + public: + Procedure(){} + Procedure(const Procedure & proc) + { + funcPtr = proc.funcPtr; + } + Procedure(typename CdeclFuncPtr<void, Arguments...>::FuncType func) + { + funcPtr = new CdeclFuncPtr<void, Arguments...>(func); + } + template<typename Class> + Procedure(Class * object, typename MemberFuncPtr<Class, void, Arguments...>::FuncType func) + { + funcPtr = new MemberFuncPtr<Class, void, Arguments...>(object, func); + } + template<typename TFuncObj> + Procedure(const TFuncObj & func) + { + funcPtr = new LambdaFuncPtr<TFuncObj, void, Arguments...>(func); + } + Procedure & operator = (typename CdeclFuncPtr<void, Arguments...>::FuncType func) + { + funcPtr = new CdeclFuncPtr<void, Arguments...>(func); + return *this; + } + template<typename Class> + Procedure & operator = (const MemberFuncPtr<Class, void, Arguments...> & func) + { + funcPtr = new MemberFuncPtr<Class, void, Arguments...>(func); + return *this; + } + template<typename TFuncObj> + Procedure & operator = (const TFuncObj & func) + { + funcPtr = new LambdaFuncPtr<TFuncObj, void, Arguments...>(func); + return *this; + } + Procedure & operator = (const Procedure & proc) + { + funcPtr = proc.funcPtr; + } + void Clear() + { + funcPtr = nullptr; + } + void operator()(Arguments... params) + { + if (funcPtr) + (*funcPtr)(params...); + } + }; + } +} + +#endif + +#endif
\ No newline at end of file diff --git a/source/core/hash.h b/source/core/hash.h new file mode 100644 index 000000000..07327a415 --- /dev/null +++ b/source/core/hash.h @@ -0,0 +1,105 @@ +#ifndef CORELIB_HASH_H +#define CORELIB_HASH_H + +#include "slang-math.h" +#include <string.h> + +namespace CoreLib +{ + namespace Basic + { + + inline int GetHashCode(double key) + { + return FloatAsInt((float)key); + } + inline int GetHashCode(float key) + { + return FloatAsInt(key); + } + inline int GetHashCode(const char * buffer) + { + if (!buffer) + return 0; + int hash = 0; + int c; + auto str = buffer; + c = *str++; + while (c) + { + hash = c + (hash << 6) + (hash << 16) - hash; + c = *str++; + } + return hash; + } + inline int GetHashCode(char * buffer) + { + return GetHashCode(const_cast<const char *>(buffer)); + } + + template<int IsInt> + class Hash + { + public: + }; + template<> + class Hash<1> + { + public: + template<typename TKey> + static int GetHashCode(TKey & key) + { + return (int)key; + } + }; + template<> + class Hash<0> + { + public: + template<typename TKey> + static int GetHashCode(TKey & key) + { + return key.GetHashCode(); + } + }; + template<int IsPointer> + class PointerHash + {}; + template<> + class PointerHash<1> + { + public: + template<typename TKey> + static int GetHashCode(TKey const& key) + { + return (int)((CoreLib::PtrInt)key) / 16; // sizeof(typename std::remove_pointer<TKey>::type); + } + }; + template<> + class PointerHash<0> + { + public: + template<typename TKey> + static int GetHashCode(TKey & key) + { + return Hash<std::is_integral<TKey>::value || std::is_enum<TKey>::value>::GetHashCode(key); + } + }; + + template<typename TKey> + int GetHashCode(const TKey & key) + { + return PointerHash<std::is_pointer<TKey>::value>::GetHashCode(key); + } + + template<typename TKey> + int GetHashCode(TKey & key) + { + return PointerHash<std::is_pointer<TKey>::value>::GetHashCode(key); + } + + + } +} + +#endif
\ No newline at end of file diff --git a/source/core/int-set.h b/source/core/int-set.h new file mode 100644 index 000000000..cb8f788f2 --- /dev/null +++ b/source/core/int-set.h @@ -0,0 +1,166 @@ +#ifndef BIT_VECTOR_INT_SET_H +#define BIT_VECTOR_INT_SET_H + +#include "list.h" +#include "slang-math.h" +#include "common.h" +#include "exception.h" + +#include <memory.h> + +namespace CoreLib +{ + namespace Basic + { + class IntSet + { + private: + List<int> buffer; + public: + IntSet() + {} + IntSet(const IntSet & other) + { + buffer = other.buffer; + } + IntSet(IntSet && other) + { + *this = (_Move(other)); + } + IntSet & operator = (IntSet && other) + { + buffer = _Move(other.buffer); + return *this; + } + IntSet & operator = (const IntSet & other) + { + buffer = other.buffer; + return *this; + } + int GetHashCode() + { + int rs = 0; + for (auto val : buffer) + rs ^= val; + return rs; + } + IntSet(int maxVal) + { + SetMax(maxVal); + } + int Size() const + { + return buffer.Count()*32; + } + void SetMax(int val) + { + Resize(val); + Clear(); + } + void SetAll() + { + for (int i = 0; i<buffer.Count(); i++) + buffer[i] = 0xFFFFFFFF; + } + void Resize(int size) + { + int oldBufferSize = buffer.Count(); + buffer.SetSize((size+31)>>5); + if (buffer.Count() > oldBufferSize) + memset(buffer.Buffer()+oldBufferSize, 0, (buffer.Count()-oldBufferSize) * sizeof(int)); + } + void Clear() + { + for (int i = 0; i<buffer.Count(); i++) + buffer[i] = 0; + } + void Add(int val) + { + int id = val>>5; + if (id < buffer.Count()) + buffer[id] |= (1<<(val&31)); + else + { + int oldSize = buffer.Count(); + buffer.SetSize(id+1); + memset(buffer.Buffer() + oldSize, 0, (buffer.Count()-oldSize)*sizeof(int)); + buffer[id] |= (1<<(val&31)); + } + } + void Remove(int val) + { + if ((val>>5) < buffer.Count()) + buffer[(val>>5)] &= ~(1<<(val&31)); + } + bool Contains(int val) const + { + if ((val>>5) >= buffer.Count()) + return false; + return (buffer[(val>>5)] & (1<<(val&31))) != 0; + } + void UnionWith(const IntSet & set) + { + for (int i = 0; i<Math::Min(set.buffer.Count(), buffer.Count()); i++) + { + buffer[i] |= set.buffer[i]; + } + if (set.buffer.Count() > buffer.Count()) + buffer.AddRange(set.buffer.Buffer()+buffer.Count(), set.buffer.Count()-buffer.Count()); + } + bool operator == (const IntSet & set) + { + if (buffer.Count() != set.buffer.Count()) + return false; + for (int i = 0; i<buffer.Count(); i++) + if (buffer[i] != set.buffer[i]) + return false; + return true; + } + bool operator != (const IntSet & set) + { + return !(*this == set); + } + void IntersectWith(const IntSet & set) + { + if (set.buffer.Count() < buffer.Count()) + memset(buffer.Buffer() + set.buffer.Count(), 0, (buffer.Count()-set.buffer.Count())*sizeof(int)); + for (int i = 0; i<Math::Min(set.buffer.Count(), buffer.Count()); i++) + { + buffer[i] &= set.buffer[i]; + } + } + static void Union(IntSet & rs, const IntSet & set1, const IntSet & set2) + { + rs.buffer.SetSize(Math::Max(set1.buffer.Count(), set2.buffer.Count())); + rs.Clear(); + for (int i = 0; i<set1.buffer.Count(); i++) + rs.buffer[i] |= set1.buffer[i]; + for (int i = 0; i<set2.buffer.Count(); i++) + rs.buffer[i] |= set2.buffer[i]; + } + static void Intersect(IntSet & rs, const IntSet & set1, const IntSet & set2) + { + rs.buffer.SetSize(Math::Min(set1.buffer.Count(), set2.buffer.Count())); + for (int i = 0; i<rs.buffer.Count(); i++) + rs.buffer[i] = set1.buffer[i] & set2.buffer[i]; + } + static void Subtract(IntSet & rs, const IntSet & set1, const IntSet & set2) + { + rs.buffer.SetSize(set1.buffer.Count()); + for (int i = 0; i<Math::Min(set1.buffer.Count(), set2.buffer.Count()); i++) + rs.buffer[i] = set1.buffer[i] & (~set2.buffer[i]); + } + static bool HasIntersection(const IntSet & set1, const IntSet & set2) + { + for (int i = 0; i<Math::Min(set1.buffer.Count(), set2.buffer.Count()); i++) + { + if (set1.buffer[i] & set2.buffer[i]) + return true; + } + return false; + } + }; + } +} + +#endif
\ No newline at end of file diff --git a/source/core/link.h b/source/core/link.h new file mode 100644 index 000000000..6abd5a9d5 --- /dev/null +++ b/source/core/link.h @@ -0,0 +1,336 @@ +#ifndef CORE_LIB_LINK_H +#define CORE_LIB_LINK_H + +#include "Common.h" +#include "Exception.h" + +namespace CoreLib +{ + namespace Basic + { + template<typename T> + class LinkedList; + + template<typename T> + class LinkedNode + { + template<typename T1> + friend class LinkedList; + private: + LinkedNode<T> *pPrev, *pNext; + LinkedList<T> * FLink; + public: + T Value; + LinkedNode (LinkedList<T> * lnk):FLink(lnk) + { + pPrev = pNext = 0; + }; + LinkedNode<T> * GetPrevious() + { + return pPrev; + }; + LinkedNode<T> * GetNext() + { + return pNext; + }; + LinkedNode<T> * InsertAfter(const T & nData) + { + LinkedNode<T> * n = new LinkedNode<T>(FLink); + n->Value = nData; + n->pPrev = this; + n->pNext = this->pNext; + LinkedNode<T> *npp = n->pNext; + if (npp) + { + npp->pPrev = n; + } + pNext = n; + if (!n->pNext) + FLink->FTail = n; + FLink->FCount ++; + return n; + }; + LinkedNode<T> * InsertBefore(const T & nData) + { + LinkedNode<T> * n = new LinkedNode<T>(FLink); + n->Value = nData; + n->pPrev = pPrev; + n->pNext = this; + pPrev = n; + LinkedNode<T> *npp = n->pPrev; + if (npp) + npp->pNext = n; + if (!n->pPrev) + FLink->FHead = n; + FLink->FCount ++; + return n; + }; + void Delete() + { + if (pPrev) + pPrev->pNext = pNext; + if (pNext) + pNext->pPrev = pPrev; + FLink->FCount --; + if (FLink->FHead == this) + { + FLink->FHead = pNext; + } + if (FLink->FTail == this) + { + FLink->FTail = pPrev; + } + delete this; + } + }; + template<typename T> + class LinkedList + { + template<typename T1> + friend class LinkedNode; + private: + LinkedNode<T> * FHead, *FTail; + int FCount; + public: + class Iterator + { + public: + LinkedNode<T> * Current, *Next; + void SetCurrent(LinkedNode<T> * cur) + { + Current = cur; + if (Current) + Next = Current->GetNext(); + else + Next = 0; + } + Iterator() + { + Current = Next = 0; + } + Iterator(LinkedNode<T> * cur) + { + SetCurrent(cur); + } + T & operator *() const + { + return Current->Value; + } + Iterator& operator ++() + { + SetCurrent(Next); + return *this; + } + Iterator operator ++(int) + { + Iterator rs = *this; + SetCurrent(Next); + return rs; + } + bool operator != (const Iterator & iter) const + { + return Current != iter.Current; + } + bool operator == (const Iterator & iter) const + { + return Current == iter.Current; + } + }; + Iterator begin() const + { + return Iterator(FHead); + } + Iterator end() const + { + return Iterator(0); + } + public: + LinkedList() : FHead(0), FTail(0), FCount(0) + { + } + ~LinkedList() + { + Clear(); + } + LinkedList(const LinkedList<T> & link) : FHead(0), FTail(0), FCount(0) + { + this->operator=(link); + } + LinkedList(LinkedList<T> && link) : FHead(0), FTail(0), FCount(0) + { + this->operator=(_Move(link)); + } + LinkedList<T> & operator = (LinkedList<T> && link) + { + if (FHead != 0) + Clear(); + FHead = link.FHead; + FTail = link.FTail; + FCount = link.FCount; + link.FHead = 0; + link.FTail = 0; + link.FCount = 0; + for (auto node = FHead; node; node = node->GetNext()) + node->FLink = this; + return *this; + } + LinkedList<T> & operator = (const LinkedList<T> & link) + { + if (FHead != 0) + Clear(); + auto p = link.FHead; + while (p) + { + AddLast(p->Value); + p = p->GetNext(); + } + return *this; + } + template<typename IteratorFunc> + void ForEach(const IteratorFunc & f) + { + auto p = FHead; + while (p) + { + f(p->Value); + p = p->GetNext(); + } + } + LinkedNode<T> * GetNode(int x) + { + LinkedNode<T> *pCur = FHead; + for (int i=0;i<x;i++) + { + if (pCur) + pCur = pCur->pNext; + else + throw "Index out of range"; + } + return pCur; + }; + LinkedNode<T> * Find(const T& fData) + { + for (LinkedNode<T> * pCur = FHead; pCur; pCur = pCur->pNext) + { + if (pCur->Value == fData) + return pCur; + } + return 0; + }; + LinkedNode<T> * FirstNode() const + { + return FHead; + }; + T & First() const + { + if (!FHead) + throw IndexOutofRangeException("LinkedList: index out of range."); + return FHead->Value; + } + T & Last() const + { + if (!FTail) + throw IndexOutofRangeException("LinkedList: index out of range."); + return FTail->Value; + } + LinkedNode<T> * LastNode() const + { + return FTail; + }; + LinkedNode<T> * AddLast(const T & nData) + { + LinkedNode<T> * n = new LinkedNode<T>(this); + n->Value = nData; + n->pPrev = FTail; + if (FTail) + FTail->pNext = n; + n->pNext = 0; + FTail = n; + if (!FHead) + FHead = n; + FCount ++; + return n; + }; + // Insert a blank node + LinkedNode<T> * AddLast() + { + LinkedNode<T> * n = new LinkedNode<T>(this); + n->pPrev = FTail; + if (FTail) + FTail->pNext = n; + n->pNext = 0; + FTail = n; + if (!FHead) + FHead = n; + FCount ++; + return n; + }; + LinkedNode<T> * AddFirst(const T& nData) + { + LinkedNode<T> *n = new LinkedNode<T>(this); + n->Value = nData; + n->pPrev = 0; + n->pNext = FHead; + if (FHead) + FHead->pPrev = n; + FHead = n; + if (!FTail) + FTail = n; + FCount ++; + return n; + }; + void Delete(LinkedNode<T>*n, int Count = 1) + { + LinkedNode<T> *n1,*n2 = 0, *tn; + n1 = n->pPrev; + tn = n; + int numDeleted = 0; + for (int i=0; i<Count; i++) + { + n2 = tn->pNext; + delete tn; + tn = n2; + numDeleted++; + if (tn == 0) + break; + } + if (n1) + n1->pNext = n2; + else + FHead = n2; + if (n2) + n2->pPrev = n1; + else + FTail = n1; + FCount -= numDeleted; + } + void Clear() + { + for (LinkedNode<T> *n = FHead; n; ) + { + LinkedNode<T> * tmp = n->pNext; + delete n; + n = tmp; + } + FHead = 0; + FTail = 0; + FCount = 0; + } + List<T> ToList() const + { + List<T> rs; + rs.Reserve(FCount); + for (auto & item : *this) + { + rs.Add(item); + } + return rs; + } + int Count() + { + return FCount; + } + }; + } +} +#endif diff --git a/source/core/linq.h b/source/core/linq.h new file mode 100644 index 000000000..bd40f1bc2 --- /dev/null +++ b/source/core/linq.h @@ -0,0 +1,669 @@ +#ifndef FUNDAMENTAL_LIB_LINQ_H +#define FUNDAMENTAL_LIB_LINQ_H + +#include "List.h" + +namespace CoreLib +{ + namespace Basic + { + + template <typename T> + T ConstructT(); + + template <typename T> + class RemoveReference + { + public: + typedef T Type; + }; + + template <typename T> + class RemoveReference<T&> + { + public: + typedef T Type; + }; + + template <typename T> + class RemoveReference<T&&> + { + public: + typedef T Type; + }; + + template<typename T> + struct RemovePointer + { + typedef T Type; + }; + + template<typename T> + struct RemovePointer<T*> + { + typedef T Type; + }; + + template <typename TQueryable1, typename TEnumerator1, typename TQueryable2, typename TEnumerator2, typename T> + class ConcatQuery + { + private: + TQueryable1 items1; + TQueryable2 items2; + public: + ConcatQuery(const TQueryable1 & queryable1, const TQueryable2 & queryable2) + : items1(queryable1), items2(queryable2) + {} + class Enumerator + { + private: + TEnumerator1 ptr1; + TEnumerator1 end1; + TEnumerator2 ptr2; + TEnumerator2 end2; + public: + Enumerator(const Enumerator &) = default; + Enumerator(TEnumerator1 pptr, TEnumerator1 pend, TEnumerator2 pptr2, TEnumerator2 pend2) + : ptr1(pptr), end1(pend), ptr2(pptr2), end2(pend2) + {} + T operator *() const + { + if (ptr1 != end1) + return *(ptr1); + else + return *(ptr2); + } + Enumerator& operator ++() + { + if (ptr1 != end1) + ++ptr1; + else + ++ptr2; + return *this; + } + Enumerator operator ++(int) + { + Enumerator rs = *this; + ++rs; + return rs; + } + bool operator != (const Enumerator & iter) const + { + return ptr1 != iter.ptr1 || ptr2 != iter.ptr2; + } + bool operator == (const Enumerator & iter) const + { + return ptr1 == iter.ptr1 && ptr2 == iter.ptr2; + } + }; + Enumerator begin() const + { + return Enumerator(items1.begin(), items1.end(), items2.begin(), items2.end()); + } + Enumerator end() const + { + return Enumerator(items1.end(), items1.end(), items2.end(), items2.end()); + } + }; + + template <typename TQueryable, typename TEnumerator, typename T, typename TFunc> + class WhereQuery + { + private: + TQueryable items; + TFunc func; + public: + WhereQuery(const TQueryable & queryable, const TFunc & f) + : items(queryable), func(f) + {} + class Enumerator + { + private: + TEnumerator ptr; + TEnumerator end; + const TFunc * func; + public: + Enumerator(const Enumerator &) = default; + Enumerator(TEnumerator ptr, TEnumerator end, const TFunc & f) + : ptr(ptr), end(end), func(&f) + {} + T operator *() const + { + return *(ptr); + } + Enumerator& operator ++() + { + ++ptr; + while (ptr != end) + { + if ((*func)(*ptr)) + break; + else + ++ptr; + } + return *this; + } + Enumerator operator ++(int) + { + Enumerator rs = *this; + while (rs.ptr != end) + { + if ((*func)(*rs.ptr)) + break; + ++rs.ptr; + } + return rs; + } + bool operator != (const Enumerator & iter) const + { + return ptr != iter.ptr; + } + bool operator == (const Enumerator & iter) const + { + return ptr == iter.ptr; + } + }; + Enumerator begin() const + { + auto ptr = items.begin(); + auto end = items.end(); + while (ptr != end) + { + if (func(*ptr)) + break; + ++ptr; + } + return Enumerator(ptr, end, func); + } + Enumerator end() const + { + return Enumerator(items.end(), items.end(), func); + } + }; + + template <typename TQueryable, typename TEnumerator, typename T> + class SkipQuery + { + private: + TQueryable items; + int count = 0; + public: + SkipQuery(const TQueryable & queryable, int pCount) + : items(queryable), count(pCount) + {} + class Enumerator + { + private: + TEnumerator ptr; + TEnumerator end; + public: + Enumerator(const Enumerator &) = default; + Enumerator(TEnumerator pptr, TEnumerator pend) + : ptr(pptr), end(pend) + { + } + T operator *() const + { + return *(ptr); + } + Enumerator& operator ++() + { + ++ptr; + return *this; + } + Enumerator operator ++(int) + { + Enumerator rs = *this; + ++ptr; + return rs; + } + bool operator != (const Enumerator & iter) const + { + return ptr != iter.ptr; + } + bool operator == (const Enumerator & iter) const + { + return ptr == iter.ptr; + } + }; + Enumerator begin() const + { + auto ptr = items.begin(); + auto end = items.end(); + for (int i = 0; i < count; i++) + if (ptr != end) + ++ptr; + return Enumerator(ptr, end); + } + Enumerator end() const + { + return Enumerator(items.end(), items.end()); + } + }; + + template <typename TQueryable, typename TEnumerator, typename T, typename TFunc> + class SelectQuery + { + private: + TQueryable items; + TFunc func; + public: + SelectQuery(const TQueryable & queryable, const TFunc & f) + : items(queryable), func(f) + {} + class Enumerator + { + private: + TEnumerator ptr; + TEnumerator end; + const TFunc * func; + public: + Enumerator(const Enumerator &) = default; + Enumerator(TEnumerator ptr, TEnumerator end, const TFunc & f) + : ptr(ptr), end(end), func(&f) + {} + auto operator *() const -> decltype((*func)(*ptr)) + { + return (*func)(*ptr); + } + Enumerator& operator ++() + { + ++ptr; + return *this; + } + Enumerator operator ++(int) + { + Enumerator rs = *this; + ++rs; + return rs; + } + bool operator != (const Enumerator & iter) const + { + return !(ptr == iter.ptr); + } + bool operator == (const Enumerator & iter) const + { + return ptr == iter.ptr; + } + }; + Enumerator begin() const + { + return Enumerator(items.begin(), items.end(), func); + } + Enumerator end() const + { + return Enumerator(items.end(), items.end(), func); + } + }; + + template <typename TQueryable, typename TEnumerator, typename T, typename TFunc> + class SelectManyQuery + { + private: + TQueryable items; + TFunc func; + SelectManyQuery() + {} + public: + SelectManyQuery(const TQueryable & queryable, const TFunc & f) + : items(queryable), func(f) + {} + template<typename TItems, typename TItemPtr> + class Enumerator + { + private: + TEnumerator ptr; + TEnumerator end; + const TFunc * func; + TItems items; + TItemPtr subPtr; + public: + Enumerator(const Enumerator &) = default; + Enumerator(TEnumerator ptr, TEnumerator end, const TFunc & f) + : ptr(ptr), end(end), func(&f) + { + if (ptr != end) + { + items = f(*ptr); + subPtr = items.begin(); + } + } + auto operator *() const -> decltype(*subPtr) + { + return *subPtr; + } + Enumerator& operator ++() + { + ++subPtr; + while (subPtr == items.end() && ptr != end) + { + ++ptr; + if (ptr != end) + { + items = (*func)(*ptr); + subPtr = items.begin(); + } + else + break; + } + + return *this; + } + Enumerator operator ++(int) + { + Enumerator rs = *this; + ++rs; + return rs; + } + bool operator != (const Enumerator & iter) const + { + return !operator==(iter); + } + bool operator == (const Enumerator & iter) const + { + if (ptr == iter.ptr) + { + if (ptr == end) + return true; + else + return subPtr == iter.subPtr; + } + else + return false; + } + }; + auto begin() const ->Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())> + { + return Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())>(items.begin(), items.end(), func); + } + auto end() const ->Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())> + { + return Enumerator<decltype(func(ConstructT<T>())), decltype(func(ConstructT<T>()).begin())>(items.end(), items.end(), func); + } + }; + + template <typename T> + struct EnumeratorType + { + typedef decltype(ConstructT<T>().begin()) Type; + }; + + template <typename TFunc, typename TArg> + class ExtractReturnType + { + public: + static TFunc * f; + static TArg ConstructArg() {}; + typedef decltype((*f)(ConstructArg())) ReturnType; + }; + + template <typename T> + class ExtractItemType + { + public: + typedef typename RemovePointer<decltype(ConstructT<T>().begin())>::Type Type; + }; + + template <typename TQueryable, typename TEnumerator, typename T> + class Queryable + { + private: + TQueryable items; + public: + auto begin() const -> decltype(items.begin()) + { + return items.begin(); + } + auto end() const -> decltype(items.end()) + { + return items.end(); + } + public: + const TQueryable & GetItems() const + { + return items; + } + Queryable(const TQueryable & items) + : items(items) + {} + + Queryable<SkipQuery<TQueryable, TEnumerator, T>, typename SkipQuery<TQueryable, TEnumerator, T>::Enumerator, T> Skip(int count) const + { + return Queryable<SkipQuery<TQueryable, TEnumerator, T>, typename SkipQuery<TQueryable, TEnumerator, T>::Enumerator, T>(SkipQuery<TQueryable, TEnumerator, T>(items, count)); + } + + template<typename TQueryable2, typename TEnumerator2> + Queryable<ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>, typename ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>::Enumerator, T> Concat(const Queryable<TQueryable2, TEnumerator2, T> & other) const + { + return Queryable<ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>, typename ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>::Enumerator, T>(ConcatQuery<TQueryable, TEnumerator, TQueryable2, TEnumerator2, T>(this->items, other.GetItems())); + } + + template<typename TFunc> + Queryable<WhereQuery<TQueryable, TEnumerator, T, TFunc>, typename WhereQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, T> Where(const TFunc & f) const + { + return Queryable<WhereQuery<TQueryable, TEnumerator, T, TFunc>, typename WhereQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, T>(WhereQuery<TQueryable, TEnumerator, T, TFunc>(items, f)); + } + + template<typename TFunc> + Queryable<SelectQuery<TQueryable, TEnumerator, T, TFunc>, typename SelectQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, typename RemoveReference<typename ExtractReturnType<TFunc, T>::ReturnType>::Type> Select(const TFunc & f) const + { + return Queryable<SelectQuery<TQueryable, TEnumerator, T, TFunc>, typename SelectQuery<TQueryable, TEnumerator, T, TFunc>::Enumerator, typename RemoveReference<typename ExtractReturnType<TFunc, T>::ReturnType>::Type>(SelectQuery<TQueryable, TEnumerator, T, TFunc>(items, f)); + } + + template<typename TFunc> + auto SelectMany(const TFunc & f) const ->Queryable<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>, typename EnumeratorType<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>>::Type, typename ExtractItemType<decltype(f(ConstructT<T>()))>::Type> + { + return Queryable<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>, typename EnumeratorType<SelectManyQuery<TQueryable, TEnumerator, T, TFunc>>::Type, typename ExtractItemType<decltype(f(ConstructT<T>()))>::Type>(SelectManyQuery<TQueryable, TEnumerator, T, TFunc>(items, f)); + } + + template<typename TAggregateResult, typename TFunc> + auto Aggregate(const TAggregateResult & initial, const TFunc & f) const -> decltype(f(initial, *items.begin())) + { + TAggregateResult rs = initial; + for (auto && x : items) + rs = f(rs, x); + return rs; + } + + template<typename TFunc> + bool Any(const TFunc & condition) const + { + for (auto && x : items) + if (condition(x)) + return true; + return false; + } + + template<typename TFunc> + T & First(const TFunc & condition) const + { + for (auto && x : items) + if (condition(x)) + return x; + } + + template <typename TFunc> + T Max(const TFunc & selector) const + { + return Aggregate(*items.begin(), [&](const T & v0, const T & v1) + { + return selector(v0) > selector(v1) ? v0 : v1; + }); + } + + template <typename TFunc> + T Min(const TFunc & selector) const + { + return Aggregate(*items.begin(), [&](const T & v0, const T & v1) + { + return selector(v0) < selector(v1) ? v0 : v1; + }); + } + + template <typename TFunc> + auto Sum(const TFunc & selector) const -> decltype(selector(ConstructT<T>())) + { + decltype(selector(ConstructT<T>())) rs(0); + for (auto && x : items) + rs = rs + selector(x); + return rs; + } + + T Max() const + { + return Aggregate(*items.begin(), [](const T & v0, const T & v1) {return v0 > v1 ? v0 : v1; }); + } + + T Min() const + { + return Aggregate(*items.begin(), [](const T & v0, const T & v1) {return v0 < v1 ? v0 : v1; }); + } + + T Sum() const + { + T rs = T(0); + for (auto && x : items) + rs = rs + x; + return rs; + } + + T Avg() const + { + T rs = T(0); + int count = 0; + for (auto && x : items) + { + rs = rs + x; + count++; + } + return rs / count; + } + + int Count() const + { + int rs = 0; + for (auto && x : items) + rs++; + return rs; + } + + List<T> ToList() const + { + List<T> rs; + for (auto && val : items) + rs.Add(val); + return rs; + } + }; + + + template<typename T, typename TAllocator> + inline Queryable<ArrayView<T>, T*, T> From(const List<T, TAllocator> & list) + { + return Queryable<ArrayView<T>, T*, T>(list.GetArrayView()); + } + + template<typename T, typename TAllocator> + inline Queryable<List<T, TAllocator>, T*, T> From(List<T, TAllocator> && list) + { + return Queryable<List<T, TAllocator>, T*, T>(_Move(list)); + } + + template<typename T> + inline Queryable<ArrayView<T>, T*, T> From(const ArrayView<T> & list) + { + return Queryable<ArrayView<T>, T*, T>(list); + } + + template<typename T, int count> + inline Queryable<Array<T, count>, T*, T> From(const Array<T, count> & list) + { + return Queryable<Array<T, count>, T*, T>(list); + } + + template<typename T> + inline auto From(const T & list) -> Queryable<T, decltype(list.begin()), decltype(*list.begin())> + { + return Queryable<T, decltype(list.begin()), decltype(*list.begin())>(list); + } + + template<typename T> + inline Queryable<Array<T, 1>, T*, T> FromSingle(const T & obj) + { + Array<T, 1> arr; + arr.Add(obj); + return From(arr); + } + + template<typename T> + struct LinkedListView + { + typename LinkedList<T>::Iterator start, last; + typename LinkedList<T>::Iterator begin() const + { + return start; + } + typename LinkedList<T>::Iterator end() const + { + return last; + } + }; + + template<typename T> + inline Queryable<LinkedListView<T>, LinkedNode<T>, T> From(const LinkedList<T> & list) + { + LinkedListView<T> view; + view.start = list.begin(); + view.last = list.end(); + return Queryable<LinkedListView<T>, LinkedNode<T>, T>(view); + } + + template<typename TKey, typename TValue> + struct EnumerableDictView + { + typename EnumerableDictionary<TKey, TValue>::Iterator start, last; + typename EnumerableDictionary<TKey, TValue>::Iterator begin() const + { + return start; + } + typename EnumerableDictionary<TKey, TValue>::Iterator end() const + { + return last; + } + }; + + template<typename TKey, typename TValue> + inline Queryable<EnumerableDictView<TKey, TValue>, typename EnumerableDictionary<TKey, TValue>::Iterator, KeyValuePair<TKey, TValue>> From(const EnumerableDictionary<TKey, TValue> & dict) + { + EnumerableDictView<TKey, TValue> view; + view.start = dict.begin(); + view.last = dict.end(); + return Queryable<EnumerableDictView<TKey, TValue>, typename EnumerableDictionary<TKey, TValue>::Iterator, KeyValuePair<TKey, TValue>>(view); + } + + template<typename TKey> + struct EnumerableHashSetView + { + typename HashSetBase<TKey, EnumerableDictionary<TKey, _DummyClass>>::Iterator start, last; + typename EnumerableHashSet<TKey>::Iterator begin() const + { + return start; + } + typename EnumerableHashSet<TKey>::Iterator end() const + { + return last; + } + }; + + template<typename TKey> + inline Queryable<EnumerableHashSetView<TKey>, typename HashSetBase<TKey, EnumerableDictionary<TKey, _DummyClass>>::Iterator, TKey> From(const EnumerableHashSet<TKey> & dict) + { + EnumerableHashSetView<TKey> view; + view.start = dict.begin(); + view.last = dict.end(); + return Queryable<EnumerableHashSetView<TKey>, typename HashSetBase<TKey, EnumerableDictionary<TKey, _DummyClass>>::Iterator, TKey>(view); + } + } +} + +#endif
\ No newline at end of file diff --git a/source/core/list.h b/source/core/list.h new file mode 100644 index 000000000..6ff68ed7d --- /dev/null +++ b/source/core/list.h @@ -0,0 +1,674 @@ +#ifndef FUNDAMENTAL_LIB_LIST_H +#define FUNDAMENTAL_LIB_LIST_H + +#include "allocator.h" +#include "slang-math.h" +#include "array-view.h" + +#include <algorithm> +#include <new> +#include <type_traits> + +const int MIN_QSORT_SIZE = 32; + +namespace CoreLib +{ + namespace Basic + { + template<typename T, int isPOD> + class Initializer + { + + }; + + template<typename T> + class Initializer<T, 0> + { + public: + static void Initialize(T * buffer, int size) + { + for (int i = 0; i<size; i++) + new (buffer + i) T(); + } + }; + + template<typename T, typename TAllocator> + class AllocateMethod + { + public: + static inline T* Alloc(int size) + { + TAllocator allocator; + T * rs = (T*)allocator.Alloc(size*sizeof(T)); + Initializer<T, std::is_pod<T>::value>::Initialize(rs, size); + return rs; + } + static inline void Free(T * ptr, int bufferSize) + { + TAllocator allocator; + if (!std::is_trivially_destructible<T>::value) + { + for (int i = 0; i<bufferSize; i++) + ptr[i].~T(); + } + allocator.Free(ptr); + } + }; + + template<typename T> + class AllocateMethod<T, StandardAllocator> + { + public: + static inline T* Alloc(int size) + { + return new T[size]; + } + static inline void Free(T* ptr, int /*bufferSize*/) + { + delete [] ptr; + } + }; + + template<typename T> + class Initializer<T, 1> + { + public: + static void Initialize(T * buffer, int size) + { + for (int i = 0; i<size; i++) + new (buffer + i) T; + } + }; + + template<typename T, typename TAllocator = StandardAllocator> + class List + { + private: + + inline T * Allocate(int size) + { + return AllocateMethod<T, TAllocator>::Alloc(size); + + } + private: + static const int InitialSize = 16; + TAllocator allocator; + private: + T * buffer; + int _count; + int bufferSize; + void FreeBuffer() + { + AllocateMethod<T, TAllocator>::Free(buffer, bufferSize); + buffer = 0; + } + void Free() + { + if (buffer) + { + FreeBuffer(); + } + buffer = 0; + _count = bufferSize = 0; + } + public: + T* begin() const + { + return buffer; + } + T* end() const + { + return buffer+_count; + } + private: + template<typename... Args> + void Init(const T & val, Args... args) + { + Add(val); + Init(args...); + } + public: + List() + : buffer(0), _count(0), bufferSize(0) + { + } + template<typename... Args> + List(const T & val, Args... args) + { + Init(val, args...); + } + List(const List<T> & list) + : buffer(0), _count(0), bufferSize(0) + { + this->operator=(list); + } + List(List<T> && list) + : buffer(0), _count(0), bufferSize(0) + { + this->operator=(static_cast<List<T>&&>(list)); + } + static List<T> Create(const T & val, int count) + { + List<T> rs; + rs.SetSize(count); + for (int i = 0; i < count; i++) + rs[i] = val; + return rs; + } + ~List() + { + Free(); + } + List<T> & operator=(const List<T> & list) + { + Free(); + AddRange(list); + + return *this; + } + + List<T> & operator=(List<T> && list) + { + Free(); + _count = list._count; + bufferSize = list.bufferSize; + buffer = list.buffer; + + list.buffer = 0; + list._count = 0; + list.bufferSize = 0; + return *this; + } + + T & First() const + { +#ifdef _DEBUG + if (_count == 0) + throw "Index out of range."; +#endif + return buffer[0]; + } + + T & Last() const + { +#ifdef _DEBUG + if (_count == 0) + throw "Index out of range."; +#endif + return buffer[_count-1]; + } + + inline void SwapWith(List<T, TAllocator> & other) + { + T* tmpBuffer = this->buffer; + this->buffer = other.buffer; + other.buffer = tmpBuffer; + int tmpBufferSize = this->bufferSize; + this->bufferSize = other.bufferSize; + other.bufferSize = tmpBufferSize; + int tmpCount = this->_count; + this->_count = other._count; + other._count = tmpCount; + TAllocator tmpAlloc = _Move(this->allocator); + this->allocator = _Move(other.allocator); + other.allocator = _Move(tmpAlloc); + } + + T* ReleaseBuffer() + { + T* rs = buffer; + buffer = nullptr; + _count = 0; + bufferSize = 0; + return rs; + } + + inline ArrayView<T> GetArrayView() const + { + return ArrayView<T>(buffer, _count); + } + + inline ArrayView<T> GetArrayView(int start, int count) const + { +#ifdef _DEBUG + if (start + count > _count || start < 0 || count < 0) + throw "Index out of range."; +#endif + return ArrayView<T>(buffer + start, count); + } + + void Add(T && obj) + { + if (bufferSize < _count + 1) + { + int newBufferSize = InitialSize; + if (bufferSize) + newBufferSize = (bufferSize << 1); + + Reserve(newBufferSize); + } + buffer[_count++] = static_cast<T&&>(obj); + } + + void Add(const T & obj) + { + if (bufferSize < _count + 1) + { + int newBufferSize = InitialSize; + if (bufferSize) + newBufferSize = (bufferSize << 1); + + Reserve(newBufferSize); + } + buffer[_count++] = obj; + + } + + int Count() const + { + return _count; + } + + T * Buffer() const + { + return buffer; + } + + int Capacity() const + { + return bufferSize; + } + + void Insert(int id, const T & val) + { + InsertRange(id, &val, 1); + } + + void InsertRange(int id, const T * vals, int n) + { + if (bufferSize < _count + n) + { + int newBufferSize = InitialSize; + while (newBufferSize < _count + n) + newBufferSize = newBufferSize << 1; + + T * newBuffer = Allocate(newBufferSize); + if (bufferSize) + { + /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) + { + memcpy(newBuffer, buffer, sizeof(T) * id); + memcpy(newBuffer + id + n, buffer + id, sizeof(T) * (_count - id)); + } + else*/ + { + for (int i = 0; i < id; i++) + newBuffer[i] = buffer[i]; + for (int i = id; i < _count; i++) + newBuffer[i + n] = T(static_cast<T&&>(buffer[i])); + } + FreeBuffer(); + } + buffer = newBuffer; + bufferSize = newBufferSize; + } + else + { + /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) + memmove(buffer + id + n, buffer + id, sizeof(T) * (_count - id)); + else*/ + { + for (int i = _count - 1; i >= id; i--) + buffer[i + n] = static_cast<T&&>(buffer[i]); + } + } + /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) + memcpy(buffer + id, vals, sizeof(T) * n); + else*/ + for (int i = 0; i < n; i++) + buffer[id + i] = vals[i]; + + _count += n; + } + + //slower than original edition + //void Add(const T & val) + //{ + // InsertRange(_count, &val, 1); + //} + + void InsertRange(int id, const List<T> & list) + { + InsertRange(id, list.buffer, list._count); + } + + void AddRange(ArrayView<T> list) + { + InsertRange(_count, list.Buffer(), list.Count()); + } + + void AddRange(const T * vals, int n) + { + InsertRange(_count, vals, n); + } + + void AddRange(const List<T> & list) + { + InsertRange(_count, list.buffer, list._count); + } + + void RemoveRange(int id, int deleteCount) + { +#if _DEBUG + if (id >= _count || id < 0) + throw "Remove: Index out of range."; + if(deleteCount < 0) + throw "Remove: deleteCount smaller than zero."; +#endif + int actualDeleteCount = ((id + deleteCount) >= _count)? (_count - id) : deleteCount; + for (int i = id + actualDeleteCount; i < _count; i++) + buffer[i - actualDeleteCount] = static_cast<T&&>(buffer[i]); + _count -= actualDeleteCount; + } + + void RemoveAt(int id) + { + RemoveRange(id, 1); + } + + void Remove(const T & val) + { + int idx = IndexOf(val); + if (idx != -1) + RemoveAt(idx); + } + + void Reverse() + { + for (int i = 0; i < (_count >> 1); i++) + { + Swap(buffer, i, _count - i - 1); + } + } + + void FastRemove(const T & val) + { + int idx = IndexOf(val); + FastRemoveAt(idx); + } + + void FastRemoveAt(int idx) + { + if (idx != -1 && _count - 1 != idx) + { + buffer[idx] = _Move(buffer[_count - 1]); + } + _count--; + } + + void Clear() + { + _count = 0; + } + + void Reserve(int size) + { + if(size > bufferSize) + { + T * newBuffer = Allocate(size); + if (bufferSize) + { + /*if (std::has_trivial_copy_assign<T>::value && std::has_trivial_destructor<T>::value) + memcpy(newBuffer, buffer, _count * sizeof(T)); + else*/ + { + for (int i = 0; i < _count; i++) + newBuffer[i] = static_cast<T&&>(buffer[i]); + } + FreeBuffer(); + } + buffer = newBuffer; + bufferSize = size; + } + } + + void GrowToSize(int size) + { + int newBufferSize = 1<<Math::Log2Ceil(size); + if (bufferSize < newBufferSize) + { + Reserve(newBufferSize); + } + this->_count = size; + } + + void SetSize(int size) + { + Reserve(size); + _count = size; + } + + void UnsafeShrinkToSize(int size) + { + _count = size; + } + + void Compress() + { + if (bufferSize > _count && _count > 0) + { + T * newBuffer = Allocate(_count); + for (int i = 0; i < _count; i++) + newBuffer[i] = static_cast<T&&>(buffer[i]); + FreeBuffer(); + buffer = newBuffer; + bufferSize = _count; + } + } + +#ifndef FORCE_INLINE +#ifdef _MSC_VER +#define FORCE_INLINE __forceinline +#else +#define FORCE_INLINE inline +#endif +#endif + + FORCE_INLINE T & operator [](int id) const + { +#if _DEBUG + if(id >= _count || id < 0) + throw IndexOutofRangeException("Operator[]: Index out of Range."); +#endif + return buffer[id]; + } + + template<typename Func> + int FindFirst(const Func & predicate) const + { + for (int i = 0; i < _count; i++) + { + if (predicate(buffer[i])) + return i; + } + return -1; + } + + template<typename Func> + int FindLast(const Func & predicate) const + { + for (int i = _count - 1; i >= 0; i--) + { + if (predicate(buffer[i])) + return i; + } + return -1; + } + + template<typename T2> + int IndexOf(const T2 & val) const + { + for (int i = 0; i < _count; i++) + { + if (buffer[i] == val) + return i; + } + return -1; + } + + template<typename T2> + int LastIndexOf(const T2 & val) const + { + for (int i = _count - 1; i >= 0; i--) + { + if(buffer[i] == val) + return i; + } + return -1; + } + + void Sort() + { + Sort([](T& t1, T& t2){return t1<t2;}); + } + + bool Contains(const T & val) + { + for (int i = 0; i<_count; i++) + if (buffer[i] == val) + return true; + return false; + } + + template<typename Comparer> + void Sort(Comparer compare) + { + //InsertionSort(buffer, 0, _count - 1); + //QuickSort(buffer, 0, _count - 1, compare); + std::sort(buffer, buffer + _count, compare); + } + + template <typename IterateFunc> + void ForEach(IterateFunc f) const + { + for (int i = 0; i<_count; i++) + f(buffer[i]); + } + + template<typename Comparer> + void QuickSort(T * vals, int startIndex, int endIndex, Comparer comparer) + { + if(startIndex < endIndex) + { + if (endIndex - startIndex < MIN_QSORT_SIZE) + InsertionSort(vals, startIndex, endIndex, comparer); + else + { + int pivotIndex = (startIndex + endIndex) >> 1; + int pivotNewIndex = Partition(vals, startIndex, endIndex, pivotIndex, comparer); + QuickSort(vals, startIndex, pivotNewIndex - 1, comparer); + QuickSort(vals, pivotNewIndex + 1, endIndex, comparer); + } + } + + } + template<typename Comparer> + int Partition(T * vals, int left, int right, int pivotIndex, Comparer comparer) + { + T pivotValue = vals[pivotIndex]; + Swap(vals, right, pivotIndex); + int storeIndex = left; + for (int i = left; i < right; i++) + { + if (comparer(vals[i], pivotValue)) + { + Swap(vals, i, storeIndex); + storeIndex++; + } + } + Swap(vals, storeIndex, right); + return storeIndex; + } + template<typename Comparer> + void InsertionSort(T * vals, int startIndex, int endIndex, Comparer comparer) + { + for (int i = startIndex + 1; i <= endIndex; i++) + { + T insertValue = static_cast<T&&>(vals[i]); + int insertIndex = i - 1; + while (insertIndex >= startIndex && comparer(insertValue, vals[insertIndex])) + { + vals[insertIndex + 1] = static_cast<T&&>(vals[insertIndex]); + insertIndex--; + } + vals[insertIndex + 1] = static_cast<T&&>(insertValue); + } + } + + inline void Swap(T * vals, int index1, int index2) + { + if (index1 != index2) + { + T tmp = static_cast<T&&>(vals[index1]); + vals[index1] = static_cast<T&&>(vals[index2]); + vals[index2] = static_cast<T&&>(tmp); + } + } + + template<typename T2, typename Comparer> + int BinarySearch(const T2 & obj, Comparer comparer) + { + int imin = 0, imax = _count - 1; + while (imax >= imin) + { + int imid = (imin + imax) >> 1; + int compareResult = comparer(buffer[imid], obj); + if (compareResult == 0) + return imid; + else if (compareResult < 0) + imin = imid + 1; + else + imax = imid - 1; + } + return -1; + } + + template<typename T2> + int BinarySearch(const T2 & obj) + { + return BinarySearch(obj, + [](T & curObj, const T2 & thatObj)->int + { + if (curObj < thatObj) + return -1; + else if (curObj == thatObj) + return 0; + else + return 1; + }); + } + }; + + template<typename T> + T Min(const List<T> & list) + { + T minVal = list.First(); + for (int i = 1; i<list.Count(); i++) + if (list[i] < minVal) + minVal = list[i]; + return minVal; + } + + template<typename T> + T Max(const List<T> & list) + { + T maxVal = list.First(); + for (int i = 1; i<list.Count(); i++) + if (list[i] > maxVal) + maxVal = list[i]; + return maxVal; + } + } +} + +#endif diff --git a/source/core/memory-pool.cpp b/source/core/memory-pool.cpp new file mode 100644 index 000000000..f9d29636b --- /dev/null +++ b/source/core/memory-pool.cpp @@ -0,0 +1,135 @@ +#include "memory-pool.h" +#include <cassert> + +namespace CoreLib +{ + namespace Basic + { + MemoryPool::MemoryPool(unsigned char * pBuffer, int pLog2BlockSize, int numBlocks) + { + Init(pBuffer, pLog2BlockSize, numBlocks); + } + void MemoryPool::Init(unsigned char * pBuffer, int pLog2BlockSize, int numBlocks) + { + assert(pLog2BlockSize >= 1 && pLog2BlockSize <= 30); + assert(numBlocks >= 4); + buffer = pBuffer; + blockSize = 1 << pLog2BlockSize; + log2BlockSize = pLog2BlockSize; + numLevels = Math::Log2Floor(numBlocks); + freeList[0] = (FreeListNode*)buffer; + freeList[0]->NextPtr = nullptr; + freeList[0]->PrevPtr = nullptr; + used.SetMax(1 << (numLevels)); + for (int i = 1; i < MaxLevels; i++) + { + freeList[i] = nullptr; + } + } + int MemoryPool::AllocBlock(int level) + { + if (level < 0) + return -1; + if (freeList[level] == nullptr) + { + auto largeBlockAddr = AllocBlock(level - 1); + if (largeBlockAddr != -1) + { + auto block1 = (FreeListNode*)(buffer + ((largeBlockAddr ^ (1 << (numLevels - level))) << log2BlockSize)); + block1->NextPtr = nullptr; + block1->PrevPtr = nullptr; + freeList[level] = block1; + + int blockIndex = (1 << level) + (largeBlockAddr >> (numLevels-level)) - 1; + used.Add(blockIndex); + return largeBlockAddr; + } + else + return -1; + } + else + { + auto node = freeList[level]; + if (node->NextPtr) + { + node->NextPtr->PrevPtr = node->PrevPtr; + } + freeList[level] = freeList[level]->NextPtr; + int rs = (int)((unsigned char *)node - buffer) >> log2BlockSize; + int blockIndex = (1 << level) + (rs >> (numLevels - level)) - 1; + used.Add(blockIndex); + return rs; + } + } + unsigned char * MemoryPool::Alloc(int size) + { + if (size == 0) + return nullptr; + int originalSize = size; + if (size < blockSize) + size = blockSize; + int order = numLevels - (Math::Log2Ceil(size) - log2BlockSize); + assert(order >= 0 && order < MaxLevels); + + bytesAllocated += (1 << ((numLevels-order) + log2BlockSize)); + bytesWasted += (1 << ((numLevels - order) + log2BlockSize)) - originalSize; + + int blockId = AllocBlock(order); + if (blockId != -1) + return buffer + (blockId << log2BlockSize); + else + return nullptr; + } + void MemoryPool::FreeBlock(unsigned char * ptr, int level) + { + int indexInLevel = (int)(ptr - buffer) >> (numLevels - level + log2BlockSize); + int blockIndex = (1 << level) + indexInLevel - 1; + assert(used.Contains(blockIndex)); + int buddyIndex = (blockIndex & 1) ? blockIndex + 1 : blockIndex - 1; + used.Remove(blockIndex); + if (level > 0 && !used.Contains(buddyIndex)) + { + auto buddyPtr = (FreeListNode *)(buffer + ((((int)(ptr - buffer) >> log2BlockSize) ^ (1 << (numLevels - level))) << log2BlockSize)); + if (buddyPtr->PrevPtr) + { + buddyPtr->PrevPtr->NextPtr = buddyPtr->NextPtr; + } + if (buddyPtr->NextPtr) + { + buddyPtr->NextPtr->PrevPtr = buddyPtr->PrevPtr; + } + if (freeList[level] == buddyPtr) + { + freeList[level] = buddyPtr->NextPtr; + } + // recursively free parent blocks + auto parentPtr = Math::Min(buddyPtr, (FreeListNode*)ptr); + if (level > 0) + FreeBlock((unsigned char*)parentPtr, level - 1); + } + else + { + // insert to freelist + auto freeNode = (FreeListNode *)ptr; + freeNode->NextPtr = freeList[level]; + freeNode->PrevPtr = nullptr; + if (freeList[level]) + freeList[level]->PrevPtr = freeNode; + freeList[level] = freeNode; + } + } + void MemoryPool::Free(unsigned char * ptr, int size) + { + if (size == 0) + return; + int originalSize = size; + if (size < blockSize) + size = blockSize; + int level = numLevels - (Math::Log2Ceil(size) - log2BlockSize); + bytesAllocated -= (1 << ((numLevels-level) + log2BlockSize)); + bytesWasted -= (1 << ((numLevels - level) + log2BlockSize)) - originalSize; + FreeBlock(ptr, level); + } + } +} + diff --git a/source/core/memory-pool.h b/source/core/memory-pool.h new file mode 100644 index 000000000..6bfded060 --- /dev/null +++ b/source/core/memory-pool.h @@ -0,0 +1,126 @@ +#ifndef CORE_LIB_MEMORY_POOL_H +#define CORE_LIB_MEMORY_POOL_H + +#include "basic.h" +#include "int-set.h" + +namespace CoreLib +{ + namespace Basic + { + struct MemoryBlockFields + { + unsigned int Occupied : 1; + unsigned int Order : 31; + }; + struct FreeListNode + { + FreeListNode * PrevPtr = nullptr, *NextPtr = nullptr; + }; + class MemoryPool + { + private: + static const int MaxLevels = 32; + int blockSize = 0, log2BlockSize = 0; + int numLevels = 0; + int bytesAllocated = 0; + int bytesWasted = 0; + unsigned char * buffer = nullptr; + FreeListNode * freeList[MaxLevels]; + IntSet used; + int AllocBlock(int level); + void FreeBlock(unsigned char * ptr, int level); + public: + MemoryPool(unsigned char * buffer, int log2BlockSize, int numBlocks); + MemoryPool() = default; + void Init(unsigned char * buffer, int log2BlockSize, int numBlocks); + unsigned char * Alloc(int size); + void Free(unsigned char * ptr, int size); + }; + + class OutofPoolMemoryException : public Exception + {}; + + template<typename T, int PoolSize> + class ObjectPool + { + static const int ObjectSize = sizeof(T) < 8 ? 8 : sizeof(T); + private: + struct FreeList + { + FreeList* Next; + }; + FreeList * freeList = nullptr; + int allocPtr = 0; + int poolSize = 0; + void * buffer = 0; + T * GetFreeObject() + { + if (freeList) + { + auto rs = (T*)freeList; + freeList = freeList->Next; + return rs; + } + return nullptr; + } + public: + ObjectPool() + { + freeList = nullptr; + allocPtr = 0; + buffer = malloc(PoolSize * ObjectSize); + } + + void Close() + { + free(buffer); + } + + void Free(T * obj) + { + auto newList = (FreeList*)obj; + newList->Next = freeList; + freeList = newList; + } + + void * Buffer() + { + return buffer; + } + + T * Alloc() + { + auto rs = GetFreeObject(); + if (!rs) + { + if (allocPtr < PoolSize) + { + rs = (T*)buffer + allocPtr; + allocPtr++; + } + } + if (!rs) + { + throw OutofPoolMemoryException(); + } + return rs; + } + }; + }; + +#define USE_POOL_ALLOCATOR(T, PoolSize) \ + private:\ + static CoreLib::ObjectPool<T, PoolSize> _pool;\ + public:\ + void * operator new(std::size_t) { return _pool.Alloc(); } \ + void operator delete(void * ptr) {_pool.Free((T*)ptr); }\ + int GetObjectId() { return (int)(this - (T*)_pool.Buffer()); }\ + static void ClosePool(); +#define IMPL_POOL_ALLOCATOR(T, PoolSize) \ + CoreLib::ObjectPool<T, PoolSize> T::_pool;\ + void T::ClosePool() { _pool.Close(); } + +} + +#endif
\ No newline at end of file diff --git a/source/core/secure-crt.h b/source/core/secure-crt.h new file mode 100644 index 000000000..12927cc24 --- /dev/null +++ b/source/core/secure-crt.h @@ -0,0 +1,75 @@ +#ifndef _MSC_VER +#ifndef CORE_LIB_SECURE_CRT_H +#define CORE_LIB_SECURE_CRT_H +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> + +inline void memcpy_s(void *dest, size_t numberOfElements, const void * src, size_t count) +{ + memcpy(dest, src, count); +} + +#define _TRUNCATE ((size_t)-1) +#define _stricmp strcasecmp + +inline void fopen_s(FILE**f, const char * fileName, const char * mode) +{ + *f = fopen(fileName, mode); +} + +inline size_t fread_s(void * buffer, size_t bufferSize, size_t elementSize, size_t count, FILE * stream) +{ + return fread(buffer, elementSize, count, stream); +} + +inline size_t wcsnlen_s(const wchar_t * str, size_t /*numberofElements*/) +{ + return wcslen(str); +} + +inline size_t strnlen_s(const char * str, size_t numberofElements) +{ + return strnlen(str, numberofElements); +} + +inline int sprintf_s(char * buffer, size_t sizeOfBuffer, const char * format, ...) +{ + va_list argptr; + va_start(argptr, format); + int rs = snprintf(buffer, sizeOfBuffer, format, argptr); + va_end(argptr); + return rs; +} + +inline int swprintf_s(wchar_t * buffer, size_t sizeOfBuffer, const wchar_t * format, ...) +{ + va_list argptr; + va_start(argptr, format); + int rs = swprintf(buffer, sizeOfBuffer, format, argptr); + va_end(argptr); + return rs; +} + +inline void wcscpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource) +{ + wcscpy(strDestination, strSource); +} +inline void strcpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource) +{ + strcpy(strDestination, strSource); +} + +inline void wcsncpy_s(wchar_t * strDestination, size_t /*numberOfElements*/, const wchar_t * strSource, size_t count) +{ + wcscpy(strDestination, strSource); + //wcsncpy(strDestination, strSource, count); +} +inline void strncpy_s(char * strDestination, size_t /*numberOfElements*/, const char * strSource, size_t count) +{ + strncpy(strDestination, strSource, count); + //wcsncpy(strDestination, strSource, count); +} +#endif +#endif diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp new file mode 100644 index 000000000..da36edbbf --- /dev/null +++ b/source/core/slang-io.cpp @@ -0,0 +1,145 @@ +#include "slang-io.h" +#include "exception.h" +#ifndef __STDC__ +#define __STDC__ 1 +#endif +#include <sys/stat.h> +#ifdef _WIN32 +#include <direct.h> +#endif +namespace CoreLib +{ + namespace IO + { + using namespace CoreLib::Basic; + + CommandLineWriter * currentCommandWriter = nullptr; + + void SetCommandLineWriter(CommandLineWriter * writer) + { + currentCommandWriter = writer; + } + + bool File::Exists(const String & fileName) + { +#ifdef _WIN32 + struct _stat32 statVar; + return ::_wstat32(((String)fileName).ToWString(), &statVar) != -1; +#else + struct stat statVar; + return ::stat(fileName.Buffer(), &statVar) == 0; +#endif + } + + String Path::TruncateExt(const String & path) + { + int dotPos = path.LastIndexOf('.'); + if (dotPos != -1) + return path.SubString(0, dotPos); + else + return path; + } + String Path::ReplaceExt(const String & path, const char * newExt) + { + StringBuilder sb(path.Length()+10); + int dotPos = path.LastIndexOf('.'); + if (dotPos == -1) + dotPos = path.Length(); + sb.Append(path.Buffer(), dotPos); + sb.Append('.'); + sb.Append(newExt); + return sb.ProduceString(); + } + String Path::GetFileName(const String & path) + { + int pos = path.LastIndexOf('/'); + pos = Math::Max(path.LastIndexOf('\\'), pos) + 1; + return path.SubString(pos, path.Length()-pos); + } + String Path::GetFileNameWithoutEXT(const String & path) + { + int pos = path.LastIndexOf('/'); + pos = Math::Max(path.LastIndexOf('\\'), pos) + 1; + int dotPos = path.LastIndexOf('.'); + if (dotPos <= pos) + dotPos = path.Length(); + return path.SubString(pos, dotPos - pos); + } + String Path::GetFileExt(const String & path) + { + int dotPos = path.LastIndexOf('.'); + if (dotPos != -1) + return path.SubString(dotPos+1, path.Length()-dotPos-1); + else + return ""; + } + String Path::GetDirectoryName(const String & path) + { + int pos = path.LastIndexOf('/'); + pos = Math::Max(path.LastIndexOf('\\'), pos); + if (pos != -1) + return path.SubString(0, pos); + else + return ""; + } + String Path::Combine(const String & path1, const String & path2) + { + if (path1.Length() == 0) return path2; + StringBuilder sb(path1.Length()+path2.Length()+2); + sb.Append(path1); + if (!path1.EndsWith('\\') && !path1.EndsWith('/')) + sb.Append(PathDelimiter); + sb.Append(path2); + return sb.ProduceString(); + } + String Path::Combine(const String & path1, const String & path2, const String & path3) + { + StringBuilder sb(path1.Length()+path2.Length()+path3.Length()+3); + sb.Append(path1); + if (!path1.EndsWith('\\') && !path1.EndsWith('/')) + sb.Append(PathDelimiter); + sb.Append(path2); + if (!path2.EndsWith('\\') && !path2.EndsWith('/')) + sb.Append(PathDelimiter); + sb.Append(path3); + return sb.ProduceString(); + } + + bool Path::CreateDir(const String & path) + { +#if defined(_WIN32) + return _wmkdir(path.ToWString()) == 0; +#else + return mkdir(path.Buffer(), 0777) == 0; +#endif + } + + CoreLib::Basic::String File::ReadAllText(const CoreLib::Basic::String & fileName) + { + StreamReader reader(new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite)); + return reader.ReadToEnd(); + } + + CoreLib::Basic::List<unsigned char> File::ReadAllBytes(const CoreLib::Basic::String & fileName) + { + RefPtr<FileStream> fs = new FileStream(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite); + List<unsigned char> buffer; + while (!fs->IsEnd()) + { + unsigned char ch; + int read = (int)fs->Read(&ch, 1); + if (read) + buffer.Add(ch); + else + break; + } + return _Move(buffer); + } + + void File::WriteAllText(const CoreLib::Basic::String & fileName, const CoreLib::Basic::String & text) + { + StreamWriter writer(new FileStream(fileName, FileMode::Create)); + writer.Write(text); + } + } +}
\ No newline at end of file diff --git a/source/core/slang-io.h b/source/core/slang-io.h new file mode 100644 index 000000000..0471cd965 --- /dev/null +++ b/source/core/slang-io.h @@ -0,0 +1,63 @@ +#ifndef CORE_LIB_IO_H +#define CORE_LIB_IO_H + +#include "slang-string.h" +#include "stream.h" +#include "text-io.h" +#include "secure-crt.h" + +namespace CoreLib +{ + namespace IO + { + class File + { + public: + static bool Exists(const CoreLib::Basic::String & fileName); + static CoreLib::Basic::String ReadAllText(const CoreLib::Basic::String & fileName); + static CoreLib::Basic::List<unsigned char> ReadAllBytes(const CoreLib::Basic::String & fileName); + static void WriteAllText(const CoreLib::Basic::String & fileName, const CoreLib::Basic::String & text); + }; + + class Path + { + public: +#ifdef _WIN32 + static const char PathDelimiter = '\\'; +#else + static const char PathDelimiter = '/'; +#endif + static String TruncateExt(const String & path); + static String ReplaceExt(const String & path, const char * newExt); + static String GetFileName(const String & path); + static String GetFileNameWithoutEXT(const String & path); + static String GetFileExt(const String & path); + static String GetDirectoryName(const String & path); + static String Combine(const String & path1, const String & path2); + static String Combine(const String & path1, const String & path2, const String & path3); + static bool CreateDir(const String & path); + }; + + class CommandLineWriter : public Object + { + public: + virtual void Write(const String & text) = 0; + }; + + void SetCommandLineWriter(CommandLineWriter * writer); + + extern CommandLineWriter * currentCommandWriter; + template<typename ...Args> + void uiprintf(const wchar_t * format, Args... args) + { + if (currentCommandWriter) + { + char buffer[1024]; + snprintf(buffer, 1024, format, args...); + currentCommandWriter->Write(buffer); + } + } + } +} + +#endif
\ No newline at end of file diff --git a/source/core/slang-math.cpp b/source/core/slang-math.cpp new file mode 100644 index 000000000..a57b0dac2 --- /dev/null +++ b/source/core/slang-math.cpp @@ -0,0 +1,9 @@ +#include "slang-math.h" + +namespace CoreLib +{ + namespace Basic + { + const float Math::Pi = 3.141592654f; + } +}
\ No newline at end of file diff --git a/source/core/slang-math.h b/source/core/slang-math.h new file mode 100644 index 000000000..454dfbfdf --- /dev/null +++ b/source/core/slang-math.h @@ -0,0 +1,220 @@ +#ifndef CORE_LIB_MATH_H +#define CORE_LIB_MATH_H + +#include <math.h> + +namespace CoreLib +{ + namespace Basic + { + class Math + { + public: + static const float Pi; + template<typename T> + static T Min(const T& v1, const T&v2) + { + return v1<v2?v1:v2; + } + template<typename T> + static T Max(const T& v1, const T&v2) + { + return v1>v2?v1:v2; + } + template<typename T> + static T Min(const T& v1, const T&v2, const T&v3) + { + return Min(v1, Min(v2, v3)); + } + template<typename T> + static T Max(const T& v1, const T&v2, const T&v3) + { + return Max(v1, Max(v2, v3)); + } + template<typename T> + static T Clamp(const T& val, const T& vmin, const T&vmax) + { + if (val < vmin) return vmin; + else if (val > vmax) return vmax; + else return val; + } + + static inline int FastFloor(float x) + { + int i = (int)x; + return i - (i > x); + } + + static inline int FastFloor(double x) + { + int i = (int)x; + return i - (i > x); + } + + static inline int IsNaN(float x) + { +#ifdef _M_X64 + return _isnanf(x); +#else + return isnan(x); +#endif + } + + static inline int IsInf(float x) + { + return isinf(x); + } + + static inline unsigned int Ones32(register unsigned int x) + { + /* 32-bit recursive reduction using SWAR... + but first step is mapping 2-bit values + into sum of 2 1-bit values in sneaky way + */ + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return(x & 0x0000003f); + } + + static inline unsigned int Log2Floor(register unsigned int x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return(Ones32(x >> 1)); + } + + static inline unsigned int Log2Ceil(register unsigned int x) + { + int y = (x & (x - 1)); + y |= -y; + y >>= (32 - 1); + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return(Ones32(x >> 1) - y); + } + /* + static inline int Log2(float x) + { + unsigned int ix = (unsigned int&)x; + unsigned int exp = (ix >> 23) & 0xFF; + int log2 = (unsigned int)(exp) - 127; + + return log2; + } + */ + }; + inline int FloatAsInt(float val) + { + union InterCast + { + float fvalue; + int ivalue; + } cast; + cast.fvalue = val; + return cast.ivalue; + } + inline float IntAsFloat(int val) + { + union InterCast + { + float fvalue; + int ivalue; + } cast; + cast.ivalue = val; + return cast.fvalue; + } + + inline unsigned short FloatToHalf(float val) + { + int x = *(int*)&val; + unsigned short bits = (x >> 16) & 0x8000; + unsigned short m = (x >> 12) & 0x07ff; + unsigned int e = (x >> 23) & 0xff; + if (e < 103) + return bits; + if (e > 142) + { + bits |= 0x7c00u; + bits |= e == 255 && (x & 0x007fffffu); + return bits; + } + if (e < 113) + { + m |= 0x0800u; + bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); + return bits; + } + bits |= ((e - 112) << 10) | (m >> 1); + bits += m & 1; + return bits; + } + + inline float HalfToFloat(unsigned short input) + { + union InterCast + { + float fvalue; + int ivalue; + InterCast() = default; + InterCast(int ival) + { + ivalue = ival; + } + }; + static const InterCast magic = InterCast((127 + (127 - 15)) << 23); + static const InterCast was_infnan = InterCast((127 + 16) << 23); + InterCast o; + o.ivalue = (input & 0x7fff) << 13; // exponent/mantissa bits + o.fvalue *= magic.fvalue; // exponent adjust + if (o.fvalue >= was_infnan.fvalue) // make sure Inf/NaN survive + o.ivalue |= 255 << 23; + o.ivalue |= (input & 0x8000) << 16; // sign bit + return o.fvalue; + } + + class Random + { + private: + unsigned int seed; + public: + Random(int seed) + { + this->seed = seed; + } + int Next() // random between 0 and RandMax (currently 0x7fff) + { + return ((seed = ((seed << 12) + 150889L) % 714025) & 0x7fff); + } + int Next(int min, int max) // inclusive min, exclusive max + { + unsigned int a = ((seed = ((seed << 12) + 150889L) % 714025) & 0xFFFF); + unsigned int b = ((seed = ((seed << 12) + 150889L) % 714025) & 0xFFFF); + unsigned int r = (a << 16) + b; + return min + r % (max - min); + } + float NextFloat() + { + return ((Next() << 15) + Next()) / ((float)(1 << 30)); + } + float NextFloat(float valMin, float valMax) + { + return valMin + (valMax - valMin) * NextFloat(); + } + static int RandMax() + { + return 0x7fff; + } + }; + } +} + +#endif diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp new file mode 100644 index 000000000..1337ceaec --- /dev/null +++ b/source/core/slang-string.cpp @@ -0,0 +1,166 @@ +#include "slang-string.h" +#include "text-io.h" + +namespace CoreLib +{ + namespace Basic + { + _EndLine EndLine; + String StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen) + { + String res; + res.length = leftLen + rightLen; + res.buffer = new char[res.length + 1]; + strcpy_s(res.buffer.Ptr(), res.length + 1, lhs); + strcpy_s(res.buffer + leftLen, res.length + 1 - leftLen, rhs); + return res; + } + String operator+(const char * op1, const String & op2) + { + if(!op2.buffer) + return String(op1); + + return StringConcat(op1, (int)strlen(op1), op2.buffer.Ptr(), op2.length); + } + + String operator+(const String & op1, const char * op2) + { + if(!op1.buffer) + return String(op2); + + return StringConcat(op1.buffer.Ptr(), op1.length, op2, (int)strlen(op2)); + } + + String operator+(const String & op1, const String & op2) + { + if(!op1.buffer && !op2.buffer) + return String(); + else if(!op1.buffer) + return String(op2); + else if(!op2.buffer) + return String(op1); + + return StringConcat(op1.buffer.Ptr(), op1.length, op2.buffer.Ptr(), op2.length); + } + + int StringToInt(const String & str, int radix) + { + if (str.StartsWith("0x")) + return (int)strtoll(str.Buffer(), NULL, 16); + else + return (int)strtoll(str.Buffer(), NULL, radix); + } + unsigned int StringToUInt(const String & str, int radix) + { + if (str.StartsWith("0x")) + return (unsigned int)strtoull(str.Buffer(), NULL, 16); + else + return (unsigned int)strtoull(str.Buffer(), NULL, radix); + } + double StringToDouble(const String & str) + { + return (double)strtod(str.Buffer(), NULL); + } + float StringToFloat(const String & str) + { + return strtof(str.Buffer(), NULL); + } + + String String::ReplaceAll(String src, String dst) const + { + String rs = *this; + int index = 0; + int srcLen = src.length; + int len = rs.length; + while ((index = rs.IndexOf(src, index)) != -1) + { + rs = rs.SubString(0, index) + dst + rs.SubString(index + srcLen, len - index - srcLen); + len = rs.length; + } + return rs; + } + + String String::FromWString(const wchar_t * wstr) + { +#ifdef _WIN32 + return CoreLib::IO::Encoding::UTF16->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t))); +#else + return CoreLib::IO::Encoding::UTF32->ToString((const char*)wstr, (int)(wcslen(wstr) * sizeof(wchar_t))); +#endif + } + + String String::FromWString(const wchar_t * wstr, const wchar_t * wend) + { +#ifdef _WIN32 + return CoreLib::IO::Encoding::UTF16->ToString((const char*)wstr, (int)((wend - wstr) * sizeof(wchar_t))); +#else + return CoreLib::IO::Encoding::UTF32->ToString((const char*)wstr, (int)((wend - wstr) * sizeof(wchar_t))); +#endif + } + + String String::FromWChar(const wchar_t ch) + { +#ifdef _WIN32 + return CoreLib::IO::Encoding::UTF16->ToString((const char*)&ch, (int)(sizeof(wchar_t))); +#else + return CoreLib::IO::Encoding::UTF32->ToString((const char*)&ch, (int)(sizeof(wchar_t))); +#endif + } + + String String::FromUnicodePoint(unsigned int codePoint) + { + char buf[6]; + int len = CoreLib::IO::EncodeUnicodePointToUTF8(buf, (int)codePoint); + buf[len] = 0; + return String(buf); + } + + const wchar_t * String::ToWString(int * len) const + { + if (!buffer) + { + if (len) + *len = 0; + return L""; + } + else + { + if (wcharBuffer) + { + if (len) + *len = (int)wcslen(wcharBuffer); + return wcharBuffer; + } + List<char> buf; + CoreLib::IO::Encoding::UTF16->GetBytes(buf, *this); + if (len) + *len = buf.Count() / sizeof(wchar_t); + buf.Add(0); + buf.Add(0); + const_cast<String*>(this)->wcharBuffer = (wchar_t*)buf.Buffer(); + buf.ReleaseBuffer(); + return wcharBuffer; + } + } + + String String::PadLeft(char ch, int pLen) + { + StringBuilder sb; + for (int i = 0; i < pLen - this->length; i++) + sb << ch; + for (int i = 0; i < this->length; i++) + sb << buffer[i]; + return sb.ProduceString(); + } + + String String::PadRight(char ch, int pLen) + { + StringBuilder sb; + for (int i = 0; i < this->length; i++) + sb << buffer[i]; + for (int i = 0; i < pLen - this->length; i++) + sb << ch; + return sb.ProduceString(); + } + } +} diff --git a/source/core/slang-string.h b/source/core/slang-string.h new file mode 100644 index 000000000..3eb99e8e3 --- /dev/null +++ b/source/core/slang-string.h @@ -0,0 +1,740 @@ +#ifndef FUNDAMENTAL_LIB_STRING_H +#define FUNDAMENTAL_LIB_STRING_H +#include <string.h> +#include <cstdlib> +#include <stdio.h> +#include "smart-pointer.h" +#include "common.h" +#include "hash.h" +#include "secure-crt.h" + +namespace CoreLib +{ + namespace Basic + { + class _EndLine + {}; + extern _EndLine EndLine; + + // in-place reversion, works only for ascii string + inline void ReverseInternalAscii(char * buffer, int length) + { + int i, j; + char c; + for (i = 0, j = length - 1; i<j; i++, j--) + { + c = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = c; + } + } + template<typename IntType> + inline int IntToAscii(char * buffer, IntType val, int radix) + { + int i = 0; + IntType sign; + sign = val; + if (sign < 0) + val = (IntType)(0 - val); + do + { + int digit = (val % radix); + if (digit <= 9) + buffer[i++] = (char)(digit + '0'); + else + buffer[i++] = (char)(digit - 10 + 'A'); + } while ((val /= radix) > 0); + if (sign < 0) + buffer[i++] = '-'; + buffer[i] = '\0'; + return i; + } + + inline bool IsUtf8LeadingByte(char ch) + { + return (((unsigned char)ch) & 0xC0) == 0xC0; + } + + inline bool IsUtf8ContinuationByte(char ch) + { + return (((unsigned char)ch) & 0xC0) == 0x80; + } + + /*! + @brief Represents a UTF-8 encoded string. + */ + + class String + { + friend class StringBuilder; + private: + RefPtr<char, RefPtrArrayDestructor> buffer; + wchar_t * wcharBuffer = nullptr; + int length = 0; + void Free() + { + if (buffer) + buffer = 0; + if (wcharBuffer) + delete[] wcharBuffer; + buffer = 0; + wcharBuffer = 0; + length = 0; + } + public: + static String FromBuffer(RefPtr<char, RefPtrArrayDestructor> buffer, int len) + { + String rs; + rs.buffer = buffer; + rs.length = len; + return rs; + } + static String FromWString(const wchar_t * wstr); + static String FromWString(const wchar_t * wstr, const wchar_t * wend); + static String FromWChar(const wchar_t ch); + static String FromUnicodePoint(unsigned int codePoint); + String() + { + } + const char * begin() const + { + return buffer.Ptr(); + } + const char * end() const + { + return buffer.Ptr() + length; + } + String(int val, int radix = 10) + { + buffer = new char[33]; + length = IntToAscii(buffer.Ptr(), val, radix); + ReverseInternalAscii(buffer.Ptr(), length); + } + String(unsigned int val, int radix = 10) + { + buffer = new char[33]; + length = IntToAscii(buffer.Ptr(), val, radix); + ReverseInternalAscii(buffer.Ptr(), length); + } + String(long long val, int radix = 10) + { + buffer = new char[65]; + length = IntToAscii(buffer.Ptr(), val, radix); + ReverseInternalAscii(buffer.Ptr(), length); + } + String(float val, const char * format = "%g") + { + buffer = new char[128]; + sprintf_s(buffer.Ptr(), 128, format, val); + length = (int)strnlen_s(buffer.Ptr(), 128); + } + String(double val, const char * format = "%g") + { + buffer = new char[128]; + sprintf_s(buffer.Ptr(), 128, format, val); + length = (int)strnlen_s(buffer.Ptr(), 128); + } + String(const char * str) + { + if (str) + { + length = (int)strlen(str); + buffer = new char[length + 1]; + memcpy(buffer.Ptr(), str, length + 1); + } + } + String(char chr) + { + if (chr) + { + length = 1; + buffer = new char[2]; + buffer[0] = chr; + buffer[1] = '\0'; + } + } + String(const String & str) + { + this->operator=(str); + } + String(String&& other) + { + this->operator=(static_cast<String&&>(other)); + } + ~String() + { + Free(); + } + String & operator=(const String & str) + { + if (str.buffer == buffer) + return *this; + Free(); + if (str.buffer) + { + length = str.length; + buffer = str.buffer; + wcharBuffer = 0; + } + return *this; + } + String & operator=(String&& other) + { + if (this != &other) + { + Free(); + buffer = _Move(other.buffer); + length = other.length; + wcharBuffer = other.wcharBuffer; + other.buffer = 0; + other.length = 0; + other.wcharBuffer = 0; + } + return *this; + } + char operator[](int id) const + { +#if _DEBUG + if (id < 0 || id >= length) + throw "Operator[]: index out of range."; +#endif + return buffer.Ptr()[id]; + } + + friend String StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen); + friend String operator+(const char*op1, const String & op2); + friend String operator+(const String & op1, const char * op2); + friend String operator+(const String & op1, const String & op2); + + String TrimStart() const + { + if (!buffer) + return *this; + int startIndex = 0; + while (startIndex < length && + (buffer[startIndex] == ' ' || buffer[startIndex] == '\t' || buffer[startIndex] == '\r' || buffer[startIndex] == '\n')) + startIndex++; + return String(buffer + startIndex); + } + + String TrimEnd() const + { + if (!buffer) + return *this; + + int endIndex = length - 1; + while (endIndex >= 0 && + (buffer[endIndex] == ' ' || buffer[endIndex] == '\t' || buffer[endIndex] == '\r' || buffer[endIndex] == '\n')) + endIndex--; + String res; + res.length = endIndex + 1; + res.buffer = new char[endIndex + 2]; + strncpy_s(res.buffer.Ptr(), endIndex + 2, buffer.Ptr(), endIndex + 1); + return res; + } + + String Trim() const + { + if (!buffer) + return *this; + + int startIndex = 0; + while (startIndex < length && + (buffer[startIndex] == ' ' || buffer[startIndex] == '\t')) + startIndex++; + int endIndex = length - 1; + while (endIndex >= startIndex && + (buffer[endIndex] == ' ' || buffer[endIndex] == '\t')) + endIndex--; + + String res; + res.length = endIndex - startIndex + 1; + res.buffer = new char[res.length + 1]; + memcpy(res.buffer.Ptr(), buffer + startIndex, res.length); + res.buffer[res.length] = '\0'; + return res; + } + + String SubString(int id, int len) const + { + if (len == 0) + return ""; + if (id + len > length) + len = length - id; +#if _DEBUG + if (id < 0 || id >= length || (id + len) > length) + throw "SubString: index out of range."; + if (len < 0) + throw "SubString: length less than zero."; +#endif + String res; + res.buffer = new char[len + 1]; + res.length = len; + strncpy_s(res.buffer.Ptr(), len + 1, buffer + id, len); + res.buffer[len] = 0; + return res; + } + + const char * Buffer() const + { + if (buffer) + return buffer.Ptr(); + else + return ""; + } + + const wchar_t * ToWString(int * len = 0) const; + + bool Equals(const String & str, bool caseSensitive = true) + { + if (!buffer) + return (str.buffer == 0); + if (caseSensitive) + return (strcmp(buffer.Ptr(), str.buffer.Ptr()) == 0); + else + { +#ifdef _MSC_VER + return (_stricmp(buffer.Ptr(), str.buffer.Ptr()) == 0); +#else + return (strcasecmp(buffer.Ptr(), str.buffer.Ptr()) == 0); +#endif + } + } + bool operator==(const char * strbuffer) const + { + if (!buffer) + return (strbuffer == 0 || strcmp(strbuffer, "") == 0); + if (!strbuffer) + return buffer == nullptr || strcmp(buffer.Ptr(), "") == 0; + return (strcmp(buffer.Ptr(), strbuffer) == 0); + } + + bool operator==(const String & str) const + { + if (!buffer) + return (str.buffer == 0 || strcmp(str.buffer.Ptr(), "") == 0); + if (!str.buffer) + return buffer == nullptr || strcmp(buffer.Ptr(), "") == 0; + return (strcmp(buffer.Ptr(), str.buffer.Ptr()) == 0); + } + bool operator!=(const char * strbuffer) const + { + if (!buffer) + return (strbuffer != 0 && strcmp(strbuffer, "") != 0); + if (strbuffer == 0) + return length != 0; + return (strcmp(buffer.Ptr(), strbuffer) != 0); + } + bool operator!=(const String & str) const + { + if (!buffer) + return (str.buffer != 0 && strcmp(str.buffer.Ptr(), "") != 0); + if (str.buffer.Ptr() == 0) + return length != 0; + return (strcmp(buffer.Ptr(), str.buffer.Ptr()) != 0); + } + bool operator>(const String & str) const + { + if (!buffer) + return false; + if (!str.buffer) + return buffer.Ptr() != nullptr && length != 0; + return (strcmp(buffer.Ptr(), str.buffer.Ptr()) > 0); + } + bool operator<(const String & str) const + { + if (!buffer) + return (str.buffer != 0); + if (!str.buffer) + return false; + return (strcmp(buffer.Ptr(), str.buffer.Ptr()) < 0); + } + bool operator>=(const String & str) const + { + if (!buffer) + return (str.buffer == 0); + if (!str.buffer) + return length == 0; + int res = strcmp(buffer.Ptr(), str.buffer.Ptr()); + return (res > 0 || res == 0); + } + bool operator<=(const String & str) const + { + if (!buffer) + return true; + if (!str.buffer) + return length > 0; + int res = strcmp(buffer.Ptr(), str.buffer.Ptr()); + return (res < 0 || res == 0); + } + + String ToUpper() const + { + if (!buffer) + return *this; + String res; + res.length = length; + res.buffer = new char[length + 1]; + for (int i = 0; i <= length; i++) + res.buffer[i] = (buffer[i] >= 'a' && buffer[i] <= 'z') ? + (buffer[i] - 'a' + 'A') : buffer[i]; + return res; + } + + String ToLower() const + { + if (!buffer) + return *this; + String res; + res.length = length; + res.buffer = new char[length + 1]; + for (int i = 0; i <= length; i++) + res.buffer[i] = (buffer[i] >= 'A' && buffer[i] <= 'Z') ? + (buffer[i] - 'A' + 'a') : buffer[i]; + return res; + } + + int Length() const + { + return length; + } + + int IndexOf(const char * str, int id) const // String str + { + if (!buffer) + return -1; + if (id < 0 || id >= length) + return -1; + auto findRs = strstr(buffer + id, str); + int res = findRs ? (int)(findRs - buffer.Ptr()) : -1; + if (res >= 0) + return res; + else + return -1; + } + + int IndexOf(const String & str, int id) const + { + return IndexOf(str.buffer.Ptr(), id); + } + + int IndexOf(const char * str) const + { + return IndexOf(str, 0); + } + + int IndexOf(const String & str) const + { + return IndexOf(str.buffer.Ptr(), 0); + } + + int IndexOf(char ch, int id) const + { +#if _DEBUG + if (id < 0 || id >= length) + throw "SubString: index out of range."; +#endif + if (!buffer) + return -1; + for (int i = id; i < length; i++) + if (buffer[i] == ch) + return i; + return -1; + } + + int IndexOf(char ch) const + { + return IndexOf(ch, 0); + } + + int LastIndexOf(char ch) const + { + for (int i = length - 1; i >= 0; i--) + if (buffer[i] == ch) + return i; + return -1; + } + + bool StartsWith(const char * str) const // String str + { + if (!buffer) + return false; + int strLen = (int)strlen(str); + if (strLen > length) + return false; + for (int i = 0; i < strLen; i++) + if (str[i] != buffer[i]) + return false; + return true; + } + + bool StartsWith(const String & str) const + { + return StartsWith(str.buffer.Ptr()); + } + + bool EndsWith(char * str) const // String str + { + if (!buffer) + return false; + int strLen = (int)strlen(str); + if (strLen > length) + return false; + for (int i = strLen - 1; i >= 0; i--) + if (str[i] != buffer[length - strLen + i]) + return false; + return true; + } + + bool EndsWith(const String & str) const + { + return EndsWith(str.buffer.Ptr()); + } + + bool Contains(const char * str) const // String str + { + if (!buffer) + return false; + return (IndexOf(str) >= 0) ? true : false; + } + + bool Contains(const String & str) const + { + return Contains(str.buffer.Ptr()); + } + + int GetHashCode() const + { + return CoreLib::Basic::GetHashCode((const char*)buffer.Ptr()); + } + String PadLeft(char ch, int length); + String PadRight(char ch, int length); + String ReplaceAll(String src, String dst) const; + }; + + class StringBuilder + { + private: + char * buffer; + int length; + int bufferSize; + static const int InitialSize = 512; + public: + StringBuilder(int bufferSize = 1024) + :buffer(0), length(0), bufferSize(0) + { + buffer = new char[InitialSize]; // new a larger buffer + buffer[0] = '\0'; + length = 0; + bufferSize = InitialSize; + } + ~StringBuilder() + { + if (buffer) + delete[] buffer; + } + void EnsureCapacity(int size) + { + if (bufferSize < size) + { + char * newBuffer = new char[size + 1]; + if (buffer) + { + strcpy_s(newBuffer, size + 1, buffer); + delete[] buffer; + } + buffer = newBuffer; + bufferSize = size; + } + } + StringBuilder & operator << (char ch) + { + Append(&ch, 1); + return *this; + } + StringBuilder & operator << (int val) + { + Append(val); + return *this; + } + StringBuilder & operator << (unsigned int val) + { + Append(val); + return *this; + } + StringBuilder & operator << (long long val) + { + Append(val); + return *this; + } + StringBuilder & operator << (float val) + { + Append(val); + return *this; + } + StringBuilder & operator << (double val) + { + Append(val); + return *this; + } + StringBuilder & operator << (const char * str) + { + Append(str, (int)strlen(str)); + return *this; + } + StringBuilder & operator << (const String & str) + { + Append(str); + return *this; + } + StringBuilder & operator << (const _EndLine) + { + Append('\n'); + return *this; + } + void Append(char ch) + { + Append(&ch, 1); + } + void Append(float val) + { + char buf[128]; + sprintf_s(buf, 128, "%g", val); + int len = (int)strnlen_s(buf, 128); + Append(buf, len); + } + void Append(double val) + { + char buf[128]; + sprintf_s(buf, 128, "%g", val); + int len = (int)strnlen_s(buf, 128); + Append(buf, len); + } + void Append(unsigned int value, int radix = 10) + { + char vBuffer[33]; + int len = IntToAscii(vBuffer, value, radix); + ReverseInternalAscii(vBuffer, len); + Append(vBuffer); + } + void Append(int value, int radix = 10) + { + char vBuffer[33]; + int len = IntToAscii(vBuffer, value, radix); + ReverseInternalAscii(vBuffer, len); + Append(vBuffer); + } + void Append(long long value, int radix = 10) + { + char vBuffer[65]; + int len = IntToAscii(vBuffer, value, radix); + ReverseInternalAscii(vBuffer, len); + Append(vBuffer); + } + void Append(const String & str) + { + Append(str.Buffer(), str.Length()); + } + void Append(const char * str) + { + Append(str, (int)strlen(str)); + } + void Append(const char * str, int strLen) + { + int newLength = length + strLen; + if (bufferSize < newLength + 1) + { + int newBufferSize = InitialSize; + while (newBufferSize < newLength + 1) + newBufferSize <<= 1; + char * newBuffer = new char[newBufferSize]; + if (buffer) + { + memcpy(newBuffer, buffer, length); + delete[] buffer; + } + memcpy(newBuffer + length, str, strLen); + newBuffer[newLength] = '\0'; + buffer = newBuffer; + bufferSize = newBufferSize; + } + else + { + memcpy(buffer + length, str, strLen); + buffer[newLength] = '\0'; + } + length = newLength; + } + + int Capacity() + { + return bufferSize; + } + + char * Buffer() + { + return buffer; + } + + int Length() + { + return length; + } + + String ToString() + { + return String(buffer); + } + + String ProduceString() + { + String rs; + rs.buffer = buffer; + rs.length = length; + buffer = 0; + bufferSize = 0; + length = 0; + return rs; + + } + + String GetSubString(int start, int count) + { + String rs; + rs.buffer = new char[count + 1]; + rs.length = count; + strncpy_s(rs.buffer.Ptr(), count + 1, buffer + start, count); + rs.buffer[count] = 0; + return rs; + } + + void Remove(int id, int len) + { +#if _DEBUG + if (id >= length || id < 0) + throw "Remove: Index out of range."; + if (len < 0) + throw "Remove: remove length smaller than zero."; +#endif + int actualDelLength = ((id + len) >= length) ? (length - id) : len; + for (int i = id + actualDelLength; i <= length; i++) + buffer[i - actualDelLength] = buffer[i]; + length -= actualDelLength; + } + + void Clear() + { + length = 0; + if (buffer) + buffer[0] = 0; + } + }; + + int StringToInt(const String & str, int radix = 10); + unsigned int StringToUInt(const String & str, int radix = 10); + double StringToDouble(const String & str); + float StringToFloat(const String & str); + } +} + +#endif diff --git a/source/core/smart-pointer.h b/source/core/smart-pointer.h new file mode 100644 index 000000000..f1fece2e5 --- /dev/null +++ b/source/core/smart-pointer.h @@ -0,0 +1,468 @@ +#ifndef FUNDAMENTAL_LIB_SMART_POINTER_H +#define FUNDAMENTAL_LIB_SMART_POINTER_H + +#include "type-traits.h" + +namespace CoreLib +{ + namespace Basic + { + class RefPtrDefaultDestructor + { + public: + template<typename T> + void operator ()(T * ptr) + { + delete ptr; + } + }; + + class RefPtrArrayDestructor + { + public: + template<typename T> + void operator() (T * ptr) + { + delete [] ptr; + } + }; + + class ReferenceCounted + { + template<typename T, bool b, typename Destructor> + friend class RefPtrImpl; + private: + int _refCount = 0; + public: + ReferenceCounted() {} + ReferenceCounted(const ReferenceCounted &) + { + _refCount = 0; + } + }; + + + class RefObject : public ReferenceCounted + { + public: + virtual ~RefObject() + {} + }; + + template<typename T, bool HasBuiltInCounter, typename Destructor> + class RefPtrImpl + { + }; + + template<typename T, typename Destructor = RefPtrDefaultDestructor> + using RefPtr = RefPtrImpl<T, IsBaseOf<ReferenceCounted, T>::Value, Destructor>; + + template<typename T, typename Destructor> + class RefPtrImpl<T, 0, Destructor> + { + template<typename T1, bool b, typename Destructor1> + friend class RefPtrImpl; + private: + T * pointer; + int * refCount; + + public: + RefPtrImpl() + { + pointer = 0; + refCount = 0; + } + RefPtrImpl(T * ptr) + : pointer(0), refCount(0) + { + this->operator=(ptr); + } + RefPtrImpl(const RefPtrImpl<T, 0, Destructor> & ptr) + : pointer(0), refCount(0) + { + this->operator=(ptr); + } + RefPtrImpl(RefPtrImpl<T, 0, Destructor> && str) + : pointer(0), refCount(0) + { + this->operator=(static_cast<RefPtrImpl<T, 0, Destructor> &&>(str)); + } + + template <typename U> + RefPtrImpl(const RefPtrImpl<U, 0, Destructor>& ptr, + typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0) + : pointer(0), refCount(0) + { + pointer = ptr.pointer; + if (ptr) + { + refCount = ptr.refCount; + (*refCount)++; + } + else + refCount = 0; + } + + template <typename U> + typename EnableIf<IsConvertible<T*, U*>::value, RefPtrImpl<T, 0, Destructor>>::type& + operator=(const RefPtrImpl<U,0,Destructor> & ptr) + { + Unreference(); + + pointer = ptr; + if (ptr) + { + refCount = ptr.refCount; + (*refCount)++; + } + else + refCount = 0; + return *this; + } + + RefPtrImpl<T, 0, Destructor>& operator=(const RefPtrImpl<T, 0, Destructor> & ptr) + { + Unreference(); + pointer = ptr.pointer; + if (ptr) + { + refCount = ptr.refCount; + (*refCount)++; + } + else + refCount = 0; + return *this; + } + + RefPtrImpl<T, 0, Destructor>& operator=(T * ptr) + { + if (ptr != pointer) + { + Unreference(); + + pointer = ptr; + if (ptr) + { + refCount = new int; + (*refCount) = 1; + } + else + refCount = 0; + } + return *this; + } + int GetHashCode() + { + return (int)(long long)(void*)pointer; + } + bool operator == (const T * ptr) const + { + return pointer == ptr; + } + bool operator != (const T * ptr) const + { + return pointer != ptr; + } + template<typename U> + bool operator == (const RefPtr<U, Destructor> & ptr) const + { + return pointer == ptr.pointer; + } + template<typename U> + bool operator != (const RefPtr<U, Destructor> & ptr) const + { + return pointer != ptr.pointer; + } + template<typename U> + RefPtrImpl<U, 0, Destructor> As() const + { + RefPtrImpl<U, 0, Destructor> result; + if (pointer) + { + result.pointer = dynamic_cast<U*>(pointer); + if (result.pointer) + { + result.refCount = refCount; + (*refCount)++; + } + } + return result; + } + + T* operator +(int offset) const + { + return pointer+offset; + } + T& operator [](int idx) const + { + return *(pointer + idx); + } + RefPtrImpl<T, 0, Destructor>& operator=(RefPtrImpl<T, 0, Destructor> && ptr) + { + if(ptr.pointer != pointer) + { + Unreference(); + pointer = ptr.pointer; + refCount = ptr.refCount; + ptr.pointer = 0; + ptr.refCount = 0; + } + return *this; + } + T* Release() + { + if(pointer) + { + if((*refCount) > 1) + { + (*refCount)--; + } + else + { + delete refCount; + } + } + auto rs = pointer; + refCount = 0; + pointer = 0; + return rs; + } + ~RefPtrImpl() + { + Unreference(); + } + + void Unreference() + { + if(pointer) + { + if((*refCount) > 1) + { + (*refCount)--; + } + else + { + Destructor destructor; + destructor(pointer); + delete refCount; + } + } + } + T & operator *() const + { + return *pointer; + } + T * operator->() const + { + return pointer; + } + T * Ptr() const + { + return pointer; + } + public: + explicit operator bool() const + { + if (pointer) + return true; + else + return false; + } + }; + + + template<typename T, typename Destructor> + class RefPtrImpl<T, 1, Destructor> + { + template<typename T1, bool b, typename Destructor1> + friend class RefPtrImpl; + + private: + T * pointer; + public: + RefPtrImpl() + { + pointer = 0; + } + RefPtrImpl(T * ptr) + : pointer(0) + { + this->operator=(ptr); + } + RefPtrImpl(const RefPtrImpl<T, 1, Destructor> & ptr) + : pointer(0) + { + this->operator=(ptr); + } + RefPtrImpl(RefPtrImpl<T, 1, Destructor> && str) + : pointer(0) + { + this->operator=(static_cast<RefPtrImpl<T, 1, Destructor> &&>(str)); + } + template <typename U> + RefPtrImpl(const RefPtrImpl<U, 1, Destructor>& ptr, + typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0) + : pointer(0) + { + pointer = ptr.pointer; + if (ptr) + { + ptr->_refCount++; + } + } + + template <typename U> + typename EnableIf<IsConvertible<T*, U*>::value, RefPtrImpl<T, 1, Destructor>&>::type + operator=(const RefPtrImpl<U, 1, Destructor> & ptr) + { + Unreference(); + + pointer = ptr.pointer; + if (ptr) + { + ptr->_refCount++; + } + return *this; + } + RefPtrImpl<T, 1, Destructor>& operator=(T * ptr) + { + if (ptr != pointer) + { + Unreference(); + + pointer = ptr; + if (ptr) + { + ptr->_refCount++; + } + } + return *this; + } + RefPtrImpl<T, 1, Destructor>& operator=(const RefPtrImpl<T, 1, Destructor> & ptr) + { + // Note: It is possible that the object this pointer references owns + // (directly or indirectly) the storage for the argument `ptr`. If + // that is the case and the `Unreference()` call below frees this + // object, then the argument would become invalid. + // + // We copy the pointer value out of the argument first, in order + // to protected against this case. + T* ptrPointer = ptr.pointer; + if (ptrPointer != pointer) + { + if (ptrPointer) + ptrPointer->_refCount++; + Unreference(); + pointer = ptrPointer; + } + return *this; + } + int GetHashCode() + { + return (int)(long long)(void*)pointer; + } + bool operator == (const T * ptr) const + { + return pointer == ptr; + } + bool operator != (const T * ptr) const + { + return pointer != ptr; + } + template<typename U> + bool operator == (const RefPtr<U, Destructor> & ptr) const + { + return pointer == ptr.pointer; + } + template<typename U> + bool operator != (const RefPtr<U, Destructor> & ptr) const + { + return pointer != ptr.pointer; + } + template<typename U> + RefPtrImpl<U, 1, Destructor> As() const + { + RefPtrImpl<U, 1, Destructor> result; + if (pointer) + { + result.pointer = dynamic_cast<U*>(pointer); + if (result.pointer) + { + result.pointer->_refCount++; + } + } + return result; + } + T* operator +(int offset) const + { + return pointer + offset; + } + T& operator [](int idx) const + { + return *(pointer + idx); + } + RefPtrImpl<T, 1, Destructor>& operator=(RefPtrImpl<T, 1, Destructor> && ptr) + { + if (ptr.pointer != pointer) + { + Unreference(); + pointer = ptr.pointer; + ptr.pointer = nullptr; + } + return *this; + } + T* Release() + { + if (pointer) + { + pointer->_refCount--; + } + auto rs = pointer; + pointer = 0; + return rs; + } + ~RefPtrImpl() + { + Unreference(); + } + + void Unreference() + { + if (pointer) + { + if (pointer->_refCount > 1) + { + pointer->_refCount--; + } + else + { + Destructor destructor; + destructor(pointer); + } + } + } + T & operator *() const + { + return *pointer; + } + T * operator->() const + { + return pointer; + } + T * Ptr() const + { + return pointer; + } + public: + explicit operator bool() const + { + if (pointer) + return true; + else + return false; + } + }; + } +} + +#endif
\ No newline at end of file diff --git a/source/core/stream.cpp b/source/core/stream.cpp new file mode 100644 index 000000000..580ea5884 --- /dev/null +++ b/source/core/stream.cpp @@ -0,0 +1,220 @@ +#include "Stream.h" +#ifdef _WIN32 +#include <share.h> +#endif +#include "slang-io.h" + +namespace CoreLib +{ + namespace IO + { + using namespace CoreLib::Basic; + FileStream::FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode) + { + Init(fileName, fileMode, fileMode==FileMode::Open?FileAccess::Read:FileAccess::Write, FileShare::None); + } + FileStream::FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share) + { + Init(fileName, fileMode, access, share); + } + void FileStream::Init(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share) + { + const wchar_t * mode = L"rt"; + const char* modeMBCS = "rt"; + switch (fileMode) + { + case CoreLib::IO::FileMode::Create: + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Create mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"w+b"; + modeMBCS = "w+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + modeMBCS = "wb"; + this->fileAccess = FileAccess::Write; + } + break; + case CoreLib::IO::FileMode::Open: + if (access == FileAccess::Read) + { + mode = L"rb"; + modeMBCS = "rb"; + this->fileAccess = FileAccess::Read; + } + else if (access == FileAccess::ReadWrite) + { + mode = L"r+b"; + modeMBCS = "r+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + modeMBCS = "wb"; + this->fileAccess = FileAccess::Write; + } + break; + case CoreLib::IO::FileMode::CreateNew: + if (File::Exists(fileName)) + { + throw IOException("Failed opening '" + fileName + "', file already exists."); + } + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Create mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"w+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"wb"; + this->fileAccess = FileAccess::Write; + } + break; + case CoreLib::IO::FileMode::Append: + if (access == FileAccess::Read) + throw ArgumentException("Read-only access is incompatible with Append mode."); + else if (access == FileAccess::ReadWrite) + { + mode = L"a+b"; + this->fileAccess = FileAccess::ReadWrite; + } + else + { + mode = L"ab"; + this->fileAccess = FileAccess::Write; + } + break; + default: + break; + } + int shFlag; +#ifdef _WIN32 + switch (share) + { + case CoreLib::IO::FileShare::None: + shFlag = _SH_DENYRW; + break; + case CoreLib::IO::FileShare::ReadOnly: + shFlag = _SH_DENYWR; + break; + case CoreLib::IO::FileShare::WriteOnly: + shFlag = _SH_DENYRD; + break; + case CoreLib::IO::FileShare::ReadWrite: + shFlag = _SH_DENYNO; + break; + default: + throw ArgumentException("Invalid file share mode."); + break; + } + if (share == CoreLib::IO::FileShare::None) +#pragma warning(suppress:4996) + handle = _wfopen(fileName.ToWString(), mode); + else + handle = _wfsopen(fileName.ToWString(), mode, shFlag); +#else + handle = fopen(fileName.Buffer(), modeMBCS); +#endif + if (!handle) + { + throw IOException("Cannot open file '" + fileName + "'"); + } + } + FileStream::~FileStream() + { + Close(); + } + Int64 FileStream::GetPosition() + { +#ifdef _WIN32 + fpos_t pos; + fgetpos(handle, &pos); + return pos; +#else + fpos64_t pos; + fgetpos64(handle, &pos); + return *(Int64*)(&pos); +#endif + } + void FileStream::Seek(SeekOrigin origin, Int64 offset) + { + int _origin; + switch (origin) + { + case CoreLib::IO::SeekOrigin::Start: + _origin = SEEK_SET; + endReached = false; + break; + case CoreLib::IO::SeekOrigin::End: + _origin = SEEK_END; + endReached = true; + break; + case CoreLib::IO::SeekOrigin::Current: + _origin = SEEK_CUR; + endReached = false; + break; + default: + throw NotSupportedException("Unsupported seek origin."); + break; + } +#ifdef _WIN32 + int rs = _fseeki64(handle, offset, _origin); +#else + int rs = fseek(handle, (int)offset, _origin); +#endif + if (rs != 0) + { + throw IOException("FileStream seek failed."); + } + } + Int64 FileStream::Read(void * buffer, Int64 length) + { + auto bytes = fread_s(buffer, (size_t)length, 1, (size_t)length, handle); + if (bytes == 0 && length > 0) + { + if (!feof(handle)) + throw IOException("FileStream read failed."); + else if (endReached) + throw EndOfStreamException("End of file is reached."); + endReached = true; + } + return (int)bytes; + } + Int64 FileStream::Write(const void * buffer, Int64 length) + { + auto bytes = (Int64)fwrite(buffer, 1, (size_t)length, handle); + if (bytes < length) + { + throw IOException("FileStream write failed."); + } + return bytes; + } + bool FileStream::CanRead() + { + return ((int)fileAccess & (int)FileAccess::Read) != 0; + } + bool FileStream::CanWrite() + { + return ((int)fileAccess & (int)FileAccess::Write) != 0; + } + void FileStream::Close() + { + if (handle) + { + fclose(handle); + handle = 0; + } + } + bool FileStream::IsEnd() + { + return endReached; + } + } +} diff --git a/source/core/stream.h b/source/core/stream.h new file mode 100644 index 000000000..30d1cc992 --- /dev/null +++ b/source/core/stream.h @@ -0,0 +1,333 @@ +#ifndef CORE_LIB_STREAM_H +#define CORE_LIB_STREAM_H + +#include "Basic.h" + +namespace CoreLib +{ + namespace IO + { + using CoreLib::Basic::Exception; + using CoreLib::Basic::String; + using CoreLib::Basic::RefPtr; + + class IOException : public Exception + { + public: + IOException() + {} + IOException(const String & message) + : CoreLib::Basic::Exception(message) + { + } + }; + + class EndOfStreamException : public IOException + { + public: + EndOfStreamException() + {} + EndOfStreamException(const String & message) + : IOException(message) + { + } + }; + + enum class SeekOrigin + { + Start, End, Current + }; + + class Stream : public CoreLib::Basic::Object + { + public: + virtual Int64 GetPosition()=0; + virtual void Seek(SeekOrigin origin, Int64 offset)=0; + virtual Int64 Read(void * buffer, Int64 length) = 0; + virtual Int64 Write(const void * buffer, Int64 length) = 0; + virtual bool IsEnd() = 0; + virtual bool CanRead() = 0; + virtual bool CanWrite() = 0; + virtual void Close() = 0; + }; + + class BinaryReader + { + private: + RefPtr<Stream> stream; + inline void Throw(Int64 val) + { + if (val == 0) + throw IOException("read operation failed."); + } + public: + BinaryReader(RefPtr<Stream> stream) + { + this->stream = stream; + } + Stream * GetStream() + { + return stream.Ptr(); + } + void ReleaseStream() + { + stream.Release(); + } + template<typename T> + void Read(T * buffer, int count) + { + stream->Read(buffer, sizeof(T)*(Int64)count); + } + template<typename T> + void Read(T & buffer) + { + Throw(stream->Read(&buffer, sizeof(T))); + } + template<typename T> + void Read(List<T> & buffer) + { + int count = ReadInt32(); + buffer.SetSize(count); + Read(buffer.Buffer(), count); + } + void Read(String & buffer) + { + buffer = ReadString(); + } + int ReadInt32() + { + int rs; + Throw(stream->Read(&rs, sizeof(int))); + return rs; + } + short ReadInt16() + { + short rs; + Throw(stream->Read(&rs, sizeof(short))); + return rs; + } + Int64 ReadInt64() + { + Int64 rs; + Throw(stream->Read(&rs, sizeof(Int64))); + return rs; + } + float ReadFloat() + { + float rs; + Throw(stream->Read(&rs, sizeof(float))); + return rs; + } + double ReadDouble() + { + double rs; + Throw(stream->Read(&rs, sizeof(double))); + return rs; + } + char ReadChar() + { + char rs; + Throw(stream->Read(&rs, sizeof(char))); + return rs; + } + String ReadString() + { + int len = ReadInt32(); + char * buffer = new char[len+1]; + try + { + Throw(stream->Read(buffer, len)); + } + catch(IOException & e) + { + delete [] buffer; + throw e; + } + buffer[len] = 0; + return String::FromBuffer(buffer, len); + } + }; + + class BinaryWriter + { + private: + RefPtr<Stream> stream; + public: + BinaryWriter(RefPtr<Stream> stream) + { + this->stream = stream; + } + Stream * GetStream() + { + return stream.Ptr(); + } + template<typename T> + void Write(const T& val) + { + stream->Write(&val, sizeof(T)); + } + template<typename T> + void Write(T * buffer, int count) + { + stream->Write(buffer, sizeof(T)*(Int64)count); + } + template<typename T> + void Write(const List<T> & list) + { + Write(list.Count()); + stream->Write(list.Buffer(), sizeof(T)*list.Count()); + } + void Write(const String & str) + { + Write(str.Length()); + Write(str.Buffer(), str.Length()); + } + void ReleaseStream() + { + stream.Release(); + } + void Close() + { + stream->Close(); + } + }; + + enum class FileMode + { + Create, Open, CreateNew, Append + }; + + enum class FileAccess + { + Read = 1, Write = 2, ReadWrite = 3 + }; + + enum class FileShare + { + None, ReadOnly, WriteOnly, ReadWrite + }; + + class FileStream : public Stream + { + private: + FILE * handle; + FileAccess fileAccess; + bool endReached = false; + void Init(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share); + public: + FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode = FileMode::Open); + FileStream(const CoreLib::Basic::String & fileName, FileMode fileMode, FileAccess access, FileShare share); + ~FileStream(); + public: + virtual Int64 GetPosition(); + virtual void Seek(SeekOrigin origin, Int64 offset); + virtual Int64 Read(void * buffer, Int64 length); + virtual Int64 Write(const void * buffer, Int64 length); + virtual bool CanRead(); + virtual bool CanWrite(); + virtual void Close(); + virtual bool IsEnd(); + }; + + class MemoryStream : public Stream + { + private: + CoreLib::List<unsigned char> writeBuffer; + CoreLib::ArrayView<unsigned char> readBuffer; + int ptr = 0; + bool isReadStream; + public: + MemoryStream() + { + isReadStream = false; + } + MemoryStream(unsigned char * mem, int length) + { + isReadStream = true; + readBuffer = MakeArrayView(mem, length); + } + MemoryStream(CoreLib::ArrayView<unsigned char> source) + { + isReadStream = true; + readBuffer = source; + } + virtual Int64 GetPosition() + { + return ptr; + } + virtual void Seek(SeekOrigin origin, Int64 offset) + { + if (origin == SeekOrigin::Start) + ptr = (int)offset; + else if (origin == SeekOrigin::End) + { + if (isReadStream) + ptr = readBuffer.Count() + (int)offset; + else + ptr = writeBuffer.Count() + (int)offset; + } + } + virtual Int64 Read(void * pbuffer, Int64 length) + { + Int64 i; + for (i = 0; i < length; i++) + { + if (ptr + i < readBuffer.Count()) + { + ((unsigned char*)pbuffer)[i] = readBuffer[(int)(ptr + i)]; + } + else + break; + } + return i; + } + virtual Int64 Write(const void * pbuffer, Int64 length) + { + writeBuffer.SetSize(ptr); + if (pbuffer) + writeBuffer.AddRange((unsigned char *)pbuffer, (int)length); + else + for (auto i = 0; i < length; i++) + writeBuffer.Add(0); + ptr = writeBuffer.Count(); + return length; + } + virtual bool CanRead() + { + return isReadStream; + } + virtual bool CanWrite() + { + return !isReadStream; + } + virtual void Close() + { + writeBuffer.SetSize(0); + writeBuffer.Compress(); + } + virtual bool IsEnd() + { + if (isReadStream) + return ptr >= readBuffer.Count(); + else + return ptr == writeBuffer.Count(); + } + void * GetBuffer() + { + if (isReadStream) + return readBuffer.Buffer(); + else + return writeBuffer.Buffer(); + } + int GetBufferSize() + { + if (isReadStream) + return readBuffer.Count(); + else + return writeBuffer.Count(); + } + }; + } +} + +#endif diff --git a/source/core/text-io.cpp b/source/core/text-io.cpp new file mode 100644 index 000000000..cf75c4762 --- /dev/null +++ b/source/core/text-io.cpp @@ -0,0 +1,344 @@ +#include "text-io.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include <Windows.h> +#undef WIN32_LEAN_AND_MEAN +#undef NOMINMAX +#define CONVERT_END_OF_LINE +#endif + +namespace CoreLib +{ + namespace IO + { + using namespace CoreLib::Basic; + + class Utf8Encoding : public Encoding + { + public: + virtual void GetBytes(List<char> & result, const String & str) override + { + result.AddRange(str.Buffer(), str.Length()); + } + virtual String ToString(const char * bytes, int /*length*/) override + { + return String(bytes); + } + }; + + class Utf32Encoding : public Encoding + { + public: + virtual void GetBytes(List<char> & result, const String & str) override + { + int ptr = 0; + while (ptr < str.Length()) + { + int codePoint = GetUnicodePointFromUTF8([&](int) + { + if (ptr < str.Length()) + return str[ptr++]; + else + return '\0'; + }); + result.AddRange((char*)&codePoint, 4); + } + } + virtual String ToString(const char * bytes, int length) override + { + StringBuilder sb; + int * content = (int*)bytes; + for (int i = 0; i < (length >> 2); i++) + { + char buf[5]; + int count = EncodeUnicodePointToUTF8(buf, content[i]); + for (int j = 0; j < count; j++) + sb.Append(buf[j]); + } + return sb.ProduceString(); + } + }; + + class Utf16Encoding : public Encoding //UTF16 + { + private: + bool reverseOrder = false; + public: + Utf16Encoding(bool pReverseOrder) + : reverseOrder(pReverseOrder) + {} + virtual void GetBytes(List<char> & result, const String & str) override + { + int ptr = 0; + while (ptr < str.Length()) + { + int codePoint = GetUnicodePointFromUTF8([&](int) + { + if (ptr < str.Length()) + return str[ptr++]; + else + return '\0'; + }); + unsigned short buffer[2]; + int count; + if (!reverseOrder) + count = EncodeUnicodePointToUTF16(buffer, codePoint); + else + count = EncodeUnicodePointToUTF16Reversed(buffer, codePoint); + result.AddRange((char*)buffer, count * 2); + } + } + virtual String ToString(const char * bytes, int length) override + { + int ptr = 0; + StringBuilder sb; + while (ptr < length) + { + int codePoint = GetUnicodePointFromUTF16([&](int) + { + if (ptr < length) + return bytes[ptr++]; + else + return '\0'; + }); + char buf[5]; + int count = EncodeUnicodePointToUTF8(buf, codePoint); + for (int i = 0; i < count; i++) + sb.Append(buf[i]); + } + return sb.ProduceString(); + } + }; + + Utf8Encoding __utf8Encoding; + Utf16Encoding __utf16Encoding(false); + Utf16Encoding __utf16EncodingReversed(true); + Utf32Encoding __utf32Encoding; + + Encoding * Encoding::UTF8 = &__utf8Encoding; + Encoding * Encoding::UTF16 = &__utf16Encoding; + Encoding * Encoding::UTF16Reversed = &__utf16EncodingReversed; + Encoding * Encoding::UTF32 = &__utf32Encoding; + + const unsigned short Utf16Header = 0xFEFF; + const unsigned short Utf16ReversedHeader = 0xFFFE; + + StreamWriter::StreamWriter(const String & path, Encoding * encoding) + { + this->stream = new FileStream(path, FileMode::Create); + this->encoding = encoding; + if (encoding == Encoding::UTF16) + { + this->stream->Write(&Utf16Header, 2); + } + else if (encoding == Encoding::UTF16Reversed) + { + this->stream->Write(&Utf16ReversedHeader, 2); + } + } + StreamWriter::StreamWriter(RefPtr<Stream> stream, Encoding * encoding) + { + this->stream = stream; + this->encoding = encoding; + if (encoding == Encoding::UTF16) + { + this->stream->Write(&Utf16Header, 2); + } + else if (encoding == Encoding::UTF16Reversed) + { + this->stream->Write(&Utf16ReversedHeader, 2); + } + } + void StreamWriter::Write(const String & str) + { + encodingBuffer.Clear(); + StringBuilder sb; + String newLine; +#ifdef _WIN32 + newLine = "\r\n"; +#else + newLine = "\n"; +#endif + for (int i = 0; i < str.Length(); i++) + { + if (str[i] == '\r') + sb << newLine; + else if (str[i] == '\n') + { + if (i > 0 && str[i - 1] != '\r') + sb << newLine; + } + else + sb << str[i]; + } + encoding->GetBytes(encodingBuffer, sb.ProduceString()); + stream->Write(encodingBuffer.Buffer(), encodingBuffer.Count()); + } + void StreamWriter::Write(const char * str) + { + Write(String(str)); + } + + StreamReader::StreamReader(const String & path) + { + stream = new FileStream(path, FileMode::Open); + ReadBuffer(); + encoding = DetermineEncoding(); + if (encoding == 0) + encoding = Encoding::UTF8; + } + StreamReader::StreamReader(RefPtr<Stream> stream, Encoding * encoding) + { + this->stream = stream; + this->encoding = encoding; + ReadBuffer(); + auto determinedEncoding = DetermineEncoding(); + if (this->encoding == nullptr) + this->encoding = determinedEncoding; + } + + Encoding * StreamReader::DetermineEncoding() + { + if (buffer.Count() >= 3 && (unsigned char)(buffer[0]) == 0xEF && (unsigned char)(buffer[1]) == 0xBB && (unsigned char)(buffer[2]) == 0xBF) + { + ptr += 3; + return Encoding::UTF8; + } + else if (*((unsigned short*)(buffer.Buffer())) == 0xFEFF) + { + ptr += 2; + return Encoding::UTF16; + } + else if (*((unsigned short*)(buffer.Buffer())) == 0xFFFE) + { + ptr += 2; + return Encoding::UTF16Reversed; + } + else + { +#ifdef _WIN32 + int flag = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_ASCII16; + int rs = IsTextUnicode(buffer.Buffer(), buffer.Count(), &flag); + if (rs) + { + if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS)) + return Encoding::UTF16; + else if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS)) + return Encoding::UTF16Reversed; + else if (flag & IS_TEXT_UNICODE_ASCII16) + return Encoding::UTF8; + } +#endif + return Encoding::UTF8; + } + } + + void StreamReader::ReadBuffer() + { + buffer.SetSize(4096); + auto len = stream->Read(buffer.Buffer(), buffer.Count()); + buffer.SetSize((int)len); + ptr = 0; + } + + char StreamReader::ReadBufferChar() + { + if (ptr<buffer.Count()) + { + return buffer[ptr++]; + } + if (!stream->IsEnd()) + ReadBuffer(); + if (ptr<buffer.Count()) + { + return buffer[ptr++]; + } + return 0; + } + int TextReader::Read(char * destBuffer, int length) + { + int i = 0; + for (i = 0; i<length; i++) + { + try + { + auto ch = Read(); + if (IsEnd()) + break; + if (ch == '\r') + { + if (Peak() == '\n') + Read(); + break; + } + else if (ch == '\n') + { + break; + } + destBuffer[i] = ch; + } + catch (EndOfStreamException) + { + break; + } + } + return i; + } + String StreamReader::ReadLine() + { + StringBuilder sb(256); + while (!IsEnd()) + { + try + { + auto ch = Read(); + if (IsEnd()) + break; + if (ch == '\r') + { + if (Peak() == '\n') + Read(); + break; + } + else if (ch == '\n') + { + break; + } + sb.Append(ch); + } + catch (EndOfStreamException) + { + break; + } + } + return sb.ProduceString(); + } + String StreamReader::ReadToEnd() + { + StringBuilder sb(16384); + while (!IsEnd()) + { + try + { + auto ch = Read(); + if (IsEnd()) + break; + if (ch == '\r') + { + sb.Append('\n'); + if (Peak() == '\n') + Read(); + } + else + sb.Append(ch); + } + catch (EndOfStreamException) + { + break; + } + } + return sb.ProduceString(); + } + } +}
\ No newline at end of file diff --git a/source/core/text-io.h b/source/core/text-io.h new file mode 100644 index 000000000..8c82177cb --- /dev/null +++ b/source/core/text-io.h @@ -0,0 +1,320 @@ +#ifndef CORE_LIB_TEXT_IO_H +#define CORE_LIB_TEXT_IO_H + +#include "secure-crt.h" +#include "stream.h" + +namespace CoreLib +{ + namespace IO + { + using CoreLib::Basic::List; + using CoreLib::Basic::_EndLine; + + class TextReader : public CoreLib::Basic::Object + { + protected: + char decodedChar[5]; + int decodedCharPtr = 0, decodedCharSize = 0; + virtual void ReadChar() = 0; + public: + ~TextReader() + { + Close(); + } + virtual void Close(){} + virtual String ReadLine()=0; + virtual String ReadToEnd()=0; + virtual bool IsEnd() = 0; + int Read(char * buffer, int count); + char Read() + { + if (decodedCharPtr == decodedCharSize) + ReadChar(); + if (decodedCharPtr < decodedCharSize) + return decodedChar[decodedCharPtr++]; + else + return 0; + } + char Peak() + { + if (decodedCharPtr == decodedCharSize) + ReadChar(); + if (decodedCharPtr < decodedCharSize) + return decodedChar[decodedCharPtr]; + else + return 0; + } + }; + + class TextWriter : public CoreLib::Basic::Object + { + public: + ~TextWriter() + { + Close(); + } + virtual void Write(const String & str)=0; + virtual void Write(const char * str)=0; + virtual void Close(){} + template<typename T> + TextWriter & operator << (const T& val) + { + Write(val.ToString()); + return *this; + } + TextWriter & operator << (int value) + { + Write(String(value)); + return *this; + } + TextWriter & operator << (float value) + { + Write(String(value)); + return *this; + } + TextWriter & operator << (double value) + { + Write(String(value)); + return *this; + } + TextWriter & operator << (const char* value) + { + Write(value); + return *this; + } + TextWriter & operator << (const String & val) + { + Write(val); + return *this; + } + TextWriter & operator << (const _EndLine &) + { +#ifdef _WIN32 + Write("\r\n"); +#else + Write("\n"); +#endif + return *this; + } + }; + + template <typename ReadCharFunc> + int GetUnicodePointFromUTF8(const ReadCharFunc & get) + { + int codePoint = 0; + int leading = get(0); + int mask = 0x80; + int count = 0; + while (leading & mask) + { + count++; + mask >>= 1; + } + codePoint = (leading & (mask - 1)); + for (int i = 1; i <= count - 1; i++) + { + codePoint <<= 6; + codePoint += (get(i) & 0x3F); + } + return codePoint; + } + + template <typename ReadCharFunc> + int GetUnicodePointFromUTF16(const ReadCharFunc & get) + { + int byte0 = (unsigned char)get(0); + int byte1 = (unsigned char)get(1); + int word0 = byte0 + (byte1 << 8); + if (word0 >= 0xD800 && word0 <= 0xDFFF) + { + int byte2 = (unsigned char)get(2); + int byte3 = (unsigned char)get(3); + int word1 = byte2 + (byte3 << 8); + return ((word0 & 0x3FF) << 10) + (word1 & 0x3FF) + 0x10000; + } + else + return word0; + } + + template <typename ReadCharFunc> + int GetUnicodePointFromUTF16Reversed(const ReadCharFunc & get) + { + int byte0 = (unsigned char)get(0); + int byte1 = (unsigned char)get(1); + int word0 = (byte0 << 8) + byte1; + if (word0 >= 0xD800 && word0 <= 0xDFFF) + { + int byte2 = (unsigned char)get(2); + int byte3 = (unsigned char)get(3); + int word1 = (byte2 << 8) + byte3; + return ((word0 & 0x3FF) << 10) + (word1 & 0x3FF); + } + else + return word0; + } + + template <typename ReadCharFunc> + int GetUnicodePointFromUTF32(const ReadCharFunc & get) + { + int byte0 = (unsigned char)get(0); + int byte1 = (unsigned char)get(1); + int byte2 = (unsigned char)get(2); + int byte3 = (unsigned char)get(3); + return byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24); + } + + inline int EncodeUnicodePointToUTF8(char * buffer, int codePoint) + { + int count = 0; + if (codePoint <= 0x7F) + buffer[count++] = ((char)codePoint); + else if (codePoint <= 0x7FF) + { + unsigned char byte = (unsigned char)(0xC0 + (codePoint >> 6)); + buffer[count++] = ((char)byte); + byte = 0x80 + (codePoint & 0x3F); + buffer[count++] = ((char)byte); + } + else if (codePoint <= 0xFFFF) + { + unsigned char byte = (unsigned char)(0xE0 + (codePoint >> 12)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + ((codePoint >> 6) & (0x3F))); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + (codePoint & 0x3F)); + buffer[count++] = ((char)byte); + } + else + { + unsigned char byte = (unsigned char)(0xF0 + (codePoint >> 18)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + ((codePoint >> 12) & 0x3F)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + ((codePoint >> 6) & 0x3F)); + buffer[count++] = ((char)byte); + byte = (unsigned char)(0x80 + (codePoint & 0x3F)); + buffer[count++] = ((char)byte); + } + return count; + } + + inline int EncodeUnicodePointToUTF16(unsigned short * buffer, int codePoint) + { + int count = 0; + if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) + buffer[count++] = (unsigned short)codePoint; + else + { + int sub = codePoint - 0x10000; + int high = (sub >> 10) + 0xD800; + int low = (sub & 0x3FF) + 0xDC00; + buffer[count++] = (unsigned short)high; + buffer[count++] = (unsigned short)low; + } + return count; + } + + inline unsigned short ReverseBitOrder(unsigned short val) + { + int byte0 = val & 0xFF; + int byte1 = val >> 8; + return (unsigned short)(byte1 + (byte0 << 8)); + } + + inline int EncodeUnicodePointToUTF16Reversed(unsigned short * buffer, int codePoint) + { + int count = 0; + if (codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) + buffer[count++] = ReverseBitOrder((unsigned short)codePoint); + else + { + int sub = codePoint - 0x10000; + int high = (sub >> 10) + 0xD800; + int low = (sub & 0x3FF) + 0xDC00; + buffer[count++] = ReverseBitOrder((unsigned short)high); + buffer[count++] = ReverseBitOrder((unsigned short)low); + } + return count; + } + + class Encoding + { + public: + static Encoding * UTF8, * UTF16, *UTF16Reversed, * UTF32; + virtual void GetBytes(List<char>& buffer, const String & str) = 0; + virtual String ToString(const char * buffer, int length) = 0; + virtual ~Encoding() + {} + }; + + class StreamWriter : public TextWriter + { + private: + List<char> encodingBuffer; + RefPtr<Stream> stream; + Encoding * encoding; + public: + StreamWriter(const String & path, Encoding * encoding = Encoding::UTF8); + StreamWriter(RefPtr<Stream> stream, Encoding * encoding = Encoding::UTF8); + virtual void Write(const String & str); + virtual void Write(const char * str); + virtual void Close() + { + stream->Close(); + } + void ReleaseStream() + { + stream.Release(); + } + }; + + class StreamReader : public TextReader + { + private: + RefPtr<Stream> stream; + List<char> buffer; + Encoding * encoding; + int ptr; + char ReadBufferChar(); + void ReadBuffer(); + + Encoding * DetermineEncoding(); + protected: + virtual void ReadChar() + { + decodedCharPtr = 0; + int codePoint = 0; + if (encoding == Encoding::UTF8) + codePoint = GetUnicodePointFromUTF8([&](int) {return ReadBufferChar(); }); + else if (encoding == Encoding::UTF16) + codePoint = GetUnicodePointFromUTF16([&](int) {return ReadBufferChar(); }); + else if (encoding == Encoding::UTF16Reversed) + codePoint = GetUnicodePointFromUTF16Reversed([&](int) {return ReadBufferChar(); }); + else if (encoding == Encoding::UTF32) + codePoint = GetUnicodePointFromUTF32([&](int) {return ReadBufferChar(); }); + decodedCharSize = EncodeUnicodePointToUTF8(decodedChar, codePoint); + } + public: + StreamReader(const String & path); + StreamReader(RefPtr<Stream> stream, Encoding * encoding = nullptr); + virtual String ReadLine(); + virtual String ReadToEnd(); + virtual bool IsEnd() + { + return ptr == buffer.Count() && stream->IsEnd(); + } + virtual void Close() + { + stream->Close(); + } + void ReleaseStream() + { + stream.Release(); + } + }; + + } +} + +#endif diff --git a/source/core/type-traits.h b/source/core/type-traits.h new file mode 100644 index 000000000..5dd81965d --- /dev/null +++ b/source/core/type-traits.h @@ -0,0 +1,49 @@ +#ifndef CORELIB_TYPETRAITS_H +#define CORELIB_TYPETRAITS_H + +namespace CoreLib +{ + namespace Basic + { + struct TraitResultYes + { + char x; + }; + struct TraitResultNo + { + char x[2]; + }; + + template <typename B, typename D> + struct IsBaseOfTraitHost + { + operator B*() const { return nullptr; } + operator D*() { return nullptr; } + }; + + template <typename B, typename D> + struct IsBaseOf + { + template <typename T> + static TraitResultYes Check(D*, T) { return TraitResultYes(); } + static TraitResultNo Check(B*, int) { return TraitResultNo(); } + enum { Value = sizeof(Check(IsBaseOfTraitHost<B, D>(), int())) == sizeof(TraitResultYes) }; + }; + + template<bool B, class T = void> + struct EnableIf {}; + + template<class T> + struct EnableIf<true, T> { typedef T type; }; + + template <typename B, typename D> + struct IsConvertible + { + static TraitResultYes Use(B) {}; + static TraitResultNo Use(...) {}; + enum { Value = sizeof(Use(*(D*)(nullptr))) == sizeof(TraitResultYes) }; + }; + } +} + +#endif |
