CMakeCache.txt
Makefile
/build/.settings/
-/test-files/test.spv
\ No newline at end of file
+/test-files/test.spv
+/build/compile_commands.json
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
- <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
- <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildProperties="" description="" id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
<folderInfo id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109.1911715907" name="/" resourcePath="">
- <toolChain id="cdt.managedbuild.toolchain.llvm.clang.linux.base.908241746" name="LLVM with Clang (Linux)" superClass="cdt.managedbuild.toolchain.llvm.clang.linux.base">
- <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.llvm.platform.base.273786633" isAbstract="true" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.llvm.platform.base"/>
- <builder id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109.1656164828" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
- <tool id="cdt.managedbuild.tool.llvm.assembler.base.668399128" name="LLVM assembler" superClass="cdt.managedbuild.tool.llvm.assembler.base"/>
- <tool id="cdt.managedbuild.tool.llvm.archiver.base.2054931917" name="LLVM archiver" superClass="cdt.managedbuild.tool.llvm.archiver.base"/>
- <tool id="cdt.managedbuild.tool.llvm.c.compiler.base.1957805273" name="LLVM Clang" superClass="cdt.managedbuild.tool.llvm.c.compiler.base">
- <inputType id="cdt.managedbuild.tool.llvm.c.compiler.input.342575696" superClass="cdt.managedbuild.tool.llvm.c.compiler.input"/>
+ <toolChain id="cdt.managedbuild.toolchain.gnu.base.311562407" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
+ <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.GNU_ELF" id="cdt.managedbuild.target.gnu.platform.base.1138173474" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+ <builder id="cdt.managedbuild.target.gnu.builder.base.1555350257" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+ <tool id="cdt.managedbuild.tool.gnu.archiver.base.865495367" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+ <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1246444643" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.509959673" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool>
- <tool id="cdt.managedbuild.tool.llvm.cpp.compiler.base.293492776" name="LLVM Clang++" superClass="cdt.managedbuild.tool.llvm.cpp.compiler.base">
- <inputType id="cdt.managedbuild.tool.llvm.cpp.compiler.input.2068687017" superClass="cdt.managedbuild.tool.llvm.cpp.compiler.input"/>
+ <tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1966157887" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+ <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1862131426" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
- <tool id="cdt.managedbuild.tool.llvm.c.linker.base.1892819112" name="LLVM Clang C linker" superClass="cdt.managedbuild.tool.llvm.c.linker.base"/>
- <tool id="cdt.managedbuild.tool.llvm.cpp.linker.base.1107548053" name="LLVM Clang C++ linker" superClass="cdt.managedbuild.tool.llvm.cpp.linker.base">
- <option id="llvm.c.link.option.libs.1380313880" name="Libraries (-l)" superClass="llvm.c.link.option.libs" valueType="libs">
- <listOptionValue builtIn="false" value="stdc++"/>
- </option>
- <option id="llvm.c.link.option.paths.726789935" name="Library search path (-L)" superClass="llvm.c.link.option.paths" valueType="libPaths">
- <listOptionValue builtIn="false" value="/usr/lib/gcc/x86_64-w64-mingw32/5.3-win32/"/>
- </option>
- <inputType id="cdt.managedbuild.tool.llvm.c.linker.input.1805560748" superClass="cdt.managedbuild.tool.llvm.c.linker.input">
+ <tool id="cdt.managedbuild.tool.gnu.c.linker.base.1883406224" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+ <tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.2103491826" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1404836314" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
</tool>
+ <tool id="cdt.managedbuild.tool.gnu.assembler.base.1750034135" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1725224913" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+ </tool>
</toolChain>
</folderInfo>
+ <sourceEntries>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="source"/>
+ </sourceEntries>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
- <storageModule moduleId="scannerConfiguration">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- <scannerConfigBuildInfo instanceId="0.1265155043">
- <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
- </scannerConfigBuildInfo>
- </storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="build.null.28162506" name="build"/>
</storageModule>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+ <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+ <storageModule moduleId="scannerConfiguration">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ <scannerConfigBuildInfo instanceId="0.1265155043">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109;cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109.1911715907;cdt.managedbuild.tool.gnu.cpp.compiler.base.1246444643;cdt.managedbuild.tool.gnu.cpp.compiler.input.509959673">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109;cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109.1911715907;cdt.managedbuild.tool.gnu.c.compiler.base.1966157887;cdt.managedbuild.tool.gnu.c.compiler.input.1862131426">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ </storageModule>
</cproject>
add_subdirectory(spirv)
add_subdirectory(demo)
add_subdirectory(json)
-add_subdirectory(util)
\ No newline at end of file
+add_subdirectory(util)
+add_subdirectory(generate_spirv_parser)
\ No newline at end of file
--- /dev/null
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+set(sources generate_spirv_parser.cpp)
+add_executable(generate_spirv_parser ${sources})
+target_link_libraries(generate_spirv_parser util json)
--- /dev/null
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <iostream>
+#include "../json/json.h"
+#include "../json/parser.h"
+
+namespace vulkan_cpu
+{
+namespace generate_spirv_parser
+{
+namespace ast = json::ast;
+
+int generate_spirv_parser_main(int argc, char **argv)
+{
+ std::string file_name;
+ if(argc >= 2)
+ file_name = argv[1];
+ if(argc != 2 || (file_name.size() > 1 && file_name[0] == '-'))
+ {
+ std::cerr << "usage: " << argv[0] << " <input.json>" << std::endl;
+ return 1;
+ }
+ try
+ {
+ const auto source = file_name == "-" ? json::source::load_stdin() :
+ json::source::load_file(std::move(file_name));
+ auto value = json::parse(&source);
+ ast::write(std::cout, value);
+ std::cout << std::endl;
+ }
+ catch(json::parse_error &e)
+ {
+ std::cerr << "error: " << e.what() << std::endl;
+ return 1;
+ }
+ catch(std::exception &e)
+ {
+ std::cerr << "error: " << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+}
+}
+}
+
+int main(int argc, char **argv)
+{
+ return vulkan_cpu::generate_spirv_parser::generate_spirv_parser_main(argc, argv);
+}
# SOFTWARE.
#
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-set(sources json.cpp)
+set(sources json.cpp
+ parser.cpp)
add_library(json STATIC ${sources})
target_link_libraries(json util)
\ No newline at end of file
}
}
-std::string number_value::to_string(std::string buffer_in, unsigned base) const
+std::string number_value::append_double_to_string(double value, std::string buffer, unsigned base)
{
- buffer_in.clear();
- std::string retval = std::move(buffer_in);
write_number(
[&](char ch)
{
- retval += ch;
+ buffer += ch;
},
value,
base);
- return retval;
+ return buffer;
}
-std::size_t number_value::to_string(char *output_buffer,
- std::size_t output_buffer_size,
- bool require_null_terminator,
- unsigned base) const noexcept
+std::size_t number_value::double_to_buffer(double value,
+ char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator,
+ unsigned base) noexcept
{
if(output_buffer_size == 0)
return 0;
return used_buffer_size; // report used buffer excluding the null terminator
}
+std::string number_value::append_unsigned_integer_to_string(std::uint64_t value,
+ std::string buffer,
+ unsigned base)
+{
+ write_unsigned_integer(
+ [&](char ch)
+ {
+ buffer += ch;
+ },
+ value,
+ base);
+ return buffer;
+}
+
+std::size_t number_value::unsigned_integer_to_buffer(std::uint64_t value,
+ char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator,
+ unsigned base) noexcept
+{
+ if(output_buffer_size == 0)
+ return 0;
+ std::size_t used_buffer_size = 0;
+ std::size_t output_buffer_size_without_terminator = output_buffer_size;
+ if(require_null_terminator)
+ output_buffer_size_without_terminator--;
+ write_unsigned_integer(
+ [&](char ch)
+ {
+ if(used_buffer_size < output_buffer_size_without_terminator)
+ output_buffer[used_buffer_size++] = ch;
+ },
+ value,
+ base);
+ if(used_buffer_size < output_buffer_size)
+ output_buffer[used_buffer_size] = '\0'; // add the null terminator if there is space
+ return used_buffer_size; // report used buffer excluding the null terminator
+}
+
+std::string number_value::append_signed_integer_to_string(std::int64_t value,
+ std::string buffer,
+ unsigned base)
+{
+ write_unsigned_integer(
+ [&](char ch)
+ {
+ buffer += ch;
+ },
+ value,
+ base);
+ return buffer;
+}
+
+std::size_t number_value::signed_integer_to_buffer(std::int64_t value,
+ char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator,
+ unsigned base) noexcept
+{
+ if(output_buffer_size == 0)
+ return 0;
+ std::size_t used_buffer_size = 0;
+ std::size_t output_buffer_size_without_terminator = output_buffer_size;
+ if(require_null_terminator)
+ output_buffer_size_without_terminator--;
+ write_unsigned_integer(
+ [&](char ch)
+ {
+ if(used_buffer_size < output_buffer_size_without_terminator)
+ output_buffer[used_buffer_size++] = ch;
+ },
+ value,
+ base);
+ if(used_buffer_size < output_buffer_size)
+ output_buffer[used_buffer_size] = '\0'; // add the null terminator if there is space
+ return used_buffer_size; // report used buffer excluding the null terminator
+}
+
void number_value::write(std::ostream &os, unsigned base) const
{
write_number(
#include <memory>
#include <utility>
#include <limits>
+#include <type_traits>
#include "../util/variant.h"
namespace vulkan_cpu
{
namespace ast
{
-struct composite_value
-{
- composite_value() = default;
- virtual ~composite_value() = default;
- virtual void write(std::ostream &os) const = 0;
- virtual std::unique_ptr<composite_value> duplicate() const = 0;
-};
-
struct null_value final
{
+ constexpr null_value() noexcept = default;
+ constexpr null_value(std::nullptr_t) noexcept
+ {
+ }
void write(std::ostream &os) const;
null_value duplicate() const noexcept
{
struct boolean_value final
{
bool value;
- constexpr boolean_value(bool value) noexcept : value(value)
+ template <typename T, typename = typename std::enable_if<std::is_same<T, bool>::value>::type>
+ constexpr boolean_value(T value) noexcept : value(value)
{
}
void write(std::ostream &os) const;
struct string_value final
{
std::string value;
- string_value(std::string value) noexcept : value(std::move(value))
- {
- }
- string_value(const char *value) : value(std::move(value))
+ template <
+ typename T,
+ typename = typename std::enable_if<!std::is_same<T, std::nullptr_t>::value
+ && std::is_convertible<T, std::string>::value>::type>
+ string_value(T value) noexcept : value(std::move(value))
{
}
static void write(std::ostream &os, const std::string &value);
double value;
static_assert(std::numeric_limits<double>::is_iec559 && std::numeric_limits<double>::radix == 2,
"double is not a ieee754 float64");
- number_value(double value) noexcept : value(value)
+ template <typename T,
+ typename = typename std::enable_if<std::is_arithmetic<T>::value
+ && !std::is_same<T, bool>::value>::type>
+ number_value(T value) noexcept : value(value)
{
}
explicit operator std::string() const
static constexpr unsigned max_base = 36;
static constexpr unsigned min_base = 2;
static constexpr unsigned default_base = 10; // the json spec only supports base 10
- std::string to_string(std::string buffer_in = {}, unsigned base = default_base) const;
- std::size_t to_string(char *output_buffer,
+ std::string append_to_string(std::string buffer, unsigned base = default_base) const
+ {
+ return append_double_to_string(value, std::move(buffer), base);
+ }
+ std::string to_string(std::string buffer = {}, unsigned base = default_base) const
+ {
+ return double_to_string(value, std::move(buffer), base);
+ }
+ std::size_t to_buffer(char *output_buffer,
std::size_t output_buffer_size,
bool require_null_terminator = true,
- unsigned base = default_base) const noexcept;
+ unsigned base = default_base) const noexcept
+ {
+ return double_to_buffer(
+ value, output_buffer, output_buffer_size, require_null_terminator, base);
+ }
+ static std::string append_unsigned_integer_to_string(std::uint64_t value,
+ std::string buffer,
+ unsigned base = default_base);
+ static std::string unsigned_integer_to_string(std::uint64_t value,
+ std::string buffer = {},
+ unsigned base = default_base)
+ {
+ buffer.clear();
+ return append_unsigned_integer_to_string(value, std::move(buffer), base);
+ }
+ static std::size_t unsigned_integer_to_buffer(std::uint64_t value,
+ char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator = true,
+ unsigned base = default_base) noexcept;
+ static std::string append_signed_integer_to_string(std::int64_t value,
+ std::string buffer,
+ unsigned base = default_base);
+ static std::string signed_integer_to_string(std::int64_t value,
+ std::string buffer = {},
+ unsigned base = default_base)
+ {
+ buffer.clear();
+ return append_signed_integer_to_string(value, std::move(buffer), base);
+ }
+ static std::size_t signed_integer_to_buffer(std::int64_t value,
+ char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator = true,
+ unsigned base = default_base) noexcept;
+ static std::string append_double_to_string(double value,
+ std::string buffer,
+ unsigned base = default_base);
+ static std::string double_to_string(double value,
+ std::string buffer = {},
+ unsigned base = default_base)
+ {
+ buffer.clear();
+ return append_double_to_string(value, std::move(buffer), base);
+ }
+ static std::size_t double_to_buffer(double value,
+ char *output_buffer,
+ std::size_t output_buffer_size,
+ bool require_null_terminator = true,
+ unsigned base = default_base) noexcept;
void write(std::ostream &os, unsigned base = default_base) const;
number_value duplicate() const noexcept
{
}
};
+struct composite_value;
+
+class composite_value_pointer
+{
+private:
+ std::shared_ptr<composite_value> value;
+
+public:
+ constexpr composite_value_pointer() noexcept = default;
+ template <typename T,
+ typename = typename std::enable_if<std::is_base_of<composite_value, T>::value>::type>
+ composite_value_pointer(std::shared_ptr<T> value) noexcept : value(std::move(value))
+ {
+ }
+ composite_value *operator->() const noexcept
+ {
+ return value.operator->();
+ }
+ composite_value &operator*() const noexcept
+ {
+ return *value;
+ }
+};
+
typedef util::
- variant<null_value, boolean_value, string_value, number_value, std::unique_ptr<composite_value>>
- value;
+ variant<null_value, boolean_value, string_value, number_value, composite_value_pointer> value;
+
+struct composite_value
+{
+ composite_value() = default;
+ virtual ~composite_value() = default;
+ virtual void write(std::ostream &os) const = 0;
+ virtual composite_value_pointer duplicate() const = 0;
+ operator value() const
+ {
+ return duplicate();
+ }
+};
inline value duplicate(const value &v)
{
{
}
virtual void write(std::ostream &os) const override;
- virtual std::unique_ptr<composite_value> duplicate() const override
+ virtual composite_value_pointer duplicate() const override
{
std::unordered_map<std::string, value> new_values;
for(auto &entry : values)
{
- new_values.emplace(std::get<0>(entry), ast::duplicate(std::get<1>(entry)));
+ new_values.emplace(std::get<0>(entry), ast::duplicate(std::get<1>(entry)));
}
- return std::unique_ptr<composite_value>(new object(std::move(new_values)));
+ return std::make_shared<object>(std::move(new_values));
}
};
{
}
virtual void write(std::ostream &os) const override;
- virtual std::unique_ptr<composite_value> duplicate() const override
+ virtual composite_value_pointer duplicate() const override
{
- std::vector<value> new_values;
- new_values.reserve(values.size());
- for(auto &value : values)
- new_values.emplace_back(ast::duplicate(value));
- return std::unique_ptr<composite_value>(new array(std::move(new_values)));
+ std::vector<value> new_values;
+ new_values.reserve(values.size());
+ for(auto &value : values)
+ new_values.emplace_back(ast::duplicate(value));
+ return std::make_shared<array>(std::move(new_values));
}
};
}
--- /dev/null
+/*
+* Copyright 2017 Jacob Lifshay
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all
+* copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*
+*/
+#include "parser.h"
+#include <fstream>
+#include <iostream>
+#include <cassert>
+#include <algorithm>
+#include <limits>
+#include "../util/soft_float.h"
+
+namespace vulkan_cpu
+{
+namespace json
+{
+namespace
+{
+constexpr bool is_new_line(char ch) noexcept
+{
+ return ch == '\r' || ch == '\n';
+}
+
+constexpr bool is_new_line_pair(char ch1, char ch2) noexcept
+{
+ return ch1 == '\r' && ch2 == '\n';
+}
+
+template <typename Add_Index>
+void find_line_start_indexes_helper(Add_Index &&add_index,
+ const char *contents,
+ std::size_t contents_size)
+{
+ for(std::size_t i = 0; i < contents_size; i++)
+ {
+ char ch = contents[i];
+ if(i + 1 < contents_size)
+ {
+ char ch2 = contents[i + 1];
+ if(is_new_line_pair(ch, ch2))
+ {
+ add_index(i + 2);
+ i++;
+ continue;
+ }
+ }
+ if(is_new_line(ch))
+ add_index(i + 1);
+ }
+}
+}
+
+std::vector<std::size_t> source::find_line_start_indexes(const char *contents,
+ std::size_t contents_size)
+{
+ std::size_t retval_size = 0;
+ find_line_start_indexes_helper(
+ [&](std::size_t)
+ {
+ retval_size++;
+ },
+ contents,
+ contents_size);
+ std::vector<std::size_t> retval;
+ retval.reserve(retval_size);
+ find_line_start_indexes_helper(
+ [&](std::size_t index)
+ {
+ retval.push_back(index);
+ },
+ contents,
+ contents_size);
+ return retval;
+}
+
+source source::load_file(std::string file_name)
+{
+ // TODO: add code to use mmap
+ std::ifstream is;
+ is.exceptions(std::ios::badbit | std::ios::failbit);
+ is.open(file_name);
+ std::vector<char> buffer;
+ while(is.peek() != std::char_traits<char>::eof())
+ {
+ if(buffer.size() == buffer.capacity())
+ buffer.reserve(buffer.size() * 2);
+ buffer.push_back(is.get());
+ }
+ is.close();
+ buffer.shrink_to_fit();
+ std::size_t contents_size = buffer.size();
+ auto buffer_ptr = std::make_shared<std::vector<char>>(std::move(buffer));
+ std::shared_ptr<const char> contents(buffer_ptr, buffer_ptr->data());
+ return source(std::move(file_name), std::move(contents), contents_size);
+}
+
+source source::load_stdin()
+{
+ auto &is = std::cin;
+ is.clear();
+ auto previous_exceptions = is.exceptions();
+ std::vector<char> buffer;
+ try
+ {
+ is.exceptions(std::ios::badbit | std::ios::failbit);
+ while(is.peek() != std::char_traits<char>::eof())
+ {
+ if(buffer.size() == buffer.capacity())
+ buffer.reserve(buffer.size() * 2);
+ buffer.push_back(is.get());
+ }
+ }
+ catch(...)
+ {
+ is.clear();
+ is.exceptions(previous_exceptions);
+ }
+ is.clear();
+ is.exceptions(previous_exceptions);
+ buffer.shrink_to_fit();
+ std::size_t contents_size = buffer.size();
+ auto buffer_ptr = std::make_shared<std::vector<char>>(std::move(buffer));
+ std::shared_ptr<const char> contents(buffer_ptr, buffer_ptr->data());
+ return source("stdin", std::move(contents), contents_size);
+}
+
+std::ostream &operator<<(std::ostream &os, const source::line_and_column &v)
+{
+ os << v.to_string();
+ return os;
+}
+
+source::line_and_index source::get_line_and_start_index(std::size_t char_index) const noexcept
+{
+ std::size_t line =
+ 1 + line_start_indexes.size()
+ + (line_start_indexes.rbegin() - std::lower_bound(line_start_indexes.rbegin(),
+ line_start_indexes.rend(),
+ char_index,
+ std::greater<std::size_t>()));
+ return line_and_index(line, line <= 1 ? 0 : line_start_indexes[line - 2]);
+}
+
+namespace
+{
+constexpr std::size_t get_column_after_tab(std::size_t column, std::size_t tab_size) noexcept
+{
+ return tab_size == 0 || column == 0 ? column + 1 :
+ column + (tab_size - (column - 1) % tab_size);
+}
+}
+
+source::line_and_column source::get_line_and_column(std::size_t char_index,
+ std::size_t tab_size) const noexcept
+{
+ auto line_and_start_index = get_line_and_start_index(char_index);
+ std::size_t column = 1;
+ for(std::size_t i = line_and_start_index.index; i < char_index; i++)
+ {
+ int ch = contents.get()[i];
+ if(ch == '\t')
+ column = get_column_after_tab(column, tab_size);
+ else
+ column++;
+ }
+ return line_and_column(line_and_start_index.line, column);
+}
+
+std::ostream &operator<<(std::ostream &os, const location &v)
+{
+ os << v.to_string();
+ return os;
+}
+
+namespace
+{
+enum class token_type
+{
+ eof,
+ l_bracket,
+ r_bracket,
+ l_brace,
+ r_brace,
+ colon,
+ comma,
+ true_literal,
+ false_literal,
+ null_literal,
+ string,
+ number,
+};
+
+class tokenizer final
+{
+private:
+ std::size_t input_char_index;
+ static constexpr int eof = std::char_traits<char>::eof();
+
+public:
+ const source *const source;
+ const parse_options options;
+ location token_location;
+ ast::value token_value;
+ token_type token_type;
+
+private:
+ int peekc() const noexcept
+ {
+ if(input_char_index >= source->contents_size)
+ return eof;
+ return static_cast<unsigned char>(source->contents.get()[input_char_index]);
+ }
+ int getc() noexcept
+ {
+ int retval = peekc();
+ input_char_index++;
+ return retval;
+ }
+ static constexpr bool is_digit(int ch, unsigned base = 10) noexcept
+ {
+ return get_digit_value(ch) >= 0;
+ }
+ static constexpr int get_digit_value(int ch, unsigned base = 10) noexcept
+ {
+ unsigned retval{};
+ if(ch >= '0' && ch <= '9')
+ retval = ch - '0';
+ else if(ch >= 'a' && ch <= 'z')
+ retval = ch - 'a' + 0xA;
+ else if(ch >= 'A' && ch <= 'Z')
+ retval = ch - 'A' + 0xA;
+ else
+ return -1;
+ if(retval >= base)
+ return -1;
+ return retval;
+ }
+ static constexpr bool is_letter(int ch) noexcept
+ {
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
+ }
+ static constexpr bool is_control_character(int ch) noexcept
+ {
+ return ch >= 0 && ch < 0x20U;
+ }
+ static constexpr bool is_whitespace(int ch) noexcept
+ {
+ return ch == '\t' || ch == '\n' || ch == '\r' || ch == ' ';
+ }
+ static bool match_buffer_with_string(const char *buffer,
+ std::size_t buffer_size,
+ const char *string) noexcept
+ {
+ for(; buffer_size != 0 && *string; string++, buffer++, buffer_size--)
+ if(*string != *buffer)
+ return false;
+ if(*string || buffer_size != 0)
+ return false;
+ return true;
+ }
+ std::uint32_t parse_4_hex_digits()
+ {
+ std::uint32_t retval = 0;
+ for(std::size_t i = 0; i < 4; i++)
+ {
+ int digit_char = peekc();
+ int digit_value = get_digit_value(digit_char, 0x10);
+ if(digit_value < 0)
+ throw parse_error(location(source, input_char_index), "missing hex digit");
+ getc();
+ retval <<= 4;
+ retval |= digit_value;
+ }
+ return retval;
+ }
+ static std::string append_utf8(std::string buffer, std::uint32_t ch)
+ {
+ if(ch < 0x80U)
+ {
+ buffer += static_cast<unsigned char>(ch);
+ }
+ else if(ch < 0x800U)
+ {
+ buffer += static_cast<unsigned char>((ch >> 6) | 0xC0U);
+ buffer += static_cast<unsigned char>((ch & 0x3FU) | 0x80U);
+ }
+ else if(ch < 0x10000UL)
+ {
+ buffer += static_cast<unsigned char>((ch >> 12) | 0xE0U);
+ buffer += static_cast<unsigned char>(((ch >> 6) & 0x3FU) | 0x80U);
+ buffer += static_cast<unsigned char>((ch & 0x3FU) | 0x80U);
+ }
+ else
+ {
+ buffer += static_cast<unsigned char>(((ch >> 18) & 0x7U) | 0xF0U);
+ buffer += static_cast<unsigned char>(((ch >> 12) & 0x3FU) | 0xE0U);
+ buffer += static_cast<unsigned char>(((ch >> 6) & 0x3FU) | 0x80U);
+ buffer += static_cast<unsigned char>((ch & 0x3FU) | 0x80U);
+ }
+ return buffer;
+ }
+
+public:
+ tokenizer(const json::source *source, parse_options options)
+ : input_char_index(0), source(source), options(options), token_location(), token_value()
+ {
+ next();
+ }
+ ast::value get()
+ {
+ auto retval = token_value;
+ next();
+ return retval;
+ }
+ void next()
+ {
+ while(is_whitespace(peekc()))
+ getc();
+ token_location = location(source, input_char_index);
+ token_value = nullptr;
+ bool got_minus = false, got_plus = false;
+ if(peekc() == '-')
+ {
+ getc();
+ got_minus = true;
+ }
+ else if(options.allow_explicit_plus_sign_in_mantissa && peekc() == '+')
+ {
+ getc();
+ got_plus = true;
+ }
+ if(is_letter(peekc()))
+ {
+ const char *name = source->contents.get() + input_char_index;
+ std::size_t name_size = 0;
+ while(is_letter(peekc()) || is_digit(peekc()))
+ {
+ getc();
+ name_size++;
+ }
+ if(!got_minus && !got_plus)
+ {
+ if(match_buffer_with_string(name, name_size, "null"))
+ {
+ token_value = nullptr;
+ token_type = json::token_type::null_literal;
+ return;
+ }
+ if(match_buffer_with_string(name, name_size, "false"))
+ {
+ token_value = false;
+ token_type = json::token_type::false_literal;
+ return;
+ }
+ if(match_buffer_with_string(name, name_size, "true"))
+ {
+ token_value = true;
+ token_type = json::token_type::true_literal;
+ return;
+ }
+ }
+ if(options.allow_infinity_and_nan)
+ {
+ if(match_buffer_with_string(name, name_size, "NaN")
+ || match_buffer_with_string(name, name_size, "nan")
+ || match_buffer_with_string(name, name_size, "NAN"))
+ {
+ token_value = std::numeric_limits<double>::quiet_NaN();
+ token_type = json::token_type::number;
+ return;
+ }
+ if(match_buffer_with_string(name, name_size, "Infinity")
+ || match_buffer_with_string(name, name_size, "INFINITY")
+ || match_buffer_with_string(name, name_size, "infinity")
+ || match_buffer_with_string(name, name_size, "inf")
+ || match_buffer_with_string(name, name_size, "INF"))
+ {
+ token_value = got_minus ? -std::numeric_limits<double>::infinity() :
+ std::numeric_limits<double>::infinity();
+ token_type = json::token_type::number;
+ return;
+ }
+ }
+ throw parse_error(token_location,
+ (got_minus || got_plus ? "invalid number: " : "invalid identifier: ")
+ + std::string(name, name_size));
+ }
+ if(got_minus || got_plus || is_digit(peekc())
+ || (options.allow_number_to_start_with_dot && peekc() == '.'))
+ {
+ auto mantissa = util::soft_float::ExtendedFloat::Zero();
+ bool got_any_digit = false;
+ if(is_digit(peekc()))
+ {
+ if(peekc() == '0')
+ {
+ getc();
+ got_any_digit = true;
+ if(is_digit(peekc()))
+ throw parse_error(location(source, input_char_index),
+ "extra leading zero not allowed in numbers");
+ }
+ else
+ {
+ while(is_digit(peekc()))
+ {
+ std::int64_t digit = get_digit_value(getc());
+ got_any_digit = true;
+ mantissa *= util::soft_float::ExtendedFloat(static_cast<std::uint64_t>(10));
+ mantissa += util::soft_float::ExtendedFloat(digit);
+ }
+ }
+ }
+ std::int64_t exponent_offset = 0;
+ if(peekc() == '.')
+ {
+ getc();
+ while(is_digit(peekc()))
+ {
+ std::int64_t digit = get_digit_value(getc());
+ got_any_digit = true;
+ mantissa *= util::soft_float::ExtendedFloat(static_cast<std::uint64_t>(10));
+ exponent_offset--;
+ mantissa += util::soft_float::ExtendedFloat(digit);
+ }
+ }
+ if(!got_any_digit)
+ throw parse_error(location(source, input_char_index), "missing digit");
+ std::int64_t exponent = 0;
+ if(peekc() == 'e' || peekc() == 'E')
+ {
+ getc();
+ bool exponent_is_negative = false;
+ if(peekc() == '-')
+ {
+ exponent_is_negative = true;
+ getc();
+ }
+ else if(peekc() == '+')
+ {
+ getc();
+ }
+ if(!is_digit(peekc()))
+ throw parse_error(location(source, input_char_index), "missing digit");
+ while(is_digit(peekc()))
+ {
+ exponent *= 10;
+ exponent += get_digit_value(getc());
+ }
+ if(exponent_is_negative)
+ exponent = -exponent;
+ }
+ exponent += exponent_offset;
+ auto value =
+ mantissa
+ * pow(util::soft_float::ExtendedFloat(static_cast<std::uint64_t>(10)), exponent);
+ token_type = json::token_type::number;
+ token_value = static_cast<double>(value);
+ return;
+ }
+ if(peekc() == '\"' || (options.allow_single_quote_strings && peekc() == '\''))
+ {
+ int quote = getc();
+ std::string value;
+ while(true)
+ {
+ if(peekc() == eof || is_control_character(peekc()))
+ throw parse_error(token_location, "string missing closing quote");
+ if(peekc() == quote)
+ {
+ getc();
+ break;
+ }
+ if(peekc() == '\\')
+ {
+ auto escape_location = location(source, input_char_index);
+ getc();
+ switch(peekc())
+ {
+ case '\"':
+ case '\\':
+ case '/':
+ value += getc();
+ break;
+ case 'b':
+ value += '\b';
+ getc();
+ break;
+ case 'f':
+ value += '\f';
+ getc();
+ break;
+ case 'n':
+ value += '\n';
+ getc();
+ break;
+ case 'r':
+ value += '\r';
+ getc();
+ break;
+ case 't':
+ value += '\t';
+ getc();
+ break;
+ case 'u':
+ {
+ getc();
+ std::uint32_t ch = parse_4_hex_digits();
+ if(ch >= 0xD800U && ch < 0xDC00U && peekc() == '\\')
+ {
+ escape_location = location(source, input_char_index);
+ getc();
+ if(peekc() == 'u')
+ {
+ getc();
+ std::uint32_t ch2 = parse_4_hex_digits();
+ if(ch2 >= 0xDC00U && ch2 < 0xE000U)
+ {
+ // got surrogate pair
+ ch = ((ch & 0x3FFU) >> 10) + (ch2 & 0x3FFU) + 0x10000UL;
+ }
+ else
+ {
+ input_char_index = escape_location.char_index;
+ }
+ }
+ else
+ {
+ input_char_index = escape_location.char_index;
+ }
+ }
+ value = append_utf8(std::move(value), ch);
+ break;
+ }
+ default:
+ if(options.allow_single_quote_strings && peekc() == '\'')
+ {
+ value += getc();
+ break;
+ }
+ throw parse_error(escape_location, "invalid escape sequence");
+ }
+ }
+ else
+ {
+ value += getc();
+ }
+ }
+ token_type = json::token_type::string;
+ token_value = std::move(value);
+ return;
+ }
+ switch(peekc())
+ {
+ case eof:
+ token_type = json::token_type::eof;
+ token_value = nullptr;
+ return;
+ case '[':
+ getc();
+ token_type = json::token_type::l_bracket;
+ token_value = nullptr;
+ return;
+ case ']':
+ getc();
+ token_type = json::token_type::r_bracket;
+ token_value = nullptr;
+ return;
+ case '{':
+ getc();
+ token_type = json::token_type::l_brace;
+ token_value = nullptr;
+ return;
+ case '}':
+ getc();
+ token_type = json::token_type::r_brace;
+ token_value = nullptr;
+ return;
+ case ':':
+ getc();
+ token_type = json::token_type::colon;
+ token_value = nullptr;
+ return;
+ case ',':
+ getc();
+ token_type = json::token_type::comma;
+ token_value = nullptr;
+ return;
+ }
+ throw parse_error(token_location, "invalid character");
+ }
+};
+
+ast::value parse_value(tokenizer &tokenizer)
+{
+ switch(tokenizer.token_type)
+ {
+ case token_type::eof:
+ throw parse_error(tokenizer.token_location, "missing value");
+ case token_type::number:
+ case token_type::string:
+ case token_type::true_literal:
+ case token_type::false_literal:
+ case token_type::null_literal:
+ return tokenizer.get();
+ case token_type::l_bracket:
+ {
+ std::vector<ast::value> values;
+ tokenizer.next();
+ if(tokenizer.token_type == token_type::r_bracket)
+ {
+ tokenizer.next();
+ }
+ else
+ {
+ while(true)
+ {
+ values.push_back(parse_value(tokenizer));
+ if(tokenizer.token_type == token_type::comma)
+ {
+ tokenizer.next();
+ continue;
+ }
+ if(tokenizer.token_type == token_type::r_bracket)
+ {
+ tokenizer.next();
+ break;
+ }
+ throw parse_error(tokenizer.token_location, "missing , or ]");
+ }
+ }
+ return ast::array(std::move(values));
+ }
+ case token_type::l_brace:
+ {
+ std::unordered_map<std::string, ast::value> values;
+ tokenizer.next();
+ if(tokenizer.token_type == token_type::r_brace)
+ {
+ tokenizer.next();
+ }
+ else
+ {
+ while(true)
+ {
+ if(tokenizer.token_type != token_type::string)
+ throw parse_error(tokenizer.token_location, "missing string");
+ auto string_value = std::move(util::get<ast::string_value>(tokenizer.get()).value);
+ if(tokenizer.token_type != token_type::colon)
+ throw parse_error(tokenizer.token_location, "missing ':'");
+ tokenizer.next();
+ values.emplace(std::move(string_value), parse_value(tokenizer));
+ if(tokenizer.token_type == token_type::comma)
+ {
+ tokenizer.next();
+ continue;
+ }
+ if(tokenizer.token_type == token_type::r_brace)
+ {
+ tokenizer.next();
+ break;
+ }
+ throw parse_error(tokenizer.token_location, "missing ',' or '}'");
+ }
+ }
+ return ast::object(std::move(values));
+ }
+ default:
+ break;
+ }
+ throw parse_error(tokenizer.token_location, "token not allowed here");
+}
+}
+
+ast::value parse(const source *source, parse_options options)
+{
+ tokenizer tokenizer(source, options);
+ auto retval = parse_value(tokenizer);
+ if(tokenizer.token_type != token_type::eof)
+ throw parse_error(tokenizer.token_location, "unexpected token");
+ return retval;
+}
+}
+}
--- /dev/null
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef JSON_PARSER_H_
+#define JSON_PARSER_H_
+
+#include <string>
+#include <memory>
+#include <stdexcept>
+#include <vector>
+#include <iosfwd>
+#include "json.h"
+#include "../util/optional.h"
+
+namespace vulkan_cpu
+{
+namespace json
+{
+struct source
+{
+ std::string file_name;
+ std::shared_ptr<const char> contents; // use a shared_ptr so you can use mmap-ed memory
+ std::size_t contents_size;
+ /** doesn't have first line to save memory */
+ std::vector<std::size_t> line_start_indexes;
+ static std::vector<std::size_t> find_line_start_indexes(const char *contents,
+ std::size_t contents_size);
+ source(source &&) = default;
+ source(const source &) = delete;
+ source &operator=(source &&) = default;
+ source &operator=(const source &) = delete;
+ source() : file_name(), contents(), contents_size(0), line_start_indexes()
+ {
+ }
+ explicit source(std::string file_name) noexcept : file_name(std::move(file_name)),
+ contents(),
+ contents_size(0),
+ line_start_indexes()
+ {
+ }
+ source(std::string file_name,
+ std::shared_ptr<const char> contents,
+ std::size_t contents_size) noexcept
+ : file_name(std::move(file_name)),
+ contents(std::move(contents)),
+ contents_size(contents_size),
+ line_start_indexes(find_line_start_indexes(this->contents.get(), contents_size))
+ {
+ }
+ source(std::string file_name, std::string contents_in)
+ : file_name(file_name),
+ contents(),
+ contents_size(contents_in.size()),
+ line_start_indexes(find_line_start_indexes(contents_in.data(), contents_size))
+ {
+ auto str = std::make_shared<std::string>(std::move(contents_in));
+ contents = std::shared_ptr<const char>(str, str->data());
+ }
+ source(std::string file_name, std::vector<char> contents_in)
+ : file_name(file_name),
+ contents(),
+ contents_size(contents_in.size()),
+ line_start_indexes(find_line_start_indexes(contents_in.data(), contents_size))
+ {
+ auto str = std::make_shared<std::vector<char>>(std::move(contents_in));
+ contents = std::shared_ptr<const char>(str, str->data());
+ }
+ source(std::string file_name, std::vector<unsigned char> contents_in)
+ : file_name(file_name),
+ contents(),
+ contents_size(contents_in.size()),
+ line_start_indexes(find_line_start_indexes(
+ reinterpret_cast<const char *>(contents_in.data()), contents_size))
+ {
+ auto str = std::make_shared<std::vector<unsigned char>>(std::move(contents_in));
+ contents = std::shared_ptr<const char>(str, reinterpret_cast<const char *>(str->data()));
+ }
+ explicit operator bool() const noexcept
+ {
+ return contents != nullptr;
+ }
+ static source load_file(std::string file_name);
+ static source load_stdin();
+ struct line_and_index
+ {
+ std::size_t line;
+ std::size_t index;
+ constexpr line_and_index() noexcept : line(), index()
+ {
+ }
+ constexpr line_and_index(std::size_t line, std::size_t index) noexcept : line(line),
+ index(index)
+ {
+ }
+ };
+ struct line_and_column
+ {
+ std::size_t line;
+ std::size_t column;
+ constexpr line_and_column() noexcept : line(), column()
+ {
+ }
+ constexpr line_and_column(std::size_t line, std::size_t column) noexcept : line(line),
+ column(column)
+ {
+ }
+ std::string append_to_string(std::string buffer) const
+ {
+ buffer = ast::number_value::append_unsigned_integer_to_string(line, std::move(buffer));
+ buffer += ':';
+ buffer =
+ ast::number_value::append_unsigned_integer_to_string(column, std::move(buffer));
+ return buffer;
+ }
+ std::string to_string(std::string buffer = {}) const
+ {
+ buffer.clear();
+ return append_to_string(std::move(buffer));
+ }
+ friend std::ostream &operator<<(std::ostream &os, const line_and_column &v);
+ };
+ static constexpr std::size_t default_tab_size = 8;
+ line_and_index get_line_and_start_index(std::size_t char_index) const noexcept;
+ line_and_column get_line_and_column(std::size_t char_index,
+ std::size_t tab_size = default_tab_size) const noexcept;
+};
+
+struct location
+{
+ const source *source;
+ std::size_t char_index;
+ constexpr location() noexcept : source(nullptr), char_index(0)
+ {
+ }
+ constexpr location(const json::source *source, std::size_t char_index) noexcept
+ : source(source),
+ char_index(char_index)
+ {
+ }
+ json::source::line_and_index get_line_and_start_index() const noexcept
+ {
+ if(!source)
+ return {};
+ return source->get_line_and_start_index(char_index);
+ }
+ json::source::line_and_column get_line_and_column(
+ std::size_t tab_size = json::source::default_tab_size) const noexcept
+ {
+ if(!source)
+ return {};
+ return source->get_line_and_column(char_index, tab_size);
+ }
+ std::string to_string(std::string buffer = {},
+ std::size_t tab_size = json::source::default_tab_size) const
+ {
+ buffer.clear();
+ return append_to_string(std::move(buffer));
+ }
+ std::string append_to_string(std::string buffer,
+ std::size_t tab_size = json::source::default_tab_size) const
+ {
+ if(!source || source->file_name.empty())
+ buffer += "<unknown>";
+ else
+ buffer += source->file_name;
+ buffer += ':';
+ buffer = get_line_and_column(tab_size).append_to_string(std::move(buffer));
+ return buffer;
+ }
+ friend std::ostream &operator<<(std::ostream &os, const location &v);
+};
+
+class parse_error : public std::runtime_error
+{
+public:
+ location location;
+ parse_error(json::location location, const std::string &message)
+ : runtime_error(location.to_string() + ": " + message)
+ {
+ }
+ parse_error(json::location location, const char *message)
+ : runtime_error(location.to_string() + ": " + message)
+ {
+ }
+};
+
+struct parse_options
+{
+ bool allow_infinity_and_nan;
+ bool allow_explicit_plus_sign_in_mantissa;
+ bool allow_single_quote_strings;
+ bool allow_number_to_start_with_dot;
+ constexpr parse_options() noexcept : allow_infinity_and_nan(false),
+ allow_explicit_plus_sign_in_mantissa(false),
+ allow_single_quote_strings(false),
+ allow_number_to_start_with_dot(false)
+ {
+ }
+ constexpr parse_options(bool allow_infinity_and_nan,
+ bool allow_explicit_plus_sign_in_mantissa,
+ bool allow_single_quote_strings,
+ bool allow_number_to_start_with_dot) noexcept
+ : allow_infinity_and_nan(allow_infinity_and_nan),
+ allow_explicit_plus_sign_in_mantissa(allow_explicit_plus_sign_in_mantissa),
+ allow_single_quote_strings(allow_single_quote_strings),
+ allow_number_to_start_with_dot(allow_number_to_start_with_dot)
+ {
+ }
+ static constexpr parse_options default_options() noexcept
+ {
+ return parse_options();
+ }
+ static constexpr parse_options relaxed_options() noexcept
+ {
+ return parse_options(true, true, true, true);
+ }
+};
+
+ast::value parse(const source *source, parse_options options = parse_options::default_options());
+}
+}
+
+#endif /* JSON_PARSER_H_ */
\ No newline at end of file
*
*/
#include "variant.h"
+
+#if 0
+#include <cstdlib>
+#include <iostream>
+#include <string>
+namespace vulkan_cpu
+{
+namespace util
+{
+namespace
+{
+void test()
+{
+ variant<std::string> v = "abc";
+}
+
+struct Test
+{
+ Test()
+ {
+ test();
+ std::exit(0);
+ }
+} tester;
+}
+}
+}
+#endif
VULKAN_CPU_UTIL_VARIANT_DISPATCH(const, &&)
#undef VULKAN_CPU_UTIL_VARIANT_DISPATCH
-template <typename T,
- typename... Types,
- typename Deduced_Type = typename decltype(
- variant_hypothetical_overload_set<Types...>::fn(std::declval<T>()))::type,
- std::size_t Index = variant_values<Types...>::template index_from_type<Deduced_Type>(),
- typename = typename std::enable_if<(Index < sizeof...(Types))>::type>
-constexpr std::size_t variant_conversion_deduce_index() noexcept
-{
- return Index;
-}
-
-template <typename T, typename... Types>
-using variant_conversion_deduce_type =
- variant_alternative_t<variant_conversion_deduce_index<T, Types...>(), variant<Types...>>;
-
template <std::size_t Type_Count>
struct variant_index_type
{
}
template <
typename T,
- std::size_t Index = detail::variant_conversion_deduce_index<T, Types...>(),
+ typename Deduced_Type = typename decltype(
+ detail::variant_hypothetical_overload_set<Types...>::fn(std::declval<T>()))::type,
+ std::size_t Index =
+ detail::variant_values<Types...>::template index_from_type<Deduced_Type>(),
typename = typename std::
- enable_if<!std::is_same<typename std::decay<T>::type, variant>::value
+ enable_if<(Index < sizeof...(Types))
+ && !std::is_same<typename std::decay<T>::type, variant>::value
&& !detail::variant_is_in_place_index<typename std::decay<T>::type>::value
&& !detail::variant_is_in_place_type<typename std::decay<T>::type>::value
&& std::is_constructible<variant_alternative_t<Index, variant<Types...>>,
}
template <
typename T,
- std::size_t Index = detail::variant_conversion_deduce_index<T, Types...>(),
+ typename Deduced_Type = typename decltype(
+ detail::variant_hypothetical_overload_set<Types...>::fn(std::declval<T>()))::type,
+ std::size_t Index =
+ detail::variant_values<Types...>::template index_from_type<Deduced_Type>(),
typename = typename std::
- enable_if<!std::is_same<typename std::decay<T>::type, variant>::value
+ enable_if<(Index < sizeof...(Types))
+ && !std::is_same<typename std::decay<T>::type, variant>::value
&& !detail::variant_is_in_place_index<typename std::decay<T>::type>::value
&& !detail::variant_is_in_place_type<typename std::decay<T>::type>::value
&& std::is_constructible<variant_alternative_t<Index, variant<Types...>>,