diff options
author | Manoj Srivastava <srivasta@debian.org> | 2020-05-23 00:33:19 -0700 |
---|---|---|
committer | Manoj Srivastava <srivasta@debian.org> | 2020-05-23 00:33:19 -0700 |
commit | d6b913d3ca2e84b75f3675fd6e9f5246c100cf27 (patch) | |
tree | 5fc28b7efc737bf2c79dc7d799e0a6013957fe11 /vendor | |
parent | c42f029316c0c004a795ca170bdb50644a800534 (diff) | |
parent | 73a0259be1d44fdb2ab34266ae0ff63f0d8f0b60 (diff) |
Merge branch 'master' into dgit/siddebian/2.4.0-ah-1archive/debian/2.4.0-ah-1
Diffstat (limited to 'vendor')
42 files changed, 25580 insertions, 0 deletions
diff --git a/vendor/fmt b/vendor/fmt new file mode 120000 index 00000000..8d7e4769 --- /dev/null +++ b/vendor/fmt @@ -0,0 +1 @@ +fmt-3.0.1
\ No newline at end of file diff --git a/vendor/fmt-3.0.1/fmt/CMakeLists.txt b/vendor/fmt-3.0.1/fmt/CMakeLists.txt new file mode 100644 index 00000000..89ef1f35 --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/CMakeLists.txt @@ -0,0 +1,93 @@ +# Define the fmt library, its includes and the needed defines. +# format.cc is added to FMT_HEADERS for the header-only configuration. +set(FMT_HEADERS format.h format.cc ostream.h ostream.cc time.h) +if (HAVE_OPEN) + set(FMT_HEADERS ${FMT_HEADERS} posix.h) + set(FMT_SOURCES ${FMT_SOURCES} posix.cc) +endif () + +add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../ChangeLog.rst) + +option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF) +if (FMT_CPPFORMAT) + message(WARNING "The cppformat library is deprecated, use fmt instead.") + add_library(cppformat ${FMT_SOURCES} ${FMT_HEADERS}) +endif () + +# Starting with cmake 3.1 the CXX_STANDARD property can be used instead. +target_compile_options(fmt PUBLIC ${CPP11_FLAG}) +if (FMT_PEDANTIC) + target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) +endif () + +target_include_directories(fmt PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> + $<INSTALL_INTERFACE:include>) + +set_target_properties(fmt PROPERTIES + VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) + +if (BUILD_SHARED_LIBS) + if (UNIX AND NOT APPLE) + # Fix rpmlint warning: + # unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6. + target_link_libraries(fmt -Wl,--as-needed) + endif () + target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED) +endif () + +#------------------------------------------------------------------------------ +# additionally define a header only library when cmake is new enough +if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0) + add_library(fmt-header-only INTERFACE) + + target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) + + target_include_directories(fmt-header-only INTERFACE + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> + $<INSTALL_INTERFACE:include>) +endif () + +# Install targets. +if (FMT_INSTALL) + include(CMakePackageConfigHelpers) + set(FMT_CMAKE_DIR lib/cmake/fmt CACHE STRING + "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") + set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) + set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) + set(targets_export_name fmt-targets) + + set (INSTALL_TARGETS fmt) + if (TARGET fmt-header-only) + set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only) + endif () + + set(FMT_LIB_DIR lib CACHE STRING + "Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.") + + # Generate the version, config and target files into the build directory. + write_basic_package_version_file( + ${version_config} + VERSION ${FMT_VERSION} + COMPATIBILITY AnyNewerVersion) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in + ${project_config} + INSTALL_DESTINATION ${FMT_CMAKE_DIR}) + export(TARGETS ${INSTALL_TARGETS} + FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) + + # Install version, config and target files. + install( + FILES ${project_config} ${version_config} + DESTINATION ${FMT_CMAKE_DIR}) + install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}) + + # Install the library and headers. + install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} + DESTINATION ${FMT_LIB_DIR}) + install(FILES ${FMT_HEADERS} DESTINATION include/fmt) + if (FMT_CPPFORMAT) + install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR}) + endif () +endif () diff --git a/vendor/fmt-3.0.1/fmt/format.cc b/vendor/fmt-3.0.1/fmt/format.cc new file mode 100644 index 00000000..2bd774e4 --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/format.cc @@ -0,0 +1,940 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "format.h" + +#include <string.h> + +#include <cctype> +#include <cerrno> +#include <climits> +#include <cmath> +#include <cstdarg> +#include <cstddef> // for std::ptrdiff_t + +#if defined(_WIN32) && defined(__MINGW32__) +# include <cstring> +#endif + +#if FMT_USE_WINDOWS_H +# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) +# include <windows.h> +# else +# define NOMINMAX +# include <windows.h> +# undef NOMINMAX +# endif +#endif + +using fmt::internal::Arg; + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +// Disable deprecation warning for strerror. The latter is not called but +// MSVC fails to detect it. +# pragma warning(disable: 4996) +#endif + +// Dummy implementations of strerror_r and strerror_s called if corresponding +// system functions are not available. +static inline fmt::internal::Null<> strerror_r(int, char *, ...) { + return fmt::internal::Null<>(); +} +static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::Null<>(); +} + +namespace fmt { + +FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} +FMT_FUNC FormatError::~FormatError() throw() {} +FMT_FUNC SystemError::~SystemError() throw() {} + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) +# define FMT_SWPRINTF snwprintf +#else +# define FMT_SWPRINTF swprintf +#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template <bool IsSigned> +struct IntChecker { + template <typename T> + static bool fits_in_int(T value) { + unsigned max = INT_MAX; + return value <= max; + } + static bool fits_in_int(bool) { return true; } +}; + +template <> +struct IntChecker<true> { + template <typename T> + static bool fits_in_int(T value) { + return value >= INT_MIN && value <= INT_MAX; + } + static bool fits_in_int(int) { return true; } +}; + +const char RESET_COLOR[] = "\x1b[0m"; + +typedef void (*FormatFunc)(Writer &, int, StringRef); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); + + class StrError { + private: + int error_code_; + char *&buffer_; + std::size_t buffer_size_; + + // A noop assignment operator to avoid bogus warnings. + void operator=(const StrError &) {} + + // Handle the result of XSI-compliant version of strerror_r. + int handle(int result) { + // glibc versions before 2.13 return result in errno. + return result == -1 ? errno : result; + } + + // Handle the result of GNU-specific version of strerror_r. + int handle(char *message) { + // If the buffer is full then the message is probably truncated. + if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) + return ERANGE; + buffer_ = message; + return 0; + } + + // Handle the case when strerror_r is not available. + int handle(internal::Null<>) { + return fallback(strerror_s(buffer_, buffer_size_, error_code_)); + } + + // Fallback to strerror_s when strerror_r is not available. + int fallback(int result) { + // If the buffer is full then the message is probably truncated. + return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? + ERANGE : result; + } + + // Fallback to strerror if strerror_r and strerror_s are not available. + int fallback(internal::Null<>) { + errno = 0; + buffer_ = strerror(error_code_); + return errno; + } + + public: + StrError(int err_code, char *&buf, std::size_t buf_size) + : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} + + int run() { + strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. + return handle(strerror_r(error_code_, buffer_, buffer_size_)); + } + }; + return StrError(error_code, buffer, buffer_size).run(); +} + +void format_error_code(Writer &out, int error_code, + StringRef message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential + // bad_alloc. + out.clear(); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + typedef internal::IntTraits<int>::MainType MainType; + MainType abs_value = static_cast<MainType>(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += internal::count_digits(abs_value); + if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) + out << message << SEP; + out << ERROR_STR << error_code; + assert(out.size() <= internal::INLINE_BUFFER_SIZE); +} + +void report_error(FormatFunc func, int error_code, + StringRef message) FMT_NOEXCEPT { + MemoryWriter full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} + +// IsZeroInt::visit(arg) returns true iff arg is a zero integer. +class IsZeroInt : public ArgVisitor<IsZeroInt, bool> { + public: + template <typename T> + bool visit_any_int(T value) { return value == 0; } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class WidthHandler : public ArgVisitor<WidthHandler, unsigned> { + private: + FormatSpec &spec_; + + FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); + + public: + explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} + + void report_unhandled_arg() { + FMT_THROW(FormatError("width is not integer")); + } + + template <typename T> + unsigned visit_any_int(T value) { + typedef typename internal::IntTraits<T>::MainType UnsignedType; + UnsignedType width = static_cast<UnsignedType>(value); + if (internal::is_negative(value)) { + spec_.align_ = ALIGN_LEFT; + width = 0 - width; + } + if (width > INT_MAX) + FMT_THROW(FormatError("number is too big")); + return static_cast<unsigned>(width); + } +}; + +class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> { + public: + void report_unhandled_arg() { + FMT_THROW(FormatError("precision is not integer")); + } + + template <typename T> + int visit_any_int(T value) { + if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) + FMT_THROW(FormatError("number is too big")); + return static_cast<int>(value); + } +}; + +template <typename T, typename U> +struct is_same { + enum { value = 0 }; +}; + +template <typename T> +struct is_same<T, T> { + enum { value = 1 }; +}; + +// An argument visitor that converts an integer argument to T for printf, +// if T is an integral type. If T is void, the argument is converted to +// corresponding signed or unsigned type depending on the type specifier: +// 'd' and 'i' - signed, other - unsigned) +template <typename T = void> +class ArgConverter : public ArgVisitor<ArgConverter<T>, void> { + private: + internal::Arg &arg_; + wchar_t type_; + + FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); + + public: + ArgConverter(internal::Arg &arg, wchar_t type) + : arg_(arg), type_(type) {} + + void visit_bool(bool value) { + if (type_ != 's') + visit_any_int(value); + } + + template <typename U> + void visit_any_int(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + using internal::Arg; + typedef typename internal::Conditional< + is_same<T, void>::value, U, T>::type TargetType; + if (sizeof(TargetType) <= sizeof(int)) { + // Extra casts are used to silence warnings. + if (is_signed) { + arg_.type = Arg::INT; + arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); + } else { + arg_.type = Arg::UINT; + typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; + arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); + } + } else { + if (is_signed) { + arg_.type = Arg::LONG_LONG; + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + arg_.long_long_value = static_cast<LongLong>(value); + } else { + arg_.type = Arg::ULONG_LONG; + arg_.ulong_long_value = + static_cast<typename internal::MakeUnsigned<U>::Type>(value); + } + } + } +}; + +// Converts an integer argument to char for printf. +class CharConverter : public ArgVisitor<CharConverter, void> { + private: + internal::Arg &arg_; + + FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); + + public: + explicit CharConverter(internal::Arg &arg) : arg_(arg) {} + + template <typename T> + void visit_any_int(T value) { + arg_.type = internal::Arg::CHAR; + arg_.int_value = static_cast<char>(value); + } +}; +} // namespace + +namespace internal { + +template <typename Char> +class PrintfArgFormatter : + public ArgFormatterBase<PrintfArgFormatter<Char>, Char> { + + void write_null_pointer() { + this->spec().type_ = 0; + this->write("(nil)"); + } + + typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base; + + public: + PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) + : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {} + + void visit_bool(bool value) { + FormatSpec &fmt_spec = this->spec(); + if (fmt_spec.type_ != 's') + return this->visit_any_int(value); + fmt_spec.type_ = 0; + this->write(value); + } + + void visit_char(int value) { + const FormatSpec &fmt_spec = this->spec(); + BasicWriter<Char> &w = this->writer(); + if (fmt_spec.type_ && fmt_spec.type_ != 'c') + w.write_int(value, fmt_spec); + typedef typename BasicWriter<Char>::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (fmt_spec.width_ > 1) { + Char fill = ' '; + out = w.grow_buffer(fmt_spec.width_); + if (fmt_spec.align_ != ALIGN_LEFT) { + std::fill_n(out, fmt_spec.width_ - 1, fill); + out += fmt_spec.width_ - 1; + } else { + std::fill_n(out + 1, fmt_spec.width_ - 1, fill); + } + } else { + out = w.grow_buffer(1); + } + *out = static_cast<Char>(value); + } + + void visit_cstring(const char *value) { + if (value) + Base::visit_cstring(value); + else if (this->spec().type_ == 'p') + write_null_pointer(); + else + this->write("(null)"); + } + + void visit_pointer(const void *value) { + if (value) + return Base::visit_pointer(value); + this->spec().type_ = 0; + write_null_pointer(); + } + + void visit_custom(Arg::CustomValue c) { + BasicFormatter<Char> formatter(ArgList(), this->writer()); + const Char format_str[] = {'}', 0}; + const Char *format = format_str; + c.format(&formatter, c.value, &format); + } +}; +} // namespace internal +} // namespace fmt + +FMT_FUNC void fmt::SystemError::init( + int err_code, CStringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + internal::format_system_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +template <typename T> +int fmt::internal::CharTraits<char>::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, width, value) : + FMT_SNPRINTF(buffer, size, format, width, precision, value); +} + +template <typename T> +int fmt::internal::CharTraits<wchar_t>::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, value) : + FMT_SWPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, width, value) : + FMT_SWPRINTF(buffer, size, format, width, precision, value); +} + +template <typename T> +const char fmt::internal::BasicData<T>::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template <typename T> +const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template <typename T> +const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), + // Multiply several constants instead of using a single long long constant + // to avoid warnings about C++98 not supporting long long. + fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 +}; + +FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { + (void)type; + if (std::isprint(static_cast<unsigned char>(code))) { + FMT_THROW(fmt::FormatError( + fmt::format("unknown format code '{}' for {}", code, type))); + } + FMT_THROW(fmt::FormatError( + fmt::format("unknown format code '\\x{:02x}' for {}", + static_cast<unsigned>(code), type))); +} + +#if FMT_USE_WINDOWS_H + +FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { + static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; + if (s.size() > INT_MAX) + FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); + int s_size = static_cast<int>(s.size()); + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_.resize(length + 1); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_[length] = 0; +} + +FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { + if (int error_code = convert(s)) { + FMT_THROW(WindowsError(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { + if (s.size() > INT_MAX) + return ERROR_INVALID_PARAMETER; + int s_size = static_cast<int>(s.size()); + int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); + if (length == 0) + return GetLastError(); + buffer_.resize(length + 1); + length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); + if (length == 0) + return GetLastError(); + buffer_[length] = 0; + return 0; +} + +FMT_FUNC void fmt::WindowsError::init( + int err_code, CStringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + internal::format_windows_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +FMT_FUNC void fmt::internal::format_windows_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + FMT_TRY { + MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + wchar_t *system_message = &buffer[0]; + int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast<uint32_t>(buffer.size()), 0); + if (result != 0) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + break; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. +} + +#endif // FMT_USE_WINDOWS_H + +FMT_FUNC void fmt::internal::format_system_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + FMT_TRY { + MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + char *system_message = &buffer[0]; + int result = safe_strerror(error_code, system_message, buffer.size()); + if (result == 0) { + out << message << ": " << system_message; + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. +} + +template <typename Char> +void fmt::internal::ArgMap<Char>::init(const ArgList &args) { + if (!map_.empty()) + return; + typedef internal::NamedArg<Char> NamedArg; + const NamedArg *named_arg = 0; + bool use_values = + args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + if (use_values) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::Arg::Type arg_type = args.type(i); + switch (arg_type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } + return; + } + for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { + internal::Arg::Type arg_type = args.type(i); + if (arg_type == internal::Arg::NAMED_ARG) { + named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + } + } + for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { + switch (args.args_[i].type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } +} + +template <typename Char> +void fmt::internal::FixedBuffer<Char>::grow(std::size_t) { + FMT_THROW(std::runtime_error("buffer overflow")); +} + +FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( + unsigned arg_index, const char *&error) { + Arg arg = args_[arg_index]; + switch (arg.type) { + case Arg::NONE: + error = "argument index out of range"; + break; + case Arg::NAMED_ARG: + arg = *static_cast<const internal::Arg*>(arg.pointer); + break; + default: + /*nothing*/; + } + return arg; +} + +template <typename Char> +void fmt::internal::PrintfFormatter<Char>::parse_flags( + FormatSpec &spec, const Char *&s) { + for (;;) { + switch (*s++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags_ |= SIGN_FLAG; + break; + case '#': + spec.flags_ |= HASH_FLAG; + break; + default: + --s; + return; + } + } +} + +template <typename Char> +Arg fmt::internal::PrintfFormatter<Char>::get_arg( + const Char *s, unsigned arg_index) { + (void)s; + const char *error = 0; + Arg arg = arg_index == UINT_MAX ? + next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); + if (error) + FMT_THROW(FormatError(!*s ? "invalid format string" : error)); + return arg; +} + +template <typename Char> +unsigned fmt::internal::PrintfFormatter<Char>::parse_header( + const Char *&s, FormatSpec &spec) { + unsigned arg_index = UINT_MAX; + Char c = *s; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + unsigned value = parse_nonnegative_int(s); + if (*s == '$') { // value is an argument index + ++s; + arg_index = value; + } else { + if (c == '0') + spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + parse_flags(spec, s); + // Parse width. + if (*s >= '0' && *s <= '9') { + spec.width_ = parse_nonnegative_int(s); + } else if (*s == '*') { + ++s; + spec.width_ = WidthHandler(spec).visit(get_arg(s)); + } + return arg_index; +} + +template <typename Char> +void fmt::internal::PrintfFormatter<Char>::format( + BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) { + const Char *start = format_str.c_str(); + const Char *s = start; + while (*s) { + Char c = *s++; + if (c != '%') continue; + if (*s == c) { + write(writer, start, s); + start = ++s; + continue; + } + write(writer, start, s - 1); + + FormatSpec spec; + spec.align_ = ALIGN_RIGHT; + + // Parse argument index, flags and width. + unsigned arg_index = parse_header(s, spec); + + // Parse precision. + if (*s == '.') { + ++s; + if ('0' <= *s && *s <= '9') { + spec.precision_ = static_cast<int>(parse_nonnegative_int(s)); + } else if (*s == '*') { + ++s; + spec.precision_ = PrecisionHandler().visit(get_arg(s)); + } + } + + Arg arg = get_arg(s, arg_index); + if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) + spec.flags_ &= ~to_unsigned<int>(HASH_FLAG); + if (spec.fill_ == '0') { + if (arg.type <= Arg::LAST_NUMERIC_TYPE) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. + } + + // Parse length and convert the argument to the required type. + switch (*s++) { + case 'h': + if (*s == 'h') + ArgConverter<signed char>(arg, *++s).visit(arg); + else + ArgConverter<short>(arg, *s).visit(arg); + break; + case 'l': + if (*s == 'l') + ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); + else + ArgConverter<long>(arg, *s).visit(arg); + break; + case 'j': + ArgConverter<intmax_t>(arg, *s).visit(arg); + break; + case 'z': + ArgConverter<std::size_t>(arg, *s).visit(arg); + break; + case 't': + ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --s; + ArgConverter<void>(arg, *s).visit(arg); + } + + // Parse type. + if (!*s) + FMT_THROW(FormatError("invalid format string")); + spec.type_ = static_cast<char>(*s++); + if (arg.type <= Arg::LAST_INTEGER_TYPE) { + // Normalize type. + switch (spec.type_) { + case 'i': case 'u': + spec.type_ = 'd'; + break; + case 'c': + // TODO: handle wchar_t + CharConverter(arg).visit(arg); + break; + } + } + + start = s; + + // Format argument. + internal::PrintfArgFormatter<Char>(writer, spec).visit(arg); + } + write(writer, start, s); +} + +FMT_FUNC void fmt::report_system_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + // 'fmt::' is for bcc32. + fmt::report_error(internal::format_system_error, error_code, message); +} + +#if FMT_USE_WINDOWS_H +FMT_FUNC void fmt::report_windows_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + // 'fmt::' is for bcc32. + fmt::report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + std::fwrite(w.data(), 1, w.size(), f); +} + +FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { + print(stdout, format_str, args); +} + +FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { + char escape[] = "\x1b[30m"; + escape[3] = static_cast<char>('0' + c); + std::fputs(escape, stdout); + print(format, args); + std::fputs(RESET_COLOR, stdout); +} + +FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + std::size_t size = w.size(); + return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); +} + +#ifndef FMT_HEADER_ONLY + +template struct fmt::internal::BasicData<void>; + +// Explicit instantiations for char. + +template void fmt::internal::FixedBuffer<char>::grow(std::size_t); + +template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args); + +template void fmt::internal::PrintfFormatter<char>::format( + BasicWriter<char> &writer, CStringRef format); + +template int fmt::internal::CharTraits<char>::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, double value); + +template int fmt::internal::CharTraits<char>::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, long double value); + +// Explicit instantiations for wchar_t. + +template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t); + +template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args); + +template void fmt::internal::PrintfFormatter<wchar_t>::format( + BasicWriter<wchar_t> &writer, WCStringRef format); + +template int fmt::internal::CharTraits<wchar_t>::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, double value); + +template int fmt::internal::CharTraits<wchar_t>::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, long double value); + +#endif // FMT_HEADER_ONLY + +#ifdef _MSC_VER +# pragma warning(pop) +#endif diff --git a/vendor/fmt-3.0.1/fmt/format.h b/vendor/fmt-3.0.1/fmt/format.h new file mode 100644 index 00000000..f8ce147c --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/format.h @@ -0,0 +1,3883 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include <cassert> +#include <clocale> +#include <cmath> +#include <cstdio> +#include <cstring> +#include <limits> +#include <memory> +#include <stdexcept> +#include <string> +#include <vector> +#include <utility> + +#ifdef _SECURE_SCL +# define FMT_SECURE_SCL _SECURE_SCL +#else +# define FMT_SECURE_SCL 0 +#endif + +#if FMT_SECURE_SCL +# include <iterator> +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +#else +# define FMT_MSC_VER 0 +#endif + +#if FMT_MSC_VER && FMT_MSC_VER <= 1500 +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int64 intmax_t; +#else +#include <stdint.h> +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifdef __GNUC__ +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FMT_GCC_EXTENSION __extension__ +# if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic push +// Disable the warning about "long long" which is sometimes reported even +// when using __extension__. +# pragma GCC diagnostic ignored "-Wlong-long" +// Disable the warning about declaration shadowing because it affects too +// many valid cases. +# pragma GCC diagnostic ignored "-Wshadow" +// Disable the warning about implicit conversions that may change the sign of +// an integer; silencing it otherwise would require many explicit casts. +# pragma GCC diagnostic ignored "-Wsign-conversion" +# endif +# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ +# define FMT_HAS_GXX_CXX11 1 +# endif +#else +# define FMT_GCC_EXTENSION +#endif + +#if defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#elif defined(__ICL) +# define FMT_ICC_VERSION __ICL +#endif + +#if defined(__clang__) && !defined(FMT_ICC_VERSION) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +# pragma clang diagnostic ignored "-Wpadded" +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#ifndef FMT_USE_VARIADIC_TEMPLATES +// Variadic templates are available in GCC since version 4.4 +// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ +// since version 2013. +# define FMT_USE_VARIADIC_TEMPLATES \ + (FMT_HAS_FEATURE(cxx_variadic_templates) || \ + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800) +#endif + +#ifndef FMT_USE_RVALUE_REFERENCES +// Don't use rvalue references when compiling with clang and an old libstdc++ +// as the latter doesn't provide std::move. +# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 +# define FMT_USE_RVALUE_REFERENCES 0 +# else +# define FMT_USE_RVALUE_REFERENCES \ + (FMT_HAS_FEATURE(cxx_rvalue_references) || \ + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) +# endif +#endif + +#if FMT_USE_RVALUE_REFERENCES +# include <utility> // for std::move +#endif + +// Check if exceptions are disabled. +#if defined(__GNUC__) && !defined(__EXCEPTIONS) +# define FMT_EXCEPTIONS 0 +#endif +#if FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#ifndef FMT_EXCEPTIONS +# define FMT_EXCEPTIONS 1 +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# define FMT_THROW(x) throw x +# else +# define FMT_THROW(x) assert(false) +# endif +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS +# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + FMT_MSC_VER >= 1900 +# define FMT_NOEXCEPT noexcept +# else +# define FMT_NOEXCEPT throw() +# endif +# else +# define FMT_NOEXCEPT +# endif +#endif + +#ifndef FMT_OVERRIDE +# if FMT_USE_OVERRIDE || FMT_HAS_FEATURE(cxx_override) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#ifndef FMT_USE_DELETED_FUNCTIONS +# define FMT_USE_DELETED_FUNCTIONS 0 +#endif + +#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 +# define FMT_DELETED_OR_UNDEFINED = delete +# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + TypeName& operator=(const TypeName&) = delete +#else +# define FMT_DELETED_OR_UNDEFINED +# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + TypeName& operator=(const TypeName&) +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// All compilers which support UDLs also support variadic templates. This +// makes the fmt::literals implementation easier. However, an explicit check +// for variadic templates is added here just in case. +// For Intel's compiler both it and the system gcc/msc must support UDLs. +# define FMT_USE_USER_DEFINED_LITERALS \ + FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ + (FMT_HAS_FEATURE(cxx_user_literals) || \ + (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ + (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) +#endif + +#ifndef FMT_ASSERT +# define FMT_ASSERT(condition, message) assert((condition) && message) +#endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +#endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or +// otherwise support __builtin_clz and __builtin_clzll, so +// only define FMT_BUILTIN_CLZ using the MSVC intrinsics +// if the clz and clzll builtins are not available. +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) +# include <intrin.h> // _BitScanReverse, _BitScanReverse64 + +namespace fmt { +namespace internal { +# pragma intrinsic(_BitScanReverse) +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) + +# ifdef _WIN64 +# pragma intrinsic(_BitScanReverse64) +# endif + +inline uint32_t clzll(uint64_t x) { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast<uint32_t>(x)); +# endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +} +#endif + +namespace fmt { +namespace internal { +struct DummyInt { + int data[2]; + operator int() const { return 0; } +}; +typedef std::numeric_limits<fmt::internal::DummyInt> FPUtil; + +// Dummy implementations of system functions such as signbit and ecvt called +// if the latter are not available. +inline DummyInt signbit(...) { return DummyInt(); } +inline DummyInt _ecvt_s(...) { return DummyInt(); } +inline DummyInt isinf(...) { return DummyInt(); } +inline DummyInt _finite(...) { return DummyInt(); } +inline DummyInt isnan(...) { return DummyInt(); } +inline DummyInt _isnan(...) { return DummyInt(); } + +// A helper function to suppress bogus "conditional expression is constant" +// warnings. +template <typename T> +inline T const_check(T value) { return value; } +} +} // namespace fmt + +namespace std { +// Standard permits specialization of std::numeric_limits. This specialization +// is used to resolve ambiguity between isinf and std::isinf in glibc: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 +// and the same for isnan and signbit. +template <> +class numeric_limits<fmt::internal::DummyInt> : + public std::numeric_limits<int> { + public: + // Portable version of isinf. + template <typename T> + static bool isinfinity(T x) { + using namespace fmt::internal; + // The resolution "priority" is: + // isinf macro > std::isinf > ::isinf > fmt::internal::isinf + if (const_check(sizeof(isinf(x)) == sizeof(bool) || + sizeof(isinf(x)) == sizeof(int))) { + return isinf(x) != 0; + } + return !_finite(static_cast<double>(x)); + } + + // Portable version of isnan. + template <typename T> + static bool isnotanumber(T x) { + using namespace fmt::internal; + if (const_check(sizeof(isnan(x)) == sizeof(bool) || + sizeof(isnan(x)) == sizeof(int))) { + return isnan(x) != 0; + } + return _isnan(static_cast<double>(x)) != 0; + } + + // Portable version of signbit. + static bool isnegative(double x) { + using namespace fmt::internal; + if (const_check(sizeof(signbit(x)) == sizeof(int))) + return signbit(x) != 0; + if (x < 0) return true; + if (!isnotanumber(x)) return false; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); + return sign != 0; + } +}; +} // namespace std + +namespace fmt { + +// Fix the warning about long long on older versions of GCC +// that don't support the diagnostic pragma. +FMT_GCC_EXTENSION typedef long long LongLong; +FMT_GCC_EXTENSION typedef unsigned long long ULongLong; + +#if FMT_USE_RVALUE_REFERENCES +using std::move; +#endif + +template <typename Char> +class BasicWriter; + +typedef BasicWriter<char> Writer; +typedef BasicWriter<wchar_t> WWriter; + +template <typename Char> +class ArgFormatter; + +template <typename CharType, + typename ArgFormatter = fmt::ArgFormatter<CharType> > +class BasicFormatter; + +/** + \rst + A string reference. It can be constructed from a C string or ``std::string``. + + You can use one of the following typedefs for common character types: + + +------------+-------------------------+ + | Type | Definition | + +============+=========================+ + | StringRef | BasicStringRef<char> | + +------------+-------------------------+ + | WStringRef | BasicStringRef<wchar_t> | + +------------+-------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template <typename... Args> + std::string format(StringRef format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template <typename Char> +class BasicStringRef { + private: + const Char *data_; + std::size_t size_; + + public: + /** Constructs a string reference object from a C string and a size. */ + BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits<Char>::length``. + \endrst + */ + BasicStringRef(const Char *s) + : data_(s), size_(std::char_traits<Char>::length(s)) {} + + /** + \rst + Constructs a string reference from an ``std::string`` object. + \endrst + */ + BasicStringRef(const std::basic_string<Char> &s) + : data_(s.c_str()), size_(s.size()) {} + + /** + \rst + Converts a string reference to an ``std::string`` object. + \endrst + */ + std::basic_string<Char> to_string() const { + return std::basic_string<Char>(data_, size_); + } + + /** Returns a pointer to the string data. */ + const Char *data() const { return data_; } + + /** Returns the string size. */ + std::size_t size() const { return size_; } + + // Lexicographically compare this string reference to other. + int compare(BasicStringRef other) const { + std::size_t size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits<Char>::compare(data_, other.data_, size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.compare(rhs) != 0; + } + friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.compare(rhs) >= 0; + } +}; + +typedef BasicStringRef<char> StringRef; +typedef BasicStringRef<wchar_t> WStringRef; + +/** + \rst + A reference to a null terminated string. It can be constructed from a C + string or ``std::string``. + + You can use one of the following typedefs for common character types: + + +-------------+--------------------------+ + | Type | Definition | + +=============+==========================+ + | CStringRef | BasicCStringRef<char> | + +-------------+--------------------------+ + | WCStringRef | BasicCStringRef<wchar_t> | + +-------------+--------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template <typename... Args> + std::string format(CStringRef format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template <typename Char> +class BasicCStringRef { + private: + const Char *data_; + + public: + /** Constructs a string reference object from a C string. */ + BasicCStringRef(const Char *s) : data_(s) {} + + /** + \rst + Constructs a string reference from an ``std::string`` object. + \endrst + */ + BasicCStringRef(const std::basic_string<Char> &s) : data_(s.c_str()) {} + + /** Returns the pointer to a C string. */ + const Char *c_str() const { return data_; } +}; + +typedef BasicCStringRef<char> CStringRef; +typedef BasicCStringRef<wchar_t> WCStringRef; + +/** A formatting error such as invalid format string. */ +class FormatError : public std::runtime_error { + public: + explicit FormatError(CStringRef message) + : std::runtime_error(message.c_str()) {} + ~FormatError() throw(); +}; + +namespace internal { + +// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T. +template <typename T> +struct MakeUnsigned { typedef T Type; }; + +#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ + template <> \ + struct MakeUnsigned<T> { typedef U Type; } + +FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); +FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); +FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); +FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); + +// Casts nonnegative integer to unsigned. +template <typename Int> +inline typename MakeUnsigned<Int>::Type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast<typename MakeUnsigned<Int>::Type>(value); +} + +// The number of characters to store in the MemoryBuffer object itself +// to avoid dynamic memory allocation. +enum { INLINE_BUFFER_SIZE = 500 }; + +#if FMT_SECURE_SCL +// Use checked iterator to avoid warnings on MSVC. +template <typename T> +inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) { + return stdext::checked_array_iterator<T*>(ptr, size); +} +#else +template <typename T> +inline T *make_ptr(T *ptr, std::size_t) { return ptr; } +#endif +} // namespace internal + +/** + \rst + A buffer supporting a subset of ``std::vector``'s operations. + \endrst + */ +template <typename T> +class Buffer { + private: + FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); + + protected: + T *ptr_; + std::size_t size_; + std::size_t capacity_; + + Buffer(T *ptr = 0, std::size_t capacity = 0) + : ptr_(ptr), size_(0), capacity_(capacity) {} + + /** + \rst + Increases the buffer capacity to hold at least *size* elements updating + ``ptr_`` and ``capacity_``. + \endrst + */ + virtual void grow(std::size_t size) = 0; + + public: + virtual ~Buffer() {} + + /** Returns the size of this buffer. */ + std::size_t size() const { return size_; } + + /** Returns the capacity of this buffer. */ + std::size_t capacity() const { return capacity_; } + + /** + Resizes the buffer. If T is a POD type new elements may not be initialized. + */ + void resize(std::size_t new_size) { + if (new_size > capacity_) + grow(new_size); + size_ = new_size; + } + + /** + \rst + Reserves space to store at least *capacity* elements. + \endrst + */ + void reserve(std::size_t capacity) { + if (capacity > capacity_) + grow(capacity); + } + + void clear() FMT_NOEXCEPT { size_ = 0; } + + void push_back(const T &value) { + if (size_ == capacity_) + grow(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template <typename U> + void append(const U *begin, const U *end); + + T &operator[](std::size_t index) { return ptr_[index]; } + const T &operator[](std::size_t index) const { return ptr_[index]; } +}; + +template <typename T> +template <typename U> +void Buffer<T>::append(const U *begin, const U *end) { + std::size_t new_size = size_ + internal::to_unsigned(end - begin); + if (new_size > capacity_) + grow(new_size); + std::uninitialized_copy(begin, end, + internal::make_ptr(ptr_, capacity_) + size_); + size_ = new_size; +} + +namespace internal { + +// A memory buffer for trivially copyable/constructible types with the first +// SIZE elements stored in the object itself. +template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> > +class MemoryBuffer : private Allocator, public Buffer<T> { + private: + T data_[SIZE]; + + // Deallocate memory allocated by the buffer. + void deallocate() { + if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); + } + + protected: + void grow(std::size_t size) FMT_OVERRIDE; + + public: + explicit MemoryBuffer(const Allocator &alloc = Allocator()) + : Allocator(alloc), Buffer<T>(data_, SIZE) {} + ~MemoryBuffer() { deallocate(); } + +#if FMT_USE_RVALUE_REFERENCES + private: + // Move data from other to this buffer. + void move(MemoryBuffer &other) { + Allocator &this_alloc = *this, &other_alloc = other; + this_alloc = std::move(other_alloc); + this->size_ = other.size_; + this->capacity_ = other.capacity_; + if (other.ptr_ == other.data_) { + this->ptr_ = data_; + std::uninitialized_copy(other.data_, other.data_ + this->size_, + make_ptr(data_, this->capacity_)); + } else { + this->ptr_ = other.ptr_; + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.ptr_ = other.data_; + } + } + + public: + MemoryBuffer(MemoryBuffer &&other) { + move(other); + } + + MemoryBuffer &operator=(MemoryBuffer &&other) { + assert(this != &other); + deallocate(); + move(other); + return *this; + } +#endif + + // Returns a copy of the allocator associated with this buffer. + Allocator get_allocator() const { return *this; } +}; + +template <typename T, std::size_t SIZE, typename Allocator> +void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) { + std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; + if (size > new_capacity) + new_capacity = size; + T *new_ptr = this->allocate(new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, + make_ptr(new_ptr, new_capacity)); + std::size_t old_capacity = this->capacity_; + T *old_ptr = this->ptr_; + this->capacity_ = new_capacity; + this->ptr_ = new_ptr; + // deallocate may throw (at least in principle), but it doesn't matter since + // the buffer already uses the new storage and will deallocate it in case + // of exception. + if (old_ptr != data_) + Allocator::deallocate(old_ptr, old_capacity); +} + +// A fixed-size buffer. +template <typename Char> +class FixedBuffer : public fmt::Buffer<Char> { + public: + FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {} + + protected: + FMT_API void grow(std::size_t size); +}; + +template <typename Char> +class BasicCharTraits { + public: +#if FMT_SECURE_SCL + typedef stdext::checked_array_iterator<Char*> CharPtr; +#else + typedef Char *CharPtr; +#endif + static Char cast(int value) { return static_cast<Char>(value); } +}; + +template <typename Char> +class CharTraits; + +template <> +class CharTraits<char> : public BasicCharTraits<char> { + private: + // Conversion from wchar_t to char is not allowed. + static char convert(wchar_t); + + public: + static char convert(char value) { return value; } + + // Formats a floating-point number. + template <typename T> + FMT_API static int format_float(char *buffer, std::size_t size, + const char *format, unsigned width, int precision, T value); +}; + +template <> +class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> { + public: + static wchar_t convert(char value) { return value; } + static wchar_t convert(wchar_t value) { return value; } + + template <typename T> + FMT_API static int format_float(wchar_t *buffer, std::size_t size, + const wchar_t *format, unsigned width, int precision, T value); +}; + +// Checks if a number is negative - used to avoid warnings. +template <bool IsSigned> +struct SignChecker { + template <typename T> + static bool is_negative(T value) { return value < 0; } +}; + +template <> +struct SignChecker<false> { + template <typename T> + static bool is_negative(T) { return false; } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template <typename T> +inline bool is_negative(T value) { + return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value); +} + +// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. +template <bool FitsIn32Bits> +struct TypeSelector { typedef uint32_t Type; }; + +template <> +struct TypeSelector<false> { typedef uint64_t Type; }; + +template <typename T> +struct IntTraits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename + TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType; +}; + +FMT_API void report_unknown_type(char code, const char *type); + +// Static data is placed in this class template to allow header-only +// configuration. +template <typename T = void> +struct FMT_API BasicData { + static const uint32_t POWERS_OF_10_32[]; + static const uint64_t POWERS_OF_10_64[]; + static const char DIGITS[]; +}; + +#ifndef FMT_USE_EXTERN_TEMPLATES +// Clang doesn't have a feature check for extern templates so we check +// for variadic templates which were introduced in the same version. +# define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES) +#endif + +#if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY) +extern template struct BasicData<void>; +#endif + +typedef BasicData<> Data; + +#ifdef FMT_BUILTIN_CLZLL +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +inline unsigned count_digits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; +} +#else +// Fallback version of count_digits used when __builtin_clz is not available. +inline unsigned count_digits(uint64_t n) { + unsigned count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#endif + +#ifdef FMT_BUILTIN_CLZ +// Optional version of count_digits for better performance on 32-bit platforms. +inline unsigned count_digits(uint32_t n) { + int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; +} +#endif + +// A functor that doesn't add a thousands separator. +struct NoThousandsSep { + template <typename Char> + void operator()(Char *) {} +}; + +// A functor that adds a thousands separator. +class ThousandsSep { + private: + fmt::StringRef sep_; + + // Index of a decimal digit with the least significant digit having index 0. + unsigned digit_index_; + + public: + explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} + + template <typename Char> + void operator()(Char *&buffer) { + if (++digit_index_ % 3 != 0) + return; + buffer -= sep_.size(); + std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), + internal::make_ptr(buffer, sep_.size())); + } +}; + +// Formats a decimal unsigned integer value writing into buffer. +// thousands_sep is a functor that is called after writing each char to +// add a thousands separator if necessary. +template <typename UInt, typename Char, typename ThousandsSep> +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, + ThousandsSep thousands_sep) { + buffer += num_digits; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = static_cast<unsigned>((value % 100) * 2); + value /= 100; + *--buffer = Data::DIGITS[index + 1]; + thousands_sep(buffer); + *--buffer = Data::DIGITS[index]; + thousands_sep(buffer); + } + if (value < 10) { + *--buffer = static_cast<char>('0' + value); + return; + } + unsigned index = static_cast<unsigned>(value * 2); + *--buffer = Data::DIGITS[index + 1]; + thousands_sep(buffer); + *--buffer = Data::DIGITS[index]; +} + +template <typename UInt, typename Char> +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { + return format_decimal(buffer, value, num_digits, NoThousandsSep()); +} + +#ifndef _WIN32 +# define FMT_USE_WINDOWS_H 0 +#elif !defined(FMT_USE_WINDOWS_H) +# define FMT_USE_WINDOWS_H 1 +#endif + +// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. +// All the functionality that relies on it will be disabled too. +#if FMT_USE_WINDOWS_H +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems support UTF-8 natively. +class UTF8ToUTF16 { + private: + MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_; + + public: + FMT_API explicit UTF8ToUTF16(StringRef s); + operator WStringRef() const { return WStringRef(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const wchar_t *c_str() const { return &buffer_[0]; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems support UTF-8 natively. +class UTF16ToUTF8 { + private: + MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_; + + public: + UTF16ToUTF8() {} + FMT_API explicit UTF16ToUTF8(WStringRef s); + operator StringRef() const { return StringRef(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const char *c_str() const { return &buffer_[0]; } + std::string str() const { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a system error code instead of + // throwing exception on conversion error. This method may still throw + // in case of memory allocation error. + FMT_API int convert(WStringRef s); +}; + +FMT_API void format_windows_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; +#endif + +FMT_API void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; + +// A formatting argument value. +struct Value { + template <typename Char> + struct StringValue { + const Char *value; + std::size_t size; + }; + + typedef void (*FormatFunc)( + void *formatter, const void *arg, void *format_str_ptr); + + struct CustomValue { + const void *value; + FormatFunc format; + }; + + union { + int int_value; + unsigned uint_value; + LongLong long_long_value; + ULongLong ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + StringValue<char> string; + StringValue<signed char> sstring; + StringValue<unsigned char> ustring; + StringValue<wchar_t> wstring; + CustomValue custom; + }; + + enum Type { + NONE, NAMED_ARG, + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + CSTRING, STRING, WSTRING, POINTER, CUSTOM + }; +}; + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in internal::MemoryBuffer. +struct Arg : Value { + Type type; +}; + +template <typename Char> +struct NamedArg; + +template <typename T = void> +struct Null {}; + +// A helper class template to enable or disable overloads taking wide +// characters and strings in MakeValue. +template <typename T, typename Char> +struct WCharHelper { + typedef Null<T> Supported; + typedef T Unsupported; +}; + +template <typename T> +struct WCharHelper<T, wchar_t> { + typedef T Supported; + typedef Null<T> Unsupported; +}; + +typedef char Yes[1]; +typedef char No[2]; + +template <typename T> +T &get(); + +// These are non-members to workaround an overload resolution bug in bcc32. +Yes &convert(fmt::ULongLong); +No &convert(...); + +template<typename T, bool ENABLE_CONVERSION> +struct ConvertToIntImpl { + enum { value = ENABLE_CONVERSION }; +}; + +template<typename T, bool ENABLE_CONVERSION> +struct ConvertToIntImpl2 { + enum { value = false }; +}; + +template<typename T> +struct ConvertToIntImpl2<T, true> { + enum { + // Don't convert numeric types. + value = ConvertToIntImpl<T, !std::numeric_limits<T>::is_specialized>::value + }; +}; + +template<typename T> +struct ConvertToInt { + enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) }; + enum { value = ConvertToIntImpl2<T, enable_conversion>::value }; +}; + +#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ + template <> \ + struct ConvertToInt<Type> { enum { value = 0 }; } + +// Silence warnings about convering float to int. +FMT_DISABLE_CONVERSION_TO_INT(float); +FMT_DISABLE_CONVERSION_TO_INT(double); +FMT_DISABLE_CONVERSION_TO_INT(long double); + +template<bool B, class T = void> +struct EnableIf {}; + +template<class T> +struct EnableIf<true, T> { typedef T type; }; + +template<bool B, class T, class F> +struct Conditional { typedef T type; }; + +template<class T, class F> +struct Conditional<false, T, F> { typedef F type; }; + +// For bcc32 which doesn't understand ! in template arguments. +template<bool> +struct Not { enum { value = 0 }; }; + +template<> +struct Not<false> { enum { value = 1 }; }; + +template<typename T, T> struct LConvCheck { + LConvCheck(int) {} +}; + +// Returns the thousands separator for the current locale. +// We check if ``lconv`` contains ``thousands_sep`` because on Android +// ``lconv`` is stubbed as an empty struct. +template <typename LConv> +inline StringRef thousands_sep( + LConv *lc, LConvCheck<char *LConv::*, &LConv::thousands_sep> = 0) { + return lc->thousands_sep; +} + +inline fmt::StringRef thousands_sep(...) { return ""; } + +// Makes an Arg object from any type. +template <typename Formatter> +class MakeValue : public Arg { + public: + typedef typename Formatter::Char Char; + + private: + // The following two methods are private to disallow formatting of + // arbitrary pointers. If you want to output a pointer cast it to + // "void *" or "const void *". In particular, this forbids formatting + // of "[const] volatile char *" which is printed as bool by iostreams. + // Do not implement! + template <typename T> + MakeValue(const T *value); + template <typename T> + MakeValue(T *value); + + // The following methods are private to disallow formatting of wide + // characters and strings into narrow strings as in + // fmt::format("{}", L"test"); + // To fix this, use a wide format string: fmt::format(L"{}", L"test"). +#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) + MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported); +#endif + MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported); + MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported); + MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported); + MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported); + + void set_string(StringRef str) { + string.value = str.data(); + string.size = str.size(); + } + + void set_string(WStringRef str) { + wstring.value = str.data(); + wstring.size = str.size(); + } + + // Formats an argument of a custom type, such as a user-defined class. + template <typename T> + static void format_custom_arg( + void *formatter, const void *arg, void *format_str_ptr) { + format(*static_cast<Formatter*>(formatter), + *static_cast<const Char**>(format_str_ptr), + *static_cast<const T*>(arg)); + } + + public: + MakeValue() {} + +#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ + MakeValue(Type value) { field = rhs; } \ + static uint64_t type(Type) { return Arg::TYPE; } + +#define FMT_MAKE_VALUE(Type, field, TYPE) \ + FMT_MAKE_VALUE_(Type, field, TYPE, value) + + FMT_MAKE_VALUE(bool, int_value, BOOL) + FMT_MAKE_VALUE(short, int_value, INT) + FMT_MAKE_VALUE(unsigned short, uint_value, UINT) + FMT_MAKE_VALUE(int, int_value, INT) + FMT_MAKE_VALUE(unsigned, uint_value, UINT) + + MakeValue(long value) { + // To minimize the number of types we need to deal with, long is + // translated either to int or to long long depending on its size. + if (const_check(sizeof(long) == sizeof(int))) + int_value = static_cast<int>(value); + else + long_long_value = value; + } + static uint64_t type(long) { + return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; + } + + MakeValue(unsigned long value) { + if (const_check(sizeof(unsigned long) == sizeof(unsigned))) + uint_value = static_cast<unsigned>(value); + else + ulong_long_value = value; + } + static uint64_t type(unsigned long) { + return sizeof(unsigned long) == sizeof(unsigned) ? + Arg::UINT : Arg::ULONG_LONG; + } + + FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) + FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) + FMT_MAKE_VALUE(float, double_value, DOUBLE) + FMT_MAKE_VALUE(double, double_value, DOUBLE) + FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) + FMT_MAKE_VALUE(signed char, int_value, INT) + FMT_MAKE_VALUE(unsigned char, uint_value, UINT) + FMT_MAKE_VALUE(char, int_value, CHAR) + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) { + int_value = value; + } + static uint64_t type(wchar_t) { return Arg::CHAR; } +#endif + +#define FMT_MAKE_STR_VALUE(Type, TYPE) \ + MakeValue(Type value) { set_string(value); } \ + static uint64_t type(Type) { return Arg::TYPE; } + + FMT_MAKE_VALUE(char *, string.value, CSTRING) + FMT_MAKE_VALUE(const char *, string.value, CSTRING) + FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) + FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) + FMT_MAKE_STR_VALUE(const std::string &, STRING) + FMT_MAKE_STR_VALUE(StringRef, STRING) + FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) + +#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ + MakeValue(typename WCharHelper<Type, Char>::Supported value) { \ + set_string(value); \ + } \ + static uint64_t type(Type) { return Arg::TYPE; } + + FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) + FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) + FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) + FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) + + FMT_MAKE_VALUE(void *, pointer, POINTER) + FMT_MAKE_VALUE(const void *, pointer, POINTER) + + template <typename T> + MakeValue(const T &value, + typename EnableIf<Not< + ConvertToInt<T>::value>::value, int>::type = 0) { + custom.value = &value; + custom.format = &format_custom_arg<T>; + } + + template <typename T> + MakeValue(const T &value, + typename EnableIf<ConvertToInt<T>::value, int>::type = 0) { + int_value = value; + } + + template <typename T> + static uint64_t type(const T &) { + return ConvertToInt<T>::value ? Arg::INT : Arg::CUSTOM; + } + + // Additional template param `Char_` is needed here because make_type always + // uses char. + template <typename Char_> + MakeValue(const NamedArg<Char_> &value) { pointer = &value; } + + template <typename Char_> + static uint64_t type(const NamedArg<Char_> &) { return Arg::NAMED_ARG; } +}; + +template <typename Formatter> +class MakeArg : public Arg { +public: + MakeArg() { + type = Arg::NONE; + } + + template <typename T> + MakeArg(const T &value) + : Arg(MakeValue<Formatter>(value)) { + type = static_cast<Arg::Type>(MakeValue<Formatter>::type(value)); + } +}; + +template <typename Char> +struct NamedArg : Arg { + BasicStringRef<Char> name; + + template <typename T> + NamedArg(BasicStringRef<Char> argname, const T &value) + : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {} +}; + +class RuntimeError : public std::runtime_error { + protected: + RuntimeError() : std::runtime_error("") {} + ~RuntimeError() throw(); +}; + +template <typename Char> +class PrintfArgFormatter; + +template <typename Char> +class ArgMap; +} // namespace internal + +/** An argument list. */ +class ArgList { + private: + // To reduce compiled code size per formatting function call, types of first + // MAX_PACKED_ARGS arguments are passed in the types_ field. + uint64_t types_; + union { + // If the number of arguments is less than MAX_PACKED_ARGS, the argument + // values are stored in values_, otherwise they are stored in args_. + // This is done to reduce compiled code size as storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const internal::Value *values_; + const internal::Arg *args_; + }; + + internal::Arg::Type type(unsigned index) const { + unsigned shift = index * 4; + uint64_t mask = 0xf; + return static_cast<internal::Arg::Type>( + (types_ & (mask << shift)) >> shift); + } + + template <typename Char> + friend class internal::ArgMap; + + public: + // Maximum number of arguments with packed types. + enum { MAX_PACKED_ARGS = 16 }; + + ArgList() : types_(0) {} + + ArgList(ULongLong types, const internal::Value *values) + : types_(types), values_(values) {} + ArgList(ULongLong types, const internal::Arg *args) + : types_(types), args_(args) {} + + /** Returns the argument at specified index. */ + internal::Arg operator[](unsigned index) const { + using internal::Arg; + Arg arg; + bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; + if (index < MAX_PACKED_ARGS) { + Arg::Type arg_type = type(index); + internal::Value &val = arg; + if (arg_type != Arg::NONE) + val = use_values ? values_[index] : args_[index]; + arg.type = arg_type; + return arg; + } + if (use_values) { + // The index is greater than the number of arguments that can be stored + // in values, so return a "none" argument. + arg.type = Arg::NONE; + return arg; + } + for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { + if (args_[i].type == Arg::NONE) + return args_[i]; + } + return args_[index]; + } +}; + +#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call + +/** + \rst + An argument visitor based on the `curiously recurring template pattern + <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_. + + To use `~fmt::ArgVisitor` define a subclass that implements some or all of the + visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, + for example, `~fmt::ArgVisitor::visit_int()`. + Pass the subclass as the *Impl* template parameter. Then calling + `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method + specific to the argument type. For example, if the argument type is + ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass + will be called. If the subclass doesn't contain a method with this signature, + then a corresponding method of `~fmt::ArgVisitor` will be called. + + **Example**:: + + class MyArgVisitor : public fmt::ArgVisitor<MyArgVisitor, void> { + public: + void visit_int(int value) { fmt::print("{}", value); } + void visit_double(double value) { fmt::print("{}", value ); } + }; + \endrst + */ +template <typename Impl, typename Result> +class ArgVisitor { + private: + typedef internal::Arg Arg; + + public: + void report_unhandled_arg() {} + + Result visit_unhandled_arg() { + FMT_DISPATCH(report_unhandled_arg()); + return Result(); + } + + /** Visits an ``int`` argument. **/ + Result visit_int(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits a ``long long`` argument. **/ + Result visit_long_long(LongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits an ``unsigned`` argument. **/ + Result visit_uint(unsigned value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits an ``unsigned long long`` argument. **/ + Result visit_ulong_long(ULongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits a ``bool`` argument. **/ + Result visit_bool(bool value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits a ``char`` or ``wchar_t`` argument. **/ + Result visit_char(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits an argument of any integral type. **/ + template <typename T> + Result visit_any_int(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a ``double`` argument. **/ + Result visit_double(double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + + /** Visits a ``long double`` argument. **/ + Result visit_long_double(long double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + + /** Visits a ``double`` or ``long double`` argument. **/ + template <typename T> + Result visit_any_double(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a null-terminated C string (``const char *``) argument. **/ + Result visit_cstring(const char *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a string argument. **/ + Result visit_string(Arg::StringValue<char>) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a wide string argument. **/ + Result visit_wstring(Arg::StringValue<wchar_t>) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a pointer argument. **/ + Result visit_pointer(const void *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits an argument of a custom (user-defined) type. **/ + Result visit_custom(Arg::CustomValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be + called. + \endrst + */ + Result visit(const Arg &arg) { + switch (arg.type) { + case Arg::NONE: + case Arg::NAMED_ARG: + FMT_ASSERT(false, "invalid argument type"); + break; + case Arg::INT: + return FMT_DISPATCH(visit_int(arg.int_value)); + case Arg::UINT: + return FMT_DISPATCH(visit_uint(arg.uint_value)); + case Arg::LONG_LONG: + return FMT_DISPATCH(visit_long_long(arg.long_long_value)); + case Arg::ULONG_LONG: + return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); + case Arg::BOOL: + return FMT_DISPATCH(visit_bool(arg.int_value != 0)); + case Arg::CHAR: + return FMT_DISPATCH(visit_char(arg.int_value)); + case Arg::DOUBLE: + return FMT_DISPATCH(visit_double(arg.double_value)); + case Arg::LONG_DOUBLE: + return FMT_DISPATCH(visit_long_double(arg.long_double_value)); + case Arg::CSTRING: + return FMT_DISPATCH(visit_cstring(arg.string.value)); + case Arg::STRING: + return FMT_DISPATCH(visit_string(arg.string)); + case Arg::WSTRING: + return FMT_DISPATCH(visit_wstring(arg.wstring)); + case Arg::POINTER: + return FMT_DISPATCH(visit_pointer(arg.pointer)); + case Arg::CUSTOM: + return FMT_DISPATCH(visit_custom(arg.custom)); + } + return Result(); + } +}; + +enum Alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum { + SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, + CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. +}; + +// An empty format specifier. +struct EmptySpec {}; + +// A type specifier. +template <char TYPE> +struct TypeSpec : EmptySpec { + Alignment align() const { return ALIGN_DEFAULT; } + unsigned width() const { return 0; } + int precision() const { return -1; } + bool flag(unsigned) const { return false; } + char type() const { return TYPE; } + char fill() const { return ' '; } +}; + +// A width specifier. +struct WidthSpec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of WidthSpec and its subclasses. + wchar_t fill_; + + WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} + + unsigned width() const { return width_; } + wchar_t fill() const { return fill_; } +}; + +// An alignment specifier. +struct AlignSpec : WidthSpec { + Alignment align_; + + AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) + : WidthSpec(width, fill), align_(align) {} + + Alignment align() const { return align_; } + + int precision() const { return -1; } +}; + +// An alignment and type specifier. +template <char TYPE> +struct AlignTypeSpec : AlignSpec { + AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} + + bool flag(unsigned) const { return false; } + char type() const { return TYPE; } +}; + +// A full format specifier. +struct FormatSpec : AlignSpec { + unsigned flags_; + int precision_; + char type_; + + FormatSpec( + unsigned width = 0, char type = 0, wchar_t fill = ' ') + : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} + + bool flag(unsigned f) const { return (flags_ & f) != 0; } + int precision() const { return precision_; } + char type() const { return type_; } +}; + +// An integer format specifier. +template <typename T, typename SpecT = TypeSpec<0>, typename Char = char> +class IntFormatSpec : public SpecT { + private: + T value_; + + public: + IntFormatSpec(T val, const SpecT &spec = SpecT()) + : SpecT(spec), value_(val) {} + + T value() const { return value_; } +}; + +// A string format specifier. +template <typename Char> +class StrFormatSpec : public AlignSpec { + private: + const Char *str_; + + public: + template <typename FillChar> + StrFormatSpec(const Char *str, unsigned width, FillChar fill) + : AlignSpec(width, fill), str_(str) { + internal::CharTraits<Char>::convert(FillChar()); + } + + const Char *str() const { return str_; } +}; + +/** + Returns an integer format specifier to format the value in base 2. + */ +IntFormatSpec<int, TypeSpec<'b'> > bin(int value); + +/** + Returns an integer format specifier to format the value in base 8. + */ +IntFormatSpec<int, TypeSpec<'o'> > oct(int value); + +/** + Returns an integer format specifier to format the value in base 16 using + lower-case letters for the digits above 9. + */ +IntFormatSpec<int, TypeSpec<'x'> > hex(int value); + +/** + Returns an integer formatter format specifier to format in base 16 using + upper-case letters for the digits above 9. + */ +IntFormatSpec<int, TypeSpec<'X'> > hexu(int value); + +/** + \rst + Returns an integer format specifier to pad the formatted argument with the + fill character to the specified width using the default (right) numeric + alignment. + + **Example**:: + + MemoryWriter out; + out << pad(hex(0xcafe), 8, '0'); + // out.str() == "0000cafe" + + \endrst + */ +template <char TYPE_CODE, typename Char> +IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad( + int value, unsigned width, Char fill = ' '); + +#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ +inline IntFormatSpec<TYPE, TypeSpec<'b'> > bin(TYPE value) { \ + return IntFormatSpec<TYPE, TypeSpec<'b'> >(value, TypeSpec<'b'>()); \ +} \ + \ +inline IntFormatSpec<TYPE, TypeSpec<'o'> > oct(TYPE value) { \ + return IntFormatSpec<TYPE, TypeSpec<'o'> >(value, TypeSpec<'o'>()); \ +} \ + \ +inline IntFormatSpec<TYPE, TypeSpec<'x'> > hex(TYPE value) { \ + return IntFormatSpec<TYPE, TypeSpec<'x'> >(value, TypeSpec<'x'>()); \ +} \ + \ +inline IntFormatSpec<TYPE, TypeSpec<'X'> > hexu(TYPE value) { \ + return IntFormatSpec<TYPE, TypeSpec<'X'> >(value, TypeSpec<'X'>()); \ +} \ + \ +template <char TYPE_CODE> \ +inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> > pad( \ + IntFormatSpec<TYPE, TypeSpec<TYPE_CODE> > f, unsigned width) { \ + return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> >( \ + f.value(), AlignTypeSpec<TYPE_CODE>(width, ' ')); \ +} \ + \ +/* For compatibility with older compilers we provide two overloads for pad, */ \ +/* one that takes a fill character and one that doesn't. In the future this */ \ +/* can be replaced with one overload making the template argument Char */ \ +/* default to char (C++11). */ \ +template <char TYPE_CODE, typename Char> \ +inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char> pad( \ + IntFormatSpec<TYPE, TypeSpec<TYPE_CODE>, Char> f, \ + unsigned width, Char fill) { \ + return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char>( \ + f.value(), AlignTypeSpec<TYPE_CODE>(width, fill)); \ +} \ + \ +inline IntFormatSpec<TYPE, AlignTypeSpec<0> > pad( \ + TYPE value, unsigned width) { \ + return IntFormatSpec<TYPE, AlignTypeSpec<0> >( \ + value, AlignTypeSpec<0>(width, ' ')); \ +} \ + \ +template <typename Char> \ +inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad( \ + TYPE value, unsigned width, Char fill) { \ + return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>( \ + value, AlignTypeSpec<0>(width, fill)); \ +} + +FMT_DEFINE_INT_FORMATTERS(int) +FMT_DEFINE_INT_FORMATTERS(long) +FMT_DEFINE_INT_FORMATTERS(unsigned) +FMT_DEFINE_INT_FORMATTERS(unsigned long) +FMT_DEFINE_INT_FORMATTERS(LongLong) +FMT_DEFINE_INT_FORMATTERS(ULongLong) + +/** + \rst + Returns a string formatter that pads the formatted argument with the fill + character to the specified width using the default (left) string alignment. + + **Example**:: + + std::string s = str(MemoryWriter() << pad("abc", 8)); + // s == "abc " + + \endrst + */ +template <typename Char> +inline StrFormatSpec<Char> pad( + const Char *str, unsigned width, Char fill = ' ') { + return StrFormatSpec<Char>(str, width, fill); +} + +inline StrFormatSpec<wchar_t> pad( + const wchar_t *str, unsigned width, char fill = ' ') { + return StrFormatSpec<wchar_t>(str, width, fill); +} + +namespace internal { + +template <typename Char> +class ArgMap { + private: + typedef std::vector< + std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType; + typedef typename MapType::value_type Pair; + + MapType map_; + + public: + FMT_API void init(const ArgList &args); + + const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const { + // The list is unsorted, so just return the first matching name. + for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); + it != end; ++it) { + if (it->first == name) + return &it->second; + } + return 0; + } +}; + +template <typename Impl, typename Char> +class ArgFormatterBase : public ArgVisitor<Impl, void> { + private: + BasicWriter<Char> &writer_; + FormatSpec &spec_; + + FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); + + void write_pointer(const void *p) { + spec_.flags_ = HASH_FLAG; + spec_.type_ = 'x'; + writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_); + } + + protected: + BasicWriter<Char> &writer() { return writer_; } + FormatSpec &spec() { return spec_; } + + void write(bool value) { + const char *str_value = value ? "true" : "false"; + Arg::StringValue<char> str = { str_value, std::strlen(str_value) }; + writer_.write_str(str, spec_); + } + + void write(const char *value) { + Arg::StringValue<char> str = {value, value != 0 ? std::strlen(value) : 0}; + writer_.write_str(str, spec_); + } + + public: + ArgFormatterBase(BasicWriter<Char> &w, FormatSpec &s) + : writer_(w), spec_(s) {} + + template <typename T> + void visit_any_int(T value) { writer_.write_int(value, spec_); } + + template <typename T> + void visit_any_double(T value) { writer_.write_double(value, spec_); } + + void visit_bool(bool value) { + if (spec_.type_) + return visit_any_int(value); + write(value); + } + + void visit_char(int value) { + if (spec_.type_ && spec_.type_ != 'c') { + spec_.flags_ |= CHAR_FLAG; + writer_.write_int(value, spec_); + return; + } + if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) + FMT_THROW(FormatError("invalid format specifier for char")); + typedef typename BasicWriter<Char>::CharPtr CharPtr; + Char fill = internal::CharTraits<Char>::cast(spec_.fill()); + CharPtr out = CharPtr(); + const unsigned CHAR_SIZE = 1; + if (spec_.width_ > CHAR_SIZE) { + out = writer_.grow_buffer(spec_.width_); + if (spec_.align_ == ALIGN_RIGHT) { + std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill); + out += spec_.width_ - CHAR_SIZE; + } else if (spec_.align_ == ALIGN_CENTER) { + out = writer_.fill_padding(out, spec_.width_, + internal::const_check(CHAR_SIZE), fill); + } else { + std::uninitialized_fill_n(out + CHAR_SIZE, + spec_.width_ - CHAR_SIZE, fill); + } + } else { + out = writer_.grow_buffer(CHAR_SIZE); + } + *out = internal::CharTraits<Char>::cast(value); + } + + void visit_cstring(const char *value) { + if (spec_.type_ == 'p') + return write_pointer(value); + write(value); + } + + void visit_string(Arg::StringValue<char> value) { + writer_.write_str(value, spec_); + } + + using ArgVisitor<Impl, void>::visit_wstring; + + void visit_wstring(Arg::StringValue<Char> value) { + writer_.write_str(value, spec_); + } + + void visit_pointer(const void *value) { + if (spec_.type_ && spec_.type_ != 'p') + report_unknown_type(spec_.type_, "pointer"); + write_pointer(value); + } +}; + +class FormatterBase { + private: + ArgList args_; + int next_arg_index_; + + // Returns the argument with specified index. + FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); + + protected: + const ArgList &args() const { return args_; } + + explicit FormatterBase(const ArgList &args) { + args_ = args; + next_arg_index_ = 0; + } + + // Returns the next argument. + Arg next_arg(const char *&error) { + if (next_arg_index_ >= 0) + return do_get_arg(internal::to_unsigned(next_arg_index_++), error); + error = "cannot switch from manual to automatic argument indexing"; + return Arg(); + } + + // Checks if manual indexing is used and returns the argument with + // specified index. + Arg get_arg(unsigned arg_index, const char *&error) { + return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); + } + + bool check_no_auto_index(const char *&error) { + if (next_arg_index_ > 0) { + error = "cannot switch from automatic to manual argument indexing"; + return false; + } + next_arg_index_ = -1; + return true; + } + + template <typename Char> + void write(BasicWriter<Char> &w, const Char *start, const Char *end) { + if (start != end) + w << BasicStringRef<Char>(start, internal::to_unsigned(end - start)); + } +}; + +// A printf formatter. +template <typename Char> +class PrintfFormatter : private FormatterBase { + private: + void parse_flags(FormatSpec &spec, const Char *&s); + + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. + Arg get_arg(const Char *s, + unsigned arg_index = (std::numeric_limits<unsigned>::max)()); + + // Parses argument index, flags and width and returns the argument index. + unsigned parse_header(const Char *&s, FormatSpec &spec); + + public: + explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {} + FMT_API void format(BasicWriter<Char> &writer, + BasicCStringRef<Char> format_str); +}; +} // namespace internal + +/** + \rst + An argument formatter based on the `curiously recurring template pattern + <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_. + + To use `~fmt::BasicArgFormatter` define a subclass that implements some or + all of the visit methods with the same signatures as the methods in + `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. + Pass the subclass as the *Impl* template parameter. When a formatting + function processes an argument, it will dispatch to a visit method + specific to the argument type. For example, if the argument type is + ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass + will be called. If the subclass doesn't contain a method with this signature, + then a corresponding method of `~fmt::BasicArgFormatter` or its superclass + will be called. + \endrst + */ +template <typename Impl, typename Char> +class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> { + private: + BasicFormatter<Char, Impl> &formatter_; + const Char *format_; + + public: + /** + \rst + Constructs an argument formatter object. + *formatter* is a reference to the main formatter object, *spec* contains + format specifier information for standard argument types, and *fmt* points + to the part of the format string being parsed for custom argument types. + \endrst + */ + BasicArgFormatter(BasicFormatter<Char, Impl> &formatter, + FormatSpec &spec, const Char *fmt) + : internal::ArgFormatterBase<Impl, Char>(formatter.writer(), spec), + formatter_(formatter), format_(fmt) {} + + /** Formats argument of a custom (user-defined) type. */ + void visit_custom(internal::Arg::CustomValue c) { + c.format(&formatter_, c.value, &format_); + } +}; + +/** The default argument formatter. */ +template <typename Char> +class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> { + public: + /** Constructs an argument formatter object. */ + ArgFormatter(BasicFormatter<Char> &formatter, + FormatSpec &spec, const Char *fmt) + : BasicArgFormatter<ArgFormatter<Char>, Char>(formatter, spec, fmt) {} +}; + +/** This template formats data and writes the output to a writer. */ +template <typename CharType, typename ArgFormatter> +class BasicFormatter : private internal::FormatterBase { + public: + /** The character type for the output. */ + typedef CharType Char; + + private: + BasicWriter<Char> &writer_; + internal::ArgMap<Char> map_; + + FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); + + using internal::FormatterBase::get_arg; + + // Checks if manual indexing is used and returns the argument with + // specified name. + internal::Arg get_arg(BasicStringRef<Char> arg_name, const char *&error); + + // Parses argument index and returns corresponding argument. + internal::Arg parse_arg_index(const Char *&s); + + // Parses argument name and returns corresponding argument. + internal::Arg parse_arg_name(const Char *&s); + + public: + /** + \rst + Constructs a ``BasicFormatter`` object. References to the arguments and + the writer are stored in the formatter object so make sure they have + appropriate lifetimes. + \endrst + */ + BasicFormatter(const ArgList &args, BasicWriter<Char> &w) + : internal::FormatterBase(args), writer_(w) {} + + /** Returns a reference to the writer associated with this formatter. */ + BasicWriter<Char> &writer() { return writer_; } + + /** Formats stored arguments and writes the output to the writer. */ + void format(BasicCStringRef<Char> format_str); + + // Formats a single argument and advances format_str, a format string pointer. + const Char *format(const Char *&format_str, const internal::Arg &arg); +}; + +// Generates a comma-separated list with results of applying f to +// numbers 0..n-1. +# define FMT_GEN(n, f) FMT_GEN##n(f) +# define FMT_GEN1(f) f(0) +# define FMT_GEN2(f) FMT_GEN1(f), f(1) +# define FMT_GEN3(f) FMT_GEN2(f), f(2) +# define FMT_GEN4(f) FMT_GEN3(f), f(3) +# define FMT_GEN5(f) FMT_GEN4(f), f(4) +# define FMT_GEN6(f) FMT_GEN5(f), f(5) +# define FMT_GEN7(f) FMT_GEN6(f), f(6) +# define FMT_GEN8(f) FMT_GEN7(f), f(7) +# define FMT_GEN9(f) FMT_GEN8(f), f(8) +# define FMT_GEN10(f) FMT_GEN9(f), f(9) +# define FMT_GEN11(f) FMT_GEN10(f), f(10) +# define FMT_GEN12(f) FMT_GEN11(f), f(11) +# define FMT_GEN13(f) FMT_GEN12(f), f(12) +# define FMT_GEN14(f) FMT_GEN13(f), f(13) +# define FMT_GEN15(f) FMT_GEN14(f), f(14) + +namespace internal { +inline uint64_t make_type() { return 0; } + +template <typename T> +inline uint64_t make_type(const T &arg) { + return MakeValue< BasicFormatter<char> >::type(arg); +} + +template <unsigned N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)> +struct ArgArray; + +template <unsigned N> +struct ArgArray<N, true/*IsPacked*/> { + typedef Value Type[N > 0 ? N : 1]; + + template <typename Formatter, typename T> + static Value make(const T &value) { +#ifdef __clang__ + Value result = MakeValue<Formatter>(value); + // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: + // https://github.com/fmtlib/fmt/issues/276 + (void)result.custom.format; + return result; +#else + return MakeValue<Formatter>(value); +#endif + } +}; + +template <unsigned N> +struct ArgArray<N, false/*IsPacked*/> { + typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE + + template <typename Formatter, typename T> + static Arg make(const T &value) { return MakeArg<Formatter>(value); } +}; + +#if FMT_USE_VARIADIC_TEMPLATES +template <typename Arg, typename... Args> +inline uint64_t make_type(const Arg &first, const Args & ... tail) { + return make_type(first) | (make_type(tail...) << 4); +} + +#else + +struct ArgType { + uint64_t type; + + ArgType() : type(0) {} + + template <typename T> + ArgType(const T &arg) : type(make_type(arg)) {} +}; + +# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() + +inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { + return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | + (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | + (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | + (t12.type << 48) | (t13.type << 52) | (t14.type << 56); +} +#endif +} // namespace internal + +# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n +# define FMT_MAKE_ARG_TYPE(n) T##n +# define FMT_MAKE_ARG(n) const T##n &v##n +# define FMT_ASSIGN_char(n) \ + arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<char> >(v##n) +# define FMT_ASSIGN_wchar_t(n) \ + arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<wchar_t> >(v##n) + +#if FMT_USE_VARIADIC_TEMPLATES +// Defines a variadic function returning void. +# define FMT_VARIADIC_VOID(func, arg_type) \ + template <typename... Args> \ + void func(arg_type arg0, const Args & ... args) { \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ + } + +// Defines a variadic constructor. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + template <typename... Args> \ + ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ + } + +#else + +# define FMT_MAKE_REF(n) \ + fmt::internal::MakeValue< fmt::BasicFormatter<Char> >(v##n) +# define FMT_MAKE_REF2(n) v##n + +// Defines a wrapper for a function taking one argument of type arg_type +// and n additional arguments of arbitrary types. +# define FMT_WRAP1(func, arg_type, n) \ + template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ + inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg1, fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ + } + +// Emulates a variadic function returning void on a pre-C++11 compiler. +# define FMT_VARIADIC_VOID(func, arg_type) \ + inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ + FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ + FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ + FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ + FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ + FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) + +# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ + template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ + ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg0, arg1, fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ + } + +// Emulates a variadic constructor on a pre-C++11 compiler. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) +#endif + +// Generates a comma-separated list with results of applying f to pairs +// (argument, index). +#define FMT_FOR_EACH1(f, x0) f(x0, 0) +#define FMT_FOR_EACH2(f, x0, x1) \ + FMT_FOR_EACH1(f, x0), f(x1, 1) +#define FMT_FOR_EACH3(f, x0, x1, x2) \ + FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) +#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ + FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) +#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ + FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) +#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ + FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) +#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ + FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) +#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ + FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) +#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ + FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) +#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ + FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) + +/** + An error returned by an operating system or a language runtime, + for example a file opening error. +*/ +class SystemError : public internal::RuntimeError { + private: + void init(int err_code, CStringRef format_str, ArgList args); + + protected: + int error_code_; + + typedef char Char; // For FMT_VARIADIC_CTOR. + + SystemError() {} + + public: + /** + \rst + Constructs a :class:`fmt::SystemError` object with the description + of the form + + .. parsed-literal:: + *<message>*: *<system-message>* + + where *<message>* is the formatted message and *<system-message>* is + the system message corresponding to the error code. + *error_code* is a system error code as given by ``errno``. + If *error_code* is not a valid error code such as -1, the system message + may look like "Unknown error -1" and is platform-dependent. + + **Example**:: + + // This throws a SystemError with the description + // cannot open file 'madeup': No such file or directory + // or similar (system message may vary). + const char *filename = "madeup"; + std::FILE *file = std::fopen(filename, "r"); + if (!file) + throw fmt::SystemError(errno, "cannot open file '{}'", filename); + \endrst + */ + SystemError(int error_code, CStringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) + + ~SystemError() throw(); + + int error_code() const { return error_code_; } +}; + +/** + \rst + This template provides operations for formatting and writing data into + a character stream. The output is stored in a buffer provided by a subclass + such as :class:`fmt::BasicMemoryWriter`. + + You can use one of the following typedefs for common character types: + + +---------+----------------------+ + | Type | Definition | + +=========+======================+ + | Writer | BasicWriter<char> | + +---------+----------------------+ + | WWriter | BasicWriter<wchar_t> | + +---------+----------------------+ + + \endrst + */ +template <typename Char> +class BasicWriter { + private: + // Output buffer. + Buffer<Char> &buffer_; + + FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); + + typedef typename internal::CharTraits<Char>::CharPtr CharPtr; + +#if FMT_SECURE_SCL + // Returns pointer value. + static Char *get(CharPtr p) { return p.base(); } +#else + static Char *get(Char *p) { return p; } +#endif + + // Fills the padding around the content and returns the pointer to the + // content area. + static CharPtr fill_padding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill); + + // Grows the buffer by n characters and returns a pointer to the newly + // allocated area. + CharPtr grow_buffer(std::size_t n) { + std::size_t size = buffer_.size(); + buffer_.resize(size + n); + return internal::make_ptr(&buffer_[size], n); + } + + // Writes an unsigned decimal integer. + template <typename UInt> + Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { + unsigned num_digits = internal::count_digits(value); + Char *ptr = get(grow_buffer(prefix_size + num_digits)); + internal::format_decimal(ptr + prefix_size, value, num_digits); + return ptr; + } + + // Writes a decimal integer. + template <typename Int> + void write_decimal(Int value) { + typedef typename internal::IntTraits<Int>::MainType MainType; + MainType abs_value = static_cast<MainType>(value); + if (internal::is_negative(value)) { + abs_value = 0 - abs_value; + *write_unsigned_decimal(abs_value, 1) = '-'; + } else { + write_unsigned_decimal(abs_value, 0); + } + } + + // Prepare a buffer for integer formatting. + CharPtr prepare_int_buffer(unsigned num_digits, + const EmptySpec &, const char *prefix, unsigned prefix_size) { + unsigned size = prefix_size + num_digits; + CharPtr p = grow_buffer(size); + std::uninitialized_copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + + template <typename Spec> + CharPtr prepare_int_buffer(unsigned num_digits, + const Spec &spec, const char *prefix, unsigned prefix_size); + + // Formats an integer. + template <typename T, typename Spec> + void write_int(T value, Spec spec); + + // Formats a floating-point number (double or long double). + template <typename T> + void write_double(T value, const FormatSpec &spec); + + // Writes a formatted string. + template <typename StrChar> + CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); + + template <typename StrChar> + void write_str(const internal::Arg::StringValue<StrChar> &str, + const FormatSpec &spec); + + // This following methods are private to disallow writing wide characters + // and strings to a char stream. If you want to print a wide string as a + // pointer as std::ostream does, cast it to const void*. + // Do not implement! + void operator<<(typename internal::WCharHelper<wchar_t, Char>::Unsupported); + void operator<<( + typename internal::WCharHelper<const wchar_t *, Char>::Unsupported); + + // Appends floating-point length specifier to the format string. + // The second argument is only used for overload resolution. + void append_float_length(Char *&format_ptr, long double) { + *format_ptr++ = 'L'; + } + + template<typename T> + void append_float_length(Char *&, T) {} + + template <typename Impl, typename Char_> + friend class internal::ArgFormatterBase; + + friend class internal::PrintfArgFormatter<Char>; + + protected: + /** + Constructs a ``BasicWriter`` object. + */ + explicit BasicWriter(Buffer<Char> &b) : buffer_(b) {} + + public: + /** + \rst + Destroys a ``BasicWriter`` object. + \endrst + */ + virtual ~BasicWriter() {} + + /** + Returns the total number of characters written. + */ + std::size_t size() const { return buffer_.size(); } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const Char *c_str() const { + std::size_t size = buffer_.size(); + buffer_.reserve(size + 1); + buffer_[size] = '\0'; + return &buffer_[0]; + } + + /** + \rst + Returns the content of the output buffer as an `std::string`. + \endrst + */ + std::basic_string<Char> str() const { + return std::basic_string<Char>(&buffer_[0], buffer_.size()); + } + + /** + \rst + Writes formatted data. + + *args* is an argument list representing arbitrary arguments. + + **Example**:: + + MemoryWriter out; + out.write("Current point:\n"); + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + Current point: + (-3.140000, +3.140000) + + The output can be accessed using :func:`data()`, :func:`c_str` or + :func:`str` methods. + + See also :ref:`syntax`. + \endrst + */ + void write(BasicCStringRef<Char> format, ArgList args) { + BasicFormatter<Char>(args, *this).format(format); + } + FMT_VARIADIC_VOID(write, BasicCStringRef<Char>) + + BasicWriter &operator<<(int value) { + write_decimal(value); + return *this; + } + BasicWriter &operator<<(unsigned value) { + return *this << IntFormatSpec<unsigned>(value); + } + BasicWriter &operator<<(long value) { + write_decimal(value); + return *this; + } + BasicWriter &operator<<(unsigned long value) { + return *this << IntFormatSpec<unsigned long>(value); + } + BasicWriter &operator<<(LongLong value) { + write_decimal(value); + return *this; + } + + /** + \rst + Formats *value* and writes it to the stream. + \endrst + */ + BasicWriter &operator<<(ULongLong value) { + return *this << IntFormatSpec<ULongLong>(value); + } + + BasicWriter &operator<<(double value) { + write_double(value, FormatSpec()); + return *this; + } + + /** + \rst + Formats *value* using the general format for floating-point numbers + (``'g'``) and writes it to the stream. + \endrst + */ + BasicWriter &operator<<(long double value) { + write_double(value, FormatSpec()); + return *this; + } + + /** + Writes a character to the stream. + */ + BasicWriter &operator<<(char value) { + buffer_.push_back(value); + return *this; + } + + BasicWriter &operator<<( + typename internal::WCharHelper<wchar_t, Char>::Supported value) { + buffer_.push_back(value); + return *this; + } + + /** + \rst + Writes *value* to the stream. + \endrst + */ + BasicWriter &operator<<(fmt::BasicStringRef<Char> value) { + const Char *str = value.data(); + buffer_.append(str, str + value.size()); + return *this; + } + + BasicWriter &operator<<( + typename internal::WCharHelper<StringRef, Char>::Supported value) { + const char *str = value.data(); + buffer_.append(str, str + value.size()); + return *this; + } + + template <typename T, typename Spec, typename FillChar> + BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) { + internal::CharTraits<Char>::convert(FillChar()); + write_int(spec.value(), spec); + return *this; + } + + template <typename StrChar> + BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) { + const StrChar *s = spec.str(); + write_str(s, std::char_traits<Char>::length(s), spec); + return *this; + } + + void clear() FMT_NOEXCEPT { buffer_.clear(); } + + Buffer<Char> &buffer() FMT_NOEXCEPT { return buffer_; } +}; + +template <typename Char> +template <typename StrChar> +typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str( + const StrChar *s, std::size_t size, const AlignSpec &spec) { + CharPtr out = CharPtr(); + if (spec.width() > size) { + out = grow_buffer(spec.width()); + Char fill = internal::CharTraits<Char>::cast(spec.fill()); + if (spec.align() == ALIGN_RIGHT) { + std::uninitialized_fill_n(out, spec.width() - size, fill); + out += spec.width() - size; + } else if (spec.align() == ALIGN_CENTER) { + out = fill_padding(out, spec.width(), size, fill); + } else { + std::uninitialized_fill_n(out + size, spec.width() - size, fill); + } + } else { + out = grow_buffer(size); + } + std::uninitialized_copy(s, s + size, out); + return out; +} + +template <typename Char> +template <typename StrChar> +void BasicWriter<Char>::write_str( + const internal::Arg::StringValue<StrChar> &s, const FormatSpec &spec) { + // Check if StrChar is convertible to Char. + internal::CharTraits<Char>::convert(StrChar()); + if (spec.type_ && spec.type_ != 's') + internal::report_unknown_type(spec.type_, "string"); + const StrChar *str_value = s.value; + std::size_t str_size = s.size; + if (str_size == 0) { + if (!str_value) { + FMT_THROW(FormatError("string pointer is null")); + } + } + std::size_t precision = static_cast<std::size_t>(spec.precision_); + if (spec.precision_ >= 0 && precision < str_size) + str_size = precision; + write_str(str_value, str_size, spec); +} + +template <typename Char> +typename BasicWriter<Char>::CharPtr + BasicWriter<Char>::fill_padding( + CharPtr buffer, unsigned total_size, + std::size_t content_size, wchar_t fill) { + std::size_t padding = total_size - content_size; + std::size_t left_padding = padding / 2; + Char fill_char = internal::CharTraits<Char>::cast(fill); + std::uninitialized_fill_n(buffer, left_padding, fill_char); + buffer += left_padding; + CharPtr content = buffer; + std::uninitialized_fill_n(buffer + content_size, + padding - left_padding, fill_char); + return content; +} + +template <typename Char> +template <typename Spec> +typename BasicWriter<Char>::CharPtr + BasicWriter<Char>::prepare_int_buffer( + unsigned num_digits, const Spec &spec, + const char *prefix, unsigned prefix_size) { + unsigned width = spec.width(); + Alignment align = spec.align(); + Char fill = internal::CharTraits<Char>::cast(spec.fill()); + if (spec.precision() > static_cast<int>(num_digits)) { + // Octal prefix '0' is counted as a digit, so ignore it if precision + // is specified. + if (prefix_size > 0 && prefix[prefix_size - 1] == '0') + --prefix_size; + unsigned number_size = + prefix_size + internal::to_unsigned(spec.precision()); + AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); + if (number_size >= width) + return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); + buffer_.reserve(width); + unsigned fill_size = width - number_size; + if (align != ALIGN_LEFT) { + CharPtr p = grow_buffer(fill_size); + std::uninitialized_fill(p, p + fill_size, fill); + } + CharPtr result = prepare_int_buffer( + num_digits, subspec, prefix, prefix_size); + if (align == ALIGN_LEFT) { + CharPtr p = grow_buffer(fill_size); + std::uninitialized_fill(p, p + fill_size, fill); + } + return result; + } + unsigned size = prefix_size + num_digits; + if (width <= size) { + CharPtr p = grow_buffer(size); + std::uninitialized_copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + CharPtr p = grow_buffer(width); + CharPtr end = p + width; + if (align == ALIGN_LEFT) { + std::uninitialized_copy(prefix, prefix + prefix_size, p); + p += size; + std::uninitialized_fill(p, end, fill); + } else if (align == ALIGN_CENTER) { + p = fill_padding(p, width, size, fill); + std::uninitialized_copy(prefix, prefix + prefix_size, p); + p += size; + } else { + if (align == ALIGN_NUMERIC) { + if (prefix_size != 0) { + p = std::uninitialized_copy(prefix, prefix + prefix_size, p); + size -= prefix_size; + } + } else { + std::uninitialized_copy(prefix, prefix + prefix_size, end - size); + } + std::uninitialized_fill(p, end - size, fill); + p = end; + } + return p - 1; +} + +template <typename Char> +template <typename T, typename Spec> +void BasicWriter<Char>::write_int(T value, Spec spec) { + unsigned prefix_size = 0; + typedef typename internal::IntTraits<T>::MainType UnsignedType; + UnsignedType abs_value = static_cast<UnsignedType>(value); + char prefix[4] = ""; + if (internal::is_negative(value)) { + prefix[0] = '-'; + ++prefix_size; + abs_value = 0 - abs_value; + } else if (spec.flag(SIGN_FLAG)) { + prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; + ++prefix_size; + } + switch (spec.type()) { + case 0: case 'd': { + unsigned num_digits = internal::count_digits(abs_value); + CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; + internal::format_decimal(get(p), abs_value, 0); + break; + } + case 'x': case 'X': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 4) != 0); + Char *p = get(prepare_int_buffer( + num_digits, spec, prefix, prefix_size)); + n = abs_value; + const char *digits = spec.type() == 'x' ? + "0123456789abcdef" : "0123456789ABCDEF"; + do { + *p-- = digits[n & 0xf]; + } while ((n >>= 4) != 0); + break; + } + case 'b': case 'B': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 1) != 0); + Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = static_cast<Char>('0' + (n & 1)); + } while ((n >>= 1) != 0); + break; + } + case 'o': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) + prefix[prefix_size++] = '0'; + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 3) != 0); + Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = static_cast<Char>('0' + (n & 7)); + } while ((n >>= 3) != 0); + break; + } + case 'n': { + unsigned num_digits = internal::count_digits(abs_value); + fmt::StringRef sep = ""; +#ifndef ANDROID + sep = internal::thousands_sep(std::localeconv()); +#endif + unsigned size = static_cast<unsigned>( + num_digits + sep.size() * ((num_digits - 1) / 3)); + CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; + internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); + break; + } + default: + internal::report_unknown_type( + spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); + break; + } +} + +template <typename Char> +template <typename T> +void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) { + // Check type. + char type = spec.type(); + bool upper = false; + switch (type) { + case 0: + type = 'g'; + break; + case 'e': case 'f': case 'g': case 'a': + break; + case 'F': +#if FMT_MSC_VER + // MSVC's printf doesn't support 'F'. + type = 'f'; +#endif + // Fall through. + case 'E': case 'G': case 'A': + upper = true; + break; + default: + internal::report_unknown_type(type, "double"); + break; + } + + char sign = 0; + // Use isnegative instead of value < 0 because the latter is always + // false for NaN. + if (internal::FPUtil::isnegative(static_cast<double>(value))) { + sign = '-'; + value = -value; + } else if (spec.flag(SIGN_FLAG)) { + sign = spec.flag(PLUS_FLAG) ? '+' : ' '; + } + + if (internal::FPUtil::isnotanumber(value)) { + // Format NaN ourselves because sprintf's output is not consistent + // across platforms. + std::size_t nan_size = 4; + const char *nan = upper ? " NAN" : " nan"; + if (!sign) { + --nan_size; + ++nan; + } + CharPtr out = write_str(nan, nan_size, spec); + if (sign) + *out = sign; + return; + } + + if (internal::FPUtil::isinfinity(value)) { + // Format infinity ourselves because sprintf's output is not consistent + // across platforms. + std::size_t inf_size = 4; + const char *inf = upper ? " INF" : " inf"; + if (!sign) { + --inf_size; + ++inf; + } + CharPtr out = write_str(inf, inf_size, spec); + if (sign) + *out = sign; + return; + } + + std::size_t offset = buffer_.size(); + unsigned width = spec.width(); + if (sign) { + buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u)); + if (width > 0) + --width; + ++offset; + } + + // Build format string. + enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg + Char format[MAX_FORMAT_SIZE]; + Char *format_ptr = format; + *format_ptr++ = '%'; + unsigned width_for_sprintf = width; + if (spec.flag(HASH_FLAG)) + *format_ptr++ = '#'; + if (spec.align() == ALIGN_CENTER) { + width_for_sprintf = 0; + } else { + if (spec.align() == ALIGN_LEFT) + *format_ptr++ = '-'; + if (width != 0) + *format_ptr++ = '*'; + } + if (spec.precision() >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + + append_float_length(format_ptr, value); + *format_ptr++ = type; + *format_ptr = '\0'; + + // Format using snprintf. + Char fill = internal::CharTraits<Char>::cast(spec.fill()); + unsigned n = 0; + Char *start = 0; + for (;;) { + std::size_t buffer_size = buffer_.capacity() - offset; +#if FMT_MSC_VER + // MSVC's vsnprintf_s doesn't work with zero size, so reserve + // space for at least one extra character to make the size non-zero. + // Note that the buffer's capacity will increase by more than 1. + if (buffer_size == 0) { + buffer_.reserve(offset + 1); + buffer_size = buffer_.capacity() - offset; + } +#endif + start = &buffer_[offset]; + int result = internal::CharTraits<Char>::format_float( + start, buffer_size, format, width_for_sprintf, spec.precision(), value); + if (result >= 0) { + n = internal::to_unsigned(result); + if (offset + n < buffer_.capacity()) + break; // The buffer is large enough - continue with formatting. + buffer_.reserve(offset + n + 1); + } else { + // If result is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buffer_.reserve(buffer_.capacity() + 1); + } + } + if (sign) { + if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || + *start != ' ') { + *(start - 1) = sign; + sign = 0; + } else { + *(start - 1) = fill; + } + ++n; + } + if (spec.align() == ALIGN_CENTER && spec.width() > n) { + width = spec.width(); + CharPtr p = grow_buffer(width); + std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); + fill_padding(p, spec.width(), n, fill); + return; + } + if (spec.fill() != ' ' || sign) { + while (*start == ' ') + *start++ = fill; + if (sign) + *(start - 1) = sign; + } + grow_buffer(n); +} + +/** + \rst + This class template provides operations for formatting and writing data + into a character stream. The output is stored in a memory buffer that grows + dynamically. + + You can use one of the following typedefs for common character types + and the standard allocator: + + +---------------+-----------------------------------------------------+ + | Type | Definition | + +===============+=====================================================+ + | MemoryWriter | BasicMemoryWriter<char, std::allocator<char>> | + +---------------+-----------------------------------------------------+ + | WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> | + +---------------+-----------------------------------------------------+ + + **Example**:: + + MemoryWriter out; + out << "The answer is " << 42 << "\n"; + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42 + (-3.140000, +3.140000) + + The output can be converted to an ``std::string`` with ``out.str()`` or + accessed as a C string with ``out.c_str()``. + \endrst + */ +template <typename Char, typename Allocator = std::allocator<Char> > +class BasicMemoryWriter : public BasicWriter<Char> { + private: + internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_; + + public: + explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) + : BasicWriter<Char>(buffer_), buffer_(alloc) {} + +#if FMT_USE_RVALUE_REFERENCES + /** + \rst + Constructs a :class:`fmt::BasicMemoryWriter` object moving the content + of the other object to it. + \endrst + */ + BasicMemoryWriter(BasicMemoryWriter &&other) + : BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) { + } + + /** + \rst + Moves the content of the other ``BasicMemoryWriter`` object to this one. + \endrst + */ + BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { + buffer_ = std::move(other.buffer_); + return *this; + } +#endif +}; + +typedef BasicMemoryWriter<char> MemoryWriter; +typedef BasicMemoryWriter<wchar_t> WMemoryWriter; + +/** + \rst + This class template provides operations for formatting and writing data + into a fixed-size array. For writing into a dynamically growing buffer + use :class:`fmt::BasicMemoryWriter`. + + Any write method will throw ``std::runtime_error`` if the output doesn't fit + into the array. + + You can use one of the following typedefs for common character types: + + +--------------+---------------------------+ + | Type | Definition | + +==============+===========================+ + | ArrayWriter | BasicArrayWriter<char> | + +--------------+---------------------------+ + | WArrayWriter | BasicArrayWriter<wchar_t> | + +--------------+---------------------------+ + \endrst + */ +template <typename Char> +class BasicArrayWriter : public BasicWriter<Char> { + private: + internal::FixedBuffer<Char> buffer_; + + public: + /** + \rst + Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the + given size. + \endrst + */ + BasicArrayWriter(Char *array, std::size_t size) + : BasicWriter<Char>(buffer_), buffer_(array, size) {} + + /** + \rst + Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the + size known at compile time. + \endrst + */ + template <std::size_t SIZE> + explicit BasicArrayWriter(Char (&array)[SIZE]) + : BasicWriter<Char>(buffer_), buffer_(array, SIZE) {} +}; + +typedef BasicArrayWriter<char> ArrayWriter; +typedef BasicArrayWriter<wchar_t> WArrayWriter; + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_system_error(int error_code, + StringRef message) FMT_NOEXCEPT; + +#if FMT_USE_WINDOWS_H + +/** A Windows error. */ +class WindowsError : public SystemError { + private: + FMT_API void init(int error_code, CStringRef format_str, ArgList args); + + public: + /** + \rst + Constructs a :class:`fmt::WindowsError` object with the description + of the form + + .. parsed-literal:: + *<message>*: *<system-message>* + + where *<message>* is the formatted message and *<system-message>* is the + system message corresponding to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + If *error_code* is not a valid error code such as -1, the system message + will look like "error -1". + + **Example**:: + + // This throws a WindowsError with the description + // cannot open file 'madeup': The system cannot find the file specified. + // or similar (system message may vary). + const char *filename = "madeup"; + LPOFSTRUCT of = LPOFSTRUCT(); + HFILE file = OpenFile(filename, &of, OF_READ); + if (file == HFILE_ERROR) { + throw fmt::WindowsError(GetLastError(), + "cannot open file '{}'", filename); + } + \endrst + */ + WindowsError(int error_code, CStringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) +}; + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_windows_error(int error_code, + StringRef message) FMT_NOEXCEPT; + +#endif + +enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; + +/** + Formats a string and prints it to stdout using ANSI escape sequences + to specify color (experimental). + Example: + print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); + */ +FMT_API void print_colored(Color c, CStringRef format, ArgList args); + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = format("The answer is {}", 42); + \endrst +*/ +inline std::string format(CStringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + return w.str(); +} + +inline std::wstring format(WCStringRef format_str, ArgList args) { + WMemoryWriter w; + w.write(format_str, args); + return w.str(); +} + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + print(stderr, "Don't {}!", "panic"); + \endrst + */ +FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +FMT_API void print(CStringRef format_str, ArgList args); + +template <typename Char> +void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) { + internal::PrintfFormatter<Char>(args).format(w, format); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = fmt::sprintf("The answer is %d", 42); + \endrst +*/ +inline std::string sprintf(CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + return w.str(); +} + +inline std::wstring sprintf(WCStringRef format, ArgList args) { + WMemoryWriter w; + printf(w, format, args); + return w.str(); +} + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::fprintf(stderr, "Don't %s!", "panic"); + \endrst + */ +FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::printf("Elapsed time: %.2f seconds", 1.23); + \endrst + */ +inline int printf(CStringRef format, ArgList args) { + return fprintf(stdout, format, args); +} + +/** + Fast integer formatter. + */ +class FormatInt { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum {BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3}; + mutable char buffer_[BUFFER_SIZE]; + char *str_; + + // Formats value in reverse and returns the number of digits. + char *format_decimal(ULongLong value) { + char *buffer_end = buffer_ + BUFFER_SIZE - 1; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = static_cast<unsigned>((value % 100) * 2); + value /= 100; + *--buffer_end = internal::Data::DIGITS[index + 1]; + *--buffer_end = internal::Data::DIGITS[index]; + } + if (value < 10) { + *--buffer_end = static_cast<char>('0' + value); + return buffer_end; + } + unsigned index = static_cast<unsigned>(value * 2); + *--buffer_end = internal::Data::DIGITS[index + 1]; + *--buffer_end = internal::Data::DIGITS[index]; + return buffer_end; + } + + void FormatSigned(LongLong value) { + ULongLong abs_value = static_cast<ULongLong>(value); + bool negative = value < 0; + if (negative) + abs_value = 0 - abs_value; + str_ = format_decimal(abs_value); + if (negative) + *--str_ = '-'; + } + + public: + explicit FormatInt(int value) { FormatSigned(value); } + explicit FormatInt(long value) { FormatSigned(value); } + explicit FormatInt(LongLong value) { FormatSigned(value); } + explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} + explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} + explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} + + /** Returns the number of characters written to the output buffer. */ + std::size_t size() const { + return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); + } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const char *data() const { return str_; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const char *c_str() const { + buffer_[BUFFER_SIZE - 1] = '\0'; + return str_; + } + + /** + \rst + Returns the content of the output buffer as an ``std::string``. + \endrst + */ + std::string str() const { return std::string(str_, size()); } +}; + +// Formats a decimal integer value writing into buffer and returns +// a pointer to the end of the formatted string. This function doesn't +// write a terminating null character. +template <typename T> +inline void format_decimal(char *&buffer, T value) { + typedef typename internal::IntTraits<T>::MainType MainType; + MainType abs_value = static_cast<MainType>(value); + if (internal::is_negative(value)) { + *buffer++ = '-'; + abs_value = 0 - abs_value; + } + if (abs_value < 100) { + if (abs_value < 10) { + *buffer++ = static_cast<char>('0' + abs_value); + return; + } + unsigned index = static_cast<unsigned>(abs_value * 2); + *buffer++ = internal::Data::DIGITS[index]; + *buffer++ = internal::Data::DIGITS[index + 1]; + return; + } + unsigned num_digits = internal::count_digits(abs_value); + internal::format_decimal(buffer, abs_value, num_digits); + buffer += num_digits; +} + +/** + \rst + Returns a named argument for formatting functions. + + **Example**:: + + print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); + + \endrst + */ +template <typename T> +inline internal::NamedArg<char> arg(StringRef name, const T &arg) { + return internal::NamedArg<char>(name, arg); +} + +template <typename T> +inline internal::NamedArg<wchar_t> arg(WStringRef name, const T &arg) { + return internal::NamedArg<wchar_t>(name, arg); +} + +// The following two functions are deleted intentionally to disable +// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. +template <typename Char> +void arg(StringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; +template <typename Char> +void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; +} + +#if FMT_GCC_VERSION +// Use the system_header pragma to suppress warnings about variadic macros +// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't +// work. It is used at the end because we want to suppress as little warnings +// as possible. +# pragma GCC system_header +#endif + +// This is used to work around VC++ bugs in handling variadic macros. +#define FMT_EXPAND(args) args + +// Returns the number of arguments. +// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. +#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) +#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) +#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define FMT_CONCAT(a, b) a##b +#define FMT_FOR_EACH_(N, f, ...) \ + FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) +#define FMT_FOR_EACH(f, ...) \ + FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) + +#define FMT_ADD_ARG_NAME(type, index) type arg##index +#define FMT_GET_ARG_NAME(type, index) arg##index + +#if FMT_USE_VARIADIC_TEMPLATES +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + template <typename... Args> \ + ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + const Args & ... args) { \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ + fmt::ArgList(fmt::internal::make_type(args...), array)); \ + } +#else +// Defines a wrapper for a function taking __VA_ARGS__ arguments +// and n additional arguments of arbitrary types. +# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ + template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + FMT_GEN(n, FMT_MAKE_ARG)) { \ + fmt::internal::ArgArray<n>::Type arr; \ + FMT_GEN(n, FMT_ASSIGN_##Char); \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ + } + +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ + } \ + FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) +#endif // FMT_USE_VARIADIC_TEMPLATES + +/** + \rst + Defines a variadic function with the specified return type, function name + and argument types passed as variable arguments to this macro. + + **Example**:: + + void print_error(const char *file, int line, const char *format, + fmt::ArgList args) { + fmt::print("{}: {}: ", file, line); + fmt::print(format, args); + } + FMT_VARIADIC(void, print_error, const char *, int, const char *) + + ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that + don't implement variadic templates. You don't have to use this macro if + you don't need legacy compiler support and can use variadic templates + directly:: + + template <typename... Args> + void print_error(const char *file, int line, const char *format, + const Args & ... args) { + fmt::print("{}: {}: ", file, line); + fmt::print(format, args...); + } + \endrst + */ +#define FMT_VARIADIC(ReturnType, func, ...) \ + FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_VARIADIC_W(ReturnType, func, ...) \ + FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) + +#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) + +/** + \rst + Convenient macro to capture the arguments' names and values into several + ``fmt::arg(name, value)``. + + **Example**:: + + int x = 1, y = 2; + print("point: ({x}, {y})", FMT_CAPTURE(x, y)); + // same as: + // print("point: ({x}, {y})", arg("x", x), arg("y", y)); + + \endrst + */ +#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) + +#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) + +namespace fmt { +FMT_VARIADIC(std::string, format, CStringRef) +FMT_VARIADIC_W(std::wstring, format, WCStringRef) +FMT_VARIADIC(void, print, CStringRef) +FMT_VARIADIC(void, print, std::FILE *, CStringRef) + +FMT_VARIADIC(void, print_colored, Color, CStringRef) +FMT_VARIADIC(std::string, sprintf, CStringRef) +FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) +FMT_VARIADIC(int, printf, CStringRef) +FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) + +namespace internal { +template <typename Char> +inline bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; +} + +// Parses an unsigned integer advancing s to the end of the parsed input. +// This function assumes that the first character of s is a digit. +template <typename Char> +unsigned parse_nonnegative_int(const Char *&s) { + assert('0' <= *s && *s <= '9'); + unsigned value = 0; + do { + unsigned new_value = value * 10 + (*s++ - '0'); + // Check if value wrapped around. + if (new_value < value) { + value = (std::numeric_limits<unsigned>::max)(); + break; + } + value = new_value; + } while ('0' <= *s && *s <= '9'); + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits<int>::max)(); + if (value > max_int) + FMT_THROW(FormatError("number is too big")); + return value; +} + +inline void require_numeric_argument(const Arg &arg, char spec) { + if (arg.type > Arg::LAST_NUMERIC_TYPE) { + std::string message = + fmt::format("format specifier '{}' requires numeric argument", spec); + FMT_THROW(fmt::FormatError(message)); + } +} + +template <typename Char> +void check_sign(const Char *&s, const Arg &arg) { + char sign = static_cast<char>(*s); + require_numeric_argument(arg, sign); + if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { + FMT_THROW(FormatError(fmt::format( + "format specifier '{}' requires signed argument", sign))); + } + ++s; +} +} // namespace internal + +template <typename Char, typename AF> +inline internal::Arg BasicFormatter<Char, AF>::get_arg( + BasicStringRef<Char> arg_name, const char *&error) { + if (check_no_auto_index(error)) { + map_.init(args()); + const internal::Arg *arg = map_.find(arg_name); + if (arg) + return *arg; + error = "argument not found"; + } + return internal::Arg(); +} + +template <typename Char, typename AF> +inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s) { + const char *error = 0; + internal::Arg arg = *s < '0' || *s > '9' ? + next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); + if (error) { + FMT_THROW(FormatError( + *s != '}' && *s != ':' ? "invalid format string" : error)); + } + return arg; +} + +template <typename Char, typename AF> +inline internal::Arg BasicFormatter<Char, AF>::parse_arg_name(const Char *&s) { + assert(internal::is_name_start(*s)); + const Char *start = s; + Char c; + do { + c = *++s; + } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); + const char *error = 0; + internal::Arg arg = get_arg(BasicStringRef<Char>(start, s - start), error); + if (error) + FMT_THROW(FormatError(error)); + return arg; +} + +template <typename Char, typename ArgFormatter> +const Char *BasicFormatter<Char, ArgFormatter>::format( + const Char *&format_str, const internal::Arg &arg) { + using internal::Arg; + const Char *s = format_str; + FormatSpec spec; + if (*s == ':') { + if (arg.type == Arg::CUSTOM) { + arg.custom.format(this, arg.custom.value, &s); + return s; + } + ++s; + // Parse fill and alignment. + if (Char c = *s) { + const Char *p = s + 1; + spec.align_ = ALIGN_DEFAULT; + do { + switch (*p) { + case '<': + spec.align_ = ALIGN_LEFT; + break; + case '>': + spec.align_ = ALIGN_RIGHT; + break; + case '=': + spec.align_ = ALIGN_NUMERIC; + break; + case '^': + spec.align_ = ALIGN_CENTER; + break; + } + if (spec.align_ != ALIGN_DEFAULT) { + if (p != s) { + if (c == '}') break; + if (c == '{') + FMT_THROW(FormatError("invalid fill character '{'")); + s += 2; + spec.fill_ = c; + } else ++s; + if (spec.align_ == ALIGN_NUMERIC) + require_numeric_argument(arg, '='); + break; + } + } while (--p >= s); + } + + // Parse sign. + switch (*s) { + case '+': + check_sign(s, arg); + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '-': + check_sign(s, arg); + spec.flags_ |= MINUS_FLAG; + break; + case ' ': + check_sign(s, arg); + spec.flags_ |= SIGN_FLAG; + break; + } + + if (*s == '#') { + require_numeric_argument(arg, '#'); + spec.flags_ |= HASH_FLAG; + ++s; + } + + // Parse zero flag. + if (*s == '0') { + require_numeric_argument(arg, '0'); + spec.align_ = ALIGN_NUMERIC; + spec.fill_ = '0'; + ++s; + } + + // Parse width. + if ('0' <= *s && *s <= '9') { + spec.width_ = internal::parse_nonnegative_int(s); + } else if (*s == '{') { + ++s; + Arg width_arg = internal::is_name_start(*s) ? + parse_arg_name(s) : parse_arg_index(s); + if (*s++ != '}') + FMT_THROW(FormatError("invalid format string")); + ULongLong value = 0; + switch (width_arg.type) { + case Arg::INT: + if (width_arg.int_value < 0) + FMT_THROW(FormatError("negative width")); + value = width_arg.int_value; + break; + case Arg::UINT: + value = width_arg.uint_value; + break; + case Arg::LONG_LONG: + if (width_arg.long_long_value < 0) + FMT_THROW(FormatError("negative width")); + value = width_arg.long_long_value; + break; + case Arg::ULONG_LONG: + value = width_arg.ulong_long_value; + break; + default: + FMT_THROW(FormatError("width is not integer")); + } + if (value > (std::numeric_limits<int>::max)()) + FMT_THROW(FormatError("number is too big")); + spec.width_ = static_cast<int>(value); + } + + // Parse precision. + if (*s == '.') { + ++s; + spec.precision_ = 0; + if ('0' <= *s && *s <= '9') { + spec.precision_ = internal::parse_nonnegative_int(s); + } else if (*s == '{') { + ++s; + Arg precision_arg = internal::is_name_start(*s) ? + parse_arg_name(s) : parse_arg_index(s); + if (*s++ != '}') + FMT_THROW(FormatError("invalid format string")); + ULongLong value = 0; + switch (precision_arg.type) { + case Arg::INT: + if (precision_arg.int_value < 0) + FMT_THROW(FormatError("negative precision")); + value = precision_arg.int_value; + break; + case Arg::UINT: + value = precision_arg.uint_value; + break; + case Arg::LONG_LONG: + if (precision_arg.long_long_value < 0) + FMT_THROW(FormatError("negative precision")); + value = precision_arg.long_long_value; + break; + case Arg::ULONG_LONG: + value = precision_arg.ulong_long_value; + break; + default: + FMT_THROW(FormatError("precision is not integer")); + } + if (value > (std::numeric_limits<int>::max)()) + FMT_THROW(FormatError("number is too big")); + spec.precision_ = static_cast<int>(value); + } else { + FMT_THROW(FormatError("missing precision specifier")); + } + if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { + FMT_THROW(FormatError( + fmt::format("precision not allowed in {} format specifier", + arg.type == Arg::POINTER ? "pointer" : "integer"))); + } + } + + // Parse type. + if (*s != '}' && *s) + spec.type_ = static_cast<char>(*s++); + } + + if (*s++ != '}') + FMT_THROW(FormatError("missing '}' in format string")); + + // Format argument. + ArgFormatter(*this, spec, s - 1).visit(arg); + return s; +} + +template <typename Char, typename AF> +void BasicFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) { + const Char *s = format_str.c_str(); + const Char *start = s; + while (*s) { + Char c = *s++; + if (c != '{' && c != '}') continue; + if (*s == c) { + write(writer_, start, s); + start = ++s; + continue; + } + if (c == '}') + FMT_THROW(FormatError("unmatched '}' in format string")); + write(writer_, start, s - 1); + internal::Arg arg = internal::is_name_start(*s) ? + parse_arg_name(s) : parse_arg_index(s); + start = s = format(s, arg); + } + write(writer_, start, s); +} +} // namespace fmt + +#if FMT_USE_USER_DEFINED_LITERALS +namespace fmt { +namespace internal { + +template <typename Char> +struct UdlFormat { + const Char *str; + + template <typename... Args> + auto operator()(Args && ... args) const + -> decltype(format(str, std::forward<Args>(args)...)) { + return format(str, std::forward<Args>(args)...); + } +}; + +template <typename Char> +struct UdlArg { + const Char *str; + + template <typename T> + NamedArg<Char> operator=(T &&value) const { + return {str, std::forward<T>(value)}; + } +}; + +} // namespace internal + +inline namespace literals { + +/** + \rst + C++11 literal equivalent of :func:`fmt::format`. + + **Example**:: + + using namespace fmt::literals; + std::string message = "The answer is {}"_format(42); + \endrst + */ +inline internal::UdlFormat<char> +operator"" _format(const char *s, std::size_t) { return {s}; } +inline internal::UdlFormat<wchar_t> +operator"" _format(const wchar_t *s, std::size_t) { return {s}; } + +/** + \rst + C++11 literal equivalent of :func:`fmt::arg`. + + **Example**:: + + using namespace fmt::literals; + print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); + \endrst + */ +inline internal::UdlArg<char> +operator"" _a(const char *s, std::size_t) { return {s}; } +inline internal::UdlArg<wchar_t> +operator"" _a(const wchar_t *s, std::size_t) { return {s}; } + +} // inline namespace literals +} // namespace fmt +#endif // FMT_USE_USER_DEFINED_LITERALS + +// Restore warnings. +#if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic pop +#endif + +#if defined(__clang__) && !defined(FMT_ICC_VERSION) +# pragma clang diagnostic pop +#endif + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +# include "format.cc" +#else +# define FMT_FUNC +#endif + +#endif // FMT_FORMAT_H_ diff --git a/vendor/fmt-3.0.1/fmt/ostream.cc b/vendor/fmt-3.0.1/fmt/ostream.cc new file mode 100644 index 00000000..bcb67fe1 --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/ostream.cc @@ -0,0 +1,43 @@ +/* + Formatting library for C++ - std::ostream support + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#include "ostream.h" + +namespace fmt { + +namespace { +// Write the content of w to os. +void write(std::ostream &os, Writer &w) { + const char *data = w.data(); + typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; + UnsignedStreamSize size = w.size(); + UnsignedStreamSize max_size = + internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); + do { + UnsignedStreamSize n = size <= max_size ? size : max_size; + os.write(data, static_cast<std::streamsize>(n)); + data += n; + size -= n; + } while (size != 0); +} +} + +FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + write(os, w); +} + +FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + write(os, w); + return static_cast<int>(w.size()); +} +} // namespace fmt diff --git a/vendor/fmt-3.0.1/fmt/ostream.h b/vendor/fmt-3.0.1/fmt/ostream.h new file mode 100644 index 00000000..29483c1b --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/ostream.h @@ -0,0 +1,115 @@ +/* + Formatting library for C++ - std::ostream support + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_OSTREAM_H_ +#define FMT_OSTREAM_H_ + +#include "format.h" +#include <ostream> + +namespace fmt { + +namespace internal { + +template <class Char> +class FormatBuf : public std::basic_streambuf<Char> { + private: + typedef typename std::basic_streambuf<Char>::int_type int_type; + typedef typename std::basic_streambuf<Char>::traits_type traits_type; + + Buffer<Char> &buffer_; + Char *start_; + + public: + FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) { + this->setp(start_, start_ + buffer_.capacity()); + } + + int_type overflow(int_type ch = traits_type::eof()) { + if (!traits_type::eq_int_type(ch, traits_type::eof())) { + size_t buf_size = size(); + buffer_.resize(buf_size); + buffer_.reserve(buf_size * 2); + + start_ = &buffer_[0]; + start_[buf_size] = traits_type::to_char_type(ch); + this->setp(start_+ buf_size + 1, start_ + buf_size * 2); + } + return ch; + } + + size_t size() const { + return to_unsigned(this->pptr() - start_); + } +}; + +Yes &convert(std::ostream &); + +struct DummyStream : std::ostream { + DummyStream(); // Suppress a bogus warning in MSVC. + // Hide all operator<< overloads from std::ostream. + void operator<<(Null<>); +}; + +No &operator<<(std::ostream &, int); + +template<typename T> +struct ConvertToIntImpl<T, true> { + // Convert to int only if T doesn't have an overloaded operator<<. + enum { + value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No) + }; +}; +} // namespace internal + +// Formats a value. +template <typename Char, typename ArgFormatter, typename T> +void format(BasicFormatter<Char, ArgFormatter> &f, + const Char *&format_str, const T &value) { + internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; + + internal::FormatBuf<Char> format_buf(buffer); + std::basic_ostream<Char> output(&format_buf); + output << value; + + BasicStringRef<Char> str(&buffer[0], format_buf.size()); + typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; + format_str = f.format(format_str, MakeArg(str)); +} + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + print(cerr, "Don't {}!", "panic"); + \endrst + */ +FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); +FMT_VARIADIC(void, print, std::ostream &, CStringRef) + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fprintf(cerr, "Don't %s!", "panic"); + \endrst + */ +FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); +FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) +} // namespace fmt + +#ifdef FMT_HEADER_ONLY +# include "ostream.cc" +#endif + +#endif // FMT_OSTREAM_H_ diff --git a/vendor/fmt-3.0.1/fmt/posix.cc b/vendor/fmt-3.0.1/fmt/posix.cc new file mode 100644 index 00000000..76eb7f05 --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/posix.cc @@ -0,0 +1,238 @@ +/* + A C++ interface to POSIX functions. + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +// Disable bogus MSVC warnings. +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include "posix.h" + +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifndef _WIN32 +# include <unistd.h> +#else +# include <windows.h> +# include <io.h> + +# define O_CREAT _O_CREAT +# define O_TRUNC _O_TRUNC + +# ifndef S_IRUSR +# define S_IRUSR _S_IREAD +# endif + +# ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +# endif + +# ifdef __MINGW32__ +# define _SH_DENYNO 0x40 +# endif + +#endif // _WIN32 + +#ifdef fileno +# undef fileno +#endif + +namespace { +#ifdef _WIN32 +// Return type of read and write functions. +typedef int RWResult; + +// On Windows the count argument to read and write is unsigned, so convert +// it from size_t preventing integer overflow. +inline unsigned convert_rwcount(std::size_t count) { + return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX; +} +#else +// Return type of read and write functions. +typedef ssize_t RWResult; + +inline std::size_t convert_rwcount(std::size_t count) { return count; } +#endif +} + +fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { + if (file_ && FMT_SYSTEM(fclose(file_)) != 0) + fmt::report_system_error(errno, "cannot close file"); +} + +fmt::BufferedFile::BufferedFile( + fmt::CStringRef filename, fmt::CStringRef mode) { + FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); + if (!file_) + FMT_THROW(SystemError(errno, "cannot open file {}", filename)); +} + +void fmt::BufferedFile::close() { + if (!file_) + return; + int result = FMT_SYSTEM(fclose(file_)); + file_ = 0; + if (result != 0) + FMT_THROW(SystemError(errno, "cannot close file")); +} + +// A macro used to prevent expansion of fileno on broken versions of MinGW. +#define FMT_ARGS + +int fmt::BufferedFile::fileno() const { + int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); + if (fd == -1) + FMT_THROW(SystemError(errno, "cannot get file descriptor")); + return fd; +} + +fmt::File::File(fmt::CStringRef path, int oflag) { + int mode = S_IRUSR | S_IWUSR; +#if defined(_WIN32) && !defined(__MINGW32__) + fd_ = -1; + FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); +#else + FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); +#endif + if (fd_ == -1) + FMT_THROW(SystemError(errno, "cannot open file {}", path)); +} + +fmt::File::~File() FMT_NOEXCEPT { + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) + fmt::report_system_error(errno, "cannot close file"); +} + +void fmt::File::close() { + if (fd_ == -1) + return; + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + int result = FMT_POSIX_CALL(close(fd_)); + fd_ = -1; + if (result != 0) + FMT_THROW(SystemError(errno, "cannot close file")); +} + +fmt::LongLong fmt::File::size() const { +#ifdef _WIN32 + // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT + // is less than 0x0500 as is the case with some default MinGW builds. + // Both functions support large file sizes. + DWORD size_upper = 0; + HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_)); + DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); + if (size_lower == INVALID_FILE_SIZE) { + DWORD error = GetLastError(); + if (error != NO_ERROR) + FMT_THROW(WindowsError(GetLastError(), "cannot get file size")); + } + fmt::ULongLong long_size = size_upper; + return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; +#else + typedef struct stat Stat; + Stat file_stat = Stat(); + if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) + FMT_THROW(SystemError(errno, "cannot get file attributes")); + FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size), + "return type of File::size is not large enough"); + return file_stat.st_size; +#endif +} + +std::size_t fmt::File::read(void *buffer, std::size_t count) { + RWResult result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); + if (result < 0) + FMT_THROW(SystemError(errno, "cannot read from file")); + return internal::to_unsigned(result); +} + +std::size_t fmt::File::write(const void *buffer, std::size_t count) { + RWResult result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); + if (result < 0) + FMT_THROW(SystemError(errno, "cannot write to file")); + return internal::to_unsigned(result); +} + +fmt::File fmt::File::dup(int fd) { + // Don't retry as dup doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html + int new_fd = FMT_POSIX_CALL(dup(fd)); + if (new_fd == -1) + FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd)); + return File(new_fd); +} + +void fmt::File::dup2(int fd) { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) { + FMT_THROW(SystemError(errno, + "cannot duplicate file descriptor {} to {}", fd_, fd)); + } +} + +void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) + ec = ErrorCode(errno); +} + +void fmt::File::pipe(File &read_end, File &write_end) { + // Close the descriptors first to make sure that assignments don't throw + // and there are no leaks. + read_end.close(); + write_end.close(); + int fds[2] = {}; +#ifdef _WIN32 + // Make the default pipe capacity same as on Linux 2.6.11+. + enum { DEFAULT_CAPACITY = 65536 }; + int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); +#else + // Don't retry as the pipe function doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html + int result = FMT_POSIX_CALL(pipe(fds)); +#endif + if (result != 0) + FMT_THROW(SystemError(errno, "cannot create pipe")); + // The following assignments don't throw because read_fd and write_fd + // are closed. + read_end = File(fds[0]); + write_end = File(fds[1]); +} + +fmt::BufferedFile fmt::File::fdopen(const char *mode) { + // Don't retry as fdopen doesn't return EINTR. + FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); + if (!f) + FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor")); + BufferedFile file(f); + fd_ = -1; + return file; +} + +long fmt::getpagesize() { +#ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +#else + long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); + if (size < 0) + FMT_THROW(SystemError(errno, "cannot get memory page size")); + return size; +#endif +} diff --git a/vendor/fmt-3.0.1/fmt/posix.h b/vendor/fmt-3.0.1/fmt/posix.h new file mode 100644 index 00000000..be1286c4 --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/posix.h @@ -0,0 +1,386 @@ +/* + A C++ interface to POSIX functions. + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_POSIX_H_ +#define FMT_POSIX_H_ + +#if defined(__MINGW32__) || defined(__CYGWIN__) +// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. +# undef __STRICT_ANSI__ +#endif + +#include <errno.h> +#include <fcntl.h> // for O_RDONLY +#include <locale.h> // for locale_t +#include <stdio.h> +#include <stdlib.h> // for strtod_l + +#include <cstddef> + +#if defined __APPLE__ || defined(__FreeBSD__) +# include <xlocale.h> // for LC_NUMERIC_MASK on OS X +#endif + +#include "format.h" + +#ifndef FMT_POSIX +# if defined(_WIN32) && !defined(__MINGW32__) +// Fix warnings about deprecated symbols. +# define FMT_POSIX(call) _##call +# else +# define FMT_POSIX(call) call +# endif +#endif + +// Calls to system functions are wrapped in FMT_SYSTEM for testability. +#ifdef FMT_SYSTEM +# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) +#else +# define FMT_SYSTEM(call) call +# ifdef _WIN32 +// Fix warnings about deprecated symbols. +# define FMT_POSIX_CALL(call) ::_##call +# else +# define FMT_POSIX_CALL(call) ::call +# endif +#endif + +#if FMT_GCC_VERSION >= 407 +# define FMT_UNUSED __attribute__((unused)) +#else +# define FMT_UNUSED +#endif + +#ifndef FMT_USE_STATIC_ASSERT +# define FMT_USE_STATIC_ASSERT 0 +#endif + +#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 +# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) +#else +# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) +# define FMT_STATIC_ASSERT(cond, message) \ + typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED +#endif + +// Retries the expression while it evaluates to error_result and errno +// equals to EINTR. +#ifndef _WIN32 +# define FMT_RETRY_VAL(result, expression, error_result) \ + do { \ + result = (expression); \ + } while (result == error_result && errno == EINTR) +#else +# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) +#endif + +#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) + +namespace fmt { + +// An error code. +class ErrorCode { + private: + int value_; + + public: + explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {} + + int get() const FMT_NOEXCEPT { return value_; } +}; + +// A buffered file. +class BufferedFile { + private: + FILE *file_; + + friend class File; + + explicit BufferedFile(FILE *f) : file_(f) {} + + public: + // Constructs a BufferedFile object which doesn't represent any file. + BufferedFile() FMT_NOEXCEPT : file_(0) {} + + // Destroys the object closing the file it represents if any. + ~BufferedFile() FMT_NOEXCEPT; + +#if !FMT_USE_RVALUE_REFERENCES + // Emulate a move constructor and a move assignment operator if rvalue + // references are not supported. + + private: + // A proxy object to emulate a move constructor. + // It is private to make it impossible call operator Proxy directly. + struct Proxy { + FILE *file; + }; + +public: + // A "move constructor" for moving from a temporary. + BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} + + // A "move constructor" for moving from an lvalue. + BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { + f.file_ = 0; + } + + // A "move assignment operator" for moving from a temporary. + BufferedFile &operator=(Proxy p) { + close(); + file_ = p.file; + return *this; + } + + // A "move assignment operator" for moving from an lvalue. + BufferedFile &operator=(BufferedFile &other) { + close(); + file_ = other.file_; + other.file_ = 0; + return *this; + } + + // Returns a proxy object for moving from a temporary: + // BufferedFile file = BufferedFile(...); + operator Proxy() FMT_NOEXCEPT { + Proxy p = {file_}; + file_ = 0; + return p; + } + +#else + private: + FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); + + public: + BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { + other.file_ = 0; + } + + BufferedFile& operator=(BufferedFile &&other) { + close(); + file_ = other.file_; + other.file_ = 0; + return *this; + } +#endif + + // Opens a file. + BufferedFile(CStringRef filename, CStringRef mode); + + // Closes the file. + void close(); + + // Returns the pointer to a FILE object representing this file. + FILE *get() const FMT_NOEXCEPT { return file_; } + + // We place parentheses around fileno to workaround a bug in some versions + // of MinGW that define fileno as a macro. + int (fileno)() const; + + void print(CStringRef format_str, const ArgList &args) { + fmt::print(file_, format_str, args); + } + FMT_VARIADIC(void, print, CStringRef) +}; + +// A file. Closed file is represented by a File object with descriptor -1. +// Methods that are not declared with FMT_NOEXCEPT may throw +// fmt::SystemError in case of failure. Note that some errors such as +// closing the file multiple times will cause a crash on Windows rather +// than an exception. You can get standard behavior by overriding the +// invalid parameter handler with _set_invalid_parameter_handler. +class File { + private: + int fd_; // File descriptor. + + // Constructs a File object with a given descriptor. + explicit File(int fd) : fd_(fd) {} + + public: + // Possible values for the oflag argument to the constructor. + enum { + RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. + WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. + RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. + }; + + // Constructs a File object which doesn't represent any file. + File() FMT_NOEXCEPT : fd_(-1) {} + + // Opens a file and constructs a File object representing this file. + File(CStringRef path, int oflag); + +#if !FMT_USE_RVALUE_REFERENCES + // Emulate a move constructor and a move assignment operator if rvalue + // references are not supported. + + private: + // A proxy object to emulate a move constructor. + // It is private to make it impossible call operator Proxy directly. + struct Proxy { + int fd; + }; + + public: + // A "move constructor" for moving from a temporary. + File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} + + // A "move constructor" for moving from an lvalue. + File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { + other.fd_ = -1; + } + + // A "move assignment operator" for moving from a temporary. + File &operator=(Proxy p) { + close(); + fd_ = p.fd; + return *this; + } + + // A "move assignment operator" for moving from an lvalue. + File &operator=(File &other) { + close(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } + + // Returns a proxy object for moving from a temporary: + // File file = File(...); + operator Proxy() FMT_NOEXCEPT { + Proxy p = {fd_}; + fd_ = -1; + return p; + } + +#else + private: + FMT_DISALLOW_COPY_AND_ASSIGN(File); + + public: + File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) { + other.fd_ = -1; + } + + File& operator=(File &&other) { + close(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } +#endif + + // Destroys the object closing the file it represents if any. + ~File() FMT_NOEXCEPT; + + // Returns the file descriptor. + int descriptor() const FMT_NOEXCEPT { return fd_; } + + // Closes the file. + void close(); + + // Returns the file size. The size has signed type for consistency with + // stat::st_size. + LongLong size() const; + + // Attempts to read count bytes from the file into the specified buffer. + std::size_t read(void *buffer, std::size_t count); + + // Attempts to write count bytes from the specified buffer to the file. + std::size_t write(const void *buffer, std::size_t count); + + // Duplicates a file descriptor with the dup function and returns + // the duplicate as a file object. + static File dup(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; + + // Creates a pipe setting up read_end and write_end file objects for reading + // and writing respectively. + static void pipe(File &read_end, File &write_end); + + // Creates a BufferedFile object associated with this file and detaches + // this File object from the file. + BufferedFile fdopen(const char *mode); +}; + +// Returns the memory page size. +long getpagesize(); + +#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ + !defined(__ANDROID__) && !defined(__CYGWIN__) +# define FMT_LOCALE +#endif + +#ifdef FMT_LOCALE +// A "C" numeric locale. +class Locale { + private: +# ifdef _MSC_VER + typedef _locale_t locale_t; + + enum { LC_NUMERIC_MASK = LC_NUMERIC }; + + static locale_t newlocale(int category_mask, const char *locale, locale_t) { + return _create_locale(category_mask, locale); + } + + static void freelocale(locale_t locale) { + _free_locale(locale); + } + + static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { + return _strtod_l(nptr, endptr, locale); + } +# endif + + locale_t locale_; + + FMT_DISALLOW_COPY_AND_ASSIGN(Locale); + + public: + typedef locale_t Type; + + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { + if (!locale_) + FMT_THROW(fmt::SystemError(errno, "cannot create locale")); + } + ~Locale() { freelocale(locale_); } + + Type get() const { return locale_; } + + // Converts string to floating-point number and advances str past the end + // of the parsed input. + double strtod(const char *&str) const { + char *end = 0; + double result = strtod_l(str, &end, locale_); + str = end; + return result; + } +}; +#endif // FMT_LOCALE +} // namespace fmt + +#if !FMT_USE_RVALUE_REFERENCES +namespace std { +// For compatibility with C++98. +inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; } +inline fmt::File &move(fmt::File &f) { return f; } +} +#endif + +#endif // FMT_POSIX_H_ diff --git a/vendor/fmt-3.0.1/fmt/time.h b/vendor/fmt-3.0.1/fmt/time.h new file mode 100644 index 00000000..10225c03 --- /dev/null +++ b/vendor/fmt-3.0.1/fmt/time.h @@ -0,0 +1,53 @@ +/* + Formatting library for C++ - time formatting + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_TIME_H_ +#define FMT_TIME_H_ + +#include "format.h" +#include <ctime> + +namespace fmt { +template <typename ArgFormatter> +void format(BasicFormatter<char, ArgFormatter> &f, + const char *&format_str, const std::tm &tm) { + if (*format_str == ':') + ++format_str; + const char *end = format_str; + while (*end && *end != '}') + ++end; + if (*end != '}') + FMT_THROW(FormatError("missing '}' in format string")); + internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; + format.append(format_str, end + 1); + format[format.size() - 1] = '\0'; + Buffer<char> &buffer = f.writer().buffer(); + std::size_t start = buffer.size(); + for (;;) { + std::size_t size = buffer.capacity() - start; + std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); + if (count != 0) { + buffer.resize(start + count); + break; + } + if (size >= format.size() * 256) { + // If the buffer is 256 times larger than the format string, assume + // that `strftime` gives an empty result. There doesn't seem to be a + // better way to distinguish the two cases: + // https://github.com/fmtlib/fmt/issues/367 + break; + } + const std::size_t MIN_GROWTH = 10; + buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); + } + format_str = end + 1; +} +} + +#endif // FMT_TIME_H_ diff --git a/vendor/jsoncons b/vendor/jsoncons new file mode 120000 index 00000000..0f3415d8 --- /dev/null +++ b/vendor/jsoncons @@ -0,0 +1 @@ +jsoncons-0.99.2
\ No newline at end of file diff --git a/vendor/jsoncons-0.99.2/jsoncons/json.hpp b/vendor/jsoncons-0.99.2/jsoncons/json.hpp new file mode 100644 index 00000000..b9058b59 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json.hpp @@ -0,0 +1,3574 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_HPP +#define JSONCONS_JSON_HPP + +#include <limits> +#include <string> +#include <vector> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <ostream> +#include <memory> +#include <typeinfo> +#include "jsoncons/json_structures.hpp" +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_output_handler.hpp" +#include "jsoncons/output_format.hpp" +#include "jsoncons/json_serializer.hpp" +#include "jsoncons/json_deserializer.hpp" +#include "jsoncons/json_reader.hpp" +#include "jsoncons/json_type_traits.hpp" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons { + +template <class T, class Alloc, typename... Args> +T* create_impl(const Alloc& allocator, Args&& ... args) +{ + typename std::allocator_traits<Alloc>:: template rebind_alloc<T> alloc(allocator); + T* storage = alloc.allocate(1); + try + { + std::allocator_traits<Alloc>:: template rebind_traits<T>::construct(alloc, storage, std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(storage,1); + throw; + } + return storage; +} + +template <class T, class Alloc> +void destroy_impl(const Alloc& allocator, T* p) +{ + typename std::allocator_traits<Alloc>:: template rebind_alloc<T> alloc(allocator); + std::allocator_traits<Alloc>:: template rebind_traits<T>::destroy(alloc, p); + alloc.deallocate(p,1); +} + +template <typename CharT, class Alloc> +class serializable_any +{ +public: + typedef Alloc allocator_type; + + serializable_any(const Alloc& allocator = Alloc()) + : impl_(nullptr) + { + (void)allocator; + } + serializable_any(const serializable_any& val) + : allocator_(std::allocator_traits<allocator_type>::select_on_container_copy_construction(val.get_allocator())) + { + impl_ = val.impl_ != nullptr ? val.impl_->clone(allocator_) : nullptr; + } + serializable_any(const serializable_any& val, const Alloc& allocator) + { + (void)allocator; + impl_ = val.impl_ != nullptr ? val.impl_->clone(Alloc()) : nullptr; + } + + serializable_any(serializable_any&& val) + : impl_(std::move(val.impl_)) + { + val.impl_ = nullptr; + } + serializable_any(serializable_any&& val, const Alloc& allocator) + : impl_(std::move(val.impl_)) + { + (void)allocator; + val.impl_ = nullptr; + } + ~serializable_any() + { + if (impl_ != nullptr) + { + destroy_impl(allocator_,impl_); + } + } + + template<typename T> + explicit serializable_any(T val) + { + impl_ = create_impl<any_handle_impl<typename type_wrapper<T>::value_type>>(allocator_,val); + } + + Alloc get_allocator() const + { + return allocator_; + } + + template <typename T> + typename type_wrapper<T>::reference cast() + { + if (typeid(*impl_) != typeid(any_handle_impl<typename type_wrapper<T>::value_type>)) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad serializable_any cast"); + } + return static_cast<any_handle_impl<typename type_wrapper<T>::value_type>&>(*impl_).value_; + } + + template <typename T> + typename type_wrapper<T>::const_reference cast() const + { + if (typeid(*impl_) != typeid(any_handle_impl<typename type_wrapper<T>::value_type>)) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad serializable_any cast"); + } + return static_cast<any_handle_impl<typename type_wrapper<T>::value_type>&>(*impl_).value_; + } + + serializable_any& operator=(serializable_any rhs) + { + std::swap(impl_,rhs.impl_); + return *this; + } + + void to_stream(basic_json_output_handler<CharT>& os) const + { + impl_->to_stream(os); + } + + class any_handle + { + public: + virtual ~any_handle() + { + } + + virtual any_handle* clone(const Alloc& allocator) const = 0; + + virtual void to_stream(basic_json_output_handler<CharT>& os) const = 0; + }; + + template <class T> + class any_handle_impl : public any_handle + { + public: + any_handle_impl(T value, const Alloc& allocator = Alloc()) + : value_(value) + { + (void)allocator; + } + + virtual any_handle* clone(const Alloc& allocator) const + { + return create_impl<any_handle_impl<T>>(allocator, value_); + } + + virtual void to_stream(basic_json_output_handler<CharT>& os) const + { + serialize(os,value_); + } + + T value_; + }; + + Alloc allocator_; + any_handle* impl_; +}; + +template <typename CharT,class T> inline +void serialize(basic_json_output_handler<CharT>& os, const T&) +{ + os.value(null_type()); +} + +template <typename CharT> +class basic_parse_error_handler; + +enum class value_types : uint8_t +{ + // Simple types + empty_object_t, + small_string_t, + double_t, + integer_t, + uinteger_t, + bool_t, + null_t, + // Non simple types + string_t, + object_t, + array_t, + any_t +}; + +inline +bool is_simple(value_types type) +{ + return type < value_types::string_t; +} + +template <typename CharT, typename Alloc = std::allocator<CharT>> +class basic_json +{ +public: + + typedef Alloc allocator_type; + + typedef CharT char_type; + typedef typename std::char_traits<CharT> char_traits_type; + + typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<CharT> string_allocator; + typedef std::basic_string<CharT,char_traits_type,string_allocator> string_type; + typedef basic_json<CharT,Alloc> value_type; + typedef name_value_pair<string_type,value_type> member_type; + + typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<basic_json<CharT,Alloc>> array_allocator; + + typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<member_type> object_allocator; + + typedef json_array<basic_json<CharT,Alloc>,array_allocator> array; + typedef json_object<string_type,basic_json<CharT,Alloc>,object_allocator> object; + typedef serializable_any<char_type,Alloc> any; + + typedef jsoncons::null_type null_type; + + typedef typename object::iterator object_iterator; + typedef typename object::const_iterator const_object_iterator; + typedef typename array::iterator array_iterator; + typedef typename array::const_iterator const_array_iterator; + + template <typename IteratorT> + class range + { + IteratorT first_; + IteratorT last_; + public: + range(const IteratorT& first, const IteratorT& last) + : first_(first), last_(last) + { + } + + public: + friend class basic_json<CharT, Alloc>; + + IteratorT begin() + { + return first_; + } + IteratorT end() + { + return last_; + } + }; + + typedef range<object_iterator> object_range; + typedef range<const_object_iterator> const_object_range; + typedef range<array_iterator> array_range; + typedef range<const_array_iterator> const_array_range; + + struct variant + { + struct string_data : public string_allocator + { + const char_type* c_str() const { return p_; } + const char_type* data() const { return p_; } + size_t length() const { return length_; } + string_allocator get_allocator() const + { + return *this; + } + + bool operator==(const string_data& rhs) const + { + return length() == rhs.length() ? std::char_traits<char_type>::compare(data(), rhs.data(), length()) == 0 : false; + } + + string_data(const string_allocator& allocator) + : string_allocator(allocator), p_(nullptr), length_(0) + { + } + + char_type* p_; + size_t length_; + private: + string_data(const string_data&); + string_data& operator=(const string_data&); + }; + + struct string_dataA + { + string_data data; + char_type c[1]; + }; + typedef typename std::aligned_storage<sizeof(string_dataA), JSONCONS_ALIGNOF(string_dataA)>::type storage_type; + + static size_t aligned_size(size_t n) + { + return sizeof(storage_type) + n; + } + + string_data* create_string_data(const char_type* s, size_t length, const string_allocator& allocator) + { + size_t mem_size = aligned_size(length*sizeof(char_type)); + + typename std::allocator_traits<string_allocator>:: template rebind_alloc<char> alloc(allocator); + + char* storage = alloc.allocate(mem_size); + string_data* ps = new(storage)string_data(allocator); + auto psa = reinterpret_cast<string_dataA*>(storage); + + ps->p_ = new(&psa->c)char_type[length + 1]; + memcpy(ps->p_, s, length*sizeof(char_type)); + ps->p_[length] = 0; + ps->length_ = length; + return ps; + } + + void destroy_string_data(const string_allocator& allocator, string_data* p) + { + size_t mem_size = aligned_size(p->length_*sizeof(char_type)); + typename std::allocator_traits<string_allocator>:: template rebind_alloc<char> alloc(allocator); + alloc.deallocate(reinterpret_cast<char*>(p),mem_size); + } + + static const size_t small_string_capacity = (sizeof(int64_t)/sizeof(char_type)) - 1; + + variant() + : type_(value_types::empty_object_t) + { + } + + variant(const Alloc& a) + : type_(value_types::object_t) + { + value_.object_val_ = create_impl<object>(a, object_allocator(a)); + } + + variant(std::initializer_list<value_type> init, + const Alloc& a) + : type_(value_types::array_t) + { + value_.array_val_ = create_impl<array>(a, std::move(init), array_allocator(a)); + } + + explicit variant(variant&& var) + : type_(value_types::null_t) + { + swap(var); + } + + explicit variant(variant&& var, const Alloc& a) + : type_(value_types::null_t) + { + swap(var); + } + + explicit variant(const variant& var) + { + init_variant(var); + } + explicit variant(const variant& var, const Alloc& a) + : type_(var.type_) + { + init_variant(var); + } + + variant(const object & val) + : type_(value_types::object_t) + { + value_.object_val_ = create_impl<object>(val.get_allocator(), val) ; + } + + variant(const object & val, const Alloc& a) + : type_(value_types::object_t) + { + value_.object_val_ = create_impl<object>(a, val, object_allocator(a)) ; + } + + variant(object&& val) + : type_(value_types::object_t) + { + value_.object_val_ = create_impl<object>(val.get_allocator(), std::move(val)); + } + + variant(object&& val, const Alloc& a) + : type_(value_types::object_t) + { + value_.object_val_ = create_impl<object>(a, std::move(val), object_allocator(a)); + } + + variant(const array& val) + : type_(value_types::array_t) + { + value_.array_val_ = create_impl<array>(val.get_allocator(), val); + } + + variant(const array& val, const Alloc& a) + : type_(value_types::array_t) + { + value_.array_val_ = create_impl<array>(a, val, array_allocator(a)); + } + + variant(array&& val) + : type_(value_types::array_t) + { + value_.array_val_ = create_impl<array>(val.get_allocator(), std::move(val)); + } + + variant(array&& val, const Alloc& a) + : type_(value_types::array_t) + { + value_.array_val_ = create_impl<array>(a, std::move(val), array_allocator(a)); + } + + explicit variant(const any& val, const Alloc& a) + : type_(value_types::any_t) + { + value_.any_val_ = create_impl<any>(a, val); + } + + explicit variant(null_type) + : type_(value_types::null_t) + { + } + + explicit variant(bool val) + : type_(value_types::bool_t) + { + value_.bool_val_ = val; + } + + explicit variant(double val, uint8_t precision) + : type_(value_types::double_t), length_or_precision_(precision) + { + value_.double_val_ = val; + } + + explicit variant(int64_t val) + : type_(value_types::integer_t) + { + value_.integer_val_ = val; + } + + explicit variant(uint64_t val) + : type_(value_types::uinteger_t) + { + value_.uinteger_val_ = val; + } + + explicit variant(const string_type& s, const Alloc& a) + { + if (s.length() > variant::small_string_capacity) + { + type_ = value_types::string_t; + //value_.string_val_ = create_impl<string_type>(a, s, string_allocator(a)); + value_.string_val_ = create_string_data(s.data(), s.length(), string_allocator(a)); + } + else + { + type_ = value_types::small_string_t; + length_or_precision_ = static_cast<uint8_t>(s.length()); + std::memcpy(value_.small_string_val_,s.data(),s.length()*sizeof(char_type)); + value_.small_string_val_[length_or_precision_] = 0; + } + } + + explicit variant(const char_type* s, const Alloc& a) + { + size_t length = std::char_traits<char_type>::length(s); + if (length > variant::small_string_capacity) + { + type_ = value_types::string_t; + //value_.string_val_ = create_impl<string_type>(a, s, string_allocator(a)); + value_.string_val_ = create_string_data(s, length, string_allocator(a)); + } + else + { + type_ = value_types::small_string_t; + length_or_precision_ = static_cast<uint8_t>(length); + std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); + value_.small_string_val_[length_or_precision_] = 0; + } + } + + explicit variant(const char_type* s, size_t length, const Alloc& a) + { + if (length > variant::small_string_capacity) + { + type_ = value_types::string_t; + //value_.string_val_ = create_impl<string_type>(a, s, length, string_allocator(a)); + value_.string_val_ = create_string_data(s, length, string_allocator(a)); + } + else + { + type_ = value_types::small_string_t; + length_or_precision_ = static_cast<uint8_t>(length); + std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); + value_.small_string_val_[length_or_precision_] = 0; + } + } + + template<class InputIterator> + variant(InputIterator first, InputIterator last, const Alloc& a) + : type_(value_types::array_t) + { + value_.array_val_ = create_impl<array>(a, first, last, array_allocator(a)); + } + + void init_variant(const variant& var) + { + type_ = var.type_; + switch (type_) + { + case value_types::null_t: + case value_types::empty_object_t: + break; + case value_types::double_t: + length_or_precision_ = 0; + value_.double_val_ = var.value_.double_val_; + break; + case value_types::integer_t: + value_.integer_val_ = var.value_.integer_val_; + break; + case value_types::uinteger_t: + value_.uinteger_val_ = var.value_.uinteger_val_; + break; + case value_types::bool_t: + value_.bool_val_ = var.value_.bool_val_; + break; + case value_types::small_string_t: + length_or_precision_ = var.length_or_precision_; + std::memcpy(value_.small_string_val_,var.value_.small_string_val_,var.length_or_precision_*sizeof(char_type)); + value_.small_string_val_[length_or_precision_] = 0; + break; + case value_types::string_t: + //value_.string_val_ = create_impl<string_type>(var.value_.string_val_->get_allocator(), *(var.value_.string_val_), string_allocator(var.value_.string_val_->get_allocator())); + value_.string_val_ = create_string_data(var.value_.string_val_->data(), var.value_.string_val_->length(), string_allocator(var.value_.string_val_->get_allocator())); + break; + case value_types::array_t: + value_.array_val_ = create_impl<array>(var.value_.array_val_->get_allocator(), *(var.value_.array_val_), array_allocator(var.value_.array_val_->get_allocator())); + break; + case value_types::object_t: + value_.object_val_ = create_impl<object>(var.value_.object_val_->get_allocator(), *(var.value_.object_val_), object_allocator(var.value_.object_val_->get_allocator())); + break; + case value_types::any_t: + value_.any_val_ = create_impl<any>(var.value_.any_val_->get_allocator(), *(var.value_.any_val_)); + break; + default: + break; + } + } + + ~variant() + { + destroy_variant(); + } + + void destroy_variant() + { + switch (type_) + { + case value_types::string_t: + //destroy_impl(value_.string_val_->get_allocator(), value_.string_val_); + destroy_string_data(value_.string_val_->get_allocator(), value_.string_val_); + break; + case value_types::array_t: + destroy_impl(value_.array_val_->get_allocator(), value_.array_val_); + break; + case value_types::object_t: + destroy_impl(value_.object_val_->get_allocator(), value_.object_val_); + break; + case value_types::any_t: + destroy_impl(value_.any_val_->get_allocator(), value_.any_val_); + break; + default: + break; + } + } + + variant& operator=(const variant& val) + { + if (this != &val) + { + if (is_simple(type_)) + { + if (is_simple(val.type_)) + { + type_ = val.type_; + length_or_precision_ = val.length_or_precision_; + value_ = val.value_; + } + else + { + init_variant(val); + } + } + else + { + destroy_variant(); + init_variant(val); + } + } + return *this; + } + + variant& operator=(variant&& val) + { + if (this != &val) + { + val.swap(*this); + } + return *this; + } + + void assign(const object & val) + { + destroy_variant(); + type_ = value_types::object_t; + value_.object_val_ = create_impl<object>(val.get_allocator(), val, object_allocator(val.get_allocator())); + } + + void assign(object && val) + { + switch (type_) + { + case value_types::object_t: + value_.object_val_->swap(val); + break; + default: + destroy_variant(); + type_ = value_types::object_t; + value_.object_val_ = create_impl<object>(val.get_allocator(), std::move(val), object_allocator(val.get_allocator())); + break; + } + } + + void assign(const array& val) + { + destroy_variant(); + type_ = value_types::array_t; + value_.array_val_ = create_impl<array>(val.get_allocator(), val, array_allocator(val.get_allocator())) ; + } + + void assign(array&& val) + { + switch (type_) + { + case value_types::array_t: + value_.array_val_->swap(val); + break; + default: + destroy_variant(); + type_ = value_types::array_t; + value_.array_val_ = create_impl<array>(val.get_allocator(), std::move(val), array_allocator(val.get_allocator())); + break; + } + } + + void assign(const string_type& s) + { + destroy_variant(); + if (s.length() > variant::small_string_capacity) + { + type_ = value_types::string_t; + //value_.string_val_ = create_impl<string_type>(s.get_allocator(), s, string_allocator(s.get_allocator())); + value_.string_val_ = create_string_data(s.data(), s.length(), string_allocator(s.get_allocator())); + } + else + { + type_ = value_types::small_string_t; + length_or_precision_ = static_cast<uint8_t>(s.length()); + std::memcpy(value_.small_string_val_,s.data(),s.length()*sizeof(char_type)); + value_.small_string_val_[length_or_precision_] = 0; + } + } + + void assign_string(const char_type* s, size_t length, const Alloc& allocator = Alloc()) + { + destroy_variant(); + if (length > variant::small_string_capacity) + { + type_ = value_types::string_t; + //value_.string_val_ = create_impl<string_type>(allocator, s, length, string_allocator(allocator)); + value_.string_val_ = create_string_data(s, length, string_allocator(allocator)); + } + else + { + type_ = value_types::small_string_t; + length_or_precision_ = static_cast<uint8_t>(length); + std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); + value_.small_string_val_[length_or_precision_] = 0; + } + } + + void assign(int64_t val) + { + destroy_variant(); + type_ = value_types::integer_t; + value_.integer_val_ = val; + } + + void assign(uint64_t val) + { + destroy_variant(); + type_ = value_types::uinteger_t; + value_.uinteger_val_ = val; + } + + void assign(double val, uint8_t precision = 0) + { + destroy_variant(); + type_ = value_types::double_t; + length_or_precision_ = precision; + value_.double_val_ = val; + } + + void assign(bool val) + { + destroy_variant(); + type_ = value_types::bool_t; + value_.bool_val_ = val; + } + + void assign(null_type) + { + destroy_variant(); + type_ = value_types::null_t; + } + + void assign(const any& rhs) + { + destroy_variant(); + type_ = value_types::any_t; + value_.any_val_ = create_impl<any>(rhs.get_allocator(), rhs); + } + + bool operator!=(const variant& rhs) const + { + return !(*this == rhs); + } + + bool operator==(const variant& rhs) const + { + if (is_number() & rhs.is_number()) + { + switch (type_) + { + case value_types::integer_t: + switch (rhs.type_) + { + case value_types::integer_t: + return value_.integer_val_ == rhs.value_.integer_val_; + case value_types::uinteger_t: + return value_.integer_val_ == rhs.value_.uinteger_val_; + case value_types::double_t: + return value_.integer_val_ == rhs.value_.double_val_; + default: + break; + } + break; + case value_types::uinteger_t: + switch (rhs.type_) + { + case value_types::integer_t: + return value_.uinteger_val_ == rhs.value_.integer_val_; + case value_types::uinteger_t: + return value_.uinteger_val_ == rhs.value_.uinteger_val_; + case value_types::double_t: + return value_.uinteger_val_ == rhs.value_.double_val_; + default: + break; + } + break; + case value_types::double_t: + switch (rhs.type_) + { + case value_types::integer_t: + return value_.double_val_ == rhs.value_.integer_val_; + case value_types::uinteger_t: + return value_.double_val_ == rhs.value_.uinteger_val_; + case value_types::double_t: + return value_.double_val_ == rhs.value_.double_val_; + default: + break; + } + break; + default: + break; + } + } + + switch (type_) + { + case value_types::bool_t: + return type_ == rhs.type_ && value_.bool_val_ == rhs.value_.bool_val_; + case value_types::null_t: + return type_ == rhs.type_; + case value_types::empty_object_t: + return type_ == rhs.type_ || (rhs.type_ == value_types::object_t && rhs.empty()); + case value_types::small_string_t: + return type_ == rhs.type_ && length_or_precision_ == rhs.length_or_precision_ ? std::char_traits<char_type>::compare(value_.small_string_val_,rhs.value_.small_string_val_,length_or_precision_) == 0 : false; + case value_types::string_t: + return type_ == rhs.type_ && *(value_.string_val_) == *(rhs.value_.string_val_); + case value_types::array_t: + return type_ == rhs.type_ && *(value_.array_val_) == *(rhs.value_.array_val_); + break; + case value_types::object_t: + return (type_ == rhs.type_ && *(value_.object_val_) == *(rhs.value_.object_val_)) || (rhs.type_ == value_types::empty_object_t && empty()); + break; + case value_types::any_t: + return type_ == rhs.type_; + default: + // throw + break; + } + return false; + } + + bool is_null() const JSONCONS_NOEXCEPT + { + return type_ == value_types::null_t; + } + + bool is_bool() const JSONCONS_NOEXCEPT + { + return type_ == value_types::bool_t; + } + + bool empty() const JSONCONS_NOEXCEPT + { + switch (type_) + { + case value_types::small_string_t: + return length_or_precision_ == 0; + case value_types::string_t: + return value_.string_val_->length() == 0; + case value_types::array_t: + return value_.array_val_->size() == 0; + case value_types::empty_object_t: + return true; + case value_types::object_t: + return value_.object_val_->size() == 0; + default: + return false; + } + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return (type_ == value_types::string_t) | (type_ == value_types::small_string_t); + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return type_ == value_types::double_t || type_ == value_types::integer_t || type_ == value_types::uinteger_t; + } + + void swap(variant& rhs) + { + using std::swap; + if (this == &rhs) + { + // same object, do nothing + } + else + { + swap(type_, rhs.type_); + swap(length_or_precision_, rhs.length_or_precision_); + swap(value_, rhs.value_); + } + } + + value_types type_; + uint8_t length_or_precision_; + union + { + double double_val_; + int64_t integer_val_; + uint64_t uinteger_val_; + bool bool_val_; + object* object_val_; + array* array_val_; + any* any_val_; + string_data* string_val_; + char_type small_string_val_[sizeof(int64_t)/sizeof(char_type)]; + } value_; + }; + + template <class ParentT> + class json_proxy + { + private: + typedef json_proxy<ParentT> proxy_type; + + ParentT& parent_; + const string_type& name_; + + json_proxy() = delete; + json_proxy& operator = (const json_proxy& other) = delete; + + json_proxy(ParentT& parent, const string_type& name) + : parent_(parent), name_(name) + { + } + + basic_json<CharT,Alloc>& evaluate() + { + return parent_.evaluate(name_); + } + + const basic_json<CharT,Alloc>& evaluate() const + { + return parent_.evaluate(name_); + } + + basic_json<CharT,Alloc>& evaluate_with_default() + { + basic_json<CharT,Alloc>& val = parent_.evaluate_with_default(); + auto it = val.find(name_.data(),name_.length()); + if (it == val.members().end()) + { + it = val.set(val.members().begin(),name_,object(val.object_value().get_allocator())); + } + return it->value(); + } + + basic_json<CharT,Alloc>& evaluate(size_t index) + { + return parent_.evaluate(name_).at(index); + } + + const basic_json<CharT,Alloc>& evaluate(size_t index) const + { + return parent_.evaluate(name_).at(index); + } + + basic_json<CharT,Alloc>& evaluate(const string_type& index) + { + return parent_.evaluate(name_).at(index); + } + + const basic_json<CharT,Alloc>& evaluate(const string_type& index) const + { + return parent_.evaluate(name_).at(index); + } + public: + + friend class basic_json<CharT,Alloc>; + + object_range members() + { + return evaluate().members(); + } + + const_object_range members() const + { + return evaluate().members(); + } + + array_range elements() + { + return evaluate().elements(); + } + + const_array_range elements() const + { + return evaluate().elements(); + } + + size_t size() const JSONCONS_NOEXCEPT + { + return evaluate().size(); + } + + value_types type() const + { + return evaluate().type(); + } + + size_t count(const string_type& name) const + { + return evaluate().count(name); + } + + bool is_null() const JSONCONS_NOEXCEPT + { + return evaluate().is_null(); + } + + bool empty() const + { + return evaluate().empty(); + } + + size_t capacity() const + { + return evaluate().capacity(); + } + + void reserve(size_t n) + { + evaluate().reserve(n); + } + + void resize(size_t n) + { + evaluate().resize(n); + } + + template <typename T> + void resize(size_t n, T val) + { + evaluate().resize(n,val); + } + + template<typename T> + bool is() const + { + return evaluate().template is<T>(); + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return evaluate().is_string(); + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return evaluate().is_number(); + } + bool is_bool() const JSONCONS_NOEXCEPT + { + return evaluate().is_bool(); + } + + bool is_object() const JSONCONS_NOEXCEPT + { + return evaluate().is_object(); + } + + bool is_array() const JSONCONS_NOEXCEPT + { + return evaluate().is_array(); + } + + bool is_any() const JSONCONS_NOEXCEPT + { + return evaluate().is_any(); + } + + bool is_integer() const JSONCONS_NOEXCEPT + { + return evaluate().is_integer(); + } + + bool is_uinteger() const JSONCONS_NOEXCEPT + { + return evaluate().is_uinteger(); + } + + bool is_double() const JSONCONS_NOEXCEPT + { + return evaluate().is_double(); + } + + string_type as_string() const JSONCONS_NOEXCEPT + { + return evaluate().as_string(); + } + + string_type as_string(const string_allocator& allocator) const JSONCONS_NOEXCEPT + { + return evaluate().as_string(allocator); + } + + string_type as_string(const basic_output_format<char_type>& format) const + { + return evaluate().as_string(format); + } + + string_type as_string(const basic_output_format<char_type>& format, + const string_allocator& allocator) const + { + return evaluate().as_string(format,allocator); + } + + template<typename T> + T as() const + { + return evaluate().template as<T>(); + } + + template<typename T> + typename std::enable_if<std::is_same<string_type,T>::value>::type as(const string_allocator& allocator) const + { + return evaluate().template as<T>(allocator); + } + + any& any_value() + { + return evaluate().any_value(); + } + + const any& any_value() const + { + return evaluate().any_value(); + } + + bool as_bool() const JSONCONS_NOEXCEPT + { + return evaluate().as_bool(); + } + + template <class T> + std::vector<T> as_vector() const + { + return evaluate().template as_vector<T>(); + } + + double as_double() const + { + return evaluate().as_double(); + } + + int64_t as_integer() const + { + return evaluate().as_integer(); + } + + unsigned long long as_ulonglong() const + { + return evaluate().as_ulonglong(); + } + + uint64_t as_uinteger() const + { + return evaluate().as_uinteger(); + } + + template <class T> + const T& any_cast() const + { + return evaluate().template any_cast<T>(); + } + // Returns a const reference to the custom data associated with name + + template <class T> + T& any_cast() + { + return evaluate().template any_cast<T>(); + } + // Returns a reference to the custom data associated with name + + operator basic_json&() + { + return evaluate(); + } + + operator const basic_json&() const + { + return evaluate(); + } + + template <typename T> + json_proxy& operator=(T val) + { + parent_.evaluate_with_default().set(name_, val); + return *this; + } + + json_proxy& operator=(const basic_json& val) + { + parent_.evaluate_with_default().set(name_, val); + return *this; + } + + json_proxy& operator=(basic_json&& val) + { + parent_.evaluate_with_default().set(name_, std::move(val)); + return *this; + } + + bool operator==(const basic_json& val) const + { + return evaluate() == val; + } + + bool operator!=(const basic_json& val) const + { + return evaluate() != val; + } + + basic_json<CharT,Alloc>& operator[](size_t i) + { + return evaluate_with_default().at(i); + } + + const basic_json<CharT,Alloc>& operator[](size_t i) const + { + return evaluate().at(i); + } + + json_proxy<proxy_type> operator[](const string_type& name) + { + return json_proxy<proxy_type>(*this,name); + } + + const json_proxy<proxy_type> operator[](const string_type& name) const + { + return json_proxy<proxy_type>(*this,name); + } + + basic_json<CharT,Alloc>& at(const string_type& name) + { + return evaluate().at(name); + } + + const basic_json<CharT,Alloc>& at(const string_type& name) const + { + return evaluate().at(name); + } + + const basic_json<CharT,Alloc>& at(size_t index) + { + return evaluate().at(index); + } + + const basic_json<CharT,Alloc>& at(size_t index) const + { + return evaluate().at(index); + } + + object_iterator find(const string_type& name) + { + return evaluate().find(name); + } + + const_object_iterator find(const string_type& name) const + { + return evaluate().find(name); + } + + object_iterator find(const char_type* name) + { + return evaluate().find(name); + } + + const_object_iterator find(const char_type* name) const + { + return evaluate().find(name); + } + + object_iterator find(const char_type* name, size_t length) + { + return evaluate().find(name,length); + } + + const_object_iterator find(const char_type* name, size_t length) const + { + return evaluate().find(name,length); + } + + template <typename T> + basic_json<CharT,Alloc> get(const string_type& name, T&& default_val) const + { + return evaluate().get(name,std::forward<T>(default_val)); + } + + void shrink_to_fit() + { + evaluate_with_default().shrink_to_fit(); + } + + void clear() + { + evaluate().clear(); + } + // Remove all elements from an array or object + + void erase(object_iterator first, object_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an object + + void erase(array_iterator first, array_iterator last) + { + evaluate().erase(first, last); + } + + void erase(const string_type& name) + { + evaluate().erase(name); + } + + // Remove a member from an object + + void set(const string_type& name, const basic_json<CharT,Alloc>& value) + { + evaluate().set(name,value); + } + + void set(string_type&& name, const basic_json<CharT,Alloc>& value) + + { + evaluate().set(std::move(name),value); + } + + void set(const string_type& name, basic_json<CharT,Alloc>&& value) + + { + evaluate().set(name,std::move(value)); + } + + void set(string_type&& name, basic_json<CharT,Alloc>&& value) + + { + evaluate().set(std::move(name),std::move(value)); + } + + object_iterator set(object_iterator hint, const string_type& name, const basic_json<CharT,Alloc>& value) + { + return evaluate().set(hint, name,value); + } + + object_iterator set(object_iterator hint, string_type&& name, const basic_json<CharT,Alloc>& value) + + { + return evaluate().set(hint, std::move(name),value); + } + + object_iterator set(object_iterator hint, const string_type& name, basic_json<CharT,Alloc>&& value) + + { + return evaluate().set(hint, name,std::move(value)); + } + + object_iterator set(object_iterator hint, string_type&& name, basic_json<CharT,Alloc>&& value) + + { + return evaluate().set(hint, std::move(name),std::move(value)); + } + + void add(basic_json<CharT,Alloc>&& value) + { + evaluate_with_default().add(std::move(value)); + } + + void add(const basic_json<CharT,Alloc>& value) + { + evaluate_with_default().add(value); + } + + array_iterator add(const_array_iterator pos, const basic_json<CharT,Alloc>& value) + { + return evaluate_with_default().add(pos, value); + } + + array_iterator add(const_array_iterator pos, basic_json<CharT,Alloc>&& value) + { + return evaluate_with_default().add(pos, std::move(value)); + } + + string_type to_string(const string_allocator& allocator = string_allocator()) const JSONCONS_NOEXCEPT + { + return evaluate().to_string(allocator); + } + + string_type to_string(const basic_output_format<char_type>& format, string_allocator& allocator = string_allocator()) const + { + return evaluate().to_string(format,allocator); + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + evaluate().to_stream(os); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format) const + { + evaluate().to_stream(os,format); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format, bool indenting) const + { + evaluate().to_stream(os,format,indenting); + } + + void swap(basic_json<CharT,Alloc>& val) + { + evaluate_with_default().swap(val); + } + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_proxy& o) + { + o.to_stream(os); + return os; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void resize_array(size_t n) + { + evaluate().resize_array(n); + } + + template <typename T> + void resize_array(size_t n, T val) + { + evaluate().resize_array(n,val); + } + + object_iterator begin_members() + { + return evaluate().begin_members(); + } + + const_object_iterator begin_members() const + { + return evaluate().begin_members(); + } + + object_iterator end_members() + { + return evaluate().end_members(); + } + + const_object_iterator end_members() const + { + return evaluate().end_members(); + } + + array_iterator begin_elements() + { + return evaluate().begin_elements(); + } + + const_array_iterator begin_elements() const + { + return evaluate().begin_elements(); + } + + array_iterator end_elements() + { + return evaluate().end_elements(); + } + + const_array_iterator end_elements() const + { + return evaluate().end_elements(); + } + + const basic_json<CharT,Alloc>& get(const string_type& name) const + { + return evaluate().get(name); + } + + bool is_ulonglong() const JSONCONS_NOEXCEPT + { + return evaluate().is_ulonglong(); + } + + bool is_longlong() const JSONCONS_NOEXCEPT + { + return evaluate().is_longlong(); + } + + int as_int() const + { + return evaluate().as_int(); + } + + unsigned int as_uint() const + { + return evaluate().as_uint(); + } + + long as_long() const + { + return evaluate().as_long(); + } + + unsigned long as_ulong() const + { + return evaluate().as_ulong(); + } + + long long as_longlong() const + { + return evaluate().as_longlong(); + } + + void add(size_t index, const basic_json<CharT,Alloc>& value) + { + evaluate_with_default().add(index, value); + } + + void add(size_t index, basic_json<CharT,Alloc>&& value) + { + evaluate_with_default().add(index, std::move(value)); + } + + bool has_member(const string_type& name) const + { + return evaluate().has_member(name); + } + + // Remove a range of elements from an array + void remove_range(size_t from_index, size_t to_index) + { + evaluate().remove_range(from_index, to_index); + } + // Remove a range of elements from an array + void remove(const string_type& name) + { + evaluate().remove(name); + } + void remove_member(const string_type& name) + { + evaluate().remove(name); + } + bool is_empty() const JSONCONS_NOEXCEPT + { + return empty(); + } + bool is_numeric() const JSONCONS_NOEXCEPT + { + return is_number(); + } +#endif + }; + + static basic_json parse_stream(std::basic_istream<char_type>& is); + static basic_json parse_stream(std::basic_istream<char_type>& is, basic_parse_error_handler<char_type>& err_handler); + + static basic_json parse(const string_type& s) + { + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + basic_json_parser<char_type> parser(handler); + parser.begin_parse(); + parser.parse(s.data(),0,s.length()); + parser.end_parse(); + parser.check_done(s.data(),parser.index(),s.length()); + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json string"); + } + return handler.get_result(); + } + + static basic_json parse(const string_type& s, basic_parse_error_handler<char_type>& err_handler) + { + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + basic_json_parser<char_type> parser(handler,err_handler); + parser.begin_parse(); + parser.parse(s.data(),0,s.length()); + parser.end_parse(); + parser.check_done(s.data(),parser.index(),s.length()); + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json string"); + } + return handler.get_result(); + } + + static basic_json parse_file(const std::string& s); + + static basic_json parse_file(const std::string& s, basic_parse_error_handler<char_type>& err_handler); + + static basic_json make_array() + { + return basic_json::array(); + } + + static basic_json make_array(size_t n, const array_allocator& allocator = array_allocator()) + { + return basic_json::array(n,allocator); + } + + template <class T> + static basic_json make_array(size_t n, const T& val, const array_allocator& allocator = array_allocator()) + { + return basic_json::array(n, val,allocator); + } + + template <size_t dim> + static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n) + { + return array(n); + } + + template <size_t dim, class T> + static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n, const T& val, const Alloc& allocator = Alloc()) + { + return array(n,val,allocator); + } + + template <size_t dim, typename... Args> + static typename std::enable_if<(dim>1),basic_json>::type make_array(size_t n, Args... args) + { + const size_t dim1 = dim - 1; + + basic_json val = make_array<dim1>(args...); + val.resize(n); + for (size_t i = 0; i < n; ++i) + { + val[i] = make_array<dim1>(args...); + } + return val; + } + + variant var_; + + basic_json() + : var_() + { + } + + basic_json(const Alloc& allocator) + : var_(allocator) + { + } + + basic_json(std::initializer_list<value_type> init, + const Alloc& allocator = Alloc()) + : var_(std::move(init), allocator) + { + } + + basic_json(const basic_json<CharT, Alloc>& val) + : var_(val.var_) + { + } + + basic_json(const basic_json<CharT, Alloc>& val, const Alloc& allocator) + : var_(val.var_,allocator) + { + } + + basic_json(basic_json<CharT,Alloc>&& other) + : var_(std::move(other.var_)) + { + } + + basic_json(basic_json<CharT,Alloc>&& other, const Alloc& allocator) + : var_(std::move(other.var_),allocator) + { + } + + basic_json(const array& val) + : var_(val) + { + } + + basic_json(array&& other) + : var_(std::move(other)) + { + } + + basic_json(const object& other) + : var_(other) + { + } + + basic_json(object&& other) + : var_(std::move(other)) + { + } + + template <class ParentT> + basic_json(const json_proxy<ParentT>& proxy, const Alloc& allocator = Alloc()) + : var_(proxy.evaluate().var_,allocator) + { + } + + template <typename T> + basic_json(T val) + : var_(null_type()) + { + json_type_traits<value_type,T>::assign(*this,val); + } + + basic_json(double val, uint8_t precision) + : var_(val,precision) + { + } + + template <typename T> + basic_json(T val, const Alloc& allocator) + : var_(allocator) + { + json_type_traits<value_type,T>::assign(*this,val); + } + + basic_json(const char_type *s, size_t length, const Alloc& allocator = Alloc()) + : var_(s, length, allocator) + { + } + template<class InputIterator> + basic_json(InputIterator first, InputIterator last, const Alloc& allocator = Alloc()) + : var_(first,last,allocator) + { + } + + ~basic_json() + { + } + + basic_json& operator=(const basic_json<CharT,Alloc>& rhs) + { + var_ = rhs.var_; + return *this; + } + + basic_json& operator=(basic_json<CharT,Alloc>&& rhs) + { + if (this != &rhs) + { + var_ = std::move(rhs.var_); + } + return *this; + } + + basic_json& operator=(std::initializer_list<value_type> init) + { + basic_json<CharT,Alloc> val(init); + swap(val); + return *this; + } + + template <class T> + basic_json<CharT, Alloc>& operator=(T val) + { + json_type_traits<value_type,T>::assign(*this,val); + return *this; + } + + bool operator!=(const basic_json<CharT,Alloc>& rhs) const; + + bool operator==(const basic_json<CharT,Alloc>& rhs) const; + + size_t size() const JSONCONS_NOEXCEPT + { + switch (var_.type_) + { + case value_types::empty_object_t: + return 0; + case value_types::object_t: + return var_.value_.object_val_->size(); + case value_types::array_t: + return var_.value_.array_val_->size(); + default: + return 0; + } + } + + basic_json<CharT,Alloc>& operator[](size_t i) + { + return at(i); + } + + const basic_json<CharT,Alloc>& operator[](size_t i) const + { + return at(i); + } + + json_proxy<basic_json<CharT, Alloc>> operator[](const string_type& name) + { + switch (var_.type_) + { + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + return json_proxy<basic_json<CharT,Alloc>>(*this, name); + break; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); + break; + } + } + + const basic_json<CharT,Alloc>& operator[](const string_type& name) const + { + return at(name); + } + + string_type to_string(const string_allocator& allocator=string_allocator()) const JSONCONS_NOEXCEPT + { + string_type s(allocator); + std::basic_ostringstream<char_type,char_traits_type,string_allocator> os(s); + { + basic_json_serializer<char_type> serializer(os); + to_stream(serializer); + } + return os.str(); + } + + string_type to_string(const basic_output_format<char_type>& format, + const string_allocator& allocator=string_allocator()) const + { + string_type s(allocator); + std::basic_ostringstream<char_type> os(s); + { + basic_json_serializer<char_type> serializer(os, format); + to_stream(serializer); + } + return os.str(); + } + + void to_stream(basic_json_output_handler<char_type>& handler) const + { + switch (var_.type_) + { + case value_types::small_string_t: + handler.value(var_.value_.small_string_val_,var_.length_or_precision_); + break; + case value_types::string_t: + handler.value(var_.value_.string_val_->data(),var_.value_.string_val_->length()); + break; + case value_types::double_t: + handler.value(var_.value_.double_val_, var_.length_or_precision_); + break; + case value_types::integer_t: + handler.value(var_.value_.integer_val_); + break; + case value_types::uinteger_t: + handler.value(var_.value_.uinteger_val_); + break; + case value_types::bool_t: + handler.value(var_.value_.bool_val_); + break; + case value_types::null_t: + handler.value(null_type()); + break; + case value_types::empty_object_t: + handler.begin_object(); + handler.end_object(); + break; + case value_types::object_t: + { + handler.begin_object(); + object* o = var_.value_.object_val_; + for (const_object_iterator it = o->begin(); it != o->end(); ++it) + { + handler.name((it->name()).data(),it->name().length()); + it->value().to_stream(handler); + } + handler.end_object(); + } + break; + case value_types::array_t: + { + handler.begin_array(); + array *o = var_.value_.array_val_; + for (const_array_iterator it = o->begin(); it != o->end(); ++it) + { + it->to_stream(handler); + } + handler.end_array(); + } + break; + case value_types::any_t: + var_.value_.any_val_->to_stream(handler); + break; + default: + break; + } + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + basic_json_serializer<char_type> serializer(os); + to_stream(serializer); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format) const + { + basic_json_serializer<char_type> serializer(os, format); + to_stream(serializer); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format, bool indenting) const + { + basic_json_serializer<char_type> serializer(os, format, indenting); + to_stream(serializer); + } + + bool is_null() const JSONCONS_NOEXCEPT + { + return var_.is_null(); + } + + size_t count(const string_type& name) const + { + switch (var_.type_) + { + case value_types::object_t: + { + auto it = var_.value_.object_val_->find(name.data(),name.length()); + if (it == members().end()) + { + return 0; + } + size_t count = 0; + while (it != members().end() && it->name() == name) + { + ++count; + ++it; + } + return count; + } + break; + default: + return 0; + } + } + + template<typename T> + bool is() const + { + return json_type_traits<value_type,T>::is(*this); + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return var_.is_string(); + } + + + bool is_bool() const JSONCONS_NOEXCEPT + { + return var_.is_bool(); + } + + bool is_object() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::object_t || var_.type_ == value_types::empty_object_t; + } + + bool is_array() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::array_t; + } + + bool is_any() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::any_t; + } + + bool is_integer() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::integer_t || (var_.type_ == value_types::uinteger_t && (as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<long long>::max JSONCONS_NO_MACRO_EXP()))); + } + + bool is_uinteger() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::uinteger_t || (var_.type_ == value_types::integer_t && as_integer() >= 0); + } + + bool is_double() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::double_t; + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return var_.is_number(); + } + + bool empty() const JSONCONS_NOEXCEPT + { + return var_.empty(); + } + + size_t capacity() const + { + switch (var_.type_) + { + case value_types::array_t: + return var_.value_.array_val_->capacity(); + case value_types::object_t: + return var_.value_.object_val_->capacity(); + default: + return 0; + } + } + + template<class U=Alloc, + typename std::enable_if<std::is_default_constructible<U>::value + >::type* = nullptr> + void create_object_implicitly() + { + var_.type_ = value_types::object_t; + var_.value_.object_val_ = create_impl<object>(Alloc(),object_allocator(Alloc())); + } + + template<class U=Alloc, + typename std::enable_if<!std::is_default_constructible<U>::value + >::type* = nullptr> + void create_object_implicitly() const + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Cannot create_impl object implicitly - allocator is not default constructible."); + } + + void reserve(size_t n) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->reserve(n); + break; + case value_types::empty_object_t: + { + create_object_implicitly(); + var_.value_.object_val_->reserve(n); + } + break; + case value_types::object_t: + { + var_.value_.object_val_->reserve(n); + } + break; + default: + break; + } + } + + void resize(size_t n) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->resize(n); + break; + default: + break; + } + } + + template <typename T> + void resize(size_t n, T val) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->resize(n, val); + break; + default: + break; + } + } + + template<typename T> + T as() const + { + return json_type_traits<value_type,T>::as(*this); + } + + template<typename T> + typename std::enable_if<std::is_same<string_type,T>::value>::type as(const string_allocator& allocator) const + { + return json_type_traits<value_type,T>::as(*this,allocator); + } + + bool as_bool() const JSONCONS_NOEXCEPT + { + switch (var_.type_) + { + case value_types::null_t: + case value_types::empty_object_t: + return false; + case value_types::bool_t: + return var_.value_.bool_val_; + case value_types::double_t: + return var_.value_.double_val_ != 0.0; + case value_types::integer_t: + return var_.value_.integer_val_ != 0; + case value_types::uinteger_t: + return var_.value_.uinteger_val_ != 0; + case value_types::small_string_t: + return var_.length_or_precision_ != 0; + case value_types::string_t: + return var_.value_.string_val_->length() != 0; + case value_types::array_t: + return var_.value_.array_val_->size() != 0; + case value_types::object_t: + return var_.value_.object_val_->size() != 0; + case value_types::any_t: + return true; + default: + return false; + } + } + + int64_t as_integer() const + { + switch (var_.type_) + { + case value_types::double_t: + return static_cast<int64_t>(var_.value_.double_val_); + case value_types::integer_t: + return static_cast<int64_t>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<int64_t>(var_.value_.uinteger_val_); + case value_types::bool_t: + return var_.value_.bool_val_ ? 1 : 0; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an integer"); + } + } + + uint64_t as_uinteger() const + { + switch (var_.type_) + { + case value_types::double_t: + return static_cast<uint64_t>(var_.value_.double_val_); + case value_types::integer_t: + return static_cast<uint64_t>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<uint64_t>(var_.value_.uinteger_val_); + case value_types::bool_t: + return var_.value_.bool_val_ ? 1 : 0; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned integer"); + } + } + + double as_double() const + { + switch (var_.type_) + { + case value_types::double_t: + return var_.value_.double_val_; + case value_types::integer_t: + return static_cast<double>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<double>(var_.value_.uinteger_val_); + case value_types::null_t: + return std::numeric_limits<double>::quiet_NaN(); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a double"); + } + } + + string_type as_string() const JSONCONS_NOEXCEPT + { + switch (var_.type_) + { + case value_types::small_string_t: + return string_type(var_.value_.small_string_val_,var_.length_or_precision_); + case value_types::string_t: + return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),var_.value_.string_val_->get_allocator()); + default: + return to_string(); + } + } + + string_type as_string(const string_allocator& allocator) const JSONCONS_NOEXCEPT + { + switch (var_.type_) + { + case value_types::small_string_t: + return string_type(var_.value_.small_string_val_,var_.length_or_precision_,allocator); + case value_types::string_t: + return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),allocator); + default: + return to_string(allocator); + } + } + + string_type as_string(const basic_output_format<char_type>& format) const + { + switch (var_.type_) + { + case value_types::small_string_t: + return string_type(var_.value_.small_string_val_,var_.length_or_precision_); + case value_types::string_t: + return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),var_.value_.string_val_->get_allocator()); + default: + return to_string(format); + } + } + + string_type as_string(const basic_output_format<char_type>& format, + const string_allocator& allocator) const + { + switch (var_.type_) + { + case value_types::small_string_t: + return string_type(var_.value_.small_string_val_,var_.length_or_precision_,allocator); + case value_types::string_t: + return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),allocator); + default: + return to_string(format,allocator); + } + } + + const char_type* as_cstring() const + { + switch (var_.type_) + { + case value_types::small_string_t: + return var_.value_.small_string_val_; + case value_types::string_t: + return var_.value_.string_val_->c_str(); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a cstring"); + } + } + + any& any_value(); + + const any& any_value() const; + + basic_json<CharT, Alloc>& at(const string_type& name) + { + switch (var_.type_) + { + case value_types::empty_object_t: + JSONCONS_THROW_EXCEPTION_1(std::out_of_range,"%s not found", name); + case value_types::object_t: + { + auto it = var_.value_.object_val_->find(name.data(),name.length()); + if (it == members().end()) + { + JSONCONS_THROW_EXCEPTION_1(std::out_of_range, "%s not found", name); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + basic_json<CharT, Alloc>& evaluate() + { + return *this; + } + + basic_json<CharT, Alloc>& evaluate_with_default() + { + return *this; + } + + const basic_json<CharT, Alloc>& evaluate() const + { + return *this; + } + + basic_json<CharT, Alloc>& evaluate(size_t i) + { + return at(i); + } + + const basic_json<CharT, Alloc>& evaluate(size_t i) const + { + return at(i); + } + + basic_json<CharT, Alloc>& evaluate(const string_type& name) + { + return at(name); + } + + const basic_json<CharT, Alloc>& evaluate(const string_type& name) const + { + return at(name); + } + + const basic_json<CharT, Alloc>& at(const string_type& name) const + { + switch (var_.type_) + { + case value_types::empty_object_t: + JSONCONS_THROW_EXCEPTION_1(std::out_of_range,"%s not found", name); + case value_types::object_t: + { + auto it = var_.value_.object_val_->find(name.data(),name.length()); + if (it == members().end()) + { + JSONCONS_THROW_EXCEPTION_1(std::out_of_range, "%s not found", name); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + basic_json<CharT, Alloc>& at(size_t i) + { + switch (var_.type_) + { + case value_types::array_t: + if (i >= var_.value_.array_val_->size()) + { + JSONCONS_THROW_EXCEPTION(std::out_of_range,"Invalid array subscript"); + } + return var_.value_.array_val_->operator[](i); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Index on non-array value not supported"); + } + } + + const basic_json<CharT, Alloc>& at(size_t i) const + { + switch (var_.type_) + { + case value_types::array_t: + if (i >= var_.value_.array_val_->size()) + { + JSONCONS_THROW_EXCEPTION(std::out_of_range,"Invalid array subscript"); + } + return var_.value_.array_val_->operator[](i); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Index on non-array value not supported"); + } + } + + object_iterator find(const string_type& name) + { + switch (var_.type_) + { + case value_types::empty_object_t: + return members().end(); + case value_types::object_t: + return var_.value_.object_val_->find(name.data(),name.length()); + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + const_object_iterator find(const string_type& name) const + { + switch (var_.type_) + { + case value_types::empty_object_t: + return members().end(); + case value_types::object_t: + return var_.value_.object_val_->find(name.data(),name.length()); + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + object_iterator find(const char_type* name) + { + switch (var_.type_) + { + case value_types::empty_object_t: + return members().end(); + case value_types::object_t: + return var_.value_.object_val_->find(name, std::char_traits<char_type>::length(name)); + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + const_object_iterator find(const char_type* name) const + { + switch (var_.type_) + { + case value_types::empty_object_t: + return members().end(); + case value_types::object_t: + return var_.value_.object_val_->find(name, std::char_traits<char_type>::length(name)); + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + object_iterator find(const char_type* name, size_t length) + { + switch (var_.type_) + { + case value_types::empty_object_t: + return members().end(); + case value_types::object_t: + return var_.value_.object_val_->find(name, length); + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + const_object_iterator find(const char_type* name, size_t length) const + { + switch (var_.type_) + { + case value_types::empty_object_t: + return members().end(); + case value_types::object_t: + return var_.value_.object_val_->find(name, length); + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + template<typename T> + basic_json<CharT, Alloc> get(const string_type& name, T&& default_val) const + { + switch (var_.type_) + { + case value_types::empty_object_t: + { + return basic_json<CharT,Alloc>(std::forward<T>(default_val)); + } + case value_types::object_t: + { + const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); + if (it != members().end()) + { + return it->value(); + } + else + { + return basic_json<CharT,Alloc>(std::forward<T>(default_val)); + } + } + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + // Modifiers + + void shrink_to_fit() + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->shrink_to_fit(); + break; + case value_types::object_t: + var_.value_.object_val_->shrink_to_fit(); + break; + default: + break; + } + } + + void clear() + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->clear(); + break; + case value_types::object_t: + var_.value_.object_val_->clear(); + break; + default: + break; + } + } + + void erase(object_iterator first, object_iterator last) + { + switch (var_.type_) + { + case value_types::empty_object_t: + break; + case value_types::object_t: + var_.value_.object_val_->erase(first, last); + break; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); + break; + } + } + + void erase(array_iterator first, array_iterator last) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->erase(first, last); + break; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); + break; + } + } + + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void erase(const string_type& name) + { + switch (var_.type_) + { + case value_types::empty_object_t: + break; + case value_types::object_t: + var_.value_.object_val_->erase(name.data(),name.length()); + break; + default: + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); + break; + } + } + + void set(const string_type& name, const basic_json<CharT, Alloc>& value) + { + switch (var_.type_) + { + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + var_.value_.object_val_->set(name, value); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); + } + } + } + + void set(string_type&& name, const basic_json<CharT, Alloc>& value){ + switch (var_.type_){ + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + var_.value_.object_val_->set(std::move(name),value); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); + } + } + } + + void set(const string_type& name, basic_json<CharT, Alloc>&& value){ + switch (var_.type_){ + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + var_.value_.object_val_->set(name,std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); + } + } + } + + void set(string_type&& name, basic_json<CharT, Alloc>&& value) + { + switch (var_.type_) + { + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + var_.value_.object_val_->set(std::move(name),std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); + } + } + } + + object_iterator set(object_iterator hint, const string_type& name, const basic_json<CharT, Alloc>& value) + { + switch (var_.type_) + { + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + return var_.value_.object_val_->set(hint, name, value); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); + } + } + } + + object_iterator set(object_iterator hint, string_type&& name, const basic_json<CharT, Alloc>& value){ + switch (var_.type_){ + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + return var_.value_.object_val_->set(hint, std::move(name),value); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); + } + } + } + + object_iterator set(object_iterator hint, const string_type& name, basic_json<CharT, Alloc>&& value){ + switch (var_.type_){ + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + return var_.value_.object_val_->set(hint, name,std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); + } + } + } + + object_iterator set(object_iterator hint, string_type&& name, basic_json<CharT, Alloc>&& value){ + switch (var_.type_){ + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + return var_.value_.object_val_->set(hint, std::move(name),std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); + } + } + } + + void add(const basic_json<CharT, Alloc>& value) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->push_back(value); + break; + default: + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); + } + } + } + + void add(basic_json<CharT, Alloc>&& value){ + switch (var_.type_){ + case value_types::array_t: + var_.value_.array_val_->push_back(std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); + } + } + } + + array_iterator add(const_array_iterator pos, const basic_json<CharT, Alloc>& value) + { + switch (var_.type_) + { + case value_types::array_t: + return var_.value_.array_val_->add(pos, value); + break; + default: + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); + } + } + } + + array_iterator add(const_array_iterator pos, basic_json<CharT, Alloc>&& value){ + switch (var_.type_){ + case value_types::array_t: + return var_.value_.array_val_->add(pos, std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); + } + } + } + + value_types type() const + { + return var_.type_; + } + + uint8_t length_or_precision() const + { + return var_.length_or_precision_; + } + + void swap(basic_json<CharT,Alloc>& b) + { + var_.swap(b.var_); + } + + template <class T> + std::vector<T> as_vector() const + { + std::vector<T> v(size()); + for (size_t i = 0; i < v.size(); ++i) + { + v[i] = json_type_traits<value_type,T>::as(at(i)); + } + return v; + } + + friend void swap(basic_json<CharT,Alloc>& a, basic_json<CharT,Alloc>& b) + { + a.swap(b); + } + + void assign_any(const typename basic_json<CharT,Alloc>::any& rhs) + { + var_.assign(rhs); + } + + void assign_string(const string_type& rhs) + { + var_.assign(rhs); + } + + void assign_string(const char_type* rhs, size_t length) + { + var_.assign_string(rhs,length); + } + + void assign_bool(bool rhs) + { + var_.assign(rhs); + } + + void assign_object(const object & rhs) + { + var_.assign(rhs); + } + + void assign_array(const array& rhs) + { + var_.assign(rhs); + } + + void assign_null() + { + var_.assign(null_type()); + } + + template <typename T> + const T& any_cast() const + { + if (var_.type_ != value_types::any_t) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad any cast"); + } + return var_.value_.any_val_->template cast<T>(); + } + template <typename T> + T& any_cast() + { + if (var_.type_ != value_types::any_t) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad any cast"); + } + return var_.value_.any_val_->template cast<T>(); + } + + void assign_integer(int64_t rhs) + { + var_.assign(rhs); + } + + void assign_uinteger(uint64_t rhs) + { + var_.assign(rhs); + } + + void assign_double(double rhs, uint8_t precision = 0) + { + var_.assign(rhs,precision); + } + + static basic_json make_2d_array(size_t m, size_t n); + + template <typename T> + static basic_json make_2d_array(size_t m, size_t n, T val); + + static basic_json make_3d_array(size_t m, size_t n, size_t k); + + template <typename T> + static basic_json make_3d_array(size_t m, size_t n, size_t k, T val); + +#if !defined(JSONCONS_NO_DEPRECATED) + typedef any json_any_type; + + static basic_json parse(std::basic_istream<char_type>& is) + { + return parse_stream(is); + } + static basic_json parse(std::basic_istream<char_type>& is, basic_parse_error_handler<char_type>& err_handler) + { + return parse_stream(is,err_handler); + } + + static basic_json parse_string(const string_type& s) + { + return parse(s); + } + + static basic_json parse_string(const string_type& s, basic_parse_error_handler<char_type>& err_handler) + { + return parse(s,err_handler); + } + + void resize_array(size_t n) + { + resize(n); + } + + template <typename T> + void resize_array(size_t n, T val) + { + resize(n,val); + } + + object_iterator begin_members() + { + return members().begin(); + } + + const_object_iterator begin_members() const + { + return members().begin(); + } + + object_iterator end_members() + { + return members().end(); + } + + const_object_iterator end_members() const + { + return members().end(); + } + + array_iterator begin_elements() + { + return elements().begin(); + } + + const_array_iterator begin_elements() const + { + return elements().begin(); + } + + array_iterator end_elements() + { + return elements().end(); + } + + const_array_iterator end_elements() const + { + return elements().end(); + } + + const basic_json<CharT,Alloc>& get(const string_type& name) const + { + static const basic_json<CharT, Alloc> a_null = null_type(); + + switch (var_.type_) + { + case value_types::empty_object_t: + return a_null; + case value_types::object_t: + { + const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); + return it != members().end() ? it->value() : a_null; + } + default: + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); + } + } + } + + bool is_longlong() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::integer_t; + } + + bool is_ulonglong() const JSONCONS_NOEXCEPT + { + return var_.type_ == value_types::uinteger_t; + } + + long long as_longlong() const + { + return as_integer(); + } + + unsigned long long as_ulonglong() const + { + return as_uinteger(); + } + + int as_int() const + { + switch (var_.type_) + { + case value_types::double_t: + return static_cast<int>(var_.value_.double_val_); + case value_types::integer_t: + return static_cast<int>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<int>(var_.value_.uinteger_val_); + case value_types::bool_t: + return var_.value_.bool_val_ ? 1 : 0; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an int"); + } + } + + unsigned int as_uint() const + { + switch (var_.type_) + { + case value_types::double_t: + return static_cast<unsigned int>(var_.value_.double_val_); + case value_types::integer_t: + return static_cast<unsigned int>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<unsigned int>(var_.value_.uinteger_val_); + case value_types::bool_t: + return var_.value_.bool_val_ ? 1 : 0; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned int"); + } + } + + long as_long() const + { + switch (var_.type_) + { + case value_types::double_t: + return static_cast<long>(var_.value_.double_val_); + case value_types::integer_t: + return static_cast<long>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<long>(var_.value_.uinteger_val_); + case value_types::bool_t: + return var_.value_.bool_val_ ? 1 : 0; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a long"); + } + } + + unsigned long as_ulong() const + { + switch (var_.type_) + { + case value_types::double_t: + return static_cast<unsigned long>(var_.value_.double_val_); + case value_types::integer_t: + return static_cast<unsigned long>(var_.value_.integer_val_); + case value_types::uinteger_t: + return static_cast<unsigned long>(var_.value_.uinteger_val_); + case value_types::bool_t: + return var_.value_.bool_val_ ? 1 : 0; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned long"); + } + } + + void add(size_t index, const basic_json<CharT, Alloc>& value) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->add(index, value); + break; + default: + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); + } + } + } + + void add(size_t index, basic_json<CharT, Alloc>&& value){ + switch (var_.type_){ + case value_types::array_t: + var_.value_.array_val_->add(index, std::move(value)); + break; + default: + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); + } + } + } + + bool has_member(const string_type& name) const + { + switch (var_.type_) + { + case value_types::object_t: + { + const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); + return it != members().end(); + } + break; + default: + return false; + } + } + + void remove_range(size_t from_index, size_t to_index) + { + switch (var_.type_) + { + case value_types::array_t: + var_.value_.array_val_->remove_range(from_index, to_index); + break; + default: + break; + } + } + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void remove(const string_type& name) + { + erase(name.data(),name.length()); + } + void remove_member(const string_type& name) + { + erase(name.data(),name.length()); + } + // Removes a member from an object value + + bool is_empty() const JSONCONS_NOEXCEPT + { + return empty(); + } + bool is_numeric() const JSONCONS_NOEXCEPT + { + return is_number(); + } + + void assign_longlong(long long rhs) + { + var_.assign(rhs); + } + void assign_ulonglong(unsigned long long rhs) + { + var_.assign(rhs); + } + + template<int size> + static typename std::enable_if<size==1,basic_json>::type make_multi_array() + { + return make_array(); + } + template<size_t size> + static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n) + { + return make_array(n); + } + template<size_t size,typename T> + static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n, T val) + { + return make_array(n,val); + } + template<size_t size> + static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n) + { + return make_array<2>(m, n); + } + template<size_t size,typename T> + static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n, T val) + { + return make_array<2>(m, n, val); + } + template<size_t size> + static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k) + { + return make_array<3>(m, n, k); + } + template<size_t size,typename T> + static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k, T val) + { + return make_array<3>(m, n, k, val); + } +#endif + + object_range members() + { + switch (var_.type_) + { + case value_types::empty_object_t: + return object_range(object_iterator(true),object_iterator(true)); + case value_types::object_t: + return object_range(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); + } + } + + const_object_range members() const + { + switch (var_.type_) + { + case value_types::empty_object_t: + return const_object_range(const_object_iterator(true),const_object_iterator(true)); + case value_types::object_t: + return const_object_range(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); + } + } + + array_range elements() + { + switch (var_.type_) + { + case value_types::array_t: + return array_range(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); + } + } + + const_array_range elements() const + { + switch (var_.type_) + { + case value_types::array_t: + return const_array_range(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); + } + } + + array& array_value() + { + switch (var_.type_) + { + case value_types::array_t: + return *(var_.value_.array_val_); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad array cast"); + break; + } + } + + const array& array_value() const + { + switch (var_.type_) + { + case value_types::array_t: + return *(var_.value_.array_val_); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad array cast"); + break; + } + } + + object& object_value() + { + switch (var_.type_) + { + case value_types::empty_object_t: + create_object_implicitly(); + case value_types::object_t: + return *(var_.value_.object_val_); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad object cast"); + break; + } + } + + const object& object_value() const + { + switch (var_.type_) + { + case value_types::empty_object_t: + const_cast<value_type*>(this)->create_object_implicitly(); // HERE + case value_types::object_t: + return *(var_.value_.object_val_); + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad object cast"); + break; + } + } + +private: + + friend std::basic_ostream<typename string_type::value_type>& operator<<(std::basic_ostream<typename string_type::value_type>& os, const basic_json<CharT, Alloc>& o) + { + o.to_stream(os); + return os; + } + + friend std::basic_istream<typename string_type::value_type>& operator<<(std::basic_istream<typename string_type::value_type>& is, basic_json<CharT, Alloc>& o) + { + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + basic_json_reader<typename string_type::value_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); + } + o = handler.get_result(); + return is; + } +}; + +template <class JsonT> +void swap(typename JsonT::member_type& a, typename JsonT::member_type& b) +{ + a.swap(b); +} + +template<typename CharT, typename Alloc> +bool basic_json<CharT, Alloc>::operator!=(const basic_json<CharT, Alloc>& rhs) const +{ + return !(*this == rhs); +} + +template<typename CharT, typename Alloc> +bool basic_json<CharT, Alloc>::operator==(const basic_json<CharT, Alloc>& rhs) const +{ + return var_ == rhs.var_; +} + +template<typename CharT, typename Alloc> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_2d_array(size_t m, size_t n) +{ + basic_json<CharT, Alloc> a = basic_json<CharT, Alloc>::array(); + a.resize(m); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] = basic_json<CharT, Alloc>::make_array(n); + } + return a; +} + +template<typename CharT, typename Alloc> +template<typename T> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_2d_array(size_t m, size_t n, T val) +{ + basic_json<CharT, Alloc> v; + v = val; + basic_json<CharT, Alloc> a = make_array(m); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] = basic_json<CharT, Alloc>::make_array(n, v); + } + return a; +} + +template<typename CharT, typename Alloc> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_3d_array(size_t m, size_t n, size_t k) +{ + basic_json<CharT, Alloc> a = basic_json<CharT, Alloc>::array(); + a.resize(m); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] = basic_json<CharT, Alloc>::make_2d_array(n, k); + } + return a; +} + +template<typename CharT, typename Alloc> +template<typename T> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_3d_array(size_t m, size_t n, size_t k, T val) +{ + basic_json<CharT, Alloc> v; + v = val; + basic_json<CharT, Alloc> a = make_array(m); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] = basic_json<CharT, Alloc>::make_2d_array(n, k, v); + } + return a; +} + +template<typename CharT, typename Alloc> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_stream(std::basic_istream<char_type>& is) +{ + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + basic_json_reader<char_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); + } + return handler.get_result(); +} + +template<typename CharT, typename Alloc> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_stream(std::basic_istream<char_type>& is, + basic_parse_error_handler<char_type>& err_handler) +{ + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + basic_json_reader<char_type> reader(is, handler, err_handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); + } + return handler.get_result(); +} + +template<typename CharT, typename Alloc> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_file(const std::string& filename) +{ + FILE* fp; + +#if defined(JSONCONS_HAS_FOPEN_S) + errno_t err = fopen_s(&fp, filename.c_str(), "rb"); + if (err != 0) + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); + } +#else + fp = std::fopen(filename.c_str(), "rb"); + if (fp == nullptr) + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); + } +#endif + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + try + { + // obtain file size: + std::fseek (fp , 0 , SEEK_END); + long size = std::ftell (fp); + std::rewind(fp); + + if (size > 0) + { + std::vector<char_type> buffer(size); + + // copy the file into the buffer: + size_t result = std::fread (buffer.data(),1,size,fp); + if (result != static_cast<unsigned long long>(size)) + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Error reading file %s", filename); + } + + basic_json_parser<char_type> parser(handler); + parser.begin_parse(); + parser.parse(buffer.data(),0,buffer.size()); + parser.end_parse(); + parser.check_done(buffer.data(),parser.index(),buffer.size()); + } + + std::fclose (fp); + } + catch (...) + { + std::fclose (fp); + throw; + } + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json file"); + } + return handler.get_result(); +} + +template<typename CharT, typename Alloc> +basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_file(const std::string& filename, + basic_parse_error_handler<char_type>& err_handler) +{ + FILE* fp; + +#if !defined(JSONCONS_HAS_FOPEN_S) + fp = std::fopen(filename.c_str(), "rb"); + if (fp == nullptr) + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); + } +#else + errno_t err = fopen_s(&fp, filename.c_str(), "rb"); + if (err != 0) + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); + } +#endif + + basic_json_deserializer<basic_json<CharT, Alloc>> handler; + try + { + // obtain file size: + std::fseek (fp , 0 , SEEK_END); + long size = std::ftell (fp); + std::rewind(fp); + + if (size > 0) + { + std::vector<char_type> buffer(size); + + // copy the file into the buffer: + size_t result = std::fread (buffer.data(),1,size,fp); + if (result != static_cast<unsigned long long>(size)) + { + JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Error reading file %s", filename); + } + + basic_json_parser<char_type> parser(handler,err_handler); + parser.begin_parse(); + parser.parse(buffer.data(),0,buffer.size()); + parser.end_parse(); + parser.check_done(buffer.data(),parser.index(),buffer.size()); + } + + std::fclose (fp); + } + catch (...) + { + std::fclose (fp); + throw; + } + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json file"); + } + return handler.get_result(); +} + +template<typename CharT, typename Alloc> +typename basic_json<CharT, Alloc>::any& basic_json<CharT, Alloc>::any_value() +{ + switch (var_.type_) + { + case value_types::any_t: + { + return *var_.value_.any_val_; + } + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an any value"); + } +} + +template<typename CharT, typename Alloc> +const typename basic_json<CharT, Alloc>::any& basic_json<CharT, Alloc>::any_value() const +{ + switch (var_.type_) + { + case value_types::any_t: + { + return *var_.value_.any_val_; + } + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an any value"); + } +} + +template <typename JsonT> +std::basic_istream<typename JsonT::char_type>& operator>>(std::basic_istream<typename JsonT::char_type>& is, JsonT& o) +{ + basic_json_deserializer<JsonT> handler; + basic_json_reader<typename JsonT::char_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); + } + o = handler.get_result(); + return is; +} + +template<typename JsonT> +class json_printable +{ +public: + typedef typename JsonT::char_type char_type; + + json_printable(const JsonT& o, + bool is_pretty_print) + : o_(&o), is_pretty_print_(is_pretty_print) + { + } + + json_printable(const JsonT& o, + bool is_pretty_print, + const basic_output_format<char_type>& format) + : o_(&o), is_pretty_print_(is_pretty_print), format_(format) + { + ; + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + o_->to_stream(os, format_, is_pretty_print_); + } + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_printable<JsonT>& o) + { + o.to_stream(os); + return os; + } + + const JsonT *o_; + bool is_pretty_print_; + basic_output_format<char_type> format_; +private: + json_printable(); +}; + +template<typename JsonT> +json_printable<JsonT> print(const JsonT& val) +{ + return json_printable<JsonT>(val,false); +} + +template<class JsonT> +json_printable<JsonT> print(const JsonT& val, + const basic_output_format<typename JsonT::char_type>& format) +{ + return json_printable<JsonT>(val, false, format); +} + +template<class JsonT> +json_printable<JsonT> pretty_print(const JsonT& val) +{ + return json_printable<JsonT>(val,true); +} + +template<typename JsonT> +json_printable<JsonT> pretty_print(const JsonT& val, + const basic_output_format<typename JsonT::char_type>& format) +{ + return json_printable<JsonT>(val, true, format); +} + +typedef basic_json<char,std::allocator<char>> json; +typedef basic_json<wchar_t,std::allocator<wchar_t>> wjson; + +typedef basic_json_deserializer<json> json_deserializer; +typedef basic_json_deserializer<wjson> wjson_deserializer; + +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_deserializer.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_deserializer.hpp new file mode 100644 index 00000000..31cd0db9 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_deserializer.hpp @@ -0,0 +1,267 @@ +// Copyright 2013-2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_DESERIALIZER_HPP +#define JSONCONS_JSON_DESERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_input_handler.hpp" + +namespace jsoncons { + +template <class JsonT> +class basic_json_deserializer : public basic_json_input_handler<typename JsonT::char_type> +{ + static const int default_stack_size = 1000; + + typedef typename JsonT::char_type char_type; + typedef typename JsonT::member_type member_type; + typedef typename JsonT::string_type string_type; + typedef typename string_type::allocator_type string_allocator; + typedef typename JsonT::allocator_type allocator_type; + typedef typename JsonT::array array; + typedef typename array::allocator_type array_allocator; + typedef typename JsonT::object object; + typedef typename object::allocator_type object_allocator; + typedef typename JsonT::value_type value_type; + + string_allocator sa_; + object_allocator oa_; + array_allocator aa_; + + JsonT result_; + size_t top_; + + struct stack_item + { + string_type name_; + value_type value_; + }; + std::vector<stack_item> stack_; + std::vector<size_t> stack2_; + bool is_valid_; + +public: + basic_json_deserializer(const string_allocator& sa = string_allocator(), + const allocator_type& allocator = allocator_type()) + : sa_(sa), + oa_(allocator), + aa_(allocator), + top_(0), + stack_(default_stack_size), + stack2_(), + is_valid_(true) // initial json value is an empty object + + { + stack2_.reserve(100); + } + + bool is_valid() const + { + return is_valid_; + } + + JsonT get_result() + { + is_valid_ = false; + return std::move(result_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JsonT& root() + { + return result_; + } +#endif + +private: + + void push_initial() + { + top_ = 0; + if (top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void pop_initial() + { + JSONCONS_ASSERT(top_ == 1); + result_.swap(stack_[0].value_); + --top_; + } + + void push_object() + { + stack2_.push_back(top_); + stack_[top_].value_ = object(oa_); + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void pop_object() + { + stack2_.pop_back(); + JSONCONS_ASSERT(top_ > 0); + } + + void push_array() + { + stack2_.push_back(top_); + stack_[top_].value_ = array(aa_); + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void pop_array() + { + stack2_.pop_back(); + JSONCONS_ASSERT(top_ > 0); + } + + void do_begin_json() override + { + is_valid_ = false; + push_initial(); + } + + void do_end_json() override + { + is_valid_ = true; + pop_initial(); + } + + void do_begin_object(const basic_parsing_context<char_type>&) override + { + push_object(); + } + + void do_end_object(const basic_parsing_context<char_type>&) override + { + end_structure(); + pop_object(); + } + + void do_begin_array(const basic_parsing_context<char_type>&) override + { + push_array(); + } + + void do_end_array(const basic_parsing_context<char_type>&) override + { + end_structure(); + pop_array(); + } + + static member_type move_pair(stack_item&& val) + { + return member_type(std::move(val.name_),std::move(val.value_)); + } + + void end_structure() + { + JSONCONS_ASSERT(stack2_.size() > 0); + if (stack_[stack2_.back()].value_.is_object()) + { + size_t count = top_ - (stack2_.back() + 1); + auto s = stack_.begin() + (stack2_.back()+1); + auto send = s + count; + stack_[stack2_.back()].value_.object_value().insert( + std::make_move_iterator(s), + std::make_move_iterator(send), + move_pair); + top_ -= count; + } + else + { + size_t count = top_ - (stack2_.back() + 1); + stack_[stack2_.back()].value_.resize(count); + + auto s = stack_.begin() + (stack2_.back()+1); + auto dend = stack_[stack2_.back()].value_.elements().end(); + for (auto it = stack_[stack2_.back()].value_.elements().begin(); + it != dend; ++it, ++s) + { + *it = std::move(s->value_); + } + top_ -= count; + } + } + + void do_name(const char_type* p, size_t length, const basic_parsing_context<char_type>&) override + { + stack_[top_].name_ = string_type(p,length,sa_); + } + + void do_string_value(const char_type* p, size_t length, const basic_parsing_context<char_type>&) override + { + stack_[top_].value_ = JsonT(p,length,sa_); + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void do_integer_value(int64_t value, const basic_parsing_context<char_type>&) override + { + stack_[top_].value_ = value; + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void do_uinteger_value(uint64_t value, const basic_parsing_context<char_type>&) override + { + stack_[top_].value_ = value; + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void do_double_value(double value, uint8_t precision, const basic_parsing_context<char_type>&) override + { + stack_[top_].value_ = value_type(value,precision); + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void do_bool_value(bool value, const basic_parsing_context<char_type>&) override + { + stack_[top_].value_ = value; + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } + + void do_null_value(const basic_parsing_context<char_type>&) override + { + stack_[top_].value_ = null_type(); + if (++top_ >= stack_.size()) + { + stack_.resize(top_*2); + } + } +}; + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_error_category.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_error_category.hpp new file mode 100644 index 00000000..90d12d56 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_error_category.hpp @@ -0,0 +1,111 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_TEXT_ERROR_CATEGORY_HPP +#define JSONCONS_JSON_TEXT_ERROR_CATEGORY_HPP + +#include "jsoncons/jsoncons.hpp" +#include <system_error> + +namespace jsoncons { + +namespace json_parser_errc +{ + const int unexpected_eof = 1; + const int invalid_json_text = 2; + const int extra_character = 3; + const int max_depth_exceeded = 4; + const int single_quote = 5; + const int illegal_character_in_string = 6; + const int extra_comma = 7; + const int expected_name = 8; + const int expected_value = 9; + const int invalid_value = 10; + const int expected_colon = 11; + const int illegal_control_character = 12; + const int illegal_escaped_character = 13; + const int expected_codepoint_surrogate_pair = 14; + const int invalid_hex_escape_sequence = 15; + const int invalid_unicode_escape_sequence = 16; + const int leading_zero = 17; + const int invalid_number = 18; + const int expected_comma_or_right_brace = 19; + const int expected_comma_or_right_bracket = 20; + const int unexpected_right_bracket = 21; + const int unexpected_right_brace = 22; +} + +class json_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "json"; + } + virtual std::string message(int ev) const + { + switch (ev) + { + case json_parser_errc::unexpected_eof: + return "Unexpected end of file"; + case json_parser_errc::invalid_json_text: + return "Invalid JSON text"; + case json_parser_errc::extra_character: + return "Unexpected non-whitespace character after JSON text"; + case json_parser_errc::max_depth_exceeded: + return "Maximum JSON depth exceeded"; + case json_parser_errc::single_quote: + return "JSON strings cannot be quoted with single quotes"; + case json_parser_errc::illegal_character_in_string: + return "Illegal character in string"; + case json_parser_errc::extra_comma: + return "Extra comma"; + case json_parser_errc::expected_name: + return "Expected object member name"; + case json_parser_errc::expected_value: + return "Expected value"; + case json_parser_errc::invalid_value: + return "Invalid value"; + case json_parser_errc::expected_colon: + return "Expected name separator ':'"; + case json_parser_errc::illegal_control_character: + return "Illegal control character in string"; + case json_parser_errc::illegal_escaped_character: + return "Illegal escaped character in string"; + case json_parser_errc::expected_codepoint_surrogate_pair: + return "Invalid codepoint, expected another \\u token to begin the second half of a codepoint surrogate pair."; + case json_parser_errc::invalid_hex_escape_sequence: + return "Invalid codepoint, expected hexadecimal digit."; + case json_parser_errc::invalid_unicode_escape_sequence: + return "Invalid codepoint, expected four hexadecimal digits."; + case json_parser_errc::leading_zero: + return "A number cannot have a leading zero"; + case json_parser_errc::invalid_number: + return "Invalid number"; + case json_parser_errc::expected_comma_or_right_brace: + return "Expected comma or right brace ']'"; + case json_parser_errc::expected_comma_or_right_bracket: + return "Expected comma or right bracket ']'"; + case json_parser_errc::unexpected_right_brace: + return "Unexpected right brace '}'"; + case json_parser_errc::unexpected_right_bracket: + return "Unexpected right bracket ']'"; + default: + return "Unknown JSON parser error"; + } + } +}; + +inline +const std::error_category& json_error_category() +{ + static json_error_category_impl instance; + return instance; +} + +} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_filter.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_filter.hpp new file mode 100644 index 00000000..2019c01d --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_filter.hpp @@ -0,0 +1,324 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_FILTER_HPP +#define JSONCONS_JSON_FILTER_HPP + +#include <string> + +#include "jsoncons/json_input_handler.hpp" +#include "jsoncons/json_output_handler.hpp" +#include "jsoncons/parse_error_handler.hpp" + +namespace jsoncons { + +template <typename CharT> +class basic_json_input_output_adapter : public basic_json_input_handler<CharT> +{ +public: + basic_json_input_output_adapter() + : writer_(std::addressof(null_json_output_handler<CharT>())) + { + } + + basic_json_input_output_adapter(basic_json_output_handler<CharT>& handler) + : writer_(std::addressof(handler)) + { + } + +private: + + void do_begin_json() override + { + writer_->begin_json(); + } + + void do_end_json() override + { + writer_->end_json(); + } + + void do_begin_object(const basic_parsing_context<CharT>& context) override + { + writer_->begin_object(); + } + + void do_end_object(const basic_parsing_context<CharT>& context) override + { + writer_->end_object(); + } + + void do_begin_array(const basic_parsing_context<CharT>& context) override + { + writer_->begin_array(); + } + + void do_end_array(const basic_parsing_context<CharT>& context) override + { + writer_->end_array(); + } + + void do_name(const CharT* name, size_t length, + const basic_parsing_context<CharT>& context) override + { + writer_->name(name, length); + } + + void do_string_value(const CharT* value, size_t length, + const basic_parsing_context<CharT>& context) override + { + writer_->value(value, length); + } + + void do_integer_value(int64_t value, const basic_parsing_context<CharT>& context) override + { + writer_->value(value); + } + + void do_uinteger_value(uint64_t value, + const basic_parsing_context<CharT>& context) override + { + writer_->value(value); + } + + void do_double_value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) override + { + writer_->value(value, precision); + } + + void do_bool_value(bool value, const basic_parsing_context<CharT>& context) override + { + writer_->value(value); + } + + void do_null_value(const basic_parsing_context<CharT>& context) override + { + writer_->value(null_type()); + } + + basic_json_output_handler<CharT>* writer_; +}; + +template <typename CharT> +class basic_json_filter : public basic_json_input_handler<CharT> +{ +public: + basic_json_filter(basic_json_input_handler<CharT>& handler) + : handler_(std::addressof(handler)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())) + { + } + + basic_json_filter(basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler) + : handler_(std::addressof(handler)), + err_handler_(std::addressof(err_handler)) + { + } + + basic_json_filter(basic_json_output_handler<CharT>& output_handler) + : input_output_adapter_(output_handler), handler_(std::addressof(input_output_adapter_)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())) + { + } + + basic_json_filter(basic_json_output_handler<CharT>& output_handler, + basic_parse_error_handler<CharT>& err_handler) + : input_output_adapter_(output_handler), handler_(std::addressof(input_output_adapter_)), + err_handler_(std::addressof(err_handler)) + { + } + + basic_json_input_handler<CharT>& input_handler() + { + return *handler_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_json_input_handler<CharT>& parent() + { + return *handler_; + } +#endif + +private: + void do_begin_json() override + { + handler_->begin_json(); + } + + void do_end_json() override + { + handler_->end_json(); + } + + void do_begin_object(const basic_parsing_context<CharT>& context) override + { + handler_->begin_object(context); + } + + void do_end_object(const basic_parsing_context<CharT>& context) override + { + handler_->end_object(context); + } + + void do_begin_array(const basic_parsing_context<CharT>& context) override + { + handler_->begin_array(context); + } + + void do_end_array(const basic_parsing_context<CharT>& context) override + { + handler_->end_array(context); + } + + void do_name(const CharT* name, size_t length, const basic_parsing_context<CharT>& context) override + { + handler_->name(name, length, context); + } + + void do_string_value(const CharT* value, size_t length, const basic_parsing_context<CharT>& context) override + { + handler_->value(value,length,context); + } + + void do_double_value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) override + { + handler_->value(value,precision,context); + } + + void do_integer_value(int64_t value, const basic_parsing_context<CharT>& context) override + { + handler_->value(value,context); + } + + void do_uinteger_value(uint64_t value, const basic_parsing_context<CharT>& context) override + { + handler_->value(value,context); + } + + void do_bool_value(bool value, const basic_parsing_context<CharT>& context) override + { + handler_->value(value,context); + } + + void do_null_value(const basic_parsing_context<CharT>& context) override + { + handler_->value(null_type(),context); + } + + basic_json_input_output_adapter<CharT> input_output_adapter_; + basic_json_input_handler<CharT>* handler_; + basic_parse_error_handler<CharT>* err_handler_; +}; + +// Filters out begin_json and end_json events +template <typename CharT> +class basic_begin_end_json_filter : public basic_json_filter<CharT> +{ +public: + basic_begin_end_json_filter(basic_json_input_handler<CharT>& handler) + : basic_json_filter<CharT>(handler) + { + } +private: + void do_begin_json() override + { + } + + void do_end_json() override + { + } +}; + +template <typename CharT> +class basic_json_output_input_adapter : public basic_json_output_handler<CharT> +{ +public: + basic_json_output_input_adapter(basic_json_input_handler<CharT>& input_handler, + const basic_parsing_context<CharT>& context) + : input_handler_(std::addressof(input_handler)), + context_(std::addressof(context)) + { + } + +private: + + void do_begin_json() override + { + input_handler_->begin_json(); + } + + void do_end_json() override + { + input_handler_->end_json(); + } + + void do_begin_object() override + { + input_handler_->begin_object(*context_); + } + + void do_end_object() override + { + input_handler_->end_object(*context_); + } + + void do_begin_array() override + { + input_handler_->begin_array(*context_); + } + + void do_end_array() override + { + input_handler_->end_array(*context_); + } + + void do_name(const CharT* name, size_t length) override + { + input_handler_->name(name, length, *context_); + } + + void do_string_value(const CharT* value, size_t length) override + { + input_handler_->value(value, length, *context_); + } + + void do_integer_value(int64_t value) override + { + input_handler_->value(value, *context_); + } + + void do_uinteger_value(uint64_t value) override + { + input_handler_->value(value, *context_); + } + + void do_double_value(double value, uint8_t precision) override + { + input_handler_->value(value, precision, *context_); + } + + void do_bool_value(bool value) override + { + input_handler_->value(value, *context_); + } + + void do_null_value() override + { + input_handler_->value(null_type(), *context_); + } + + basic_json_input_handler<CharT>* input_handler_; + const basic_parsing_context<CharT>* context_; +}; + +typedef basic_json_filter<char> json_filter; +typedef basic_json_filter<wchar_t> wjson_filter; + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_input_handler.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_input_handler.hpp new file mode 100644 index 00000000..566209e5 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_input_handler.hpp @@ -0,0 +1,282 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_INPUT_HANDLER_HPP +#define JSONCONS_JSON_INPUT_HANDLER_HPP + +#include <string> +#include "jsoncons/jsoncons.hpp" + +namespace jsoncons { + +template<typename CharT> +uint64_t string_to_uinteger(const CharT *s, size_t length) throw(std::overflow_error) +{ + static const uint64_t max_value = std::numeric_limits<uint64_t>::max JSONCONS_NO_MACRO_EXP(); + static const uint64_t max_value_div_10 = max_value / 10; + uint64_t n = 0; + for (size_t i = 0; i < length; ++i) + { + uint64_t x = s[i] - '0'; + if (n > max_value_div_10) + { + throw std::overflow_error("Unsigned overflow"); + } + n = n * 10; + if (n > max_value - x) + { + throw std::overflow_error("Unsigned overflow"); + } + + n += x; + } + return n; +} + +template<typename CharT> +int64_t string_to_integer(bool has_neg, const CharT *s, size_t length) throw(std::overflow_error) +{ + const long long max_value = std::numeric_limits<int64_t>::max JSONCONS_NO_MACRO_EXP(); + const long long max_value_div_10 = max_value / 10; + + long long n = 0; + for (size_t i = 0; i < length; ++i) + { + long long x = s[i] - '0'; + if (n > max_value_div_10) + { + throw std::overflow_error("Integer overflow"); + } + n = n * 10; + if (n > max_value - x) + { + throw std::overflow_error("Integer overflow"); + } + + n += x; + } + return has_neg ? -n : n; +} + +template <typename CharT> +class basic_parsing_context; + +template <typename CharT> +class basic_json_input_handler +{ +public: + virtual ~basic_json_input_handler() {} + + void begin_json() + { + do_begin_json(); + } + + void end_json() + { + do_end_json(); + } + + void begin_object(const basic_parsing_context<CharT>& context) + { + do_begin_object(context); + } + + void end_object(const basic_parsing_context<CharT>& context) + { + do_end_object(context); + } + + void begin_array(const basic_parsing_context<CharT>& context) + { + do_begin_array(context); + } + + void end_array(const basic_parsing_context<CharT>& context) + { + do_end_array(context); + } + + void name(const std::basic_string<CharT>& name, const basic_parsing_context<CharT>& context) + { + do_name(name.data(), name.length(), context); + } + + void name(const CharT* p, size_t length, const basic_parsing_context<CharT>& context) + { + do_name(p, length, context); + } + + void value(const std::basic_string<CharT>& value, const basic_parsing_context<CharT>& context) + { + do_string_value(value.data(), value.length(), context); + } + + void value(const CharT* p, size_t length, const basic_parsing_context<CharT>& context) + { + do_string_value(p, length, context); + } + + void value(const CharT* p, const basic_parsing_context<CharT>& context) + { + do_string_value(p, std::char_traits<CharT>::length(p), context); + } + + void value(int value, const basic_parsing_context<CharT>& context) + { + do_integer_value(value,context); + } + + void value(long value, const basic_parsing_context<CharT>& context) + { + do_integer_value(value,context); + } + + void value(long long value, const basic_parsing_context<CharT>& context) + { + do_integer_value(value,context); + } + + void value(unsigned int value, const basic_parsing_context<CharT>& context) + { + do_uinteger_value(value,context); + } + + void value(unsigned long value, const basic_parsing_context<CharT>& context) + { + do_uinteger_value(value,context); + } + + void value(unsigned long long value, const basic_parsing_context<CharT>& context) + { + do_uinteger_value(value,context); + } + + void value(float value, uint8_t precision, const basic_parsing_context<CharT>& context) + { + do_double_value(value, precision, context); + } + + void value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) + { + do_double_value(value, precision, context); + } + + void value(bool value, const basic_parsing_context<CharT>& context) + { + do_bool_value(value,context); + } + + void value(null_type, const basic_parsing_context<CharT>& context) + { + do_null_value(context); + } + +private: + virtual void do_begin_json() = 0; + + virtual void do_end_json() = 0; + + virtual void do_begin_object(const basic_parsing_context<CharT>& context) = 0; + + virtual void do_end_object(const basic_parsing_context<CharT>& context) = 0; + + virtual void do_begin_array(const basic_parsing_context<CharT>& context) = 0; + + virtual void do_end_array(const basic_parsing_context<CharT>& context) = 0; + + virtual void do_name(const CharT* name, size_t length, const basic_parsing_context<CharT>& context) = 0; + + virtual void do_null_value(const basic_parsing_context<CharT>& context) = 0; + + virtual void do_string_value(const CharT* value, size_t length, const basic_parsing_context<CharT>& context) = 0; + + virtual void do_double_value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) = 0; + + virtual void do_integer_value(int64_t value, const basic_parsing_context<CharT>& context) = 0; + + virtual void do_uinteger_value(uint64_t value, const basic_parsing_context<CharT>& context) = 0; + + virtual void do_bool_value(bool value, const basic_parsing_context<CharT>& context) = 0; +}; + + +template <typename CharT> +class basic_empty_json_input_handler : public basic_json_input_handler<CharT> +{ +public: + static basic_json_input_handler<CharT>& instance() + { + static basic_empty_json_input_handler<CharT> instance; + return instance; + } +private: + void do_begin_json() override + { + } + + void do_end_json() override + { + } + + void do_begin_object(const basic_parsing_context<CharT>&) override + { + } + + void do_end_object(const basic_parsing_context<CharT>&) override + { + } + + void do_begin_array(const basic_parsing_context<CharT>&) override + { + } + + void do_end_array(const basic_parsing_context<CharT>&) override + { + } + + void do_name(const CharT* p, size_t length, const basic_parsing_context<CharT>&) override + { + (void)p; + (void)length; + } + + void do_null_value(const basic_parsing_context<CharT>&) override + { + } + + void do_string_value(const CharT* p, size_t length, const basic_parsing_context<CharT>&) override + { + (void)p; + (void)length; + } + + void do_double_value(double, uint8_t, const basic_parsing_context<CharT>&) override + { + } + + void do_integer_value(int64_t, const basic_parsing_context<CharT>&) override + { + } + + void do_uinteger_value(uint64_t, const basic_parsing_context<CharT>&) override + { + } + + void do_bool_value(bool, const basic_parsing_context<CharT>&) override + { + } +}; + +typedef basic_json_input_handler<char> json_input_handler; +typedef basic_json_input_handler<wchar_t> wjson_input_handler; + +typedef basic_empty_json_input_handler<char> empty_json_input_handler; +typedef basic_empty_json_input_handler<wchar_t> wempty_json_input_handler; + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_output_handler.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_output_handler.hpp new file mode 100644 index 00000000..d0f3de8f --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_output_handler.hpp @@ -0,0 +1,262 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_OUTPUT_HANDLER_HPP +#define JSONCONS_JSON_OUTPUT_HANDLER_HPP + +#include <string> +#include "jsoncons/jsoncons.hpp" + +namespace jsoncons { + +template<typename CharT> +void print_integer(int64_t value, buffered_ostream<CharT>& os) +{ + CharT buf[255]; + uint64_t u = (value < 0) ? static_cast<uint64_t>(-value) : static_cast<uint64_t>(value); + CharT* p = buf; + do + { + *p++ = static_cast<CharT>(48 + u%10); + } + while (u /= 10); + if (value < 0) + { + os.put('-'); + } + while (--p >= buf) + { + os.put(*p); + } +} + +template<typename CharT> +void print_uinteger(uint64_t value, buffered_ostream<CharT>& os) +{ + CharT buf[255]; + CharT* p = buf; + do + { + *p++ = static_cast<CharT>(48 + value % 10); + } while (value /= 10); + while (--p >= buf) + { + os.put(*p); + } +} + +template <typename CharT> +class basic_json_output_handler +{ +public: + virtual ~basic_json_output_handler() {} + + // Overloaded methods + + void begin_json() + { + do_begin_json(); + } + + void end_json() + { + do_end_json(); + } + + void begin_object() + { + do_begin_object(); + } + + void end_object() + { + do_end_object(); + } + + void begin_array() + { + do_begin_array(); + } + + void end_array() + { + do_end_array(); + } + + void name(const std::basic_string<CharT>& name) + { + do_name(name.data(), name.length()); + } + + void name(const CharT* p, size_t length) + { + do_name(p, length); + } + + void value(const std::basic_string<CharT>& value) + { + do_string_value(value.data(), value.length()); + } + + void value(const CharT* p, size_t length) + { + do_string_value(p, length); + } + + void value(const CharT* p) + { + do_string_value(p, std::char_traits<CharT>::length(p)); + } + + void value(int value) + { + do_integer_value(value); + } + + void value(long value) + { + do_integer_value(value); + } + + void value(long long value) + { + do_integer_value(value); + } + + void value(unsigned int value) + { + do_uinteger_value(value); + } + + void value(unsigned long value) + { + do_uinteger_value(value); + } + + void value(unsigned long long value) + { + do_uinteger_value(value); + } + + void value(double value, uint8_t precision = 0) + { + do_double_value(value, precision); + } + + void value(bool value) + { + do_bool_value(value); + } + + void value(null_type) + { + do_null_value(); + } + +private: + + virtual void do_begin_json() = 0; + + virtual void do_end_json() = 0; + + virtual void do_name(const CharT* name, size_t length) = 0; + + virtual void do_begin_object() = 0; + + virtual void do_end_object() = 0; + + virtual void do_begin_array() = 0; + + virtual void do_end_array() = 0; + + virtual void do_null_value() = 0; + + virtual void do_string_value(const CharT* value, size_t length) = 0; + + virtual void do_double_value(double value, uint8_t precision) = 0; + + virtual void do_integer_value(int64_t value) = 0; + + virtual void do_uinteger_value(uint64_t value) = 0; + + virtual void do_bool_value(bool value) = 0; +}; + +template <typename CharT> +class null_json_output_handler_impl : public basic_json_output_handler<CharT> +{ +private: + + void do_begin_json() override + { + } + + void do_end_json() override + { + } + + void do_name(const CharT* name, size_t length) override + { + (void)name; + (void)length; + } + + void do_begin_object() override + { + } + + void do_end_object() override + { + } + + void do_begin_array() override + { + } + + void do_end_array() override + { + } + + void do_null_value() override + { + } + + void do_string_value(const CharT* p, size_t length) override + { + (void)p; + (void)length; + } + + void do_double_value(double, uint8_t) override + { + } + + void do_integer_value(int64_t) override + { + } + + void do_uinteger_value(uint64_t) override + { + } + + void do_bool_value(bool) override + { + } + +}; + +template<typename CharT> +basic_json_output_handler<CharT>& null_json_output_handler() +{ + static null_json_output_handler_impl<CharT> instance; + return instance; +} + +typedef basic_json_output_handler<char> json_output_handler; +typedef basic_json_output_handler<wchar_t> wjson_output_handler; + +} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp new file mode 100644 index 00000000..8a06c2e7 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp @@ -0,0 +1,1587 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_PARSER_HPP +#define JSONCONS_JSON_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_input_handler.hpp" +#include "jsoncons/parse_error_handler.hpp" +#include "jsoncons/json_error_category.hpp" + +namespace jsoncons { + +enum class states +{ + root, + start, + slash, + slash_slash, + slash_star, + slash_star_star, + expect_comma_or_end, + object, + expect_member_name_or_end, + expect_member_name, + expect_colon, + expect_value_or_end, + expect_value, + array, + string, + member_name, + escape, + u1, + u2, + u3, + u4, + expect_surrogate_pair1, + expect_surrogate_pair2, + u6, + u7, + u8, + u9, + minus, + zero, + integer, + fraction, + exp1, + exp2, + exp3, + n, + t, + f, + cr, + lf, + done +}; + +template<typename CharT> +class basic_json_parser : private basic_parsing_context<CharT> +{ + static const int default_initial_stack_capacity_ = 100; + + std::vector<states> stack_; + basic_json_input_handler<CharT> *handler_; + basic_parse_error_handler<CharT> *err_handler_; + size_t column_; + size_t line_; + uint32_t cp_; + uint32_t cp2_; + std::basic_string<CharT> string_buffer_; + std::basic_string<char> number_buffer_; + bool is_negative_; + size_t index_; + int initial_stack_capacity_; + int nesting_depth_; + int max_depth_; + float_reader float_reader_; + const CharT* begin_input_; + const CharT* end_input_; + const CharT* p_; + uint8_t precision_; + std::pair<const CharT*,size_t> literal_; + size_t literal_index_; + +public: + basic_json_parser(basic_json_input_handler<CharT>& handler) + : handler_(std::addressof(handler)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), + column_(0), + line_(0), + cp_(0), + is_negative_(false), + index_(0), + initial_stack_capacity_(default_initial_stack_capacity_) + { + max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); + } + + basic_json_parser(basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler) + : handler_(std::addressof(handler)), + err_handler_(std::addressof(err_handler)), + column_(0), + line_(0), + cp_(0), + is_negative_(false), + index_(0), + initial_stack_capacity_(default_initial_stack_capacity_) + + { + max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); + } + + const basic_parsing_context<CharT>& parsing_context() const + { + return *this; + } + + ~basic_json_parser() + { + } + + size_t max_nesting_depth() const + { + return static_cast<size_t>(max_depth_); + } + + void max_nesting_depth(size_t max_nesting_depth) + { + max_depth_ = static_cast<int>(std::min(max_nesting_depth,static_cast<size_t>(std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP()))); + } + + states parent() const + { + return stack_[stack_.size()-2]; + } + + bool done() const + { + return stack_.back() == states::done; + } + + void do_space() + { + while ((p_ + 1) < end_input_ && (*(p_ + 1) == ' ' || *(p_ + 1) == '\t')) + { + ++p_; + ++column_; + } + } + + void do_begin_object() + { + if (++nesting_depth_ >= max_depth_) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + stack_.back() = states::object; + stack_.push_back(states::expect_member_name_or_end); + handler_->begin_object(*this); + } + + void do_end_object() + { + --nesting_depth_; + JSONCONS_ASSERT(!stack_.empty()) + stack_.pop_back(); + if (stack_.back() == states::object) + { + handler_->end_object(*this); + } + else if (stack_.back() == states::array) + { + err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); + } + else + { + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); + } + + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::root) + { + stack_.back() = states::done; + handler_->end_json(); + } + else + { + stack_.back() = states::expect_comma_or_end; + } + } + + void do_begin_array() + { + if (++nesting_depth_ >= max_depth_) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + stack_.back() = states::array; + stack_.push_back(states::expect_value_or_end); + handler_->begin_array(*this); + } + + void do_end_array() + { + --nesting_depth_; + JSONCONS_ASSERT(!stack_.empty()) + stack_.pop_back(); + if (stack_.back() == states::array) + { + handler_->end_array(*this); + } + else if (stack_.back() == states::object) + { + err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); + } + else + { + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); + } + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::root) + { + stack_.back() = states::done; + handler_->end_json(); + } + else + { + stack_.back() = states::expect_comma_or_end; + } + } + + void begin_parse() + { + stack_.clear(); + stack_.reserve(initial_stack_capacity_); + stack_.push_back(states::root); + stack_.push_back(states::start); + line_ = 1; + column_ = 1; + nesting_depth_ = 0; + } + + void check_done(const CharT* input, size_t start, size_t length) + { + index_ = start; + for (; index_ < length; ++index_) + { + CharT curr_char_ = input[index_]; + switch (curr_char_) + { + case '\n': + case '\r': + case '\t': + case ' ': + break; + default: + err_handler_->error(std::error_code(json_parser_errc::extra_character, json_error_category()), *this); + break; + } + } + } + + void parse_string() + { + const CharT* sb = p_; + bool done = false; + while (!done && p_ < end_input_) + { + switch (*p_) + { + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: + string_buffer_.append(sb,p_-sb); + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); + // recovery - skip + done = true; + ++p_; + break; + case '\r': + { + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); + // recovery - keep + string_buffer_.append(sb, p_ - sb + 1); + stack_.push_back(states::cr); + done = true; + ++p_; + } + break; + case '\n': + { + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); + // recovery - keep + string_buffer_.append(sb, p_ - sb + 1); + stack_.push_back(states::lf); + done = true; + ++p_; + } + break; + case '\t': + { + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); + // recovery - keep + string_buffer_.append(sb, p_ - sb + 1); + done = true; + ++p_; + } + break; + case '\\': + string_buffer_.append(sb,p_-sb); + column_ += (p_ - sb + 1); + stack_.back() = states::escape; + done = true; + ++p_; + break; + case '\"': + if (string_buffer_.length() == 0) + { + end_string_value(sb,p_-sb); + } + else + { + string_buffer_.append(sb,p_-sb); + end_string_value(string_buffer_.data(),string_buffer_.length()); + string_buffer_.clear(); + } + column_ += (p_ - sb + 1); + done = true; + ++p_; + break; + default: + ++p_; + break; + } + } + if (!done) + { + string_buffer_.append(sb,p_-sb); + column_ += (p_ - sb + 1); + } + } + + void parse(const CharT* const input, size_t start, size_t length) + { + begin_input_ = input + start; + end_input_ = input + length; + p_ = begin_input_; + + index_ = start; + while ((p_ < end_input_) && (stack_.back() != states::done)) + { + switch (*p_) + { + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: + err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); + break; + default: + break; + } + + switch (stack_.back()) + { + case states::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + JSONCONS_ASSERT(!stack_.empty()) + stack_.pop_back(); + ++p_; + break; + default: + JSONCONS_ASSERT(!stack_.empty()) + stack_.pop_back(); + break; + } + break; + case states::lf: + ++line_; + column_ = 1; + JSONCONS_ASSERT(!stack_.empty()) + stack_.pop_back(); + break; + case states::start: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case '{': + handler_->begin_json(); + do_begin_object(); + break; + case '[': + handler_->begin_json(); + do_begin_array(); + break; + case '\"': + handler_->begin_json(); + stack_.back() = states::string; + break; + case '-': + handler_->begin_json(); + is_negative_ = true; + stack_.back() = states::minus; + break; + case '0': + handler_->begin_json(); + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + handler_->begin_json(); + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::integer; + break; + case 'f': + handler_->begin_json(); + stack_.back() = states::f; + literal_ = json_literals<CharT>::false_literal(); + literal_index_ = 1; + break; + case 'n': + handler_->begin_json(); + stack_.back() = states::n; + literal_ = json_literals<CharT>::null_literal(); + literal_index_ = 1; + break; + case 't': + handler_->begin_json(); + stack_.back() = states::t; + literal_ = json_literals<CharT>::true_literal(); + literal_index_ = 1; + break; + case '}': + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); + break; + case ']': + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); + break; + default: + err_handler_->fatal_error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + + case states::expect_comma_or_end: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case '}': + do_end_object(); + break; + case ']': + do_end_array(); + break; + case ',': + begin_member_or_element(); + break; + default: + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::array) + { + err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); + } + else if (parent() == states::object) + { + err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); + } + break; + } + } + ++p_; + ++column_; + break; + case states::expect_member_name_or_end: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case '}': + do_end_object(); + break; + case '\"': + stack_.back() = states::member_name; + stack_.push_back(states::string); + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_member_name: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case '\"': + //stack_.back() = states::string; + stack_.back() = states::member_name; + stack_.push_back(states::string); + break; + case '}': + --nesting_depth_; + err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_colon: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case ':': + stack_.back() = states::expect_value; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_colon, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_value: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case '{': + do_begin_object(); + break; + case '[': + do_begin_array(); + break; + case '\"': + stack_.back() = states::string; + break; + case '-': + is_negative_ = true; + stack_.back() = states::minus; + break; + case '0': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::integer; + break; + case 'f': + stack_.back() = states::f; + literal_ = json_literals<CharT>::false_literal(); + literal_index_ = 1; + break; + case 'n': + stack_.back() = states::n; + literal_ = json_literals<CharT>::null_literal(); + literal_index_ = 1; + break; + case 't': + stack_.back() = states::t; + literal_ = json_literals<CharT>::true_literal(); + literal_index_ = 1; + break; + case ']': + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::array) + { + err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); + } + else + { + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + } + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_value_or_end: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case ' ':case '\t': + do_space(); + break; + case '/': + stack_.push_back(states::slash); + break; + case '{': + do_begin_object(); + break; + case '[': + do_begin_array(); + break; + case ']': + do_end_array(); + break; + case '\"': + stack_.back() = states::string; + break; + case '-': + is_negative_ = true; + stack_.back() = states::minus; + break; + case '0': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::integer; + break; + case 'f': + stack_.back() = states::f; + literal_ = json_literals<CharT>::false_literal(); + literal_index_ = 1; + break; + case 'n': + stack_.back() = states::n; + literal_ = json_literals<CharT>::null_literal(); + literal_index_ = 1; + break; + case 't': + stack_.back() = states::t; + literal_ = json_literals<CharT>::true_literal(); + literal_index_ = 1; + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::string: + parse_string(); + break; + case states::escape: + { + escape_next_char(*p_); + } + ++p_; + ++column_; + break; + case states::u1: + { + append_codepoint(*p_); + stack_.back() = states::u2; + } + ++p_; + ++column_; + break; + case states::u2: + { + append_codepoint(*p_); + stack_.back() = states::u3; + } + ++p_; + ++column_; + break; + case states::u3: + { + append_codepoint(*p_); + stack_.back() = states::u4; + } + ++p_; + ++column_; + break; + case states::u4: + { + append_codepoint(*p_); + if (cp_ >= min_lead_surrogate && cp_ <= max_lead_surrogate) + { + stack_.back() = states::expect_surrogate_pair1; + } + else + { + json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp_, string_buffer_); + stack_.back() = states::string; + } + } + ++p_; + ++column_; + break; + case states::expect_surrogate_pair1: + { + switch (*p_) + { + case '\\': + cp2_ = 0; + stack_.back() = states::expect_surrogate_pair2; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_surrogate_pair2: + { + switch (*p_) + { + case 'u': + stack_.back() = states::u6; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::u6: + { + append_second_codepoint(*p_); + stack_.back() = states::u7; + } + ++p_; + ++column_; + break; + case states::u7: + { + append_second_codepoint(*p_); + stack_.back() = states::u8; + } + ++p_; + ++column_; + break; + case states::u8: + { + append_second_codepoint(*p_); + stack_.back() = states::u9; + } + ++p_; + ++column_; + break; + case states::u9: + { + append_second_codepoint(*p_); + uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); + json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp, string_buffer_); + stack_.back() = states::string; + } + ++p_; + ++column_; + break; + case states::minus: + { + switch (*p_) + { + case '0': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::integer; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::zero: + { + switch (*p_) + { + case '\r': + end_integer_value(); + stack_.push_back(states::cr); + break; + case '\n': + end_integer_value(); + stack_.push_back(states::lf); + break; + case ' ':case '\t': + end_integer_value(); + do_space(); + break; + case '/': + end_integer_value(); + stack_.push_back(states::slash); + break; + case '}': + end_integer_value(); + do_end_object(); + break; + case ']': + end_integer_value(); + do_end_array(); + break; + case '.': + precision_ = static_cast<uint8_t>(number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::fraction; + break; + case ',': + end_integer_value(); + begin_member_or_element(); + break; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + err_handler_->error(std::error_code(json_parser_errc::leading_zero, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::integer: + { + switch (*p_) + { + case '\r': + end_integer_value(); + stack_.push_back(states::cr); + break; + case '\n': + end_integer_value(); + stack_.push_back(states::lf); + break; + case ' ':case '\t': + end_integer_value(); + do_space(); + break; + case '/': + end_integer_value(); + stack_.push_back(states::slash); + break; + case '}': + end_integer_value(); + do_end_object(); + break; + case ']': + end_integer_value(); + do_end_array(); + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::integer; + break; + case '.': + precision_ = static_cast<uint8_t>(number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::fraction; + break; + case ',': + end_integer_value(); + begin_member_or_element(); + break; + case 'e':case 'E': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::exp1; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::fraction: + { + switch (*p_) + { + case '\r': + end_fraction_value(); + stack_.push_back(states::cr); + break; + case '\n': + end_fraction_value(); + stack_.push_back(states::lf); + break; + case ' ':case '\t': + end_fraction_value(); + do_space(); + break; + case '/': + end_fraction_value(); + stack_.push_back(states::slash); + break; + case '}': + end_fraction_value(); + do_end_object(); + break; + case ']': + end_fraction_value(); + do_end_array(); + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + ++precision_; + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::fraction; + break; + case ',': + end_fraction_value(); + begin_member_or_element(); + break; + case 'e':case 'E': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::exp1; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::exp1: + { + switch (*p_) + { + case '+': + stack_.back() = states::exp2; + break; + case '-': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::exp2; + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::exp3; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::exp2: + { + switch (*p_) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::exp3; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::exp3: + { + switch (*p_) + { + case '\r': + end_fraction_value(); + stack_.push_back(states::cr); + break; + case '\n': + end_fraction_value(); + stack_.push_back(states::lf); + break; + case ' ':case '\t': + end_fraction_value(); + do_space(); + break; + case '/': + end_fraction_value(); + stack_.push_back(states::slash); + break; + case '}': + end_fraction_value(); + do_end_object(); + break; + case ']': + end_fraction_value(); + do_end_array(); + break; + case ',': + end_fraction_value(); + begin_member_or_element(); + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + stack_.back() = states::exp3; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::t: + while (p_ < end_input_ && literal_index_ < literal_.second) + { + if (*p_ != literal_.first[literal_index_]) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); + } + ++p_; + ++literal_index_; + ++column_; + } + if (literal_index_ == literal_.second) + { + handler_->value(true, *this); + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::root) + { + stack_.back() = states::done; + handler_->end_json(); + } + else + { + stack_.back() = states::expect_comma_or_end; + } + } + break; + case states::f: + while (p_ < end_input_ && literal_index_ < literal_.second) + { + if (*p_ != literal_.first[literal_index_]) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); + } + ++p_; + ++literal_index_; + ++column_; + } + if (literal_index_ == literal_.second) + { + handler_->value(false, *this); + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::root) + { + stack_.back() = states::done; + handler_->end_json(); + } + else + { + stack_.back() = states::expect_comma_or_end; + } + } + break; + case states::n: + while (p_ < end_input_ && literal_index_ < literal_.second) + { + if (*p_ != literal_.first[literal_index_]) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); + } + ++p_; + ++literal_index_; + ++column_; + } + if (literal_index_ == literal_.second) + { + handler_->value(null_type(), *this); + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::root) + { + stack_.back() = states::done; + handler_->end_json(); + } + else + { + stack_.back() = states::expect_comma_or_end; + } + } + break; + case states::slash: + { + switch (*p_) + { + case '*': + stack_.back() = states::slash_star; + break; + case '/': + stack_.back() = states::slash_slash; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::slash_star: + { + switch (*p_) + { + case '\r': + stack_.push_back(states::cr); + break; + case '\n': + stack_.push_back(states::lf); + break; + case '*': + stack_.back() = states::slash_star_star; + break; + } + } + ++p_; + ++column_; + break; + case states::slash_slash: + { + switch (*p_) + { + case '\r': + stack_.pop_back(); + break; + case '\n': + stack_.pop_back(); + break; + default: + ++p_; + ++column_; + } + } + break; + case states::slash_star_star: + { + switch (*p_) + { + case '/': + JSONCONS_ASSERT(!stack_.empty()) + stack_.pop_back(); + break; + default: + stack_.back() = states::slash_star; + break; + } + } + ++p_; + ++column_; + break; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad parser state"); + break; + } + } + index_ += (p_-begin_input_); + } + + void end_parse() + { + JSONCONS_ASSERT(stack_.size() >= 2); + if (parent() == states::root) + { + switch (stack_.back()) + { + case states::zero: + case states::integer: + end_integer_value(); + break; + case states::fraction: + case states::exp3: + end_fraction_value(); + break; + default: + break; + } + } + if (stack_.back() == states::lf || stack_.back() == states::cr) + { + stack_.pop_back(); + } + if (!(stack_.back() == states::done || stack_.back() == states::start)) + { + err_handler_->error(std::error_code(json_parser_errc::unexpected_eof, json_error_category()), *this); + } + } + + states state() const + { + return stack_.back(); + } + + size_t index() const + { + return index_; + } +private: + void end_fraction_value() + { + try + { + double d = float_reader_.read(number_buffer_.data(), precision_); + if (is_negative_) + d = -d; + handler_->value(d, static_cast<uint8_t>(precision_), *this); + } + catch (...) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + handler_->value(null_type(), *this); // recovery + } + number_buffer_.clear(); + is_negative_ = false; + + JSONCONS_ASSERT(stack_.size() >= 2); + switch (parent()) + { + case states::array: + case states::object: + stack_.back() = states::expect_comma_or_end; + break; + case states::root: + stack_.back() = states::done; + handler_->end_json(); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + + void end_integer_value() + { + if (is_negative_) + { + try + { + int64_t d = string_to_integer(is_negative_, number_buffer_.data(), number_buffer_.length()); + handler_->value(d, *this); + } + catch (const std::exception&) + { + try + { + double d = float_reader_.read(number_buffer_.data(), number_buffer_.length()); + handler_->value(-d, static_cast<uint8_t>(number_buffer_.length()), *this); + } + catch (...) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + handler_->value(null_type(), *this); + } + } + } + else + { + try + { + uint64_t d = string_to_uinteger(number_buffer_.data(), number_buffer_.length()); + handler_->value(d, *this); + } + catch (const std::exception&) + { + try + { + double d = float_reader_.read(number_buffer_.data(),number_buffer_.length()); + handler_->value(d, static_cast<uint8_t>(number_buffer_.length()), *this); + } + catch (...) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + handler_->value(null_type(), *this); + } + } + } + + JSONCONS_ASSERT(stack_.size() >= 2); + switch (parent()) + { + case states::array: + case states::object: + stack_.back() = states::expect_comma_or_end; + break; + case states::root: + stack_.back() = states::done; + handler_->end_json(); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + number_buffer_.clear(); + is_negative_ = false; + } + + void append_codepoint(int c) + { + switch (c) + { + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp_ = append_to_codepoint(cp_, c); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + + void append_second_codepoint(int c) + { + switch (c) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp2_ = append_to_codepoint(cp2_, c); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + + void escape_next_char(int next_input) + { + switch (next_input) + { + case '\"': + string_buffer_.push_back('\"'); + stack_.back() = states::string; + break; + case '\\': + string_buffer_.push_back('\\'); + stack_.back() = states::string; + break; + case '/': + string_buffer_.push_back('/'); + stack_.back() = states::string; + break; + case 'b': + string_buffer_.push_back('\b'); + stack_.back() = states::string; + break; + case 'f': + string_buffer_.push_back('\f'); + stack_.back() = states::string; + break; + case 'n': + string_buffer_.push_back('\n'); + stack_.back() = states::string; + break; + case 'r': + string_buffer_.push_back('\r'); + stack_.back() = states::string; + break; + case 't': + string_buffer_.push_back('\t'); + stack_.back() = states::string; + break; + case 'u': + cp_ = 0; + stack_.back() = states::u1; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::illegal_escaped_character, json_error_category()), *this); + break; + } + } + + void end_string_value(const CharT* s, size_t length) + { + JSONCONS_ASSERT(stack_.size() >= 2); + switch (parent()) + { + case states::member_name: + handler_->name(s, length, *this); + stack_.pop_back(); + stack_.back() = states::expect_colon; + break; + case states::object: + case states::array: + handler_->value(s, length, *this); + stack_.back() = states::expect_comma_or_end; + break; + case states::root: + handler_->value(s, length, *this); + stack_.back() = states::done; + handler_->end_json(); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + + void begin_member_or_element() + { + JSONCONS_ASSERT(stack_.size() >= 2); + switch (parent()) + { + case states::object: + stack_.back() = states::expect_member_name; + break; + case states::array: + stack_.back() = states::expect_value; + break; + case states::root: + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + + uint32_t append_to_codepoint(uint32_t cp, int c) + { + cp *= 16; + if (c >= '0' && c <= '9') + { + cp += c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + cp += c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + cp += c - 'A' + 10; + } + else + { + err_handler_->error(std::error_code(json_parser_errc::invalid_hex_escape_sequence, json_error_category()), *this); + } + return cp; + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + CharT do_current_char() const override + { + return p_ < end_input_? *p_ : 0; + } +}; + +typedef basic_json_parser<char> json_parser; +typedef basic_json_parser<wchar_t> wjson_parser; + +} + +#endif + diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp.orig b/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp.orig new file mode 100644 index 00000000..e4769d5c --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp.orig @@ -0,0 +1,2157 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_PARSER_HPP +#define JSONCONS_JSON_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_input_handler.hpp" +#include "jsoncons/parse_error_handler.hpp" +#include "jsoncons/json_error_category.hpp" + +namespace jsoncons { + +enum class modes +{ + done, + start, + array_element, + object_member_name, + object_member_value +}; + +enum class states +{ + start, + slash, + slash_slash, + slash_star, + slash_star_star, + expect_comma_or_end, + object, + expect_member_name, + expect_colon, + expect_value, + array, + string, + escape, + u1, + u2, + u3, + u4, + expect_surrogate_pair1, + expect_surrogate_pair2, + u6, + u7, + u8, + u9, + minus, + zero, + integer, + fraction, + exp1, + exp2, + exp3, + n, + t, + f, + cr, + lf, + done, + scalar +}; + +template<typename CharT> +class basic_json_parser : private basic_parsing_context<CharT> +{ + static const int default_depth = 100; + + std::vector<states> state_stack_; + int top_; + std::vector<modes> stack_; + basic_json_input_handler<CharT> *handler_; + basic_parse_error_handler<CharT> *err_handler_; + size_t column_; + size_t line_; + uint32_t cp_; + uint32_t cp2_; + std::basic_string<CharT> string_buffer_; + std::basic_string<char> number_buffer_; + bool is_negative_; + states saved_state_; + states pre_line_break_state_; + size_t index_; + int depth_; + int max_depth_; + float_reader float_reader_; + const CharT* begin_input_; + const CharT* end_input_; + const CharT* p_; + uint8_t precision_; + std::pair<const CharT*,size_t> literal_; + size_t literal_index_; + + std::vector<states> stack2_; + +public: + basic_json_parser(basic_json_input_handler<CharT>& handler) + : top_(-1), + stack_(default_depth), + handler_(std::addressof(handler)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), + column_(0), + line_(0), + cp_(0), + is_negative_(false), + index_(0), + depth_(default_depth) + { + max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); + } + + basic_json_parser(basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler) + : top_(-1), + stack_(default_depth), + handler_(std::addressof(handler)), + err_handler_(std::addressof(err_handler)), + column_(0), + line_(0), + cp_(0), + is_negative_(false), + index_(0), + depth_(default_depth) + + { + max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); + } + + const basic_parsing_context<CharT>& parsing_context() const + { + return *this; + } + + ~basic_json_parser() + { + } + + size_t max_nesting_depth() const + { + return static_cast<size_t>(max_depth_); + } + + void max_nesting_depth(size_t max_nesting_depth) + { + max_depth_ = static_cast<int>(std::min(max_nesting_depth,static_cast<size_t>(std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP()))); + if (depth_ > max_depth_) + { + depth_ = max_depth_; + stack_.resize(depth_); + } + } + + bool done() const + { + return state_stack_.back() == states::done; + } + + void begin_parse() + { + if (!push(modes::done)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + state_stack_.clear(); + state_stack_.push_back(states::start); + line_ = 1; + column_ = 1; + stack2_.push_back(states::start); + stack2_.push_back(states::scalar); + } + + void check_done(const CharT* input, size_t start, size_t length) + { + index_ = start; + for (; index_ < length; ++index_) + { + CharT curr_char_ = input[index_]; + switch (curr_char_) + { + case '\n': + case '\r': + case '\t': + case ' ': + break; + default: + err_handler_->error(std::error_code(json_parser_errc::extra_character, json_error_category()), *this); + break; + } + } + } + + bool parse_string(const CharT** first, const CharT** last) + { + const CharT* sb = p_; + bool done = false; + bool complete = false; + while (!done && p_ < end_input_) + { + switch (*p_) + { + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: + string_buffer_.append(sb,p_-sb); + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); + // recovery - skip + done = true; + ++p_; + break; + case '\r': + { + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); + // recovery - keep + string_buffer_.append(sb, p_ - sb + 1); +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + done = true; + ++p_; + + stack2_.push_back(states::cr); + } + break; + case '\n': + { + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); + // recovery - keep + string_buffer_.append(sb, p_ - sb + 1); + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; + done = true; + ++p_; + + stack2_.push_back(states::lf); + } + break; + case '\t': + { + column_ += (p_ - sb + 1); + err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); + // recovery - keep + string_buffer_.append(sb, p_ - sb + 1); + done = true; + ++p_; + } + break; + case '\\': + string_buffer_.append(sb,p_-sb); + column_ += (p_ - sb + 1); +<<<<<<< HEAD + state_stack_.back() = states::escape; +======= + state_ = states::escape; + stack2_.front() = states::escape; +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + done = true; + ++p_; + break; + case '\"': + if (string_buffer_.length() == 0) + { + *first = sb; + *last = p_; + //end_string_value(sb,p_-sb); + } + else + { + string_buffer_.append(sb,p_-sb); + *first = string_buffer_.data(); + *last = string_buffer_.data() + string_buffer_.length(); + //end_string_value(string_buffer_.data(),string_buffer_.length()); + //string_buffer_.clear(); + } + column_ += (p_ - sb + 1); + done = true; + complete = true; + ++p_; + break; + default: + ++p_; + break; + } + } + if (!done) + { + string_buffer_.append(sb,p_-sb); + column_ += (p_ - sb + 1); + } + + return complete; + } + + void parse(const CharT* const input, size_t start, size_t length) + { + begin_input_ = input + start; + end_input_ = input + length; + p_ = begin_input_; + + index_ = start; + while ((p_ < end_input_) && (state_stack_.back() != states::done)) + { + switch (*p_) + { + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: + err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); + break; + default: + break; + } + + switch (state_stack_.back()) + { + case states::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_stack_.back() = pre_line_break_state_; + ++p_; + break; + default: + state_stack_.back() = pre_line_break_state_; + break; + } + JSONCONS_ASSERT(stack2_.size() > 0); + stack2_.pop_back(); + break; + case states::lf: + ++line_; + column_ = 1; +<<<<<<< HEAD + state_stack_.back() = pre_line_break_state_; +======= + state_ = pre_line_break_state_; + JSONCONS_ASSERT(stack2_.size() > 0); + stack2_.pop_back(); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case states::start: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case '{': + handler_->begin_json(); + if (!push(modes::object_member_name)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } +<<<<<<< HEAD + state_stack_.back() = states::object; +======= + state_ = states::object; + +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + handler_->begin_object(*this); + break; + case '[': + handler_->begin_json(); + if (!push(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + state_stack_.back() = states::array; + handler_->begin_array(*this); + break; + case '\"': + handler_->begin_json(); + flip(modes::done, modes::start); + state_stack_.back() = states::string; + break; + case '-': + handler_->begin_json(); + flip(modes::done, modes::start); + is_negative_ = true; + state_stack_.back() = states::minus; + break; + case '0': + handler_->begin_json(); + flip(modes::done, modes::start); + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + handler_->begin_json(); + flip(modes::done, modes::start); + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::integer; + break; + case 'f': + handler_->begin_json(); + flip(modes::done, modes::start); + state_stack_.back() = states::f; + literal_ = json_literals<CharT>::false_literal(); + literal_index_ = 1; + break; + case 'n': + handler_->begin_json(); + flip(modes::done, modes::start); + state_stack_.back() = states::n; + literal_ = json_literals<CharT>::null_literal(); + literal_index_ = 1; + break; + case 't': + handler_->begin_json(); + flip(modes::done, modes::start); + state_stack_.back() = states::t; + literal_ = json_literals<CharT>::true_literal(); + literal_index_ = 1; + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + case '}': + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); + break; + case ']': + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); + break; + default: + err_handler_->fatal_error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + + case states::expect_comma_or_end: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case '}': + if (peek() == modes::object_member_value) + { + pop(modes::object_member_value); + handler_->end_object(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + else if (peek() == modes::array_element) + { + err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); + } + else + { + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); + } + break; + case ']': + if (peek() == modes::array_element) + { + pop(modes::array_element); + handler_->end_array(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + else if (peek() == modes::object_member_value) + { + err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); + } + else + { + err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); + } + break; + case ',': + begin_member_or_element(); + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + default: + if (peek() == modes::array_element) + { + err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); + } + else if (peek() == modes::object_member_value) + { + err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); + } + break; + } + } + ++p_; + ++column_; + break; + case states::object: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case '}': + if (!pop(modes::object_member_name)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_object(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case '\"': + state_stack_.back() = states::string; + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_member_name: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case '\"': + state_stack_.back() = states::string; + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + case '}': + err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_colon: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case ':': + begin_member_value(); + state_stack_.back() = states::expect_value; + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_colon, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_value: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case '{': + if (!push(modes::object_member_name)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + state_stack_.back() = states::object; + handler_->begin_object(*this); + break; + case '[': + if (!push(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + state_stack_.back() = states::array; + handler_->begin_array(*this); + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + + case '\"': + state_stack_.back() = states::string; + break; + case '-': + is_negative_ = true; + state_stack_.back() = states::minus; + break; + case '0': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::integer; + break; + case 'f': + state_stack_.back() = states::f; + literal_ = json_literals<CharT>::false_literal(); + literal_index_ = 1; + /*if ((p_+4) < end_input_) + { + if ((*(p_+1) == 'a') & (*(p_+2) == 'l') & (*(p_+3) == 's') & (*(p_+4) == 'e')) + { + p_ += 4; + column_ += 4; + handler_->value(false, *this); + if (peek() == modes::start) + { + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + }*/ + break; + case 'n': + state_stack_.back() = states::n; + literal_ = json_literals<CharT>::null_literal(); + literal_index_ = 1; + break; + case 't': + state_stack_.back() = states::t; + literal_ = json_literals<CharT>::true_literal(); + literal_index_ = 1; + break; + case ']': + if (peek() == modes::array_element) + { + err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); + } + else + { + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + } + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::array: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + break; + case '{': + if (!push(modes::object_member_name)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + state_stack_.back() = states::object; + handler_->begin_object(*this); + break; + case '[': + if (!push(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); + } + state_stack_.back() = states::array; + handler_->begin_array(*this); + break; + case ']': + if (!pop(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_array(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case '\"': + state_stack_.back() = states::string; + break; + case '/': + saved_state_ = state_stack_.back(); + state_stack_.back() = states::slash; + break; + case '-': + is_negative_ = true; + state_stack_.back() = states::minus; + break; + case '0': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::integer; + break; + case 'f': + state_stack_.back() = states::f; + literal_ = json_literals<CharT>::false_literal(); + literal_index_ = 1; + /*if ((p_+4) < end_input_) + { + if ((*(p_+1) == 'a') & (*(p_+2) == 'l') & (*(p_+3) == 's') & (*(p_+4) == 'e')) + { + p_ += 4; + column_ += 4; + handler_->value(false, *this); + if (peek() == modes::start) + { + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + }*/ + break; + case 'n': + state_stack_.back() = states::n; + literal_ = json_literals<CharT>::null_literal(); + literal_index_ = 1; + break; + case 't': + state_stack_.back() = states::t; + literal_ = json_literals<CharT>::true_literal(); + literal_index_ = 1; + break; + case '\'': + err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::string: + { + const CharT* first; + const CharT* last; + if (parse_string(&first,&last)) + { + end_string_value(first,last-first); + string_buffer_.clear(); + } + } + break; + case states::escape: + { + escape_next_char(*p_); + } + ++p_; + ++column_; + break; + case states::u1: + { + append_codepoint(*p_); + state_stack_.back() = states::u2; + } + ++p_; + ++column_; + break; + case states::u2: + { + append_codepoint(*p_); + state_stack_.back() = states::u3; + } + ++p_; + ++column_; + break; + case states::u3: + { + append_codepoint(*p_); + state_stack_.back() = states::u4; + } + ++p_; + ++column_; + break; + case states::u4: + { + append_codepoint(*p_); + if (cp_ >= min_lead_surrogate && cp_ <= max_lead_surrogate) + { + state_stack_.back() = states::expect_surrogate_pair1; + } + else + { + json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp_, string_buffer_); + state_stack_.back() = states::string; + } + } + ++p_; + ++column_; + break; + case states::expect_surrogate_pair1: + { + switch (*p_) + { + case '\\': + cp2_ = 0; + state_stack_.back() = states::expect_surrogate_pair2; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::expect_surrogate_pair2: + { + switch (*p_) + { + case 'u': + state_stack_.back() = states::u6; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::u6: + { + append_second_codepoint(*p_); + state_stack_.back() = states::u7; + } + ++p_; + ++column_; + break; + case states::u7: + { + append_second_codepoint(*p_); + state_stack_.back() = states::u8; + } + ++p_; + ++column_; + break; + case states::u8: + { + append_second_codepoint(*p_); + state_stack_.back() = states::u9; + } + ++p_; + ++column_; + break; + case states::u9: + { + append_second_codepoint(*p_); + uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); + json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp, string_buffer_); + state_stack_.back() = states::string; + } + ++p_; + ++column_; + break; + case states::minus: + { + switch (*p_) + { + case '0': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::integer; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::zero: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + end_integer_value(); + break; // No change + case '}': + end_integer_value(); + if (!pop(modes::object_member_value)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_object(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case ']': + end_integer_value(); + if (!pop(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_array(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case '.': + precision_ = static_cast<uint8_t>(number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::fraction; + break; + case ',': + end_integer_value(); + begin_member_or_element(); + break; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + err_handler_->error(std::error_code(json_parser_errc::leading_zero, json_error_category()), *this); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::integer: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + end_integer_value(); + break; + case '}': + end_integer_value(); + if (!pop(modes::object_member_value)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_object(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case ']': + end_integer_value(); + if (!pop(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_array(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::integer; + break; + case '.': + precision_ = static_cast<uint8_t>(number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::fraction; + break; + case ',': + end_integer_value(); + begin_member_or_element(); + break; + case 'e':case 'E': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::exp1; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::fraction: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + end_fraction_value(); + break; + case '}': + end_fraction_value(); + if (!pop(modes::object_member_value)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_object(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case ']': + end_fraction_value(); + if (!pop(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_array(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + ++precision_; + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::fraction; + break; + case ',': + end_fraction_value(); + begin_member_or_element(); + break; + case 'e':case 'E': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::exp1; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::exp1: + { + switch (*p_) + { + case '+': + state_stack_.back() = states::exp2; + break; + case '-': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::exp2; + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::exp3; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::exp2: + { + switch (*p_) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::exp3; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::exp3: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case ' ':case '\t': + { + bool done = false; + while (!done && (p_ + 1) < end_input_) + { + switch (*(p_ + 1)) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + default: + done = true; + break; + } + } + } + end_fraction_value(); + break; + case '}': + end_fraction_value(); + if (!pop(modes::object_member_value)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_object(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case ']': + end_fraction_value(); + if (!pop(modes::array_element)) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + } + handler_->end_array(*this); + if (peek() == modes::done) + { + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + break; + case ',': + end_fraction_value(); + begin_member_or_element(); + break; + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*p_)); + state_stack_.back() = states::exp3; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::t: + while (p_ < end_input_ && literal_index_ < literal_.second) + { + if (*p_ != literal_.first[literal_index_]) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); + } + ++p_; + ++literal_index_; + ++column_; + } + if (literal_index_ == literal_.second) + { + handler_->value(true, *this); + if (peek() == modes::start) + { + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + break; + case states::f: + while (p_ < end_input_ && literal_index_ < literal_.second) + { + if (*p_ != literal_.first[literal_index_]) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); + } + ++p_; + ++literal_index_; + ++column_; + } + if (literal_index_ == literal_.second) + { + handler_->value(false, *this); + if (peek() == modes::start) + { + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + break; + case states::n: + while (p_ < end_input_ && literal_index_ < literal_.second) + { + if (*p_ != literal_.first[literal_index_]) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); + } + ++p_; + ++literal_index_; + ++column_; + } + if (literal_index_ == literal_.second) + { + handler_->value(null_type(), *this); + if (peek() == modes::start) + { + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + } + else + { + state_stack_.back() = states::expect_comma_or_end; + } + } + break; + case states::slash: + { + switch (*p_) + { + case '*': + state_stack_.back() = states::slash_star; + break; + case '/': + state_stack_.back() = states::slash_slash; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + ++p_; + ++column_; + break; + case states::slash_star: + { + switch (*p_) + { + case '\r': +<<<<<<< HEAD + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = state_stack_.back(); + state_stack_.back() = states::lf; +======= + pre_line_break_state_ = state_; + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + case '*': + state_stack_.back() = states::slash_star_star; + break; + } + } + ++p_; + ++column_; + break; + case states::slash_slash: + { + switch (*p_) + { + case '\r': + pre_line_break_state_ = saved_state_; +<<<<<<< HEAD + state_stack_.back() = states::cr; + break; + case '\n': + pre_line_break_state_ = saved_state_; + state_stack_.back() = states::lf; +======= + state_ = states::cr; + stack2_.push_back(states::cr); + break; + case '\n': + pre_line_break_state_ = saved_state_; + state_ = states::lf; + stack2_.push_back(states::lf); +>>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 + break; + } + } + ++p_; + ++column_; + break; + case states::slash_star_star: + { + switch (*p_) + { + case '/': + state_stack_.back() = saved_state_; + break; + default: + state_stack_.back() = states::slash_star; + break; + } + } + ++p_; + ++column_; + break; + default: + JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad parser state"); + break; + } + } + index_ += (p_-begin_input_); + } + + void end_parse() + { + if (peek() == modes::start) + { + switch (state_stack_.back()) + { + case states::zero: + case states::integer: + end_integer_value(); + break; + case states::fraction: + case states::exp3: + end_fraction_value(); + break; + default: + break; + } + } + if (!pop(modes::done)) + { + err_handler_->error(std::error_code(json_parser_errc::unexpected_eof, json_error_category()), *this); + } + } + + states state() const + { + return state_stack_.back(); + } + + size_t index() const + { + return index_; + } +private: + void end_fraction_value() + { + try + { + double d = float_reader_.read(number_buffer_.data(), precision_); + if (is_negative_) + d = -d; + handler_->value(d, static_cast<uint8_t>(precision_), *this); + } + catch (...) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + handler_->value(null_type(), *this); // recovery + } + number_buffer_.clear(); + is_negative_ = false; + switch (stack_[top_]) + { + case modes::array_element: + case modes::object_member_value: + state_stack_.back() = states::expect_comma_or_end; + break; + case modes::start: + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + + void end_integer_value() + { + if (is_negative_) + { + try + { + int64_t d = string_to_integer(is_negative_, number_buffer_.data(), number_buffer_.length()); + handler_->value(d, *this); + } + catch (const std::exception&) + { + try + { + double d = float_reader_.read(number_buffer_.data(), number_buffer_.length()); + handler_->value(-d, static_cast<uint8_t>(number_buffer_.length()), *this); + } + catch (...) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + handler_->value(null_type(), *this); + } + } + } + else + { + try + { + uint64_t d = string_to_uinteger(number_buffer_.data(), number_buffer_.length()); + handler_->value(d, *this); + } + catch (const std::exception&) + { + try + { + double d = float_reader_.read(number_buffer_.data(),number_buffer_.length()); + handler_->value(d, static_cast<uint8_t>(number_buffer_.length()), *this); + } + catch (...) + { + err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); + handler_->value(null_type(), *this); + } + } + } + + switch (stack_[top_]) + { + case modes::array_element: + case modes::object_member_value: + state_stack_.back() = states::expect_comma_or_end; + break; + case modes::start: + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + number_buffer_.clear(); + is_negative_ = false; + } + + void append_codepoint(int c) + { + switch (c) + { + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp_ = append_to_codepoint(cp_, c); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + + void append_second_codepoint(int c) + { + switch (c) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp2_ = append_to_codepoint(cp2_, c); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); + break; + } + } + + void escape_next_char(int next_input) + { + switch (next_input) + { + case '\"': + string_buffer_.push_back('\"'); + state_stack_.back() = states::string; + break; + case '\\': + string_buffer_.push_back('\\'); + state_stack_.back() = states::string; + break; + case '/': + string_buffer_.push_back('/'); + state_stack_.back() = states::string; + break; + case 'b': + string_buffer_.push_back('\b'); + state_stack_.back() = states::string; + break; + case 'f': + string_buffer_.push_back('\f'); + state_stack_.back() = states::string; + break; + case 'n': + string_buffer_.push_back('\n'); + state_stack_.back() = states::string; + break; + case 'r': + string_buffer_.push_back('\r'); + state_stack_.back() = states::string; + break; + case 't': + string_buffer_.push_back('\t'); + state_stack_.back() = states::string; + break; + case 'u': + cp_ = 0; + state_stack_.back() = states::u1; + break; + default: + err_handler_->error(std::error_code(json_parser_errc::illegal_escaped_character, json_error_category()), *this); + break; + } + } + + void end_string_value(const CharT* s, size_t length) + { + switch (stack_[top_]) + { + case modes::object_member_name: + handler_->name(s, length, *this); + state_stack_.back() = states::expect_colon; + break; + case modes::array_element: + case modes::object_member_value: + handler_->value(s, length, *this); + state_stack_.back() = states::expect_comma_or_end; + break; + case modes::start: + handler_->value(s, length, *this); + flip(modes::start,modes::done); + state_stack_.back() = states::done; + handler_->end_json(); + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + + void begin_member_or_element() + { + switch (stack_[top_]) + { + case modes::object_member_value: + // A comma causes a flip from object_member_value modes to object_member_name modes. + flip(modes::object_member_value, modes::object_member_name); + state_stack_.back() = states::expect_member_name; + break; + case modes::array_element: + state_stack_.back() = states::expect_value; + break; + case modes::done: + break; + default: + err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); + break; + } + } + + void begin_member_value() + { + flip(modes::object_member_name, modes::object_member_value); + state_stack_.back() = states::expect_value; + } + + uint32_t append_to_codepoint(uint32_t cp, int c) + { + cp *= 16; + if (c >= '0' && c <= '9') + { + cp += c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + cp += c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + cp += c - 'A' + 10; + } + else + { + err_handler_->error(std::error_code(json_parser_errc::invalid_hex_escape_sequence, json_error_category()), *this); + } + return cp; + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + CharT do_current_char() const override + { + return p_ < end_input_? *p_ : 0; + } + + bool push(modes mode) + { + ++top_; + if (top_ >= depth_) + { + if (top_ >= max_depth_) + { + return false; + } + depth_ *= 2; + stack_.resize(depth_); + } + stack_[top_] = mode; + return true; + } + + modes peek() + { + return stack_[top_]; + } + + bool peek(modes mode) + { + return stack_[top_] == mode; + } + + void flip(modes mode1, modes mode2) + { + JSONCONS_ASSERT((top_ >= 0) && (stack_[top_] == mode1)) + stack_[top_] = mode2; + } + + bool pop(modes mode) + { + if (top_ < 0 || stack_[top_] != mode) + { + return false; + } + --top_; + return true; + } +}; + +typedef basic_json_parser<char> json_parser; +typedef basic_json_parser<wchar_t> wjson_parser; + +} + +#endif + diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_reader.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_reader.hpp new file mode 100644 index 00000000..a0dd4641 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_reader.hpp @@ -0,0 +1,176 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_READER_HPP +#define JSONCONS_JSON_READER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_input_handler.hpp" +#include "jsoncons/parse_error_handler.hpp" +#include "jsoncons/json_parser.hpp" + +namespace jsoncons { + +template<typename CharT> +class basic_json_reader +{ + static const size_t default_max_buffer_length = 16384; + + basic_json_parser<CharT> parser_; + std::basic_istream<CharT> *is_; + basic_parse_error_handler<CharT> *err_handler_; + bool eof_; + std::vector<CharT> buffer_; + size_t buffer_length_; + size_t buffer_capacity_; + size_t index_; +public: + basic_json_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler) + : parser_(handler), + is_(std::addressof(is)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), + eof_(false), + buffer_length_(0), + buffer_capacity_(default_max_buffer_length), + index_(0) + { + buffer_.resize(buffer_capacity_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler) + : parser_(handler,err_handler), + is_(std::addressof(is)), + err_handler_(std::addressof(err_handler)), + eof_(false), + buffer_length_(0), + buffer_capacity_(default_max_buffer_length), + index_(0) + { + buffer_.resize(buffer_capacity_); + } + + size_t buffer_capacity() const + { + return buffer_capacity_; + } + + void buffer_capacity(size_t capacity) + { + buffer_capacity_ = capacity; + buffer_.resize(buffer_capacity_); + } + + size_t max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_nesting_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } + + void read_next() + { + parser_.begin_parse(); + while (!eof_ && !parser_.done()) + { + if (!(index_ < buffer_length_)) + { + if (!is_->eof()) + { + is_->read(buffer_.data(), buffer_capacity_); + buffer_length_ = static_cast<size_t>(is_->gcount()); + if (buffer_length_ == 0) + { + eof_ = true; + } + index_ = 0; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.parse(buffer_.data(),index_,buffer_length_); + index_ = parser_.index(); + } + } + parser_.end_parse(); + } + + void check_done() + { + while (!eof_) + { + if (!(index_ < buffer_length_)) + { + if (!is_->eof()) + { + is_->read(buffer_.data(), buffer_capacity_); + buffer_length_ = static_cast<size_t>(is_->gcount()); + if (buffer_length_ == 0) + { + eof_ = true; + } + index_ = 0; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.check_done(buffer_.data(),index_,buffer_length_); + index_ = parser_.index(); + } + } + } + + bool eof() const + { + return eof_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + void read() + { + read_next(); + } + + size_t max_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } +#endif +}; + +typedef basic_json_reader<char> json_reader; +typedef basic_json_reader<wchar_t> wjson_reader; + +} + +#endif + diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_serializer.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_serializer.hpp new file mode 100644 index 00000000..d9f3bf4f --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_serializer.hpp @@ -0,0 +1,435 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_SERIALIZER_HPP +#define JSONCONS_JSON_SERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> // std::numeric_limits +#include <fstream> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/output_format.hpp" +#include "jsoncons/json_output_handler.hpp" + +namespace jsoncons { + +template<typename CharT> +class basic_json_serializer : public basic_json_output_handler<CharT> +{ + static const size_t default_buffer_length = 16384; + + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0), option_(block_options::next_line), multiline_(false) + { + scalar_option_ = is_object ? block_options::next_line : block_options::same_line; + } + stack_item(bool is_object, block_options option) + : is_object_(is_object), count_(0), option_(option), multiline_(false) + { + scalar_option_ = is_object ? block_options::next_line : block_options::same_line; + } + bool is_multiline() const + { + return multiline_; + } + + bool is_object() const + { + return is_object_; + } + + bool is_same_line() const + { + return option_ = block_options::same_line; + } + + bool is_next_line() const + { + return option_ == block_options::next_line; + } + + bool scalar_next_line() const + { + return scalar_option_ == block_options::next_line; + } + + bool is_object_; + size_t count_; + block_options option_; + block_options scalar_option_; + bool multiline_; + }; + basic_output_format<CharT> format_; + std::vector<stack_item> stack_; + int indent_; + std::streamsize original_precision_; + std::ios_base::fmtflags original_format_flags_; + bool indenting_; + float_printer<CharT> fp_; + buffered_ostream<CharT> bos_; +public: + basic_json_serializer(std::basic_ostream<CharT>& os) + : indent_(0), + indenting_(false), + fp_(format_.precision()), + bos_(os) + { + } + + basic_json_serializer(std::basic_ostream<CharT>& os, bool indenting) + : indent_(0), + indenting_(indenting), + fp_(format_.precision()), + bos_(os) + { + } + + basic_json_serializer(std::basic_ostream<CharT>& os, const basic_output_format<CharT>& format) + : format_(format), + indent_(0), + indenting_(false), + fp_(format_.precision()), + bos_(os) + { + } + basic_json_serializer(std::basic_ostream<CharT>& os, const basic_output_format<CharT>& format, bool indenting) + : format_(format), + indent_(0), + indenting_(indenting), + fp_(format_.precision()), + bos_(os) + { + } + + ~basic_json_serializer() + { + } + +private: + // Implementing methods + void do_begin_json() override + { + } + + void do_end_json() override + { + bos_.flush(); + } + + void do_begin_object() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + bos_. put(','); + } + } + } + + if (indenting_) + { + if (!stack_.empty() && stack_.back().is_object()) + { + if (format_.object_object_block_option() == block_options::next_line) + { + write_indent(); + } + stack_.push_back(stack_item(true,format_.object_object_block_option())); + } + else if (!stack_.empty()) + { + if (format_.array_object_block_option() == block_options::next_line) + { + write_indent(); + } + stack_.push_back(stack_item(true,format_.array_object_block_option())); + } + else + { + stack_.push_back(stack_item(true)); + } + indent(); + } + else + { + stack_.push_back(stack_item(true)); + } + bos_.put('{'); + } + + void do_end_object() override + { + JSONCONS_ASSERT(!stack_.empty()); + if (indenting_) + { + unindent(); + write_indent(); + } + stack_.pop_back(); + bos_.put('}'); + + end_value(); + } + + + void do_begin_array() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + bos_. put(','); + } + } + } + if (indenting_) + { + if (!stack_.empty() && stack_.back().is_object()) + { + if (format_.object_array_block_option() == block_options::next_line) + { + write_indent(); + } + stack_.push_back(stack_item(false,format_.object_array_block_option())); + } + else if (!stack_.empty()) + { + if (format_.array_array_block_option() == block_options::next_line) + { + write_indent(); + } + stack_.push_back(stack_item(false,format_.array_array_block_option())); + } + else + { + stack_.push_back(stack_item(false)); + } + indent(); + } + else + { + stack_.push_back(stack_item(false)); + } + bos_.put('['); + } + + void do_end_array() override + { + JSONCONS_ASSERT(!stack_.empty()); + if (indenting_) + { + unindent(); + if (stack_.back().is_multiline()) + { + write_indent(); + } + } + stack_.pop_back(); + bos_.put(']'); + end_value(); + } + + void do_name(const CharT* name, size_t length) override + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + bos_. put(','); + } + if (indenting_) + { + if (stack_.back().scalar_next_line()) + { + write_indent(); + } + } + } + + bos_.put('\"'); + escape_string<CharT>(name, length, format_, bos_); + bos_.put('\"'); + bos_.put(':'); + bos_.put(' '); + } + + void do_null_value() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + auto buf = json_literals<CharT>::null_literal(); + bos_.write(buf.first,buf.second); + + end_value(); + } + + void do_string_value(const CharT* value, size_t length) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + bos_. put('\"'); + escape_string<CharT>(value, length, format_, bos_); + bos_. put('\"'); + + end_value(); + } + + void do_double_value(double value, uint8_t precision) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + if (is_nan(value) && format_.replace_nan()) + { + bos_.write(format_.nan_replacement()); + } + else if (is_pos_inf(value) && format_.replace_pos_inf()) + { + bos_.write(format_.pos_inf_replacement()); + } + else if (is_neg_inf(value) && format_.replace_neg_inf()) + { + bos_.write(format_.neg_inf_replacement()); + } + else + { + fp_.print(value,precision,bos_); + } + + end_value(); + } + + void do_integer_value(int64_t value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + print_integer(value,bos_); + end_value(); + } + + void do_uinteger_value(uint64_t value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + print_uinteger(value,bos_); + end_value(); + } + + void do_bool_value(bool value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + if (value) + { + auto buf = json_literals<CharT>::true_literal(); + bos_.write(buf.first,buf.second); + } + else + { + auto buf = json_literals<CharT>::false_literal(); + bos_.write(buf.first,buf.second); + } + + end_value(); + } + + void begin_scalar_value() + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + bos_. put(','); + } + if (indenting_) + { + if (stack_.back().scalar_next_line()) + { + write_indent(); + } + } + } + } + + void begin_value() + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + bos_. put(','); + } + if (indenting_ && stack_.back().is_next_line()) + { + write_indent(); + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } + + void indent() + { + indent_ += static_cast<int>(format_.indent()); + } + + void unindent() + { + indent_ -= static_cast<int>(format_.indent()); + } + + void write_indent() + { + if (!stack_.empty()) + { + stack_.back().multiline_ = true; + } + bos_. put('\n'); + for (int i = 0; i < indent_; ++i) + { + bos_. put(' '); + } + } +}; + +typedef basic_json_serializer<char> json_serializer; +typedef basic_json_serializer<wchar_t> wjson_serializer; + +} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_structures.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_structures.hpp new file mode 100644 index 00000000..ee8f75af --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_structures.hpp @@ -0,0 +1,860 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_STRUCTURES_HPP +#define JSONCONS_JSON_STRUCTURES_HPP + +#include <string> +#include <vector> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <algorithm> +#include <sstream> +#include <iomanip> +#include <utility> +#include <initializer_list> +#include "jsoncons/jsoncons.hpp" + +namespace jsoncons { + +template <class JsonT, class Alloc> +class json_array +{ +public: + typedef Alloc allocator_type; + typedef JsonT value_type; + typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<JsonT> vector_allocator_type; + typedef typename std::vector<JsonT,Alloc>::reference reference; + typedef typename std::vector<JsonT,Alloc>::const_reference const_reference; + typedef typename std::vector<JsonT,Alloc>::iterator iterator; + typedef typename std::vector<JsonT,Alloc>::const_iterator const_iterator; + + json_array() + : elements_() + { + } + + explicit json_array(const Alloc& allocator) + : elements_(allocator) + { + } + + explicit json_array(size_t n, const Alloc& allocator = Alloc()) + : elements_(n,JsonT(),allocator) + { + } + + explicit json_array(size_t n, const JsonT& value, const Alloc& allocator = Alloc()) + : elements_(n,value,allocator) + { + } + + template <class InputIterator> + json_array(InputIterator begin, InputIterator end, const Alloc& allocator = Alloc()) + : elements_(begin,end,allocator) + { + } + + json_array(const json_array& val) + : elements_(val.elements_) + { + } + + json_array(const json_array& val, const Alloc& allocator) + : elements_(val.elements_,allocator) + { + } + json_array(json_array&& val) + : elements_(std::move(val.elements_)) + { + } + json_array(json_array&& val, const Alloc& allocator) + : elements_(std::move(val.elements_),allocator) + { + } + + json_array(std::initializer_list<JsonT> init, + const Alloc& allocator = Alloc()) + : elements_(std::move(init),allocator) + { + } + + Alloc get_allocator() const + { + return elements_.get_allocator(); + } + + void swap(json_array<JsonT,Alloc>& val) + { + elements_.swap(val.elements_); + } + + size_t size() const {return elements_.size();} + + size_t capacity() const {return elements_.capacity();} + + void clear() {elements_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < elements_.size(); ++i) + { + elements_[i].shrink_to_fit(); + } + elements_.shrink_to_fit(); + } + + void reserve(size_t n) {elements_.reserve(n);} + + void resize(size_t n) {elements_.resize(n);} + + void resize(size_t n, const JsonT& val) {elements_.resize(n,val);} + + void remove_range(size_t from_index, size_t to_index) + { + JSONCONS_ASSERT(from_index <= to_index); + JSONCONS_ASSERT(to_index <= elements_.size()); + elements_.erase(elements_.begin()+from_index,elements_.begin()+to_index); + } + + void erase(iterator first, iterator last) + { + elements_.erase(first,last); + } + + JsonT& operator[](size_t i) {return elements_[i];} + + const JsonT& operator[](size_t i) const {return elements_[i];} + + void push_back(const JsonT& value) + { + elements_.push_back(value); + } + + void push_back(JsonT&& value) + { + elements_.push_back(std::move(value)); + } + + void add(size_t index, const JsonT& value) + { + auto position = index < elements_.size() ? elements_.begin() + index : elements_.end(); + elements_.insert(position, value); + } + + void add(size_t index, JsonT&& value) + { + auto it = index < elements_.size() ? elements_.begin() + index : elements_.end(); + elements_.insert(it, std::move(value)); + } + +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator add(const_iterator pos, const JsonT& value) + { + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.insert(it, value); + } + + iterator add(const_iterator pos, JsonT&& value) + { + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.insert(it, std::move(value)); + } +#else + iterator add(const_iterator pos, const JsonT& value) + { + return elements_.insert(pos, value); + } + + iterator add(const_iterator pos, JsonT&& value) + { + return elements_.insert(pos, std::move(value)); + } +#endif + + iterator begin() {return elements_.begin();} + + iterator end() {return elements_.end();} + + const_iterator begin() const {return elements_.begin();} + + const_iterator end() const {return elements_.end();} + + bool operator==(const json_array<JsonT,Alloc>& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (size_t i = 0; i < size(); ++i) + { + if (elements_[i] != rhs.elements_[i]) + { + return false; + } + } + return true; + } +private: + json_array& operator=(const json_array<JsonT,Alloc>&); + std::vector<JsonT,Alloc> elements_; +}; + +template <class ValueT,typename CharT> +class member_lt_string +{ + size_t length_; +public: + member_lt_string(size_t length) + : length_(length) + { + } + + bool operator()(const ValueT& a, const CharT* b) const + { + size_t len = std::min JSONCONS_NO_MACRO_EXP(a.name().length(),length_); + int result = std::char_traits<CharT>::compare(a.name().data(),b,len); + if (result != 0) + { + return result < 0; + } + + return a.name().length() < length_; + } +}; + +template <class StringT,typename CharT> +bool name_le_string(const StringT& a, const CharT* b, size_t length) +{ + size_t min_len = std::min JSONCONS_NO_MACRO_EXP(a.length(),length); + int result = std::char_traits<CharT>::compare(a.data(),b, min_len); + if (result != 0) + { + return result < 0; + } + + return a.length() <= length; +} + +template <class StringT,typename CharT> +bool name_eq_string(const StringT& a, const CharT* b, size_t length) +{ + return a.length() == length && std::char_traits<CharT>::compare(a.data(),b,length) == 0; +} + +template <class ValueT> +class member_lt_member +{ + typedef typename ValueT::char_type char_type; +public: + bool operator()(const ValueT& a, const ValueT& b) const + { + if (a.name().length() == b.name().length()) + { + return std::char_traits<char_type>::compare(a.name().data(),b.name().data(),a.name().length()) < 0; + } + + size_t len = std::min JSONCONS_NO_MACRO_EXP(a.name().length(),b.name().length()); + int result = std::char_traits<char_type>::compare(a.name().data(),b.name().data(),len); + if (result != 0) + { + return result < 0; + } + + return a.name().length() < b.name().length(); + } +}; + +template <class StringT, class ValueT> +class name_value_pair +{ +public: + typedef StringT string_type; + typedef typename StringT::value_type char_type; + + name_value_pair() + { + } + name_value_pair(const string_type& name) + : name_(name) + { + } + name_value_pair(string_type&& name) + : name_(std::move(name)) + { + } + + name_value_pair(const string_type& name, const ValueT& val) + : name_(name), value_(val) + { + } + name_value_pair(string_type&& name, const ValueT& val) + : name_(std::move(name)), value_(val) + { + } + name_value_pair(const string_type& name, ValueT&& val) + : name_(name), value_(std::move(val)) + { + } + name_value_pair(string_type&& name, ValueT&& val) + : name_(std::move(name)), value_(std::move(val)) + { + } + name_value_pair(const name_value_pair& member) + : name_(member.name_), value_(member.value_) + { + } + name_value_pair(name_value_pair&& member) + : name_(std::move(member.name_)), value_(std::move(member.value_)) + { + } + + const string_type& name() const + { + return name_; + } + + ValueT& value() + { + return value_; + } + + const ValueT& value() const + { + return value_; + } + + void value(const ValueT& value) + { + value_ = value; + } + + void value(ValueT&& value) + { + value_ = std::move(value); + } + + void swap(name_value_pair& member) + { + name_.swap(member.name_); + value_.swap(member.value_); + } + + name_value_pair& operator=(const name_value_pair& member) + { + if (this != & member) + { + name_ = member.name_; + value_ = member.value_; + } + return *this; + } + + name_value_pair& operator=(name_value_pair&& member) + { + if (this != &member) + { + name_.swap(member.name_); + value_.swap(member.value_); + } + return *this; + } + + void shrink_to_fit() + { + name_.shrink_to_fit(); + value_.shrink_to_fit(); + } +private: + string_type name_; + ValueT value_; +}; + +template <class IteratorT,class NonConstIteratorT> +class json_object_iterator +{ +public: + typedef IteratorT iterator; + typedef typename std::iterator_traits<IteratorT>::value_type value_type; + typedef typename std::iterator_traits<IteratorT>::difference_type difference_type; + typedef typename std::iterator_traits<IteratorT>::pointer pointer; + typedef typename std::iterator_traits<IteratorT>::reference reference; + typedef std::bidirectional_iterator_tag iterator_category; + + json_object_iterator(bool empty = false) + : empty_(empty) + { + } + + json_object_iterator(iterator it) + : empty_(false), it_(it) + { + } + + json_object_iterator(const json_object_iterator<NonConstIteratorT,NonConstIteratorT>& it) + : empty_(it.empty_), it_(it.it_) + { + } + + json_object_iterator& operator=(json_object_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_object_iterator& operator++() + { + ++it_; + return *this; + } + + json_object_iterator operator++(int) // postfix increment + { + json_object_iterator temp(*this); + ++it_; + return temp; + } + + json_object_iterator& operator--() + { + --it_; + return *this; + } + + json_object_iterator operator--(int) + { + json_object_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return *it_; + } + + pointer operator->() const + { + return &(*it_); + } + + bool empty() const + { + return empty_; + } + + friend bool operator==(const json_object_iterator& it1, const json_object_iterator& it2) + { + return (it1.empty() && it2.empty()) || (it1.it_ == it2.it_); + } + friend bool operator!=(const json_object_iterator& it1, const json_object_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_object_iterator& lhs, json_object_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + + iterator get() + { + return it_; + } + +//private: + bool empty_; + IteratorT it_; +}; + +template <class StringT,class JsonT,class Alloc> +class json_object +{ +public: + typedef Alloc allocator_type; + typedef typename JsonT::char_type char_type; + typedef StringT string_type; + typedef name_value_pair<StringT,JsonT> value_type; + typedef typename std::vector<value_type, allocator_type>::iterator base_iterator; + typedef typename std::vector<value_type, allocator_type>::const_iterator const_base_iterator; + + typedef json_object_iterator<base_iterator,base_iterator> iterator; + typedef json_object_iterator<const_base_iterator,base_iterator> const_iterator; +private: + std::vector<value_type,allocator_type> members_; +public: + json_object(const allocator_type& allocator = allocator_type()) + : members_(allocator) + { + } + + json_object(const json_object<StringT,JsonT,Alloc>& val) + : members_(val.members_) + { + } + + json_object(json_object&& val) + : members_(std::move(val.members_)) + { + } + + json_object(const json_object<StringT,JsonT,Alloc>& val, const allocator_type& allocator) : + members_(val.members_,allocator) + { + } + + json_object(json_object&& val,const allocator_type& allocator) : + members_(std::move(val.members_),allocator) + { + } + + Alloc get_allocator() const + { + return members_.get_allocator(); + } + + iterator begin() + { + //return members_.begin(); + return iterator(members_.begin()); + } + + iterator end() + { + //return members_.end(); + return iterator(members_.end()); + } + + const_iterator begin() const + { + //return iterator(members.data()); + return const_iterator(members_.begin()); + } + + const_iterator end() const + { + //return members_.end(); + return const_iterator(members_.end()); + } +/* + const_iterator cbegin() const + { + return members_.begin(); + } + + const_iterator cend() const + { + return members_.end(); + } +*/ + void swap(json_object& val) + { + members_.swap(val.members_); + } + + size_t size() const {return members_.size();} + + size_t capacity() const {return members_.capacity();} + + void clear() {members_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < members_.size(); ++i) + { + members_[i].shrink_to_fit(); + } + members_.shrink_to_fit(); + } + + void reserve(size_t n) {members_.reserve(n);} + + iterator find(const char_type* name, size_t length) + { + member_lt_string<value_type,char_type> comp(length); + auto it = std::lower_bound(members_.begin(),members_.end(), name, comp); + auto result = (it != members_.end() && name_eq_string(it->name(),name,length)) ? it : members_.end(); + return iterator(result); + } + + const_iterator find(const char_type* name, size_t length) const + { + member_lt_string<value_type,char_type> comp(length); + auto it = std::lower_bound(members_.begin(),members_.end(), name, comp); + auto result = (it != members_.end() && name_eq_string(it->name(),name,length)) ? it : members_.end(); + return const_iterator(result); + } + + void erase(iterator first, iterator last) + { + members_.erase(first.get(),last.get()); + } + + void erase(const char_type* name, size_t length) + { + member_lt_string<value_type,char_type> comp(length); + auto it = std::lower_bound(members_.begin(),members_.end(), name, comp); + if (it != members_.end() && name_eq_string(it->name(),name,length)) + { + members_.erase(it); + } + } + + template<class InputIt, class UnaryPredicate> + void insert(InputIt first, InputIt last, UnaryPredicate pred) + { + size_t count = std::distance(first,last); + size_t pos = members_.size(); + members_.resize(pos+count); + auto d = members_.begin()+pos; + for (auto s = first; s != last; ++s, ++d) + { + *d = pred(*s); + } + std::sort(members_.begin(),members_.end(),member_lt_member<value_type>()); + } + + void set(const char_type* s, size_t length, const JsonT& value) + { + auto it = std::lower_bound(members_.begin(),members_.end(),s,member_lt_string<value_type,char_type>(length)); + if (it == members_.end()) + { + members_.push_back(value_type(string_type(s,length),value)); + } + else if (name_eq_string(it->name(),s,length)) + { + it->value(value); + } + else + { + members_.insert(it,value_type(string_type(s,length),value)); + } + } + + void set(const char_type* s, size_t length, JsonT&& value) + { + auto it = std::lower_bound(members_.begin(),members_.end(),s,member_lt_string<value_type,char_type>(length)); + if (it == members_.end()) + { + members_.push_back(value_type(string_type(s,length),std::move(value))); + } + else if (name_eq_string(it->name(),s,length)) + { + it->value(std::move(value)); + } + else + { + members_.insert(it,value_type(string_type(s,length),std::move(value))); + } + } + + void set(string_type&& name, const JsonT& value) + { + auto it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); + if (it == members_.end()) + { + members_.push_back(value_type(std::move(name), value)); + } + else if (it->name() == name) + { + it->value(value); + } + else + { + members_.insert(it,value_type(std::move(name),value)); + } + } + + void set(const string_type& name, const JsonT& value) + { + set(name.data(),name.length(),value); + } + + void set(const string_type& name, JsonT&& value) + { + set(name.data(),name.length(),std::move(value)); + } + + void set(string_type&& name, JsonT&& value) + { + auto it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); + if (it == members_.end()) + { + members_.push_back(value_type(std::move(name), std::move(value))); + } + else if (it->name() == name) + { + it->value(std::move(value)); + } + else + { + members_.insert(it,value_type(std::move(name),std::move(value))); + } + } + + iterator set(iterator hint, const char_type* name, const JsonT& value) + { + return set(hint, name, std::char_traits<char_type>::length(name), value); + } + + iterator set(iterator hint, const char_type* name, JsonT&& value) + { + return set(hint, name, std::char_traits<char_type>::length(name), std::move(value)); + } + + iterator set(iterator hint, const char_type* s, size_t length, const JsonT& value) + { + base_iterator it; + if (hint.get() != members_.end() && name_le_string(hint.get()->name(), s, length)) + { + it = std::lower_bound(hint.get(),members_.end(),s,member_lt_string<value_type,char_type>(length)); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(),s, member_lt_string<value_type,char_type>(length)); + } + + if (it == members_.end()) + { + members_.push_back(value_type(string_type(s, length), value)); + it = members_.begin() + (members_.size() - 1); + } + else if (name_eq_string(it->name(),s,length)) + { + it->value(value); + } + else + { + it = members_.insert(it,value_type(string_type(s,length),value)); + } + return iterator(it); + } + + iterator set(iterator hint, const char_type* s, size_t length, JsonT&& value) + { + base_iterator it; + if (hint.get() != members_.end() && name_le_string(hint.get()->name(), s, length)) + { + it = std::lower_bound(hint.get(),members_.end(),s,member_lt_string<value_type,char_type>(length)); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(),s, member_lt_string<value_type,char_type>(length)); + } + + if (it == members_.end()) + { + members_.push_back(value_type(string_type(s, length), std::move(value))); + it = members_.begin() + (members_.size() - 1); + } + else if (name_eq_string(it->name(),s,length)) + { + it->value(std::move(value)); + } + else + { + it = members_.insert(it,value_type(string_type(s,length),std::move(value))); + } + return iterator(it); + } + + iterator set(iterator hint, const string_type& name, const JsonT& value) + { + return set(hint,name.data(),name.length(),value); + } + + iterator set(iterator hint, string_type&& name, const JsonT& value) + { + base_iterator it; + if (hint.get() != members_.end() && hint.get()->name() <= name) + { + it = std::lower_bound(hint.get(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); + } + + if (it == members_.end()) + { + members_.push_back(value_type(std::move(name), value)); + it = members_.begin() + (members_.size() - 1); + } + else if (it->name() == name) + { + it->value(value); + } + else + { + it = members_.insert(it,value_type(std::move(name),value)); + } + return iterator(it); + } + + iterator set(iterator hint, const string_type& name, JsonT&& value) + { + return set(hint,name.data(),name.length(),std::move(value)); + } + + iterator set(iterator hint, string_type&& name, JsonT&& value) + { + typename std::vector<value_type,allocator_type>::iterator it; + if (hint.get() != members_.end() && hint.get()->name() <= name) + { + it = std::lower_bound(hint.get(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); + } + + if (it == members_.end()) + { + members_.push_back(value_type(std::move(name), std::move(value))); + it = members_.begin() + (members_.size() - 1); + } + else if (it->name() == name) + { + it->value(std::move(value)); + } + else + { + it = members_.insert(it,value_type(std::move(name),std::move(value))); + } + return iterator(it); + } + + bool operator==(const json_object<StringT,JsonT,Alloc>& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (auto it = members_.begin(); it != members_.end(); ++it) + { + + auto rhs_it = std::lower_bound(rhs.members_.begin(), rhs.members_.end(), *it, member_lt_member<value_type>()); + // member_lt_member actually only compares keys, so we need to check the value separately + if (rhs_it == rhs.members_.end() || rhs_it->name() != it->name() || rhs_it->value() != it->value()) + { + return false; + } + } + return true; + } +private: + json_object<StringT,JsonT,Alloc>& operator=(const json_object<StringT,JsonT,Alloc>&); +}; + + + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_type_traits.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_type_traits.hpp new file mode 100644 index 00000000..aeda7a0b --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/json_type_traits.hpp @@ -0,0 +1,594 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_TYPE_TRAITS_HPP +#define JSONCONS_JSON_TYPE_TRAITS_HPP + +#include <string> +#include <vector> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <utility> +#include <algorithm> +#include <fstream> +#include <limits> +#include "jsoncons/jsoncons.hpp" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons { + +template <class JsonT, typename T> +class json_type_traits +{ +public: + static bool is(const JsonT&) + { + return false; + } +}; + +template<class JsonT> +class json_type_traits<JsonT, typename JsonT::string_type> +{ +public: + typedef typename JsonT::string_type string_type; + typedef typename string_type::allocator_type string_allocator; + + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_string(); + } + static string_type as(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.as_string(); + } + static string_type as(const JsonT& rhs, const string_allocator& allocator) JSONCONS_NOEXCEPT + { + return rhs.as_string(allocator); + } + static void assign(JsonT& lhs, const string_type& rhs) + { + lhs.assign_string(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, typename JsonT::any> +{ +public: + static bool is(const JsonT& lhs) JSONCONS_NOEXCEPT + { + return lhs.is_any(); + } + static typename JsonT::any as(const JsonT& rhs) + { + return rhs.any_value(); + } + static void assign(JsonT& lhs, typename JsonT::any rhs) + { + lhs.assign_any(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, typename type_wrapper<typename JsonT::char_type>::const_pointer_type> +{ +public: + typedef typename JsonT::char_type char_type; + + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_string(); + } + static const char_type* as(const JsonT& rhs) + { + return rhs.as_cstring(); + } + static void assign(JsonT& lhs, const char_type *rhs) + { + size_t length = std::char_traits<char_type>::length(rhs); + lhs.assign_string(rhs,length); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, typename type_wrapper<typename JsonT::char_type>::pointer_type> +{ +public: + typedef typename JsonT::char_type char_type; + + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_string(); + } + static const char_type* as(const JsonT& rhs) + { + return rhs.as_cstring(); + } + static void assign(JsonT& lhs, const char_type *rhs) + { + size_t length = std::char_traits<char_type>::length(rhs); + lhs.assign_string(rhs,length); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, char> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= std::numeric_limits<char>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<char>::max JSONCONS_NO_MACRO_EXP(); + } + else + { + return false; + } + } + static char as(const JsonT& rhs) + { + return static_cast<char>(rhs.as_integer()); + } + static void assign(JsonT& lhs, char ch) + { + lhs.assign_integer(ch); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, unsigned char> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned char>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= std::numeric_limits<unsigned char>::max JSONCONS_NO_MACRO_EXP(); + } + else + { + return false; + } + } + static unsigned char as(const JsonT& rhs) + { + return static_cast<unsigned char>(rhs.as_uinteger()); + } + static void assign(JsonT& lhs, unsigned char ch) + { + lhs.assign_uinteger(ch); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, signed char> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= std::numeric_limits<char>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<char>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<char>::max JSONCONS_NO_MACRO_EXP()); + } + else + { + return false; + } + } + static signed char as(const JsonT& rhs) + { + return static_cast<signed char>(rhs.as_integer()); + } + static void assign(JsonT& lhs, signed char ch) + { + lhs.assign_integer(ch); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, wchar_t> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= std::numeric_limits<wchar_t>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<wchar_t>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<wchar_t>::max JSONCONS_NO_MACRO_EXP()); + } + else + { + return false; + } + } + static wchar_t as(const JsonT& rhs) + { + return static_cast<wchar_t>(rhs.as_integer()); + } + static void assign(JsonT& lhs, wchar_t ch) + { + lhs.assign_integer(ch); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, typename JsonT::object> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_object(); + } + static typename JsonT::object as(JsonT rhs) + { + JSONCONS_ASSERT(rhs.is_object()); + return rhs.object_value(); + } + static void assign(JsonT& lhs, typename JsonT::object rhs) + { + lhs.assign_object(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, typename JsonT::array> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_array(); + } + static typename JsonT::array as(const JsonT& rhs) + { + JSONCONS_ASSERT(rhs.is_array()); + return rhs.array_value(); + } + static void assign(JsonT& lhs, typename JsonT::array rhs) + { + lhs.assign_array(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, jsoncons::null_type> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_null(); + } + static typename jsoncons::null_type as(const JsonT& rhs) + { + JSONCONS_ASSERT(rhs.is_null()); + return jsoncons::null_type(); + } + static void assign(JsonT& lhs, null_type) + { + lhs.assign_null(); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, bool> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_bool(); + } + static bool as(const JsonT& rhs) + { + return rhs.as_bool(); + } + static void assign(JsonT& lhs, bool rhs) + { + lhs.assign_bool(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, short> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= std::numeric_limits<short>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<short>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<short>::max JSONCONS_NO_MACRO_EXP()); + } + else + { + return false; + } + } + static short as(const JsonT& rhs) + { + return static_cast<short>(rhs.as_integer()); + } + static void assign(JsonT& lhs, short rhs) + { + lhs.assign_integer(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, unsigned short> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned short>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= std::numeric_limits<unsigned short>::max JSONCONS_NO_MACRO_EXP(); + } + else + { + return false; + } + } + static unsigned short as(const JsonT& rhs) + { + return (unsigned short)rhs.as_uinteger(); + } + static void assign(JsonT& lhs, unsigned short rhs) + { + lhs.assign_uinteger(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, int> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= std::numeric_limits<int>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP()); + } + else + { + return false; + } + } + static int as(const JsonT& rhs) + { + return static_cast<int>(rhs.as_integer()); + } + static void assign(JsonT& lhs, int rhs) + { + lhs.assign_integer(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, unsigned int> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned int>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= std::numeric_limits<unsigned int>::max JSONCONS_NO_MACRO_EXP(); + } + else + { + return false; + } + } + static unsigned int as(const JsonT& rhs) + { + return static_cast<unsigned int>(rhs.as_uinteger()); + } + static void assign(JsonT& lhs, unsigned int rhs) + { + lhs.assign_uinteger(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, long> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= std::numeric_limits<long>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<long>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<long>::max JSONCONS_NO_MACRO_EXP()); + } + else + { + return false; + } + } + static long as(const JsonT& rhs) + { + return static_cast<long>(rhs.as_integer()); + } + static void assign(JsonT& lhs, long rhs) + { + lhs.assign_integer(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, unsigned long> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + if (rhs.is_integer()) + { + return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned long>::max JSONCONS_NO_MACRO_EXP(); + } + else if (rhs.is_uinteger()) + { + return rhs.as_uinteger() <= std::numeric_limits<unsigned long>::max JSONCONS_NO_MACRO_EXP(); + } + else + { + return false; + } + } + static unsigned long as(const JsonT& rhs) + { + return static_cast<unsigned long>(rhs.as_uinteger()); + } + static void assign(JsonT& lhs, unsigned long rhs) + { + lhs.assign_uinteger(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, long long> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_integer(); + } + static long long as(const JsonT& rhs) + { + return rhs.as_integer(); + } + static void assign(JsonT& lhs, long long rhs) + { + lhs.assign_integer(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, unsigned long long> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_uinteger(); + } + static unsigned long long as(const JsonT& rhs) + { + return rhs.as_uinteger(); + } + static void assign(JsonT& lhs, unsigned long long rhs) + { + lhs.assign_uinteger(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, double> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_double(); + } + + static double as(const JsonT& rhs) + { + return rhs.as_double(); + } + static void assign(JsonT& lhs, double rhs) + { + lhs.assign_double(rhs); + } +}; + +template<class JsonT> +class json_type_traits<JsonT, float> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + return rhs.is_double(); + } + static double as(const JsonT& rhs) + { + return static_cast<float>(rhs.as_double()); + } + static void assign(JsonT& lhs, float rhs) + { + lhs.assign_double(static_cast<double>(rhs)); + } +}; + +template<class JsonT, typename T> +class json_type_traits<JsonT, std::vector<T>> +{ +public: + static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT + { + bool result = rhs.is_array(); + for (size_t i = 0; result && i < rhs.size(); ++i) + { + if (!rhs[i].template is<T>()) + { + result = false; + } + } + return result; + } + static std::vector<T> as(const JsonT& rhs) + { + std::vector<T> v(rhs.size()); + for (size_t i = 0; i < v.size(); ++i) + { + v[i] = rhs[i].template as<T>(); + } + return v; + } + static void assign(JsonT& lhs, const std::vector<T>& rhs) + { + lhs = JsonT(rhs.begin(), rhs.end()); + } +}; + +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/jsoncons.hpp b/vendor/jsoncons-0.99.2/jsoncons/jsoncons.hpp new file mode 100644 index 00000000..a45e4f8c --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/jsoncons.hpp @@ -0,0 +1,347 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONS_HPP +#define JSONCONS_JSONCONS_HPP + +#include <locale> +#include <string> +#include <vector> +#include <cstdlib> +#include <cwchar> +#include <cstdint> +#include <iostream> +#include <vector> +#include "jsoncons/jsoncons_config.hpp" +#include "jsoncons/jsoncons_io.hpp" + +namespace jsoncons { + +// null_type + +struct null_type +{ +}; + +// json_exception + +class json_exception +{ +public: + virtual const char* what() const JSONCONS_NOEXCEPT = 0; +}; + +template <typename Base> +class json_exception_0 : public Base, public virtual json_exception +{ +public: + json_exception_0(std::string s) JSONCONS_NOEXCEPT + : Base(""), message_(s) + { + } + ~json_exception_0() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT + { + return message_.c_str(); + } +private: + std::string message_; +}; + +template <typename Base> +class json_exception_1 : public Base, public virtual json_exception +{ +public: + json_exception_1(const std::string& format, const std::string& arg1) JSONCONS_NOEXCEPT + : Base(""), format_(format), arg1_(arg1) + { + } + json_exception_1(const std::string& format, const std::wstring& arg1) JSONCONS_NOEXCEPT + : Base(""), format_(format) + { + char buf[255]; + size_t retval; +#if defined(JSONCONS_HAS_WCSTOMBS_S) + wcstombs_s(&retval, buf, sizeof(buf), arg1.c_str(), arg1.size()); +#else + retval = wcstombs(buf, arg1.c_str(), sizeof(buf)); +#endif + if (retval != static_cast<std::size_t>(-1)) + { + arg1_ = buf; + } + } + ~json_exception_1() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT + { + c99_snprintf(const_cast<char*>(message_),255, format_.c_str(),arg1_.c_str()); + return message_; + } +private: + std::string format_; + std::string arg1_; + char message_[255]; +}; + +#define JSONCONS_STR2(x) #x +#define JSONCONS_STR(x) JSONCONS_STR2(x) + +#define JSONCONS_THROW_EXCEPTION(Base,x) throw jsoncons::json_exception_0<Base>((x)) +#define JSONCONS_THROW_EXCEPTION_1(Base,fmt,arg1) throw jsoncons::json_exception_1<Base>((fmt),(arg1)) +#define JSONCONS_ASSERT(x) if (!(x)) { \ + throw jsoncons::json_exception_0<std::runtime_error>("assertion '" #x "' failed at " __FILE__ ":" \ + JSONCONS_STR(__LINE__)); } + +// json_char_traits + +const uint16_t min_lead_surrogate = 0xD800; +const uint16_t max_lead_surrogate = 0xDBFF; +const uint16_t min_trail_surrogate = 0xDC00; +const uint16_t max_trail_surrogate = 0xDFFF; + +template <typename CharT> +struct json_literals +{ +}; + +template <> +struct json_literals<char> +{ + static std::pair<const char*,size_t> null_literal() + { + static const char* value = "null"; + return std::pair<const char*,size_t>(value,4); + } + + static std::pair<const char*,size_t> true_literal() + { + static const char* value = "true"; + return std::pair<const char*,size_t>(value,4); + } + + static std::pair<const char*,size_t> false_literal() + { + static const char* value = "false"; + return std::pair<const char*,size_t>(value,5); + } +}; + +template <> +struct json_literals<wchar_t> +{ + static std::pair<const wchar_t*,size_t> null_literal() + { + static const wchar_t* value = L"null"; + return std::pair<const wchar_t*,size_t>(value,4); + } + + static std::pair<const wchar_t*,size_t> true_literal() + { + static const wchar_t* value = L"true"; + return std::pair<const wchar_t*,size_t>(value,4); + } + + static std::pair<const wchar_t*,size_t> false_literal() + { + static const wchar_t* value = L"false"; + return std::pair<const wchar_t*,size_t>(value,5); + } +}; + +template <typename CharT,size_t Size> +struct json_char_traits +{ +}; + +template <> +struct json_char_traits<char,1> +{ + static uint32_t convert_char_to_codepoint(const char*& it, + const char*) + { + char c = *it; + uint32_t u(c >= 0 ? c : 256 + c ); + uint32_t cp = u; + if (u < 0x80) + { + } + else if ((u >> 5) == 0x6) + { + c = *(++it); + u = (c >= 0 ? c : 256 + c ); + cp = ((cp << 6) & 0x7ff) + (u & 0x3f); + } + else if ((u >> 4) == 0xe) + { + c = *(++it); + u = (c >= 0 ? c : 256 + c ); + cp = ((cp << 12) & 0xffff) + ((static_cast<uint32_t>(0xff & u) << 6) & 0xfff); + c = *(++it); + u = (c >= 0 ? c : 256 + c ); + cp += (u) & 0x3f; + } + else if ((u >> 3) == 0x1e) + { + c = *(++it); + u = (c >= 0 ? c : 256 + c ); + cp = ((cp << 18) & 0x1fffff) + ((static_cast<uint32_t>(0xff & u) << 12) & 0x3ffff); + c = *(++it); + u = (c >= 0 ? c : 256 + c ); + cp += (static_cast<uint32_t>(0xff & u) << 6) & 0xfff; + c = *(++it); + u = (c >= 0 ? c : 256 + c ); + cp += (u) & 0x3f; + } + else + { + } + return cp; + } + + static void append_codepoint_to_string(uint32_t cp, std::string& s) + { + if (cp <= 0x7f) + { + s.push_back(static_cast<char>(cp)); + } + else if (cp <= 0x7FF) + { + s.push_back(static_cast<char>(0xC0 | (0x1f & (cp >> 6)))); + s.push_back(static_cast<char>(0x80 | (0x3f & cp))); + } + else if (cp <= 0xFFFF) + { + s.push_back(0xE0 | static_cast<char>((0xf & (cp >> 12)))); + s.push_back(0x80 | static_cast<char>((0x3f & (cp >> 6)))); + s.push_back(static_cast<char>(0x80 | (0x3f & cp))); + } + else if (cp <= 0x10FFFF) + { + s.push_back(static_cast<char>(0xF0 | (0x7 & (cp >> 18)))); + s.push_back(static_cast<char>(0x80 | (0x3f & (cp >> 12)))); + s.push_back(static_cast<char>(0x80 | (0x3f & (cp >> 6)))); + s.push_back(static_cast<char>(0x80 | (0x3f & cp))); + } + } + +}; + +template <> +struct json_char_traits<wchar_t,2> // assume utf16 +{ + static void append_codepoint_to_string(uint32_t cp, std::wstring& s) + { + if (cp <= 0xFFFF) + { + s.push_back(static_cast<wchar_t>(cp)); + } + else if (cp <= 0x10FFFF) + { + s.push_back(static_cast<wchar_t>((cp >> 10) + min_lead_surrogate - (0x10000 >> 10))); + s.push_back(static_cast<wchar_t>((cp & 0x3ff) + min_trail_surrogate)); + } + } + + static uint32_t convert_char_to_codepoint(const wchar_t*& it, const wchar_t*) + { + uint32_t cp = (0xffff & *it); + if ((cp >= min_lead_surrogate && cp <= max_lead_surrogate)) // surrogate pair + { + uint32_t trail_surrogate = 0xffff & *(++it); + cp = (cp << 10) + trail_surrogate + 0x10000u - (min_lead_surrogate << 10) - min_trail_surrogate; + } + return cp; + } +}; + +template <> +struct json_char_traits<wchar_t,4> // assume utf32 +{ + static void append_codepoint_to_string(uint32_t cp, std::wstring& s) + { + if (cp <= 0xFFFF) + { + s.push_back(static_cast<wchar_t>(cp)); + } + else if (cp <= 0x10FFFF) + { + s.push_back(static_cast<wchar_t>(cp)); + } + } + + static uint32_t convert_char_to_codepoint(const wchar_t*& it, const wchar_t*) + { + uint32_t cp = static_cast<uint32_t>(*it); + return cp; + } +}; + +inline +bool is_control_character(uint32_t c) +{ + return c <= 0x1F || c == 0x7f; +} + +inline +char to_hex_character(unsigned char c) +{ + JSONCONS_ASSERT(c <= 0xF); + + return (c < 10) ? ('0' + c) : ('A' - 10 + c); +} + +inline +bool is_non_ascii_character(uint32_t c) +{ + return c >= 0x80; +} + +template <typename T> +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <typename T> +struct type_wrapper<const T> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <typename T> +struct type_wrapper<T&> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <typename T> +struct type_wrapper<const T&> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/jsoncons_config.hpp b/vendor/jsoncons-0.99.2/jsoncons/jsoncons_config.hpp new file mode 100644 index 00000000..7d261ec0 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/jsoncons_config.hpp @@ -0,0 +1,123 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONS_CONFIG_HPP +#define JSONCONS_JSONCONS_CONFIG_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <limits> // std::numeric_limits + +// Uncomment the following line to suppress deprecated names (recommended for new code) +// #define JSONCONS_NO_DEPRECATED + +#define JSONCONS_NO_MACRO_EXP + +namespace jsoncons +{ + +// Follow boost + +#if defined (__clang__) +#if defined(_GLIBCXX_USE_NOEXCEPT) +#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#else +#define JSONCONS_NOEXCEPT noexcept +#endif +#elif defined(__GNUC__) +#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define JSONCONS_NOEXCEPT noexcept +#else +#define JSONCONS_NOEXCEPT +#endif +#else +#define JSONCONS_NOEXCEPT +#endif + +#if defined(_MSC_VER) +#define JSONCONS_HAS_FOPEN_S +#define JSONCONS_HAS_WCSTOMBS_S +#if _MSC_VER < 1800 // VS2013 +#define JSONCONS_NO_RAW_STRING_LITERALS +#define JSONCONS_NO_FOR_RANGE +#endif +#if _MSC_VER >= 1900 +#define JSONCONS_ALIGNOF alignof +#else +#define JSONCONS_ALIGNOF __alignof +#endif +#else +#define JSONCONS_ALIGNOF alignof +#endif + +#ifdef _MSC_VER +#pragma warning( disable : 4290 ) +inline bool is_nan(double x) { return _isnan(x) != 0; } +inline bool is_inf(double x) +{ + return !_finite(x) && !_isnan(x); +} +inline bool is_pos_inf(double x) +{ + return is_inf(x) && x > 0; +} +inline bool is_neg_inf(double x) +{ + return is_inf(x) && x < 0; +} + +inline +int c99_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + if (count == -1) count = _vscprintf(format, ap); + + return count; +} + +inline +int c99_snprintf(char *str, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(str, size, format, ap); + va_end(ap); + + return count; +} +#else +inline bool is_nan(double x) +{ return std::isnan( x ); } +inline bool is_pos_inf(double x) +{return std::isinf(x) && x > 0;} +inline bool is_neg_inf(double x) +{return std::isinf(x) && x > 0;} + +#if __cplusplus >= 201103L +#define c99_snprintf snprintf +#else +#define c99_snprintf std::snprintf +#endif + +#endif + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/jsoncons_io.hpp b/vendor/jsoncons-0.99.2/jsoncons/jsoncons_io.hpp new file mode 100644 index 00000000..27c90fa1 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/jsoncons_io.hpp @@ -0,0 +1,358 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONS_IO_HPP +#define JSONCONS_JSONCONS_IO_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <limits> // std::numeric_limits +#include "jsoncons_config.hpp" +#include "ovectorstream.hpp" + +namespace jsoncons +{ + +template <typename CharT> +class buffered_ostream +{ + static const size_t default_buffer_length = 16384; + + std::basic_ostream<CharT>* os_; + std::vector<CharT> buffer_; + CharT * const begin_buffer_; + const CharT* const end_buffer_; + CharT* p_; +public: + buffered_ostream(std::basic_ostream<CharT>& os) + : os_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(buffer_.data()+default_buffer_length), p_(buffer_.data()) + { + } + ~buffered_ostream() + { + os_->write(begin_buffer_, (p_ - begin_buffer_)); + os_->flush(); + } + + void flush() + { + os_->write(begin_buffer_, (p_ - begin_buffer_)); + p_ = begin_buffer_; + os_->flush(); + } + + void write(const CharT* s, size_t length) + { + size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(CharT)); + p_ += length; + } + else + { + os_->write(begin_buffer_, (p_ - begin_buffer_)); + os_->write(s, length); + p_ = begin_buffer_; + } + } + + void write(const std::basic_string<CharT>& s) + { + write(s.data(),s.length()); + } + + void put(CharT c) + { + if (p_ < end_buffer_) + { + *p_++ = c; + } + else + { + os_->write(begin_buffer_, (p_-begin_buffer_)); + p_ = begin_buffer_; + *p_++ = c; + } + } + +}; + +#ifdef _MSC_VER + +template <typename CharT> +class float_printer +{ + uint8_t precision_; +public: + float_printer(int precision) + : precision_(precision) + { + } + + void print(double val, uint8_t precision, buffered_ostream<CharT>& os) + { + char buf[_CVTBUFSIZE]; + int decimal_point = 0; + int sign = 0; + + int prec = (precision == 0) ? precision_ : precision; + + int err = _ecvt_s(buf, _CVTBUFSIZE, val, prec, &decimal_point, &sign); + if (err != 0) + { + throw std::runtime_error("Failed attempting double to string conversion"); + } + char* s = buf; + char* se = s + prec; + + int i, k; + int j; + + if (sign) + { + os.put('-'); + } + if (decimal_point <= -4 || decimal_point > se - s + 5) + { + os.put(*s++); + if (s < se) + { + os.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + + while(s < se) + { + os.put(*s++); + } + } + os.put('e'); + /* sprintf(b, "%+.2d", decimal_point - 1); */ + if (--decimal_point < 0) { + os.put('-'); + decimal_point = -decimal_point; + } + else + os.put('+'); + for(j = 2, k = 10; 10*k <= decimal_point; j++, k *= 10); + for(;;) + { + i = decimal_point / k; + os.put(i + '0'); + if (--j <= 0) + break; + decimal_point -= i*k; + decimal_point *= 10; + } + } + else if (decimal_point <= 0) + { + os.put('0'); + os.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + for(; decimal_point < 0; decimal_point++) + { + os.put('0'); + } + while(s < se) + { + os.put(*s++); + } + } + else { + while(s < se) + { + os.put(*s++); + if ((--decimal_point == 0) && s < se) + { + os.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + } + } + for(; decimal_point > 0; decimal_point--) + { + os.put('0'); + } + } + } +}; + +#else + +template <typename CharT> +class float_printer +{ + jsoncons::basic_ovectorstream<CharT> vs_; + uint8_t precision_; +public: + float_printer(uint8_t precision) + : vs_(255), precision_(precision) + { + vs_.set_locale(std::locale::classic()); + vs_.precision(precision); + } + + void print(double val, uint8_t precision, buffered_ostream<CharT>& os) + { + vs_.reset(); + vs_.precision(precision == 0 ? precision_ : precision); + vs_ << val; + + const CharT* s = vs_.data(); + const CharT* se = s + vs_.length(); + + bool dot = false; + while (s < se) + { + if (*s == '.') + { + dot = true; + } + else if (*s == 'e') + { + if (!dot) + { + os.put('.'); + os.put('0'); + dot = true; + } + } + os.put(*s); + ++s; + } + if (!dot) + { + os.put('.'); + os.put('0'); + } + } +}; + +#endif + +// string_to_float only requires narrow char +#ifdef _MSC_VER +class float_reader +{ +private: + _locale_t locale_; +public: + float_reader() + { + locale_ = _create_locale(LC_NUMERIC, "C"); + } + ~float_reader() + { + _free_locale(locale_); + } + + double read(const char* s, size_t length) + { + const char *begin = s; + char *end = nullptr; + double val = _strtod_l(begin, &end, locale_); + if (begin == end) + { + throw std::invalid_argument("Invalid float value"); + } + return val; + } + + float_reader(const float_reader& fr) = delete; + float_reader& operator=(const float_reader& fr) = delete; +}; + +#else +class float_reader +{ +private: + std::vector<char> buffer_; + std::string decimal_point_; + bool is_dot_; +public: + float_reader() + : buffer_() + { + struct lconv * lc = localeconv(); + if (lc != nullptr) + { + decimal_point_ = std::string(lc->decimal_point); + } + else + { + decimal_point_ = std::string("."); + } + buffer_.reserve(100); + is_dot_ = decimal_point_ == "."; + } + + double read(const char* s, size_t length) + { + double val; + if (is_dot_) + { + const char *begin = s; + char *end = nullptr; + val = strtod(begin, &end); + if (begin == end) + { + throw std::invalid_argument("Invalid float value"); + } + } + else + { + buffer_.clear(); + size_t j = 0; + const char* pe = s + length; + for (const char* p = s; p < pe; ++p) + { + if (*p == '.') + { + buffer_.insert(buffer_.begin() + j, decimal_point_.begin(), decimal_point_.end()); + j += decimal_point_.length(); + } + else + { + buffer_.push_back(*p); + ++j; + } + } + const char *begin = buffer_.data(); + char *end = nullptr; + val = strtod(begin, &end); + if (begin == end) + { + throw std::invalid_argument("Invalid float value"); + } + } + return val; + } + + float_reader(const float_reader& fr) = delete; + float_reader& operator=(const float_reader& fr) = delete; +}; +#endif + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/output_format.hpp b/vendor/jsoncons-0.99.2/jsoncons/output_format.hpp new file mode 100644 index 00000000..54e74874 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/output_format.hpp @@ -0,0 +1,330 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_OUTPUT_FORMAT_HPP +#define JSONCONS_OUTPUT_FORMAT_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> +#include <cwchar> + +namespace jsoncons { + +enum class block_options {next_line,same_line}; + +template <typename CharT> +class buffered_ostream; + +template <typename CharT> +class basic_output_format +{ + int indent_; + uint8_t precision_; + bool replace_nan_; + bool replace_pos_inf_; + bool replace_neg_inf_; + std::basic_string<CharT> nan_replacement_; + std::basic_string<CharT> pos_inf_replacement_; + std::basic_string<CharT> neg_inf_replacement_; + bool escape_all_non_ascii_; + bool escape_solidus_; + block_options object_array_block_option_; + block_options array_array_block_option_; + block_options object_object_block_option_; + block_options array_object_block_option_; +public: + static const size_t default_indent = 4; + +// Constructors + + basic_output_format() + : + indent_(default_indent), + precision_(16), + replace_nan_(true), + replace_pos_inf_(true), + replace_neg_inf_(true), + nan_replacement_(json_literals<CharT>::null_literal().first), + pos_inf_replacement_(json_literals<CharT>::null_literal().first), + neg_inf_replacement_(json_literals<CharT>::null_literal().first), + escape_all_non_ascii_(false), + escape_solidus_(false), + object_array_block_option_(block_options::same_line), + array_array_block_option_(block_options::next_line), + object_object_block_option_(block_options::same_line), + array_object_block_option_(block_options::next_line) + { + } + +// Accessors + + block_options object_array_block_option() + { + return object_array_block_option_; + } + + basic_output_format<CharT>& object_array_block_option(block_options value) + { + object_array_block_option_ = value; + return *this; + } + + block_options object_object_block_option() + { + return object_object_block_option_; + } + + basic_output_format<CharT>& object_object_block_option(block_options value) + { + object_object_block_option_ = value; + return *this; + } + + block_options array_array_block_option() + { + return array_array_block_option_; + } + + basic_output_format<CharT>& array_array_block_option(block_options value) + { + array_array_block_option_ = value; + return *this; + } + + block_options array_object_block_option() + { + return array_object_block_option_; + } + + basic_output_format<CharT>& array_object_block_option(block_options value) + { + array_object_block_option_ = value; + return *this; + } + + int indent() const + { + return indent_; + } + + uint8_t precision() const + { + return precision_; + } + + bool escape_all_non_ascii() const + { + return escape_all_non_ascii_; + } + + bool escape_solidus() const + { + return escape_solidus_; + } + + bool replace_nan() const {return replace_nan_;} + + bool replace_pos_inf() const {return replace_pos_inf_;} + + bool replace_neg_inf() const {return replace_neg_inf_;} + + std::basic_string<CharT> nan_replacement() const + { + return nan_replacement_; + } + + std::basic_string<CharT> pos_inf_replacement() const + { + return pos_inf_replacement_; + } + + std::basic_string<CharT> neg_inf_replacement() const + { + return neg_inf_replacement_; + } + +// Modifiers + + basic_output_format<CharT>& precision(uint8_t prec) + { + precision_ = prec; + return *this; + } + + basic_output_format<CharT>& escape_all_non_ascii(bool value) + { + escape_all_non_ascii_ = value; + return *this; + } + + basic_output_format<CharT>& escape_solidus(bool value) + { + escape_solidus_ = value; + return *this; + } + + basic_output_format<CharT>& replace_nan(bool replace) + { + replace_nan_ = replace; + return *this; + } + + basic_output_format<CharT>& replace_inf(bool replace) + { + replace_pos_inf_ = replace; + replace_neg_inf_ = replace; + return *this; + } + + basic_output_format<CharT>& replace_pos_inf(bool replace) + { + replace_pos_inf_ = replace; + return *this; + } + + basic_output_format<CharT>& replace_neg_inf(bool replace) + { + replace_neg_inf_ = replace; + return *this; + } + + basic_output_format<CharT>& nan_replacement(const std::basic_string<CharT>& replacement) + { + nan_replacement_ = replacement; + return *this; + } + + basic_output_format<CharT>& pos_inf_replacement(const std::basic_string<CharT>& replacement) + { + pos_inf_replacement_ = replacement; + return *this; + } + + basic_output_format<CharT>& neg_inf_replacement(const std::basic_string<CharT>& replacement) + { + neg_inf_replacement_ = replacement; + return *this; + } + + basic_output_format<CharT>& indent(int value) + { + indent_ = value; + return *this; + } +}; + +template<typename CharT> +void escape_string(const CharT* s, + size_t length, + const basic_output_format<CharT>& format, + buffered_ostream<CharT>& os) +{ + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + switch (c) + { + case '\\': + os.put('\\'); + os.put('\\'); + break; + case '"': + os.put('\\'); + os.put('\"'); + break; + case '\b': + os.put('\\'); + os.put('b'); + break; + case '\f': + os.put('\\'); + os.put('f'); + break; + case '\n': + os.put('\\'); + os.put('n'); + break; + case '\r': + os.put('\\'); + os.put('r'); + break; + case '\t': + os.put('\\'); + os.put('t'); + break; + default: + uint32_t u(c >= 0 ? c : 256 + c); + if (format.escape_solidus() && c == '/') + { + os.put('\\'); + os.put('/'); + } + else if (is_control_character(u) || format.escape_all_non_ascii()) + { + // convert utf8 to codepoint + uint32_t cp = json_char_traits<CharT, sizeof(CharT)>::convert_char_to_codepoint(it, end); + if (is_non_ascii_character(cp) || is_control_character(u)) + { + if (cp > 0xFFFF) + { + cp -= 0x10000; + uint32_t first = (cp >> 10) + 0xD800; + uint32_t second = ((cp & 0x03FF) + 0xDC00); + + os.put('\\'); + os.put('u'); + os.put(to_hex_character(first >> 12 & 0x000F)); + os.put(to_hex_character(first >> 8 & 0x000F)); + os.put(to_hex_character(first >> 4 & 0x000F)); + os.put(to_hex_character(first & 0x000F)); + os.put('\\'); + os.put('u'); + os.put(to_hex_character(second >> 12 & 0x000F)); + os.put(to_hex_character(second >> 8 & 0x000F)); + os.put(to_hex_character(second >> 4 & 0x000F)); + os.put(to_hex_character(second & 0x000F)); + } + else + { + os.put('\\'); + os.put('u'); + os.put(to_hex_character(cp >> 12 & 0x000F)); + os.put(to_hex_character(cp >> 8 & 0x000F)); + os.put(to_hex_character(cp >> 4 & 0x000F)); + os.put(to_hex_character(cp & 0x000F)); + } + } + else + { + os.put(c); + } + } + else if (format.escape_solidus() && c == '/') + { + os.put('\\'); + os.put('/'); + } + else + { + os.put(c); + } + break; + } + } +} + +typedef basic_output_format<char> output_format; +typedef basic_output_format<wchar_t> woutput_format; + +} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/ovectorstream.hpp b/vendor/jsoncons-0.99.2/jsoncons/ovectorstream.hpp new file mode 100644 index 00000000..e19f5085 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/ovectorstream.hpp @@ -0,0 +1,227 @@ +// Copyright 2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_OVECTORSTREAM_HPP +#define JSONCONS_OVECTORSTREAM_HPP + +#include <ios> +#include <ostream> +#include <string> +#include <cstddef> +#include <vector> +#include "jsoncons/jsoncons_config.hpp" + +namespace jsoncons { + +template< + class CharT, + class Traits = std::char_traits<CharT> +> class basic_ovectorstream; + +template<class CharT, class CharTraits> +class basic_ovectorbuf + : public std::basic_streambuf<CharT, CharTraits> +{ +private: + std::ios_base::openmode mode_; + std::vector<CharT> buf_; + +public: + typedef CharT char_type; + typedef typename CharTraits::int_type int_type; + typedef typename CharTraits::pos_type pos_type; + typedef typename CharTraits::off_type off_type; + typedef CharTraits traits_type; + typedef std::basic_streambuf<char_type, traits_type> base_streambuf; + +public: + + explicit basic_ovectorbuf(std::size_t length) JSONCONS_NOEXCEPT + : base_streambuf(), + mode_(std::ios_base::out | std::ios_base::binary), + buf_(length) + { + // Set write position to beginning of buffer. + this->setp(buf_.data(), buf_.data() + buf_.size()); + } + + virtual ~basic_ovectorbuf() {} + + const CharT* data() const + { + return buf_.data(); + } + +protected: + int_type underflow() override + { + return this->gptr() != this->egptr() ? + CharTraits::to_int_type(*this->gptr()) : CharTraits::eof(); + } + + int_type pbackfail(int_type c = CharTraits::eof()) override + { + if (this->gptr() != this->eback()) + { + if (!CharTraits::eq_int_type(c, CharTraits::eof())) + { + if (CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) + { + this->gbump(-1); + return c; + } + this->gbump(-1); + *this->gptr() = c; + return c; + } + else + { + this->gbump(-1); + return CharTraits::not_eof(c); + } + } + else + { + return CharTraits::eof(); + } + } + + int_type overflow(int_type c = CharTraits::eof()) override + { + if (!CharTraits::eq_int_type(c, CharTraits::eof())) + { + size_t pos = buf_.size(); + buf_.resize(pos*2); + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->pubseekpos(pos, std::ios_base::out); + *this->pptr() = CharTraits::to_char_type(c); + this->pbump(1); + this->pubsync(); + return c; + } + else + { + return CharTraits::not_eof(c); + } + } + + pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode mode = std::ios_base::out) override + { + (void)mode; // Always out + + std::streamoff newoff; + switch (dir) + { + case std::ios_base::beg: + newoff = 0; + break; + case std::ios_base::end: + newoff = static_cast<std::streamoff>(buf_.size()); + break; + case std::ios_base::cur: + newoff = static_cast<std::streamoff>(this->pptr() - this->pbase()); + break; + default: + return pos_type(off_type(-1)); + } + + off += newoff; + + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if (off < 0 || off > n) return pos_type(off_type(-1)); + else + { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(static_cast<int>(off)); + } + + return pos_type(off); + } + + pos_type seekoff_beg(off_type off) + { + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if (off < 0 || off > n) + { + return pos_type(off_type(-1)); + } + else + { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(static_cast<int>(off)); + } + + return pos_type(off); + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode mode + = std::ios_base::out) override + { + (void)mode; // Always out + + return seekoff_beg(pos - pos_type(off_type(0))); + } +}; + +template<class CharT, class CharTraits> +class basic_ovectorstream : + private basic_ovectorbuf<CharT, CharTraits>, + public std::basic_ostream<CharT, CharTraits> +{ +public: + typedef typename std::basic_ios + <CharT, CharTraits>::char_type char_type; + typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type; + typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type; + typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type; + typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type; + +private: + typedef basic_ovectorbuf<CharT, CharTraits> base_ouputbuf; + typedef std::basic_ios<char_type, CharTraits> base_ios; + typedef std::basic_ostream<char_type, CharTraits> base_streambuf; + base_ouputbuf& get_buf() {return *this;} + const base_ouputbuf& get_buf() const {return *this;} + +public: + basic_ovectorstream(std::size_t length) JSONCONS_NOEXCEPT + : base_ouputbuf(length), + base_streambuf(&get_buf()) + {} + + ~basic_ovectorstream() {} + +public: + + size_t length() + { + return this->pptr() - this->pbase(); + } + + void set_locale(const std::locale& loc) + { + std::locale result = std::basic_ostream<CharT, CharTraits>::imbue(loc); + this->pubimbue(loc); + } + + void reset() + { + this->clear(); + this->seekp(0, std::ios::beg); + } + + const CharT* data() const + { + return get_buf().data(); + } +}; + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/parse_error_handler.hpp b/vendor/jsoncons-0.99.2/jsoncons/parse_error_handler.hpp new file mode 100644 index 00000000..9081fc95 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons/parse_error_handler.hpp @@ -0,0 +1,172 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_PARSE_ERROR_HANDLER_HPP +#define JSONCONS_PARSE_ERROR_HANDLER_HPP + +#include "jsoncons/jsoncons.hpp" +#include <system_error> + +namespace jsoncons { + +class parse_exception : public std::exception, public virtual json_exception +{ +public: + parse_exception(std::error_code ec, + size_t line, + size_t column) + : error_code_(ec), + line_number_(line), + column_number_(column) + { + } + parse_exception(const parse_exception& other) + : error_code_(other.error_code_), + line_number_(other.line_number_), + column_number_(other.column_number_) + { + } + const char* what() const JSONCONS_NOEXCEPT + { + std::ostringstream os; + os << error_code_.message() << " at line " << line_number_ << " and column " << column_number_; + const_cast<std::string&>(buffer_) = os.str(); + return buffer_.c_str(); + } + + const std::error_code code() const + { + return error_code_; + } + + size_t line_number() const + { + return line_number_; + } + + size_t column_number() const + { + return column_number_; + } +private: + std::error_code error_code_; + std::string buffer_; + size_t line_number_; + size_t column_number_; +}; + +typedef parse_exception json_parse_exception; + +template<typename CharT> +class basic_parsing_context +{ +public: + virtual ~basic_parsing_context() {} + + size_t line_number() const + { + return do_line_number(); + } + size_t column_number() const + { + return do_column_number(); + } + CharT current_char() const + { + return do_current_char(); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + CharT last_char() const + { + return do_current_char(); + } +#endif + +private: + virtual size_t do_line_number() const = 0; + virtual size_t do_column_number() const = 0; + virtual CharT do_current_char() const = 0; +}; + +typedef basic_parsing_context<char> parsing_context; +typedef basic_parsing_context<wchar_t> wparsing_context; + +template <typename CharT> +class basic_parse_error_handler +{ +public: + virtual ~basic_parse_error_handler() + { + } + + void warning(std::error_code ec, + const basic_parsing_context<CharT>& context) throw (parse_exception) + { + do_warning(ec,context); + } + + void error(std::error_code ec, + const basic_parsing_context<CharT>& context) throw (parse_exception) + { + do_error(ec,context); + } + + void fatal_error(std::error_code ec, + const basic_parsing_context<CharT>& context) throw (parse_exception) + { + do_fatal_error(ec,context); + throw parse_exception(ec,context.line_number(),context.column_number()); + } + +private: + virtual void do_warning(std::error_code, + const basic_parsing_context<CharT>& context) throw (parse_exception) = 0; + + virtual void do_error(std::error_code, + const basic_parsing_context<CharT>& context) throw (parse_exception) = 0; + + virtual void do_fatal_error(std::error_code, + const basic_parsing_context<CharT>& context) throw (parse_exception) + { + (void)context; + } +}; + +template <typename CharT> +class basic_default_parse_error_handler : public basic_parse_error_handler<CharT> +{ +public: + static basic_parse_error_handler<CharT>& instance() + { + static basic_default_parse_error_handler<CharT> instance; + return instance; + } +private: + virtual void do_warning(std::error_code, + const basic_parsing_context<CharT>& context) throw (parse_exception) + { + (void)context; + } + + virtual void do_error(std::error_code ec, + const basic_parsing_context<CharT>& context) throw (parse_exception) + { + throw parse_exception(ec,context.line_number(),context.column_number()); + } +}; + +typedef basic_parse_error_handler<char> parse_error_handler; +typedef basic_parse_error_handler<wchar_t> wparse_error_handler; + +typedef basic_default_parse_error_handler<char> default_parse_error_handler; +typedef basic_default_parse_error_handler<wchar_t> wdefault_parse_error_handler; + +typedef basic_parsing_context<char> parsing_context; +typedef basic_parsing_context<wchar_t> wparsing_context; + +} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/boost/type_extensions.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/boost/type_extensions.hpp new file mode 100644 index 00000000..59936cd7 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/boost/type_extensions.hpp @@ -0,0 +1,59 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_EXT_TYPE_EXTENSIONS_HPP +#define JSONCONS_EXT_TYPE_EXTENSIONS_HPP + +#include "jsoncons/json.hpp" +#include "boost/date_time/gregorian/gregorian.hpp" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons +{ + template <typename JsonT> + class json_type_traits<JsonT,boost::gregorian::date> + { + public: + static bool is(const JsonT& val) JSONCONS_NOEXCEPT + { + if (!val.is_string()) + { + return false; + } + std::string s = val.template as<std::string>(); + try + { + boost::gregorian::date_from_iso_string(s); + return true; + } + catch (...) + { + return false; + } + } + + static boost::gregorian::date as(const JsonT& val) + { + std::string s = val.template as<std::string>(); + return boost::gregorian::from_simple_string(s); + } + + static void assign(JsonT& lhs, boost::gregorian::date val) + { + lhs = to_iso_extended_string(val); + } + }; +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_error_category.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_error_category.hpp new file mode 100644 index 00000000..5056d380 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_error_category.hpp @@ -0,0 +1,55 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_TEXT_ERROR_CATEGORY_HPP +#define JSONCONS_CSV_CSV_TEXT_ERROR_CATEGORY_HPP + +#include "jsoncons/jsoncons.hpp" +#include <system_error> + +namespace jsoncons { namespace csv { + +namespace csv_parser_errc +{ + const int unexpected_eof = 1; + const int expected_quote = 2; + const int invalid_csv_text = 3; + const int invalid_state = 4; +} + +class csv_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "csv"; + } + virtual std::string message(int ev) const + { + switch (ev) + { + case csv_parser_errc::unexpected_eof: + return "Unexpected end of file"; + case csv_parser_errc::expected_quote: + return "Expected quote character"; + case csv_parser_errc::invalid_csv_text: + return "Invalid CSV text"; + default: + return "Unknown JSON parser error"; + } + } +}; + +inline +const std::error_category& csv_error_category() +{ + static csv_error_category_impl instance; + return instance; +} + +}} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parameters.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parameters.hpp new file mode 100644 index 00000000..099a154f --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parameters.hpp @@ -0,0 +1,341 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARAMETERS_HPP +#define JSONCONS_CSV_CSV_PARAMETERS_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> +#include <cwchar> + +namespace jsoncons { namespace csv { + +enum class quote_styles +{ + all,minimal,none,nonnumeric +}; + +template <typename CharT> +class basic_csv_parameters +{ +public: + static const size_t default_indent = 4; + +// Constructors + + basic_csv_parameters() + : + assume_header_(false), + ignore_empty_values_(false), + trim_leading_(false), + trim_trailing_(false), + trim_leading_inside_quotes_(false), + trim_trailing_inside_quotes_(false), + unquoted_empty_value_is_null_(false), + field_delimiter_(','), + quote_char_('\"'), + quote_escape_char_('\"'), + comment_starter_('\0'), + quote_style_(quote_styles::minimal), + max_lines_(std::numeric_limits<unsigned long>::max JSONCONS_NO_MACRO_EXP()), + header_lines_(0) + { + line_delimiter_.push_back('\n'); + } + +// Properties + + size_t header_lines() const + { + return (assume_header_ && header_lines_ <= 1) ? 1 : header_lines_; + } + + basic_csv_parameters<CharT>& header_lines(size_t value) + { + header_lines_ = value; + return *this; + } + + bool assume_header() const + { + return assume_header_; + } + + basic_csv_parameters<CharT>& assume_header(bool value) + { + assume_header_ = value; + return *this; + } + + bool ignore_empty_values() const + { + return ignore_empty_values_; + } + + basic_csv_parameters<CharT>& ignore_empty_values(bool value) + { + ignore_empty_values_ = value; + return *this; + } + + bool trim_leading() const + { + return trim_leading_; + } + + basic_csv_parameters<CharT>& trim_leading(bool value) + { + trim_leading_ = value; + return *this; + } + + bool trim_trailing() const + { + return trim_trailing_; + } + + basic_csv_parameters<CharT>& trim_trailing(bool value) + { + trim_trailing_ = value; + return *this; + } + + bool trim_leading_inside_quotes() const + { + return trim_leading_inside_quotes_; + } + + basic_csv_parameters<CharT>& trim_leading_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + return *this; + } + + bool trim_trailing_inside_quotes() const + { + return trim_trailing_inside_quotes_; + } + + basic_csv_parameters<CharT>& trim_trailing_inside_quotes(bool value) + { + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool trim() const + { + return trim_leading_ && trim_trailing_; + } + + basic_csv_parameters<CharT>& trim(bool value) + { + trim_leading_ = value; + trim_trailing_ = value; + return *this; + } + + bool trim_inside_quotes() const + { + return trim_leading_inside_quotes_ && trim_trailing_inside_quotes_; + } + + basic_csv_parameters<CharT>& trim_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool unquoted_empty_value_is_null() const + { + return unquoted_empty_value_is_null_; + } + + basic_csv_parameters<CharT>& unquoted_empty_value_is_null(bool value) + { + unquoted_empty_value_is_null_ = value; + return *this; + } + + std::vector<std::basic_string<CharT>> column_names() const + { + return column_names_; + } + + basic_csv_parameters<CharT>& column_names(const std::vector<std::basic_string<CharT>>& value) + { + column_names_ = value; + return *this; + } + + std::vector<std::basic_string<CharT>> column_types() const + { + return column_types_; + } + + basic_csv_parameters<CharT>& column_types(const std::vector<std::basic_string<CharT>>& value) + { + column_types_ = value; + return *this; + } + + std::vector<std::basic_string<CharT>> column_defaults() const + { + return column_defaults_; + } + + basic_csv_parameters<CharT>& column_defaults(const std::vector<std::basic_string<CharT>>& value) + { + column_defaults_ = value; + return *this; + } + + CharT field_delimiter() const + { + return field_delimiter_; + } + + basic_csv_parameters<CharT>& field_delimiter(CharT value) + { + field_delimiter_ = value; + return *this; + } + + std::basic_string<CharT> line_delimiter() const + { + return line_delimiter_; + } + + basic_csv_parameters<CharT>& line_delimiter(std::basic_string<CharT> value) + { + line_delimiter_ = value; + return *this; + } + + CharT quote_char() const + { + return quote_char_; + } + + basic_csv_parameters<CharT>& quote_char(CharT value) + { + quote_char_ = value; + return *this; + } + + CharT quote_escape_char() const + { + return quote_escape_char_; + } + + basic_csv_parameters<CharT>& quote_escape_char(CharT value) + { + quote_escape_char_ = value; + return *this; + } + + CharT comment_starter() const + { + return comment_starter_; + } + + basic_csv_parameters<CharT>& comment_starter(CharT value) + { + comment_starter_ = value; + return *this; + } + + quote_styles quote_style() const + { + return quote_style_; + } + + basic_csv_parameters<CharT>& assume_header(quote_styles value) + { + quote_style_ = value; + return *this; + } + + unsigned long max_lines() const + { + return max_lines_; + } + + basic_csv_parameters<CharT>& max_lines(unsigned long value) + { + max_lines_ = value; + return *this; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + std::basic_string<CharT> header() const + { + return header_; + } + + basic_csv_parameters<CharT>& header(const std::basic_string<CharT>& value) + { + header_ = value; + return *this; + } + + std::basic_string<CharT> data_types() const + { + return data_types_; + } + + basic_csv_parameters<CharT>& data_types(const std::basic_string<CharT>& value) + { + data_types_ = value; + return *this; + } + + std::basic_string<CharT> default_values() const + { + return default_values_; + } + + basic_csv_parameters<CharT>& default_values(const std::basic_string<CharT>& value) + { + default_values_ = value; + return *this; + } +#endif +private: + bool assume_header_; + bool ignore_empty_values_; + bool trim_leading_; + bool trim_trailing_; + bool trim_leading_inside_quotes_; + bool trim_trailing_inside_quotes_; + bool unquoted_empty_value_is_null_; + CharT field_delimiter_; + CharT quote_char_; + CharT quote_escape_char_; + CharT comment_starter_; + quote_styles quote_style_; + unsigned long max_lines_; + size_t header_lines_; + std::basic_string<CharT> line_delimiter_; + std::basic_string<CharT> header_; + std::basic_string<CharT> data_types_; + std::basic_string<CharT> default_values_; + std::vector<std::basic_string<CharT>> column_names_; + std::vector<std::basic_string<CharT>> column_types_; + std::vector<std::basic_string<CharT>> column_defaults_; +}; + +typedef basic_csv_parameters<char> csv_parameters; +typedef basic_csv_parameters<wchar_t> wcsv_parameters; + +}} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parser.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parser.hpp new file mode 100644 index 00000000..14323666 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parser.hpp @@ -0,0 +1,903 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARSER_HPP +#define JSONCONS_CSV_CSV_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <cctype> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_input_handler.hpp" +#include "jsoncons/parse_error_handler.hpp" +#include "jsoncons/json_parser.hpp" +#include "jsoncons/json_filter.hpp" +#include "jsoncons_ext/csv/csv_error_category.hpp" +#include "jsoncons_ext/csv/csv_parameters.hpp" + +namespace jsoncons { namespace csv { + +template <typename CharT> +struct json_csv_parser_traits +{ +}; + +template <> +struct json_csv_parser_traits<char> +{ + static const std::string string_literal() {return "string";}; + + static const std::string integer_literal() {return "integer";}; + + static const std::string float_literal() {return "float";}; + + static const std::string boolean_literal() {return "boolean";}; +}; + +template <> +struct json_csv_parser_traits<wchar_t> // assume utf16 +{ + static const std::wstring string_literal() {return L"string";}; + + static const std::wstring integer_literal() {return L"integer";}; + + static const std::wstring float_literal() {return L"float";}; + + static const std::wstring boolean_literal() {return L"boolean";}; +}; + +enum class csv_modes { + done, + header, + array, + object +}; + +enum class csv_states +{ + start, + comment, + expect_value, + between_fields, + quoted_string, + unquoted_string, + escaped_value, + minus, + zero, + integer, + fraction, + exp1, + exp2, + exp3, + done +}; + +enum class data_types +{ + string_t,integer_t,float_t,boolean_t +}; + +template<typename CharT> +class basic_csv_parser : private basic_parsing_context<CharT> +{ + static const int default_depth = 3; + + csv_states state_; + int top_; + std::vector<csv_modes> stack_; + basic_json_input_handler<CharT> *handler_; + basic_parse_error_handler<CharT> *err_handler_; + bool is_negative_; + uint32_t cp_; + size_t index_; + unsigned long column_; + unsigned long line_; + int curr_char_; + int prev_char_; + std::basic_string<CharT> string_buffer_; + csv_states saved_state_; + int depth_; + basic_csv_parameters<CharT> parameters_; + std::vector<std::basic_string<CharT>> column_names_; + std::vector<data_types> column_types_; + std::vector<std::basic_string<CharT>> column_defaults_; + size_t column_index_; + basic_begin_end_json_filter<CharT> filter_; + basic_json_parser<CharT> parser_; + +public: + basic_csv_parser(basic_json_input_handler<CharT>& handler) + : top_(-1), + stack_(default_depth), + handler_(std::addressof(handler)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), + is_negative_(false), + cp_(0), + index_(0), + filter_(handler), + parser_(filter_) + { + depth_ = default_depth; + state_ = csv_states::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + basic_csv_parameters<CharT> params) + : top_(-1), + stack_(default_depth), + handler_(std::addressof(handler)), + err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), + is_negative_(false), + cp_(0), + index_(0), + parameters_(params), + filter_(handler), + parser_(filter_) + { + depth_ = default_depth; + state_ = csv_states::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler) + : top_(-1), + stack_(default_depth), + handler_(std::addressof(handler)), + err_handler_(std::addressof(err_handler)), + is_negative_(false), + cp_(0), + index_(0), + filter_(handler), + parser_(filter_) + { + depth_ = default_depth; + state_ = csv_states::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler, + basic_csv_parameters<CharT> params) + : top_(-1), + stack_(default_depth), + handler_(std::addressof(handler)), + err_handler_(std::addressof(err_handler)), + is_negative_(false), + cp_(0), + index_(0), + parameters_(params), + filter_(handler), + parser_(filter_) + { + depth_ = default_depth; + state_ = csv_states::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + ~basic_csv_parser() + { + } + + const basic_parsing_context<CharT>& parsing_context() const + { + return *this; + } + + bool done() const + { + return state_ == csv_states::done; + } + + const std::vector<std::basic_string<CharT>>& column_labels() const + { + return column_names_; + } + + void after_field() + { + ++column_index_; + } + + void before_record() + { + if (column_index_ == 0) + { + switch (stack_[top_]) + { + case csv_modes::array: + handler_->begin_array(*this); + break; + case csv_modes::object: + handler_->begin_object(*this); + break; + default: + break; + } + } + } + + void after_record() + { + switch (stack_[top_]) + { + case csv_modes::array: + handler_->end_array(*this); + break; + case csv_modes::object: + handler_->end_object(*this); + break; + case csv_modes::header: + if (line_ >= parameters_.header_lines()) + { + if (column_names_.size() > 0) + { + flip(csv_modes::header, csv_modes::object); + } + else + { + flip(csv_modes::header, csv_modes::array); + } + } + break; + default: + break; + } + column_index_ = 0; + } + + void begin_parse() + { + push(csv_modes::done); + handler_->begin_json(); + + if (parameters_.column_names().size() > 0) + { + column_names_ = parameters_.column_names(); + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (parameters_.header().length() > 0) + { + basic_empty_json_input_handler<CharT> ih; + basic_csv_parameters<CharT> params; + params.field_delimiter(parameters_.field_delimiter()); + params.quote_char(parameters_.quote_char()); + params.quote_escape_char(parameters_.quote_escape_char()); + params.assume_header(true); + basic_csv_parser<CharT> p(ih,params); + p.begin_parse(); + p.parse(parameters_.header().data(),0,parameters_.header().length()); + p.end_parse(); + column_names_ = p.column_labels(); + } +#endif + if (parameters_.column_types().size() > 0) + { + column_types_.resize(parameters_.column_types().size()); + for (size_t i = 0; i < parameters_.column_types().size(); ++i) + { + if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::string_literal()) + { + column_types_[i] = data_types::string_t; + } + else if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::integer_literal()) + { + column_types_[i] = data_types::integer_t; + } + else if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::float_literal()) + { + column_types_[i] = data_types::float_t; + } + else if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::boolean_literal()) + { + column_types_[i] = data_types::boolean_t; + } + } + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (parameters_.data_types().length() > 0) + { + basic_empty_json_input_handler<CharT> ih; + basic_csv_parameters<CharT> params; + params.field_delimiter(parameters_.field_delimiter()); + params.assume_header(true); + basic_csv_parser<CharT> p(ih,params); + p.begin_parse(); + p.parse(parameters_.data_types().data(),0,parameters_.data_types().length()); + p.end_parse(); + column_types_.resize(p.column_labels().size()); + for (size_t i = 0; i < p.column_labels().size(); ++i) + { + if (p.column_labels()[i] == json_csv_parser_traits<CharT>::string_literal()) + { + column_types_[i] = data_types::string_t; + } + else if (p.column_labels()[i] == json_csv_parser_traits<CharT>::integer_literal()) + { + column_types_[i] = data_types::integer_t; + } + else if (p.column_labels()[i] == json_csv_parser_traits<CharT>::float_literal()) + { + column_types_[i] = data_types::float_t; + } + else if (p.column_labels()[i] == json_csv_parser_traits<CharT>::boolean_literal()) + { + column_types_[i] = data_types::boolean_t; + } + } + } +#endif + if (parameters_.column_defaults().size() > 0) + { + column_defaults_ = parameters_.column_defaults(); + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (parameters_.default_values().length() > 0) + { + basic_empty_json_input_handler<CharT> ih; + basic_csv_parameters<CharT> params; + params.field_delimiter(parameters_.field_delimiter()); + params.assume_header(true); + basic_csv_parser<CharT> p(ih,params); + p.begin_parse(); + p.parse(parameters_.default_values().data(),0,parameters_.default_values().length()); + p.end_parse(); + column_defaults_.resize(p.column_labels().size()); + for (size_t i = 0; i < p.column_labels().size(); ++i) + { + column_defaults_[i] = p.column_labels()[i]; + } + } +#endif + if (parameters_.header_lines() > 0) + { + push(csv_modes::header); + } + else + { + push(csv_modes::array); + } + handler_->begin_array(*this); + state_ = csv_states::expect_value; + column_index_ = 0; + prev_char_ = 0; + curr_char_ = 0; + column_ = 1; + } + + void parse(const CharT* p, size_t start, size_t length) + { + index_ = start; + for (; index_ < length && state_ != csv_states::done; ++index_) + { + curr_char_ = p[index_]; +all_csv_states: + switch (state_) + { + case csv_states::comment: + if (curr_char_ == '\n') + { + state_ = csv_states::expect_value; + } + else if (prev_char_ == '\r') + { + state_ = csv_states::expect_value; + goto all_csv_states; + } + break; + case csv_states::expect_value: + if (column_ == 1 && curr_char_ == parameters_.comment_starter()) + { + state_ = csv_states::comment; + } + else + { + state_ = csv_states::unquoted_string; + goto all_csv_states; + } + break; + case csv_states::between_fields: + if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) + { + after_record(); + state_ = csv_states::expect_value; + } + else if (curr_char_ == parameters_.field_delimiter()) + { + state_ = csv_states::expect_value; + } + break; + case csv_states::escaped_value: + { + if (curr_char_ == parameters_.quote_char()) + { + string_buffer_.push_back(curr_char_); + state_ = csv_states::quoted_string; + } + else if (parameters_.quote_escape_char() == parameters_.quote_char()) + { + before_record(); + end_quoted_string_value(); + after_field(); + state_ = csv_states::between_fields; + goto all_csv_states; + } + } + break; + case csv_states::quoted_string: + { + if (curr_char_ == parameters_.quote_escape_char()) + { + state_ = csv_states::escaped_value; + } + else if (curr_char_ == parameters_.quote_char()) + { + before_record(); + end_quoted_string_value(); + after_field(); + state_ = csv_states::between_fields; + } + else + { + string_buffer_.push_back(curr_char_); + } + } + break; + case csv_states::unquoted_string: + { + if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) + { + before_record(); + end_unquoted_string_value(); + after_field(); + after_record(); + state_ = csv_states::expect_value; + } + else if (curr_char_ == '\n') + { + if (prev_char_ != '\r') + { + before_record(); + end_unquoted_string_value(); + after_field(); + after_record(); + state_ = csv_states::expect_value; + } + } + else if (curr_char_ == parameters_.field_delimiter()) + { + before_record(); + end_unquoted_string_value(); + after_field(); + state_ = csv_states::expect_value; + } + else if (curr_char_ == parameters_.quote_char()) + { + string_buffer_.clear(); + state_ = csv_states::quoted_string; + } + else + { + string_buffer_.push_back(curr_char_); + } + } + break; + default: + err_handler_->error(std::error_code(csv_parser_errc::invalid_state, csv_error_category()), *this); + break; + } + if (line_ > parameters_.max_lines()) + { + state_ = csv_states::done; + } + switch (curr_char_) + { + case '\r': + ++line_; + column_ = 1; + break; + case '\n': + if (prev_char_ != '\r') + { + ++line_; + } + column_ = 1; + break; + default: + ++column_; + break; + } + prev_char_ = curr_char_; + } + } + + void end_parse() + { + switch (state_) + { + case csv_states::unquoted_string: + before_record(); + end_unquoted_string_value(); + after_field(); + break; + case csv_states::escaped_value: + if (parameters_.quote_escape_char() == parameters_.quote_char()) + { + before_record(); + end_quoted_string_value(); + after_field(); + } + break; + default: + break; + } + if (column_index_ > 0) + { + after_record(); + } + switch (stack_[top_]) + { + case csv_modes::array: + if (!pop(csv_modes::array)) + { + err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); + } + break; + case csv_modes::object: + if (!pop(csv_modes::object)) + { + err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); + } + break; + case csv_modes::header: + if (!pop(csv_modes::header)) + { + err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); + } + break; + default: + break; + } + handler_->end_array(*this); + if (!pop(csv_modes::done)) + { + err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); + } + handler_->end_json(); + } + + csv_states state() const + { + return state_; + } + + size_t index() const + { + return index_; + } +private: + + void trim_string_buffer(bool trim_leading, bool trim_trailing) + { + size_t start = 0; + size_t length = string_buffer_.length(); + if (trim_leading) + { + bool done = false; + while (!done && start < string_buffer_.length()) + { + if ((string_buffer_[start] < 256) && std::isspace(string_buffer_[start])) + { + ++start; + } + else + { + done = true; + } + } + } + if (trim_trailing) + { + bool done = false; + while (!done && length > 0) + { + if ((string_buffer_[length-1] < 256) && std::isspace(string_buffer_[length-1])) + { + --length; + } + else + { + done = true; + } + } + } + if (start != 0 || length != string_buffer_.size()) + { + string_buffer_ = string_buffer_.substr(start,length-start); + } + } + + void end_unquoted_string_value() + { + if (parameters_.trim_leading() | parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + switch (stack_[top_]) + { + case csv_modes::header: + if (parameters_.assume_header() && line_ == 1) + { + column_names_.push_back(string_buffer_); + } + break; + case csv_modes::object: + if (!(parameters_.ignore_empty_values() && string_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size()) + { + handler_->name(column_names_[column_index_].data(), column_names_[column_index_].length(), *this); + if (parameters_.unquoted_empty_value_is_null() && string_buffer_.length() == 0) + { + handler_->value(jsoncons::null_type(),*this); + } + else + { + end_value(); + } + } + } + break; + case csv_modes::array: + if (parameters_.unquoted_empty_value_is_null() && string_buffer_.length() == 0) + { + handler_->value(jsoncons::null_type(),*this); + } + else + { + end_value(); + } + break; + default: + err_handler_->error(std::error_code(csv_parser_errc::invalid_csv_text, csv_error_category()), *this); + break; + } + state_ = csv_states::expect_value; + string_buffer_.clear(); + } + + void end_quoted_string_value() + { + if (parameters_.trim_leading_inside_quotes() | parameters_.trim_trailing_inside_quotes()) + { + trim_string_buffer(parameters_.trim_leading_inside_quotes(),parameters_.trim_trailing_inside_quotes()); + } + switch (stack_[top_]) + { + case csv_modes::header: + if (parameters_.assume_header() && line_ == 1) + { + column_names_.push_back(string_buffer_); + } + break; + case csv_modes::object: + if (!(parameters_.ignore_empty_values() && string_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size()) + { + handler_->name(column_names_[column_index_].data(), column_names_[column_index_].length(), *this); + end_value(); + } + } + break; + case csv_modes::array: + end_value(); + break; + default: + err_handler_->error(std::error_code(csv_parser_errc::invalid_csv_text, csv_error_category()), *this); + break; + } + state_ = csv_states::expect_value; + string_buffer_.clear(); + } + + void end_value() + { + if (column_index_ < column_types_.size()) + { + switch (column_types_[column_index_]) + { + case data_types::integer_t: + { + std::istringstream iss(string_buffer_); + long long val; + iss >> val; + if (!iss.fail()) + { + handler_->value(val, *this); + } + else + { + if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) + { + parser_.begin_parse(); + parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); + parser_.end_parse(); + } + else + { + handler_->value(null_type(), *this); + } + } + } + break; + case data_types::float_t: + { + std::istringstream iss(string_buffer_); + double val; + iss >> val; + if (!iss.fail()) + { + handler_->value(val, 0, *this); + } + else + { + if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) + { + parser_.begin_parse(); + parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); + parser_.end_parse(); + } + else + { + handler_->value(null_type(), *this); + } + } + } + break; + case data_types::boolean_t: + { + if (string_buffer_.length() == 1 && string_buffer_[0] == '0') + { + handler_->value(false, *this); + } + else if (string_buffer_.length() == 1 && string_buffer_[0] == '1') + { + handler_->value(true, *this); + } + else if (string_buffer_.length() == 5 && ((string_buffer_[0] == 'f' || string_buffer_[0] == 'F') && (string_buffer_[1] == 'a' || string_buffer_[1] == 'A') && (string_buffer_[2] == 'l' || string_buffer_[2] == 'L') && (string_buffer_[3] == 's' || string_buffer_[3] == 'S') && (string_buffer_[4] == 'e' || string_buffer_[4] == 'E'))) + { + handler_->value(false, *this); + } + else if (string_buffer_.length() == 4 && ((string_buffer_[0] == 't' || string_buffer_[0] == 'T') && (string_buffer_[1] == 'r' || string_buffer_[1] == 'R') && (string_buffer_[2] == 'u' || string_buffer_[2] == 'U') && (string_buffer_[3] == 'e' || string_buffer_[3] == 'E'))) + { + handler_->value(true, *this); + } + else + { + if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) + { + parser_.begin_parse(); + parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); + parser_.end_parse(); + } + else + { + handler_->value(null_type(), *this); + } + } + } + break; + default: + if (string_buffer_.length() > 0) + { + handler_->value(string_buffer_.data(), string_buffer_.length(), *this); + } + else + { + if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) + { + parser_.begin_parse(); + parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); + parser_.end_parse(); + } + else + { + handler_->value("", *this); + } + } + break; + } + } + else + { + handler_->value(string_buffer_.data(), string_buffer_.length(), *this); + } + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + CharT do_current_char() const override + { + return (CharT)prev_char_; + } + + void push(csv_modes mode) + { + ++top_; + if (top_ >= depth_) + { + depth_ *= 2; + stack_.resize(depth_); + } + stack_[top_] = mode; + } + + int peek() + { + return stack_[top_]; + } + + bool peek(csv_modes mode) + { + return stack_[top_] == mode; + } + + bool flip(csv_modes mode1, csv_modes mode2) + { + if (top_ < 0 || stack_[top_] != mode1) + { + return false; + } + stack_[top_] = mode2; + return true; + } + + bool pop(csv_modes mode) + { + if (top_ < 0 || stack_[top_] != mode) + { + return false; + } + --top_; + return true; + } +}; + +typedef basic_csv_parser<char> csv_parser; +typedef basic_csv_parser<wchar_t> wcsv_parser; + +}} + +#endif + diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_reader.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_reader.hpp new file mode 100644 index 00000000..38213e25 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_reader.hpp @@ -0,0 +1,175 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_READER_HPP +#define JSONCONS_CSV_CSV_READER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/json_input_handler.hpp" +#include "jsoncons/parse_error_handler.hpp" +#include "jsoncons_ext/csv/csv_error_category.hpp" +#include "jsoncons_ext/csv/csv_parser.hpp" +#include "jsoncons/json.hpp" + +namespace jsoncons { namespace csv { + +template<typename CharT> +class basic_csv_reader +{ + struct stack_item + { + stack_item() + : array_begun_(false) + { + } + + bool array_begun_; + }; +public: + // Structural characters + static const size_t default_max_buffer_length = 16384; + //! Parse an input stream of CSV text into a json object + /*! + \param is The input stream to read from + */ + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler) + + : parser_(handler), + is_(std::addressof(is)), + buffer_(default_max_buffer_length), + buffer_capacity_(default_max_buffer_length), + buffer_position_(0), + buffer_length_(0), + eof_(false), + index_(0) + { + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + basic_csv_parameters<CharT> params) + + : parser_(handler,params), + is_(std::addressof(is)), + buffer_(default_max_buffer_length), + buffer_capacity_(default_max_buffer_length), + buffer_position_(0), + buffer_length_(0), + eof_(false), + index_(0) + { + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler) + : + parser_(handler,err_handler), + is_(std::addressof(is)), + buffer_(), + buffer_capacity_(default_max_buffer_length), + buffer_position_(0), + buffer_length_(0), + eof_(false), + index_(0) + + + { + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + basic_parse_error_handler<CharT>& err_handler, + basic_csv_parameters<CharT> params) + : + parser_(handler,err_handler,params), + is_(std::addressof(is)), + buffer_(), + buffer_capacity_(default_max_buffer_length), + buffer_position_(0), + buffer_length_(0), + eof_(false), + index_(0) + { + } + + ~basic_csv_reader() + { + } + + void read() + { + parser_.begin_parse(); + while (!eof_ && !parser_.done()) + { + if (!(index_ < buffer_length_)) + { + if (!is_->eof()) + { + is_->read(buffer_.data(), buffer_capacity_); + buffer_length_ = static_cast<size_t>(is_->gcount()); + if (buffer_length_ == 0) + { + eof_ = true; + } + index_ = 0; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.parse(buffer_.data(),index_,buffer_length_); + index_ = parser_.index(); + } + } + parser_.end_parse(); + } + + bool eof() const + { + return eof_; + } + + size_t buffer_capacity() const + { + return buffer_capacity_; + } + + void buffer_capacity(size_t buffer_capacity) + { + buffer_capacity_ = buffer_capacity; + } + +private: + basic_csv_reader(const basic_csv_reader&) = delete; + basic_csv_reader& operator = (const basic_csv_reader&) = delete; + + basic_csv_parser<CharT> parser_; + std::basic_istream<CharT>* is_; + std::vector<CharT> buffer_; + size_t buffer_capacity_; + size_t buffer_position_; + size_t buffer_length_; + bool eof_; + size_t index_; +}; + +typedef basic_csv_reader<char> csv_reader; + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_serializer.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_serializer.hpp new file mode 100644 index 00000000..f331b629 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_serializer.hpp @@ -0,0 +1,445 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_SERIALIZER_HPP +#define JSONCONS_CSV_CSV_SERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <ostream> +#include <cstdlib> +#include <map> +#include "jsoncons/jsoncons.hpp" +#include "jsoncons/output_format.hpp" +#include "jsoncons/json_output_handler.hpp" +#include <limits> // std::numeric_limits + +namespace jsoncons { namespace csv { + +template <typename CharT> +struct csv_char_traits +{ +}; + +template <> +struct csv_char_traits<char> +{ + static const std::string all_literal() {return "all";}; + + static const std::string minimal_literal() {return "minimal";}; + + static const std::string none_literal() {return "none";}; + + static const std::string nonnumeric_literal() {return "nonumeric";}; +}; + +template <> +struct csv_char_traits<wchar_t> +{ + static const std::wstring all_literal() {return L"all";}; + + static const std::wstring minimal_literal() {return L"minimal";}; + + static const std::wstring none_literal() {return L"none";}; + + static const std::wstring nonnumeric_literal() {return L"nonumeric";}; +}; + +template <typename CharT> +void escape_string(const CharT* s, + size_t length, + CharT quote_char, CharT quote_escape_char, + buffered_ostream<CharT>& os) +{ + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + if (c == quote_char) + { + os.put(quote_escape_char); + os.put(quote_char); + } + else + { + os.put(c); + } + } +} + +template<typename CharT> +class basic_csv_serializer : public basic_json_output_handler<CharT> +{ + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0), skip_(false) + { + } + bool is_object() const + { + return is_object_; + } + + bool is_object_; + size_t count_; + bool skip_; + }; + buffered_ostream<CharT> os_; + basic_csv_parameters<CharT> parameters_; + basic_output_format<CharT> format_; + std::vector<stack_item> stack_; + std::streamsize original_precision_; + std::ios_base::fmtflags original_format_flags_; + std::basic_ostringstream<CharT> header_oss_; + buffered_ostream<CharT> header_os_; + std::map<std::basic_string<CharT>,size_t> header_; + float_printer<CharT> fp_; +public: + basic_csv_serializer(std::basic_ostream<CharT>& os) + : + os_(os), + format_(), + stack_(), + original_precision_(), + original_format_flags_(), + header_os_(header_oss_), + header_(), + fp_(format_.precision()) + { + } + + basic_csv_serializer(std::basic_ostream<CharT>& os, + basic_csv_parameters<CharT> params) + : + os_(os), + parameters_(params), + format_(), + stack_(), + original_precision_(), + original_format_flags_(), + header_os_(header_oss_), + header_(), + fp_(format_.precision()) + { + } + + ~basic_csv_serializer() + { + } + +private: + + void do_begin_json() override + { + } + + void do_end_json() override + { + } + + void do_begin_object() override + { + stack_.push_back(stack_item(true)); + } + + void do_end_object() override + { + if (stack_.size() == 2) + { + os_.write(parameters_.line_delimiter()); + if (stack_[0].count_ == 0) + { + os_.write(header_oss_.str()); + os_.write(parameters_.line_delimiter()); + } + } + stack_.pop_back(); + + end_value(); + } + + void do_begin_array() override + { + stack_.push_back(stack_item(false)); + } + + void do_end_array() override + { + if (stack_.size() == 2) + { + os_.write(parameters_.line_delimiter()); + } + stack_.pop_back(); + + end_value(); + } + + void do_name(const CharT* name, size_t length) override + { + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + if (stack_.back().count_ > 0) + { + os_.put(parameters_.field_delimiter()); + } + bool quote = false; + if (parameters_.quote_style() == quote_styles::all || parameters_.quote_style() == quote_styles::nonnumeric || + (parameters_.quote_style() == quote_styles::minimal && std::char_traits<CharT>::find(name,length,parameters_.field_delimiter()) != nullptr)) + { + quote = true; + os_.put(parameters_.quote_char()); + } + jsoncons::csv::escape_string<CharT>(name, length, parameters_.quote_char(), parameters_.quote_escape_char(), os_); + if (quote) + { + os_.put(parameters_.quote_char()); + } + header_[name] = stack_.back().count_; + } + else + { + typename std::map<std::basic_string<CharT>,size_t>::iterator it = header_.find(std::basic_string<CharT>(name,length)); + if (it == header_.end()) + { + stack_.back().skip_ = true; + //std::cout << " Not found "; + } + else + { + stack_.back().skip_ = false; + while (stack_.back().count_ < it->second) + { + os_.put(parameters_.field_delimiter()); + ++stack_.back().count_; + } + // std::cout << " (" << it->value() << " " << stack_.back().count_ << ") "; + } + } + } + } + + void do_null_value() override + { + if (stack_.size() == 2 && !stack_.back().skip_) + { + if (stack_.back().is_object() && stack_[0].count_ == 0) + { + do_null_value(header_os_); + } + else + { + do_null_value(os_); + } + } + } + + void do_string_value(const CharT* val, size_t length) override + { + if (stack_.size() == 2 && !stack_.back().skip_) + { + if (stack_.back().is_object() && stack_[0].count_ == 0) + { + value(val,length,header_os_); + } + else + { + value(val,length,os_); + } + } + } + + void do_double_value(double val, uint8_t precision) override + { + if (stack_.size() == 2 && !stack_.back().skip_) + { + if (stack_.back().is_object() && stack_[0].count_ == 0) + { + value(val,header_os_); + } + else + { + value(val,os_); + } + } + } + + void do_integer_value(int64_t val) override + { + if (stack_.size() == 2 && !stack_.back().skip_) + { + if (stack_.back().is_object() && stack_[0].count_ == 0) + { + value(val,header_os_); + } + else + { + value(val,os_); + } + } + } + + void do_uinteger_value(uint64_t val) override + { + if (stack_.size() == 2 && !stack_.back().skip_) + { + if (stack_.back().is_object() && stack_[0].count_ == 0) + { + value(val,header_os_); + } + else + { + value(val,os_); + } + } + } + + void do_bool_value(bool val) override + { + if (stack_.size() == 2 && !stack_.back().skip_) + { + if (stack_.back().is_object() && stack_[0].count_ == 0) + { + value(val,header_os_); + } + else + { + value(val,os_); + } + } + } + + void value(const CharT* val, size_t length, buffered_ostream<CharT>& os) + { + begin_value(os); + + bool quote = false; + if (parameters_.quote_style() == quote_styles::all || parameters_.quote_style() == quote_styles::nonnumeric || + (parameters_.quote_style() == quote_styles::minimal && std::char_traits<CharT>::find(val, length, parameters_.field_delimiter()) != nullptr)) + { + quote = true; + os.put(parameters_.quote_char()); + } + jsoncons::csv::escape_string<CharT>(val, length, parameters_.quote_char(), parameters_.quote_escape_char(), os); + if (quote) + { + os.put(parameters_.quote_char()); + } + + end_value(); + } + + void value(double val, buffered_ostream<CharT>& os) + { + begin_value(os); + + if (is_nan(val) && format_.replace_nan()) + { + os.write(format_.nan_replacement()); + } + else if (is_pos_inf(val) && format_.replace_pos_inf()) + { + os.write(format_.pos_inf_replacement()); + } + else if (is_neg_inf(val) && format_.replace_neg_inf()) + { + os.write(format_.neg_inf_replacement()); + } + //else if (format_.floatfield() != 0) + //{ + // std::basic_ostringstream<CharT> ss; + // ss.imbue(std::locale::classic()); + // ss.setf(format_.floatfield(), std::ios::floatfield); + // ss << std::showpoint << std::setprecision(format_.precision()) << val; + // os.write(ss.str()); + //} + else + { + fp_.print(val,format_.precision(),os); + } + + end_value(); + + } + + void value(int64_t val, buffered_ostream<CharT>& os) + { + begin_value(os); + + std::basic_ostringstream<CharT> ss; + ss << val; + os.write(ss.str()); + + end_value(); + } + + void value(uint64_t val, buffered_ostream<CharT>& os) + { + begin_value(os); + + std::basic_ostringstream<CharT> ss; + ss << val; + os.write(ss.str()); + + end_value(); + } + + void value(bool val, buffered_ostream<CharT>& os) + { + begin_value(os); + + if (val) + { + auto buf = json_literals<CharT>::true_literal(); + os.write(buf.first,buf.second); + } + else + { + auto buf = json_literals<CharT>::false_literal(); + os.write(buf.first,buf.second); + } + + end_value(); + } + + void do_null_value(buffered_ostream<CharT>& os) + { + begin_value(os); + auto buf = json_literals<CharT>::null_literal(); + os.write(buf.first,buf.second); + end_value(); + + } + + void begin_value(buffered_ostream<CharT>& os) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + os.put(parameters_.field_delimiter()); + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +typedef basic_csv_serializer<char> csv_serializer; + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp new file mode 100644 index 00000000..7e530abd --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp @@ -0,0 +1,921 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONQUERY_HPP +#define JSONCONS_JSONPATH_JSONQUERY_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include "jsoncons/json.hpp" +#include "jsonpath_filter.hpp" +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { + + template<typename CharT> + bool try_string_to_index(const CharT *s, size_t length, size_t* value) + { + static const size_t max_value = std::numeric_limits<size_t>::max JSONCONS_NO_MACRO_EXP(); + static const size_t max_value_div_10 = max_value / 10; + + size_t n = 0; + for (size_t i = 0; i < length; ++i) + { + CharT c = s[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + { + size_t x = c - '0'; + if (n > max_value_div_10) + { + return false; + } + n = n * 10; + if (n > max_value - x) + { + return false; + } + + n += x; + } + break; + default: + return false; + break; + } + } + *value = n; + return true; + } + + template <typename CharT> + struct json_jsonpath_traits + { + }; + + template <> + struct json_jsonpath_traits<char> + { + static const std::string length_literal() {return "length";}; + }; + + template <> + struct json_jsonpath_traits<wchar_t> // assume utf16 + { + static const std::wstring length_literal() {return L"length";}; + }; + +// here + +template<class JsonT> +JsonT json_query(const JsonT& root, const typename JsonT::char_type* path, size_t length) +{ + jsonpath_evaluator<JsonT> evaluator; + evaluator.evaluate(root,path,length); + return evaluator.get_values(); +} + +template<class JsonT> +JsonT json_query(const JsonT& root, const typename JsonT::string_type& path) +{ + return json_query(root,path.data(),path.length()); +} + +template<class JsonT> +JsonT json_query(const JsonT& root, const typename JsonT::char_type* path) +{ + return json_query(root,path,std::char_traits<typename JsonT::char_type>::length(path)); +} + +enum class states +{ + start, + cr, + lf, + expect_separator, + expect_unquoted_name, + unquoted_name, + single_quoted_name, + double_quoted_name, + left_bracket, + left_bracket_start, + left_bracket_end, + left_bracket_end2, + left_bracket_step, + left_bracket_step2, + expect_right_bracket, + dot +}; + +template<class JsonT> +class jsonpath_evaluator : private basic_parsing_context<typename JsonT::char_type> +{ +private: + typedef typename JsonT::char_type char_type; + typedef typename JsonT::string_type string_type; + typedef const JsonT* cjson_ptr; + typedef std::vector<cjson_ptr> node_set; + + basic_parse_error_handler<char_type> *err_handler_; + states state_; + string_type buffer_; + size_t start_; + size_t end_; + size_t step_; + bool positive_start_; + bool positive_end_; + bool positive_step_; + bool end_undefined_; + std::vector<node_set> stack_; + bool recursive_descent_; + std::vector<cjson_ptr> nodes_; + std::vector<std::shared_ptr<JsonT>> temp_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + states pre_line_break_state_; + + void transfer_nodes() + { + stack_.push_back(nodes_); + nodes_.clear(); + } + +public: + jsonpath_evaluator() + : err_handler_(std::addressof(basic_default_parse_error_handler<char_type>::instance())) + { + } + + JsonT get_values() const + { + JsonT result = JsonT::make_array(); + + if (stack_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + result.add(*p); + } + } + return result; + } + + void evaluate(const JsonT& root, const string_type& path) + { + evaluate(root,path.data(),path.length()); + } + void evaluate(const JsonT& root, const char_type* path) + { + evaluate(root,path,std::char_traits<char_type>::length(path)); + } + + void evaluate(const JsonT& root, const char_type* path, size_t length) + { + begin_input_ = path; + end_input_ = path + length; + p_ = begin_input_; + + line_ = 1; + column_ = 1; + state_ = states::start; + buffer_.clear(); + start_ = 0; + end_ = 0; + step_ = 1; + recursive_descent_ = false; + positive_start_ = true; + positive_end_ = true; + positive_step_ = true; + end_undefined_ = false; + + while (p_ < end_input_) + { + switch (state_) + { + case states::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_ = pre_line_break_state_; + ++p_; + ++column_; + break; + default: + state_ = pre_line_break_state_; + break; + } + break; + case states::lf: + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case states::start: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '$': + case '@': + { + node_set v; + v.push_back(std::addressof(root)); + stack_.push_back(v); + state_ = states::expect_separator; + } + break; + default: + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_root, jsonpath_error_category()), *this); + break; + }; + ++p_; + ++column_; + break; + case states::dot: + switch (*p_) + { + case '.': + recursive_descent_ = true; + ++p_; + ++column_; + state_ = states::expect_unquoted_name; + break; + default: + state_ = states::expect_unquoted_name; + break; + } + break; + case states::expect_unquoted_name: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '.': + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_name, jsonpath_error_category()), *this); + ++p_; + ++column_; + break; + case '*': + end_all(); + transfer_nodes(); + state_ = states::expect_separator; + ++p_; + ++column_; + break; + default: + state_ = states::unquoted_name; + break; + } + break; + case states::expect_separator: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '.': + state_ = states::dot; + break; + case '[': + state_ = states::left_bracket; + break; + default: + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_separator, jsonpath_error_category()), *this); + break; + }; + ++p_; + ++column_; + break; + case states::expect_right_bracket: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ',': + state_ = states::left_bracket; + break; + case ']': + transfer_nodes(); + state_ = states::expect_separator; + break; + case ' ':case '\t': + break; + default: + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_right_bracket, jsonpath_error_category()), *this); + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_step: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '-': + positive_step_ = false; + state_ = states::left_bracket_step2; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = static_cast<size_t>(*p_-'0'); + state_ = states::left_bracket_step2; + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_step2: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = step_*10 + static_cast<size_t>(*p_-'0'); + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_end: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '-': + positive_end_ = false; + state_ = states::left_bracket_end2; + break; + case ':': + step_ = 0; + state_ = states::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + end_undefined_ = false; + end_ = static_cast<size_t>(*p_-'0'); + state_ = states::left_bracket_end2; + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_end2: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ':': + step_ = 0; + state_ = states::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + end_undefined_ = false; + end_ = end_*10 + static_cast<size_t>(*p_-'0'); + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_start: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ':': + step_ = 1; + end_undefined_ = true; + state_ = states::left_bracket_end; + break; + case ',': + find_elements(); + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + start_ = start_*10 + static_cast<size_t>(*p_-'0'); + break; + case ']': + find_elements(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '(': + { + if (stack_.back().size() == 1) + { + jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_); + parser.parse(p_,end_input_); + auto index = parser.eval(*(stack_.back()[0])); + if (index.template is<size_t>()) + { + start_ = index. template as<size_t>(); + find_elements(); + } + else if (index.is_string()) + { + find(index.as_string()); + } + } + else + { + ++p_; + ++column_; + } + } + break; + case '?': + { + jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_); + parser.parse(p_,end_input_); + nodes_.clear(); + for (size_t j = 0; j < stack_.back().size(); ++j) + { + accept(*(stack_.back()[j]),parser); + } + } + break; + + case ':': + step_ = 1; + end_undefined_ = true; + state_ = states::left_bracket_end; + ++p_; + ++column_; + break; + case ',': + find_elements(); + ++p_; + ++column_; + break; + case '-': + positive_start_ = false; + state_ = states::left_bracket_start; + ++p_; + ++column_; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + start_ = static_cast<size_t>(*p_-'0'); + state_ = states::left_bracket_start; + ++p_; + ++column_; + break; + case ']': + //find_elements(); + transfer_nodes(); + state_ = states::expect_separator; + ++p_; + ++column_; + break; + case '*': + end_all(); + //transfer_nodes(); + state_ = states::expect_right_bracket; + ++p_; + ++column_; + break; + case '\'': + state_ = states::single_quoted_name; + ++p_; + ++column_; + break; + case '\"': + state_ = states::double_quoted_name; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + break; + case states::unquoted_name: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '[': + find(buffer_); + buffer_.clear(); + transfer_nodes(); + start_ = 0; + state_ = states::left_bracket; + break; + case '.': + find(buffer_); + buffer_.clear(); + transfer_nodes(); + state_ = states::dot; + break; + case ' ':case '\t': + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case states::single_quoted_name: + switch (*p_) + { + case '\'': + find(buffer_); + buffer_.clear(); + state_ = states::expect_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case states::double_quoted_name: + switch (*p_) + { + case '\"': + find(buffer_); + buffer_.clear(); + state_ = states::expect_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + switch (state_) + { + case states::unquoted_name: + { + find(buffer_); + buffer_.clear(); + transfer_nodes(); + } + break; + default: + break; + } + } + + void accept(const JsonT& val, + jsonpath_filter_parser<JsonT>& filter) + { + if (val.is_object()) + { + if (recursive_descent_ && val.is_object()) + { + for (auto it = val.members().begin(); it != val.members().end(); ++it) + { + accept(it->value(),filter); + } + } + if (filter.exists(val)) + { + nodes_.push_back(std::addressof(val)); + } + } + else if (val.is_array()) + { + for (auto it = val.elements().begin(); it != val.elements().end(); ++it) + { + accept(*it,filter); + } + } + } + + + + void end_all() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + if (p->is_array()) + { + for (auto it = p->elements().begin(); it != p->elements().end(); ++it) + { + nodes_.push_back(std::addressof(*it)); + } + } + else if (p->is_object()) + { + for (auto it = p->members().begin(); it != p->members().end(); ++it) + { + nodes_.push_back(std::addressof(it->value())); + } + } + + } + start_ = 0; + } + + void find_elements() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + if (p->is_array() && start_ < p->size()) + { + nodes_.push_back(std::addressof((*p)[start_])); + } + } + start_ = 0; + } + + void end_array_slice() + { + if (positive_step_) + { + end_array_slice1(); + } + else + { + end_array_slice2(); + } + start_ = 0; + end_ = 0; + step_ = 1; + positive_start_ = positive_end_ = positive_step_ = true; + end_undefined_ = true; + } + + void end_array_slice1() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + if (p->is_array()) + { + size_t start = positive_start_ ? start_ : p->size() - start_; + size_t end; + if (!end_undefined_) + { + end = positive_end_ ? end_ : p->size() - end_; + } + else + { + end = p->size(); + } + for (size_t j = start; j < end; j += step_) + { + if (p->is_array() && j < p->size()) + { + nodes_.push_back(std::addressof((*p)[j])); + } + } + } + } + } + + void end_array_slice2() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + size_t start = positive_start_ ? start_ : p->size() - start_; + size_t end; + if (!end_undefined_) + { + end = positive_end_ ? end_ : p->size() - end_; + } + else + { + end = p->size(); + } + + size_t j = end + step_ - 1; + while (j > (start+step_-1)) + { + j -= step_; + if (p->is_array() && j < p->size()) + { + nodes_.push_back(std::addressof((*p)[j])); + } + } + } + } + + void find(const string_type& name) + { + if (name.length() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + find1(*(stack_.back()[i]), name); + } + recursive_descent_ = false; + } + } + + void find1(const JsonT& context_val, const string_type& name) + { + if (context_val.is_object()) + { + if (context_val.count(name) > 0) + { + nodes_.push_back(std::addressof(context_val.at(name))); + } + if (recursive_descent_) + { + for (auto it = context_val.members().begin(); it != context_val.members().end(); ++it) + { + if (it->value().is_object() || it->value().is_array()) + { + find1(it->value(), name); + } + } + } + } + else if (context_val.is_array()) + { + size_t index = 0; + if (try_string_to_index(name.data(),name.size(),&index)) + { + if (index < context_val.size()) + { + nodes_.push_back(std::addressof(context_val[index])); + } + } + else if (name == json_jsonpath_traits<char_type>::length_literal() && context_val.size() > 0) + { + auto q = std::make_shared<JsonT>(context_val.size()); + temp_.push_back(q); + nodes_.push_back(q.get()); + } + if (recursive_descent_) + { + for (auto it = context_val.elements().begin(); it != context_val.elements().end(); ++it) + { + if (it->is_object() || it->is_array()) + { + find1(*it, name); + } + } + } + } + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + char_type do_current_char() const override + { + return 0; //p_ < end_input_? *p_ : 0; + } + +}; + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp new file mode 100644 index 00000000..7f6b6a12 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp @@ -0,0 +1,75 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP + +#include "jsoncons/jsoncons.hpp" +#include <system_error> + +namespace jsoncons { namespace jsonpath { + +namespace jsonpath_parser_errc +{ + const int expected_root = 1; + const int expected_right_bracket = 2; + const int expected_name = 3; + const int expected_separator = 4; + const int invalid_filter = 5; + const int invalid_filter_expected_slash = 6; + const int invalid_filter_unbalanced_paren = 7; + const int invalid_filter_unsupported_operator = 8; + const int invalid_filter_expected_right_brace = 9; + const int invalid_filter_expected_primary = 10; +} + +class jsonpath_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsonpath"; + } + virtual std::string message(int ev) const + { + switch (ev) + { + case jsonpath_parser_errc::expected_root: + return "Expected $"; + case jsonpath_parser_errc::expected_right_bracket: + return "Expected ]"; + case jsonpath_parser_errc::expected_name: + return "Expected a name following a dot"; + case jsonpath_parser_errc::expected_separator: + return "Expected dot or left bracket separator"; + case jsonpath_parser_errc::invalid_filter: + return "Invalid path filter"; + case jsonpath_parser_errc::invalid_filter_expected_slash: + return "Invalid path filter, expected '/'"; + case jsonpath_parser_errc::invalid_filter_unbalanced_paren: + return "Invalid path filter, unbalanced parenthesis"; + case jsonpath_parser_errc::invalid_filter_unsupported_operator: + return "Unsupported operator"; + case jsonpath_parser_errc::invalid_filter_expected_right_brace: + return "Invalid path filter, expected right brace }"; + case jsonpath_parser_errc::invalid_filter_expected_primary: + return "Invalid path filter, expected primary expression."; + default: + return "Unknown jsonpath parser error"; + } + } +}; + +inline +const std::error_category& jsonpath_error_category() +{ + static jsonpath_error_category_impl instance; + return instance; +} + +}} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp new file mode 100644 index 00000000..b0ac51c6 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp @@ -0,0 +1,1495 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_FILTER_HPP +#define JSONCONS_JSONPATH_FILTER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <regex> +#include "jsoncons/json.hpp" +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { + +template <class JsonT> +class jsonpath_evaluator; + +enum class filter_states +{ + start, + cr, + lf, + expect_right_round_bracket, + expect_oper_or_right_round_bracket, + expect_path_or_value, + expect_regex, + regex, + single_quoted_text, + double_quoted_text, + unquoted_text, + path, + value, + oper +}; + +enum class token_types +{ + left_paren, + right_paren, + term, + eq, + ne, + regex, + ampamp, + pipepipe, + lt, + gt, + lte, + gte, + plus, + minus, + exclaim, + done +}; + +template <class JsonT> +class term +{ +public: + typedef typename JsonT::string_type string_type; + typedef typename JsonT::char_type char_type; + + virtual void initialize(const JsonT& context_node) + { + } + virtual bool accept_single_node() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT evaluate_single_node() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool exclaim() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool eq(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool eq(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ne(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ne(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool regex(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool regex2(const string_type& subject) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ampamp(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ampamp(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool pipepipe(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool pipepipe(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool lt(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool lt(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool gt(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool gt(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT minus(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT minus(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT unary_minus() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT plus(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT plus(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } +}; + +template <class JsonT> +class token +{ + token_types type_; + std::shared_ptr<term<JsonT>> term_ptr_; +public: + token(token_types type) + : type_(type) + { + } + token(token_types type, std::shared_ptr<term<JsonT>> term_ptr) + : type_(type), term_ptr_(term_ptr) + { + } + token(const token& t) + : type_(t.type_), term_ptr_(t.term_ptr_) + { + } + + token_types type() const + { + return type_; + } + + std::shared_ptr<term<JsonT>> term_ptr() + { + return term_ptr_; + } + + void initialize(const JsonT& context_node) + { + if (term_ptr_.get() != nullptr) + { + term_ptr_->initialize(context_node); + } + } +}; + +template <class JsonT> +class token_stream +{ + std::vector<token<JsonT>>& tokens_; + size_t index_; +public: + token_stream(std::vector<token<JsonT>>& tokens) + : tokens_(tokens), index_(0) + { + } + + token<JsonT> get() + { + static token<JsonT> done = token<JsonT>(token_types::done); + return index_ < tokens_.size() ? tokens_[index_++] : done; + } + void putback() + { + --index_; + } +}; + +template <class JsonT> +bool ampamp(const JsonT& lhs, const JsonT& rhs) +{ + return lhs.as_bool() && rhs.as_bool(); +} + +template <class JsonT> +bool pipepipe(const JsonT& lhs, const JsonT& rhs) +{ + return lhs.as_bool() || rhs.as_bool(); +} + +template <class JsonT> +bool lt(const JsonT& lhs, const JsonT& rhs) +{ + bool result = false; + if (lhs. template is<unsigned long long>() && rhs. template is<unsigned long long>()) + { + result = lhs. template as<unsigned long long>() < rhs. template as<unsigned long long>(); + } + else if (lhs. template is<long long>() && rhs. template is<long long>()) + { + result = lhs. template as<long long>() < rhs. template as<long long>(); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = lhs.as_double() < rhs.as_double(); + } + else if (lhs.is_string() && rhs.is_string()) + { + result = lhs.as_string() < rhs.as_string(); + } + return result; +} + +template <class JsonT> +bool gt(const JsonT& lhs, const JsonT& rhs) +{ + return lt(rhs,lhs); +} + +template <class JsonT> +JsonT plus(const JsonT& lhs, const JsonT& rhs) +{ + JsonT result = jsoncons::null_type(); + if (lhs.is_integer() && rhs.is_integer()) + { + result = ((lhs.as_integer() + rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = (lhs.as_double() + rhs.as_double()); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = (lhs.as_uinteger() + rhs.as_uinteger()); + } + return result; +} + +template <class JsonT> +JsonT unary_minus(const JsonT& lhs) +{ + JsonT result = jsoncons::null_type(); + if (lhs.is_integer()) + { + result = -lhs.as_integer(); + } + else if (lhs.is_double()) + { + result = -lhs.as_double(); + } + return result; +} + +template <class JsonT> +JsonT minus(const JsonT& lhs, const JsonT& rhs) +{ + JsonT result = jsoncons::null_type(); + if (lhs.is_integer() && rhs.is_integer()) + { + result = ((lhs.as_integer() - rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = (lhs.as_double() - rhs.as_double()); + } + else if (lhs.is_uinteger() && rhs.is_uinteger() && lt(rhs,lhs)) + { + result = (lhs.as_uinteger() - rhs.as_uinteger()); + } + return result; +} + +template <class JsonT> +class value_term : public term<JsonT> +{ + JsonT value_; +public: + template <class T> + value_term(const T& value) + : value_(value) + { + } + + bool accept_single_node() const override + { + return value_.as_bool(); + } + + JsonT evaluate_single_node() const override + { + return value_; + } + + bool exclaim() const override + { + return !value_.as_bool(); + } + + bool eq(const term<JsonT>& rhs) const override + { + return rhs.eq(value_); + } + + bool eq(const JsonT& rhs) const override + { + return value_ == rhs; + } + + bool ne(const term<JsonT>& rhs) const override + { + return rhs.ne(value_); + } + bool ne(const JsonT& rhs) const override + { + return value_ != rhs; + } + bool regex(const term<JsonT>& rhs) const override + { + return rhs.regex2(value_.as_string()); + } + bool ampamp(const term<JsonT>& rhs) const override + { + return rhs.ampamp(value_); + } + bool ampamp(const JsonT& rhs) const override + { + return jsoncons::jsonpath::ampamp(value_,rhs); + } + bool pipepipe(const term<JsonT>& rhs) const override + { + return rhs.pipepipe(value_); + } + bool pipepipe(const JsonT& rhs) const override + { + return jsoncons::jsonpath::pipepipe(value_,rhs); + } + + bool lt(const term<JsonT>& rhs) const override + { + return rhs.gt(value_); + } + + bool lt(const JsonT& rhs) const override + { + return jsoncons::jsonpath::lt(value_,rhs); + } + + bool gt(const term<JsonT>& rhs) const override + { + return rhs.lt(value_); + } + + bool gt(const JsonT& rhs) const override + { + return jsoncons::jsonpath::gt(value_,rhs); + } + + JsonT minus(const term<JsonT>& rhs) const override + { + return jsoncons::jsonpath::plus(rhs.unary_minus(),value_); + } + + JsonT minus(const JsonT& rhs) const override + { + return jsoncons::jsonpath::minus(value_,rhs); + } + + JsonT unary_minus() const override + { + return jsoncons::jsonpath::unary_minus(value_); + } + + JsonT plus(const term<JsonT>& rhs) const override + { + return rhs.plus(value_); + } + + JsonT plus(const JsonT& rhs) const override + { + return jsoncons::jsonpath::plus(value_,rhs); + } +}; + +template <class JsonT> +class regex_term : public term<JsonT> +{ + typedef typename JsonT::char_type char_type; + typedef typename JsonT::string_type string_type; + string_type pattern_; + std::regex::flag_type flags_; +public: + regex_term(const string_type& pattern, std::regex::flag_type flags) + : pattern_(pattern), flags_(flags) + { + } + + bool regex2(const string_type& subject) const override + { + std::basic_regex<char_type> pattern(pattern_, + flags_); + return std::regex_match(subject, pattern); + } +}; + +template <class JsonT> +class path_term : public term<JsonT> +{ + typedef typename JsonT::string_type string_type; + + string_type path_; + JsonT nodes_; +public: + path_term(const string_type& path) + : path_(path) + { + } + + void initialize(const JsonT& context_node) override + { + jsonpath_evaluator<JsonT> evaluator; + evaluator.evaluate(context_node,path_); + nodes_ = evaluator.get_values(); + } + + bool accept_single_node() const override + { + return nodes_.size() != 0; + } + + JsonT evaluate_single_node() const override + { + return nodes_.size() == 1 ? nodes_[0] : nodes_; + } + + bool exclaim() const override + { + return nodes_.size() == 0; + } + + bool eq(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.eq(nodes_[i]); + } + } + return result; + } + + bool eq(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] == rhs; + } + } + return result; + } + + bool ne(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ne(nodes_[i]); + } + } + return result; + + } + bool ne(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] != rhs; + } + } + return result; + } + bool regex(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.regex2(nodes_[i].as_string()); + } + } + return result; + } + bool ampamp(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ampamp(nodes_[i]); + } + } + return result; + } + bool ampamp(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::ampamp(nodes_[i],rhs); + } + } + return result; + } + bool pipepipe(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.pipepipe(nodes_[i]); + } + } + return result; + } + bool pipepipe(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::pipepipe(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::lt(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.gt(nodes_[i]); + } + } + return result; + } + + bool gt(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::gt(nodes_[i],rhs); + } + } + return result; + } + + bool gt(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.lt(nodes_[i]); + } + } + return result; + } + + JsonT minus(const JsonT& rhs) const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::minus(nodes_[0],rhs) : jsoncons::null_type(); + } + + JsonT minus(const term<JsonT>& rhs) const override + { + + return nodes_.size() == 1 ? jsoncons::jsonpath::plus(rhs.unary_minus(),nodes_[0]) : jsoncons::null_type(); + } + + JsonT unary_minus() const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::unary_minus(nodes_[0]) : jsoncons::null_type(); + } + + JsonT plus(const JsonT& rhs) const override + { + static auto a_null = jsoncons::null_type(); + return nodes_.size() == 1 ? jsoncons::jsonpath::plus(nodes_[0],rhs) : a_null; + } + + JsonT plus(const term<JsonT>& rhs) const override + { + static auto a_null = jsoncons::null_type(); + return nodes_.size() == 1 ? rhs.plus(nodes_[0]) : a_null; + } +}; + +template <class JsonT> +class jsonpath_filter_parser +{ + typedef typename JsonT::string_type string_type; + typedef typename JsonT::char_type char_type; + + size_t& line_; + size_t& column_; + filter_states state_; + string_type buffer_; + std::vector<token<JsonT>> tokens_; + int depth_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type*& p_; + filter_states pre_line_break_state_; +public: + jsonpath_filter_parser(const char_type** expr, size_t* line,size_t* column) + : line_(*line), column_(*column),p_(*expr) + { + } + + bool exists(const JsonT& context_node) + { + for (auto it=tokens_.begin(); it != tokens_.end(); ++it) + { + it->initialize(context_node); + } + bool result = false; + + token_stream<JsonT> ts(tokens_); + auto e = expression(ts); + result = e->accept_single_node(); + + return result; + } + + JsonT eval(const JsonT& context_node) + { + try + { + for (auto it=tokens_.begin(); it != tokens_.end(); ++it) + { + it->initialize(context_node); + } + + token_stream<JsonT> ts(tokens_); + auto e = expression(ts); + JsonT result = e->evaluate_single_node(); + + return result; + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + } + + std::shared_ptr<term<JsonT>> primary(token_stream<JsonT>& ts) + { + auto t = ts.get(); + + switch (t.type()) + { + case token_types::left_paren: + { + auto expr = expression(ts); + t = ts.get(); + if (t.type() != token_types::right_paren) + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_right_brace, jsonpath_error_category()),line_,column_); + } + return expr; + } + case token_types::term: + return t.term_ptr(); + case token_types::exclaim: + { + JsonT val = primary(ts)->exclaim(); + auto expr = std::make_shared<value_term<JsonT>>(val); + return expr; + } + case token_types::minus: + { + JsonT val = primary(ts)->unary_minus(); + auto expr = std::make_shared<value_term<JsonT>>(val); + return expr; + } + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_primary, jsonpath_error_category()),line_,column_); + } + } + + std::shared_ptr<term<JsonT>> expression(token_stream<JsonT>& ts) + { + auto left = make_term(ts); + auto t = ts.get(); + while (true) + { + switch (t.type()) + { + case token_types::plus: + { + JsonT val = left->plus(*(make_term(ts))); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::minus: + { + JsonT val = left->minus(*(make_term(ts))); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + default: + ts.putback(); + return left; + } + } + return left; + } + + std::shared_ptr<term<JsonT>> make_term(token_stream<JsonT>& ts) + { + auto left = primary(ts); + auto t = ts.get(); + while (true) + { + switch (t.type()) + { + case token_types::eq: + { + bool e = left->eq(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::ne: + { + bool e = left->ne(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::regex: + { + bool e = left->regex(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::ampamp: + { + bool e = left->ampamp(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::pipepipe: + { + bool e = left->pipepipe(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::lt: + { + bool e = left->lt(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::gt: + { + bool e = left->gt(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::lte: + { + bool e = left->lt(*(primary(ts))) || left->eq(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::gte: + { + bool e = left->gt(*(primary(ts))) || left->eq(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + default: + ts.putback(); + return left; + } + } + } + + void parse(const char_type* expr, size_t length) + { + parse(expr,expr+length); + } + + void parse(const char_type* expr, const char_type* end_expr) + { + p_ = expr; + end_input_ = end_expr; + depth_ = 0; + tokens_.clear(); + state_ = filter_states::start; + bool done = false; + while (!done && p_ < end_input_) + { + switch (state_) + { + case filter_states::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_ = pre_line_break_state_; + ++p_; + ++column_; + break; + default: + state_ = pre_line_break_state_; + break; + } + break; + case filter_states::lf: + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case filter_states::start: + switch (*p_) + { + case '\r': + case '\n': + pre_line_break_state_ = state_; + state_ = filter_states::lf; + break; + case '(': + state_ = filter_states::expect_path_or_value; + ++depth_; + tokens_.push_back(token<JsonT>(token_types::left_paren)); + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + } + break; + } + ++p_; + ++column_; + break; + case filter_states::oper: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '!': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::ne)); + } + else + { + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::exclaim)); + } + break; + case '&': + if (p_+1 < end_input_ && *(p_+1) == '&') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::ampamp)); + } + break; + case '|': + if (p_+1 < end_input_ && *(p_+1) == '|') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::pipepipe)); + } + break; + case '=': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::eq)); + } + else if (p_+1 < end_input_ && *(p_+1) == '~') + { + ++p_; + ++column_; + state_ = filter_states::expect_regex; + tokens_.push_back(token<JsonT>(token_types::regex)); + } + break; + case '>': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::gte)); + } + else + { + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::gt)); + } + break; + case '<': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::lte)); + } + else + { + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::lt)); + } + break; + case '+': + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::plus)); + break; + case '-': + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::minus)); + break; + case ' ':case '\t': + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); + break; + + } + ++p_; + ++column_; + break; + case filter_states::unquoted_text: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + { + if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + state_ = filter_states::oper; + } + break; + case ')': + if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + state_ = filter_states::start; + done = true; + } + else + { + state_ = filter_states::expect_path_or_value; + } + ++p_; + ++column_; + break; + case ' ':case '\t': + if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + ++p_; + ++column_; + break; + default: + buffer_.push_back(*p_); + ++p_; + ++column_; + break; + } + } + break; + case filter_states::single_quoted_text: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + case '\'': + buffer_.push_back('\"'); + //if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + state_ = filter_states::expect_path_or_value; + break; + + default: + buffer_.push_back(*p_); + break; + } + } + ++p_; + ++column_; + break; + case filter_states::double_quoted_text: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + case '\"': + buffer_.push_back(*p_); + //if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + state_ = filter_states::expect_path_or_value; + break; + + default: + buffer_.push_back(*p_); + break; + } + } + ++p_; + ++column_; + break; + case filter_states::expect_path_or_value: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + state_ = filter_states::oper; + // don't increment + break; + case '@': + buffer_.push_back(*p_); + state_ = filter_states::path; + ++p_; + ++column_; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '\'': + buffer_.push_back('\"'); + state_ = filter_states::single_quoted_text; + ++p_; + ++column_; + break; + case '\"': + buffer_.push_back(*p_); + state_ = filter_states::double_quoted_text; + ++p_; + ++column_; + break; + case '(': + ++depth_; + tokens_.push_back(token<JsonT>(token_types::left_paren)); + ++p_; + ++column_; + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + state_ = filter_states::start; + } + ++p_; + ++column_; + break; + default: + // don't increment + state_ = filter_states::unquoted_text; + break; + }; + break; + case filter_states::expect_oper_or_right_round_bracket: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case ' ':case '\t': + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + state_ = filter_states::start; + } + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + { + state_ = filter_states::oper; + // don't increment p + } + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); + break; + }; + break; + case filter_states::expect_right_round_bracket: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case ' ':case '\t': + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + state_ = filter_states::start; + } + else + { + state_ = filter_states::expect_oper_or_right_round_bracket; + } + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); + break; + }; + ++p_; + ++column_; + break; + case filter_states::path: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + { + if (buffer_.length() > 0) + { + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<path_term<JsonT>>(buffer_))); + buffer_.clear(); + } + state_ = filter_states::oper; + // don't increment + } + break; + case ')': + if (buffer_.length() > 0) + { + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<path_term<JsonT>>(buffer_))); + tokens_.push_back(token<JsonT>(token_types::right_paren)); + buffer_.clear(); + } + if (--depth_ == 0) + { + state_ = filter_states::start; + done = true; + } + else + { + state_ = filter_states::expect_path_or_value; + } + ++p_; + ++column_; + break; + default: + buffer_.push_back(*p_); + ++p_; + ++column_; + break; + }; + break; + case filter_states::expect_regex: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '/': + state_ = filter_states::regex; + break; + case ' ':case '\t': + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_slash, jsonpath_error_category()),line_,column_); + break; + }; + ++p_; + ++column_; + break; + case filter_states::regex: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '/': + //if (buffer_.length() > 0) + { + std::regex::flag_type flags = std::regex_constants::ECMAScript; + if (p_+1 < end_input_ && *(p_+1) == 'i') + { + ++p_; + ++column_; + flags |= std::regex_constants::icase; + } + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<regex_term<JsonT>>(buffer_,flags))); + buffer_.clear(); + } + state_ = filter_states::expect_path_or_value; + break; + + default: + buffer_.push_back(*p_); + break; + } + } + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + if (depth_ != 0) + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unbalanced_paren, jsonpath_error_category()),line_,column_); + } + } +}; + + +}} +#endif
\ No newline at end of file diff --git a/vendor/pcg-cpp b/vendor/pcg-cpp new file mode 120000 index 00000000..13a0799b --- /dev/null +++ b/vendor/pcg-cpp @@ -0,0 +1 @@ +pcg-cpp-0.98
\ No newline at end of file diff --git a/vendor/pcg-cpp-0.98/.gitignore b/vendor/pcg-cpp-0.98/.gitignore new file mode 100644 index 00000000..9f598fd5 --- /dev/null +++ b/vendor/pcg-cpp-0.98/.gitignore @@ -0,0 +1,33 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Debug Information +*.dSYM + +# Executables +*.exe +*.out +*.app + +# Actual Project Executables diff --git a/vendor/pcg-cpp-0.98/include/pcg_extras.hpp b/vendor/pcg-cpp-0.98/include/pcg_extras.hpp new file mode 100644 index 00000000..9b2e4e27 --- /dev/null +++ b/vendor/pcg-cpp-0.98/include/pcg_extras.hpp @@ -0,0 +1,637 @@ +/* + * PCG Random Number Generation for C++ + * + * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* + * This file provides support code that is useful for random-number generation + * but not specific to the PCG generation scheme, including: + * - 128-bit int support for platforms where it isn't available natively + * - bit twiddling operations + * - I/O of 128-bit and 8-bit integers + * - Handling the evilness of SeedSeq + * - Support for efficiently producing random numbers less than a given + * bound + */ + +#ifndef PCG_EXTRAS_HPP_INCLUDED +#define PCG_EXTRAS_HPP_INCLUDED 1 + +#include <cinttypes> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <cassert> +#include <limits> +#include <iostream> +#include <type_traits> +#include <utility> +#include <locale> +#include <iterator> +#include <utility> + +#ifdef __GNUC__ + #include <cxxabi.h> +#endif + +/* + * Abstractions for compiler-specific directives + */ + +#ifdef __GNUC__ + #define PCG_NOINLINE __attribute__((noinline)) +#else + #define PCG_NOINLINE +#endif + +/* + * Some members of the PCG library use 128-bit math. When compiling on 64-bit + * platforms, both GCC and Clang provide 128-bit integer types that are ideal + * for the job. + * + * On 32-bit platforms (or with other compilers), we fall back to a C++ + * class that provides 128-bit unsigned integers instead. It may seem + * like we're reinventing the wheel here, because libraries already exist + * that support large integers, but most existing libraries provide a very + * generic multiprecision code, but here we're operating at a fixed size. + * Also, most other libraries are fairly heavyweight. So we use a direct + * implementation. Sadly, it's much slower than hand-coded assembly or + * direct CPU support. + * + */ +#if __SIZEOF_INT128__ + namespace pcg_extras { + typedef __uint128_t pcg128_t; + } + #define PCG_128BIT_CONSTANT(high,low) \ + ((pcg128_t(high) << 64) + low) +#else + #include "pcg_uint128.hpp" + namespace pcg_extras { + typedef pcg_extras::uint_x4<uint32_t,uint64_t> pcg128_t; + } + #define PCG_128BIT_CONSTANT(high,low) \ + pcg128_t(high,low) + #define PCG_EMULATED_128BIT_MATH 1 +#endif + + +namespace pcg_extras { + +/* + * We often need to represent a "number of bits". When used normally, these + * numbers are never greater than 128, so an unsigned char is plenty. + * If you're using a nonstandard generator of a larger size, you can set + * PCG_BITCOUNT_T to have it define it as a larger size. (Some compilers + * might produce faster code if you set it to an unsigned int.) + */ + +#ifndef PCG_BITCOUNT_T + typedef uint8_t bitcount_t; +#else + typedef PCG_BITCOUNT_T bitcount_t; +#endif + +/* + * C++ requires us to be able to serialize RNG state by printing or reading + * it from a stream. Because we use 128-bit ints, we also need to be able + * ot print them, so here is code to do so. + * + * This code provides enough functionality to print 128-bit ints in decimal + * and zero-padded in hex. It's not a full-featured implementation. + */ + +template <typename CharT, typename Traits> +std::basic_ostream<CharT,Traits>& +operator<<(std::basic_ostream<CharT,Traits>& out, pcg128_t value) +{ + auto desired_base = out.flags() & out.basefield; + bool want_hex = desired_base == out.hex; + + if (want_hex) { + uint64_t highpart = uint64_t(value >> 64); + uint64_t lowpart = uint64_t(value); + auto desired_width = out.width(); + if (desired_width > 16) { + out.width(desired_width - 16); + } + if (highpart != 0 || desired_width > 16) + out << highpart; + CharT oldfill; + if (highpart != 0) { + out.width(16); + oldfill = out.fill('0'); + } + auto oldflags = out.setf(decltype(desired_base){}, out.showbase); + out << lowpart; + out.setf(oldflags); + if (highpart != 0) { + out.fill(oldfill); + } + return out; + } + constexpr size_t MAX_CHARS_128BIT = 40; + + char buffer[MAX_CHARS_128BIT]; + char* pos = buffer+sizeof(buffer); + *(--pos) = '\0'; + constexpr auto BASE = pcg128_t(10ULL); + do { + auto div = value / BASE; + auto mod = uint32_t(value - (div * BASE)); + *(--pos) = '0' + mod; + value = div; + } while(value != pcg128_t(0ULL)); + return out << pos; +} + +template <typename CharT, typename Traits> +std::basic_istream<CharT,Traits>& +operator>>(std::basic_istream<CharT,Traits>& in, pcg128_t& value) +{ + typename std::basic_istream<CharT,Traits>::sentry s(in); + + if (!s) + return in; + + constexpr auto BASE = pcg128_t(10ULL); + pcg128_t current(0ULL); + bool did_nothing = true; + bool overflow = false; + for(;;) { + CharT wide_ch = in.get(); + if (!in.good()) + break; + auto ch = in.narrow(wide_ch, '\0'); + if (ch < '0' || ch > '9') { + in.unget(); + break; + } + did_nothing = false; + pcg128_t digit(uint32_t(ch - '0')); + pcg128_t timesbase = current*BASE; + overflow = overflow || timesbase < current; + current = timesbase + digit; + overflow = overflow || current < digit; + } + + if (did_nothing || overflow) { + in.setstate(std::ios::failbit); + if (overflow) + current = ~pcg128_t(0ULL); + } + + value = current; + + return in; +} + +/* + * Likewise, if people use tiny rngs, we'll be serializing uint8_t. + * If we just used the provided IO operators, they'd read/write chars, + * not ints, so we need to define our own. We *can* redefine this operator + * here because we're in our own namespace. + */ + +template <typename CharT, typename Traits> +std::basic_ostream<CharT,Traits>& +operator<<(std::basic_ostream<CharT,Traits>&out, uint8_t value) +{ + return out << uint32_t(value); +} + +template <typename CharT, typename Traits> +std::basic_istream<CharT,Traits>& +operator>>(std::basic_istream<CharT,Traits>& in, uint8_t &target) +{ + uint32_t value = 0xdecea5edU; + in >> value; + if (!in && value == 0xdecea5edU) + return in; + if (value > uint8_t(~0)) { + in.setstate(std::ios::failbit); + value = ~0U; + } + target = uint8_t(value); + return in; +} + +/* Unfortunately, the above functions don't get found in preference to the + * built in ones, so we create some more specific overloads that will. + * Ugh. + */ + +inline std::ostream& operator<<(std::ostream& out, uint8_t value) +{ + return pcg_extras::operator<< <char>(out, value); +} + +inline std::istream& operator>>(std::istream& in, uint8_t& value) +{ + return pcg_extras::operator>> <char>(in, value); +} + + + +/* + * Useful bitwise operations. + */ + +/* + * XorShifts are invertable, but they are someting of a pain to invert. + * This function backs them out. It's used by the whacky "inside out" + * generator defined later. + */ + +template <typename itype> +inline itype unxorshift(itype x, bitcount_t bits, bitcount_t shift) +{ + if (2*shift >= bits) { + return x ^ (x >> shift); + } + itype lowmask1 = (itype(1U) << (bits - shift*2)) - 1; + itype highmask1 = ~lowmask1; + itype top1 = x; + itype bottom1 = x & lowmask1; + top1 ^= top1 >> shift; + top1 &= highmask1; + x = top1 | bottom1; + itype lowmask2 = (itype(1U) << (bits - shift)) - 1; + itype bottom2 = x & lowmask2; + bottom2 = unxorshift(bottom2, bits - shift, shift); + bottom2 &= lowmask1; + return top1 | bottom2; +} + +/* + * Rotate left and right. + * + * In ideal world, compilers would spot idiomatic rotate code and convert it + * to a rotate instruction. Of course, opinions vary on what the correct + * idiom is and how to spot it. For clang, sometimes it generates better + * (but still crappy) code if you define PCG_USE_ZEROCHECK_ROTATE_IDIOM. + */ + +template <typename itype> +inline itype rotl(itype value, bitcount_t rot) +{ + constexpr bitcount_t bits = sizeof(itype) * 8; + constexpr bitcount_t mask = bits - 1; +#if PCG_USE_ZEROCHECK_ROTATE_IDIOM + return rot ? (value << rot) | (value >> (bits - rot)) : value; +#else + return (value << rot) | (value >> ((- rot) & mask)); +#endif +} + +template <typename itype> +inline itype rotr(itype value, bitcount_t rot) +{ + constexpr bitcount_t bits = sizeof(itype) * 8; + constexpr bitcount_t mask = bits - 1; +#if PCG_USE_ZEROCHECK_ROTATE_IDIOM + return rot ? (value >> rot) | (value << (bits - rot)) : value; +#else + return (value >> rot) | (value << ((- rot) & mask)); +#endif +} + +/* Unfortunately, both Clang and GCC sometimes perform poorly when it comes + * to properly recognizing idiomatic rotate code, so for we also provide + * assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss. + * (I hope that these compilers get better so that this code can die.) + * + * These overloads will be preferred over the general template code above. + */ +#if PCG_USE_INLINE_ASM && __GNUC__ && (__x86_64__ || __i386__) + +inline uint8_t rotr(uint8_t value, bitcount_t rot) +{ + asm ("rorb %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +} + +inline uint16_t rotr(uint16_t value, bitcount_t rot) +{ + asm ("rorw %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +} + +inline uint32_t rotr(uint32_t value, bitcount_t rot) +{ + asm ("rorl %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +} + +#if __x86_64__ +inline uint64_t rotr(uint64_t value, bitcount_t rot) +{ + asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +} +#endif // __x86_64__ + +#endif // PCG_USE_INLINE_ASM + + +/* + * The C++ SeedSeq concept (modelled by seed_seq) can fill an array of + * 32-bit integers with seed data, but sometimes we want to produce + * larger or smaller integers. + * + * The following code handles this annoyance. + * + * uneven_copy will copy an array of 32-bit ints to an array of larger or + * smaller ints (actually, the code is general it only needing forward + * iterators). The copy is identical to the one that would be performed if + * we just did memcpy on a standard little-endian machine, but works + * regardless of the endian of the machine (or the weirdness of the ints + * involved). + * + * generate_to initializes an array of integers using a SeedSeq + * object. It is given the size as a static constant at compile time and + * tries to avoid memory allocation. If we're filling in 32-bit constants + * we just do it directly. If we need a separate buffer and it's small, + * we allocate it on the stack. Otherwise, we fall back to heap allocation. + * Ugh. + * + * generate_one produces a single value of some integral type using a + * SeedSeq object. + */ + + /* uneven_copy helper, case where destination ints are less than 32 bit. */ + +template<class SrcIter, class DestIter> +SrcIter uneven_copy_impl( + SrcIter src_first, DestIter dest_first, DestIter dest_last, + std::true_type) +{ + typedef typename std::iterator_traits<SrcIter>::value_type src_t; + typedef typename std::iterator_traits<DestIter>::value_type dest_t; + + constexpr bitcount_t SRC_SIZE = sizeof(src_t); + constexpr bitcount_t DEST_SIZE = sizeof(dest_t); + constexpr bitcount_t DEST_BITS = DEST_SIZE * 8; + constexpr bitcount_t SCALE = SRC_SIZE / DEST_SIZE; + + size_t count = 0; + src_t value; + + while (dest_first != dest_last) { + if ((count++ % SCALE) == 0) + value = *src_first++; // Get more bits + else + value >>= DEST_BITS; // Move down bits + + *dest_first++ = dest_t(value); // Truncates, ignores high bits. + } + return src_first; +} + + /* uneven_copy helper, case where destination ints are more than 32 bit. */ + +template<class SrcIter, class DestIter> +SrcIter uneven_copy_impl( + SrcIter src_first, DestIter dest_first, DestIter dest_last, + std::false_type) +{ + typedef typename std::iterator_traits<SrcIter>::value_type src_t; + typedef typename std::iterator_traits<DestIter>::value_type dest_t; + + constexpr auto SRC_SIZE = sizeof(src_t); + constexpr auto SRC_BITS = SRC_SIZE * 8; + constexpr auto DEST_SIZE = sizeof(dest_t); + constexpr auto SCALE = (DEST_SIZE+SRC_SIZE-1) / SRC_SIZE; + + while (dest_first != dest_last) { + dest_t value(0UL); + unsigned int shift = 0; + + for (size_t i = 0; i < SCALE; ++i) { + value |= dest_t(*src_first++) << shift; + shift += SRC_BITS; + } + + *dest_first++ = value; + } + return src_first; +} + +/* uneven_copy, call the right code for larger vs. smaller */ + +template<class SrcIter, class DestIter> +inline SrcIter uneven_copy(SrcIter src_first, + DestIter dest_first, DestIter dest_last) +{ + typedef typename std::iterator_traits<SrcIter>::value_type src_t; + typedef typename std::iterator_traits<DestIter>::value_type dest_t; + + constexpr bool DEST_IS_SMALLER = sizeof(dest_t) < sizeof(src_t); + + return uneven_copy_impl(src_first, dest_first, dest_last, + std::integral_constant<bool, DEST_IS_SMALLER>{}); +} + +/* generate_to, fill in a fixed-size array of integral type using a SeedSeq + * (actually works for any random-access iterator) + */ + +template <size_t size, typename SeedSeq, typename DestIter> +inline void generate_to_impl(SeedSeq&& generator, DestIter dest, + std::true_type) +{ + generator.generate(dest, dest+size); +} + +template <size_t size, typename SeedSeq, typename DestIter> +void generate_to_impl(SeedSeq&& generator, DestIter dest, + std::false_type) +{ + typedef typename std::iterator_traits<DestIter>::value_type dest_t; + constexpr auto DEST_SIZE = sizeof(dest_t); + constexpr auto GEN_SIZE = sizeof(uint32_t); + + constexpr bool GEN_IS_SMALLER = GEN_SIZE < DEST_SIZE; + constexpr size_t FROM_ELEMS = + GEN_IS_SMALLER + ? size * ((DEST_SIZE+GEN_SIZE-1) / GEN_SIZE) + : (size + (GEN_SIZE / DEST_SIZE) - 1) + / ((GEN_SIZE / DEST_SIZE) + GEN_IS_SMALLER); + // this odd code ^^^^^^^^^^^^^^^^^ is work-around for + // a bug: http://llvm.org/bugs/show_bug.cgi?id=21287 + + if (FROM_ELEMS <= 1024) { + uint32_t buffer[FROM_ELEMS]; + generator.generate(buffer, buffer+FROM_ELEMS); + uneven_copy(buffer, dest, dest+size); + } else { + uint32_t* buffer = (uint32_t*) malloc(GEN_SIZE * FROM_ELEMS); + generator.generate(buffer, buffer+FROM_ELEMS); + uneven_copy(buffer, dest, dest+size); + free(buffer); + } +} + +template <size_t size, typename SeedSeq, typename DestIter> +inline void generate_to(SeedSeq&& generator, DestIter dest) +{ + typedef typename std::iterator_traits<DestIter>::value_type dest_t; + constexpr bool IS_32BIT = sizeof(dest_t) == sizeof(uint32_t); + + generate_to_impl<size>(std::forward<SeedSeq>(generator), dest, + std::integral_constant<bool, IS_32BIT>{}); +} + +/* generate_one, produce a value of integral type using a SeedSeq + * (optionally, we can have it produce more than one and pick which one + * we want) + */ + +template <typename UInt, size_t i = 0UL, size_t N = i+1UL, typename SeedSeq> +inline UInt generate_one(SeedSeq&& generator) +{ + UInt result[N]; + generate_to<N>(std::forward<SeedSeq>(generator), result); + return result[i]; +} + +template <typename RngType> +auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound) + -> typename RngType::result_type +{ + typedef typename RngType::result_type rtype; + rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound) + % upper_bound; + for (;;) { + rtype r = rng() - RngType::min(); + if (r >= threshold) + return r % upper_bound; + } +} + +template <typename Iter, typename RandType> +void shuffle(Iter from, Iter to, RandType&& rng) +{ + typedef typename std::iterator_traits<Iter>::difference_type delta_t; + auto count = to - from; + while (count > 1) { + delta_t chosen(bounded_rand(rng, count)); + --count; + --to; + using std::swap; + swap(*(from+chosen), *to); + } +} + +/* + * Although std::seed_seq is useful, it isn't everything. Often we want to + * initialize a random-number generator some other way, such as from a random + * device. + * + * Technically, it does not meet the requirements of a SeedSequence because + * it lacks some of the rarely-used member functions (some of which would + * be impossible to provide). However the C++ standard is quite specific + * that actual engines only called the generate method, so it ought not to be + * a problem in practice. + */ + +template <typename RngType> +class seed_seq_from { +private: + RngType rng_; + + typedef uint_least32_t result_type; + +public: + template<typename... Args> + seed_seq_from(Args&&... args) : + rng_(std::forward<Args>(args)...) + { + // Nothing (else) to do... + } + + template<typename Iter> + void generate(Iter start, Iter finish) + { + for (auto i = start; i != finish; ++i) + *i = result_type(rng_()); + } + + constexpr size_t size() const + { + return (sizeof(typename RngType::result_type) > sizeof(result_type) + && RngType::max() > ~size_t(0UL)) + ? ~size_t(0UL) + : size_t(RngType::max()); + } +}; + +/* + * Sometimes you might want a distinct seed based on when the program + * was compiled. That way, a particular instance of the program will + * behave the same way, but when recompiled it'll produce a different + * value. + */ + +template <typename IntType> +struct static_arbitrary_seed { +private: + static constexpr IntType fnv(IntType hash, const char* pos) { + return *pos == '\0' + ? hash + : fnv((hash * IntType(16777619U)) ^ *pos, (pos+1)); + } + +public: + static constexpr IntType value = fnv(IntType(2166136261U ^ sizeof(IntType)), + __DATE__ __TIME__ __FILE__); +}; + +// Sometimes, when debugging or testing, it's handy to be able print the name +// of a (in human-readable form). This code allows the idiom: +// +// cout << printable_typename<my_foo_type_t>() +// +// to print out my_foo_type_t (or its concrete type if it is a synonym) + +template <typename T> +struct printable_typename {}; + +template <typename T> +std::ostream& operator<<(std::ostream& out, printable_typename<T>) { + const char *implementation_typename = typeid(T).name(); +#ifdef __GNUC__ + int status; + const char* pretty_name = + abi::__cxa_demangle(implementation_typename, NULL, NULL, &status); + if (status == 0) + out << pretty_name; + free((void*) pretty_name); + if (status == 0) + return out; +#endif + out << implementation_typename; + return out; +} + +} // namespace pcg_extras + +#endif // PCG_EXTRAS_HPP_INCLUDED diff --git a/vendor/pcg-cpp-0.98/include/pcg_random.hpp b/vendor/pcg-cpp-0.98/include/pcg_random.hpp new file mode 100644 index 00000000..3f04d854 --- /dev/null +++ b/vendor/pcg-cpp-0.98/include/pcg_random.hpp @@ -0,0 +1,1751 @@ +/* + * PCG Random Number Generation for C++ + * + * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* + * This code provides the reference implementation of the PCG family of + * random number generators. The code is complex because it implements + * + * - several members of the PCG family, specifically members corresponding + * to the output functions: + * - XSH RR (good for 64-bit state, 32-bit output) + * - XSH RS (good for 64-bit state, 32-bit output) + * - XSL RR (good for 128-bit state, 64-bit output) + * - RXS M XS (statistically most powerful generator) + * - XSL RR RR (good for 128-bit state, 128-bit output) + * - and RXS, RXS M, XSH, XSL (mostly for testing) + * - at potentially *arbitrary* bit sizes + * - with four different techniques for random streams (MCG, one-stream + * LCG, settable-stream LCG, unique-stream LCG) + * - and the extended generation schemes allowing arbitrary periods + * - with all features of C++11 random number generation (and more), + * some of which are somewhat painful, including + * - initializing with a SeedSequence which writes 32-bit values + * to memory, even though the state of the generator may not + * use 32-bit values (it might use smaller or larger integers) + * - I/O for RNGs and a prescribed format, which needs to handle + * the issue that 8-bit and 128-bit integers don't have working + * I/O routines (e.g., normally 8-bit = char, not integer) + * - equality and inequality for RNGs + * - and a number of convenience typedefs to mask all the complexity + * + * The code employes a fairly heavy level of abstraction, and has to deal + * with various C++ minutia. If you're looking to learn about how the PCG + * scheme works, you're probably best of starting with one of the other + * codebases (see www.pcg-random.org). But if you're curious about the + * constants for the various output functions used in those other, simpler, + * codebases, this code shows how they are calculated. + * + * On the positive side, at least there are convenience typedefs so that you + * can say + * + * pcg32 myRNG; + * + * rather than: + * + * pcg_detail::engine< + * uint32_t, // Output Type + * uint64_t, // State Type + * pcg_detail::xsh_rr_mixin<uint32_t, uint64_t>, true, // Output Func + * pcg_detail::specific_stream<uint64_t>, // Stream Kind + * pcg_detail::default_multiplier<uint64_t> // LCG Mult + * > myRNG; + * + */ + +#ifndef PCG_RAND_HPP_INCLUDED +#define PCG_RAND_HPP_INCLUDED 1 + +#include <cinttypes> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <cassert> +#include <limits> +#include <iostream> +#include <type_traits> +#include <utility> +#include <locale> +#include <new> +#include <stdexcept> + +/* + * The pcg_extras namespace contains some support code that is likley to + * be useful for a variety of RNGs, including: + * - 128-bit int support for platforms where it isn't available natively + * - bit twiddling operations + * - I/O of 128-bit and 8-bit integers + * - Handling the evilness of SeedSeq + * - Support for efficiently producing random numbers less than a given + * bound + */ + +#include "pcg_extras.hpp" + +namespace pcg_detail { + +using namespace pcg_extras; + +/* + * The LCG generators need some constants to function. This code lets you + * look up the constant by *type*. For example + * + * default_multiplier<uint32_t>::multiplier() + * + * gives you the default multipler for 32-bit integers. We use the name + * of the constant and not a generic word like value to allow these classes + * to be used as mixins. + */ + +template <typename T> +struct default_multiplier { + // Not defined for an arbitrary type +}; + +template <typename T> +struct default_increment { + // Not defined for an arbitrary type +}; + +#define PCG_DEFINE_CONSTANT(type, what, kind, constant) \ + template <> \ + struct what ## _ ## kind<type> { \ + static constexpr type kind() { \ + return constant; \ + } \ + }; + +PCG_DEFINE_CONSTANT(uint8_t, default, multiplier, 141U) +PCG_DEFINE_CONSTANT(uint8_t, default, increment, 77U) + +PCG_DEFINE_CONSTANT(uint16_t, default, multiplier, 12829U) +PCG_DEFINE_CONSTANT(uint16_t, default, increment, 47989U) + +PCG_DEFINE_CONSTANT(uint32_t, default, multiplier, 747796405U) +PCG_DEFINE_CONSTANT(uint32_t, default, increment, 2891336453U) + +PCG_DEFINE_CONSTANT(uint64_t, default, multiplier, 6364136223846793005ULL) +PCG_DEFINE_CONSTANT(uint64_t, default, increment, 1442695040888963407ULL) + +PCG_DEFINE_CONSTANT(pcg128_t, default, multiplier, + PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL)) +PCG_DEFINE_CONSTANT(pcg128_t, default, increment, + PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL)) + + +/* + * Each PCG generator is available in four variants, based on how it applies + * the additive constant for its underlying LCG; the variations are: + * + * single stream - all instances use the same fixed constant, thus + * the RNG always somewhere in same sequence + * mcg - adds zero, resulting in a single stream and reduced + * period + * specific stream - the constant can be changed at any time, selecting + * a different random sequence + * unique stream - the constant is based on the memory addresss of the + * object, thus every RNG has its own unique sequence + * + * This variation is provided though mixin classes which define a function + * value called increment() that returns the nesessary additive constant. + */ + + + +/* + * unique stream + */ + + +template <typename itype> +class unique_stream { +protected: + static constexpr bool is_mcg = false; + + // Is never called, but is provided for symmetry with specific_stream + void set_stream(...) + { + abort(); + } + +public: + typedef itype state_type; + + constexpr itype increment() const { + return itype(reinterpret_cast<unsigned long>(this) | 1); + } + + constexpr itype stream() const + { + return increment() >> 1; + } + + static constexpr bool can_specify_stream = false; + + static constexpr size_t streams_pow2() + { + return (sizeof(itype) < sizeof(size_t) ? sizeof(itype) + : sizeof(size_t))*8 - 1u; + } + +protected: + constexpr unique_stream() = default; +}; + + +/* + * no stream (mcg) + */ + +template <typename itype> +class no_stream { +protected: + static constexpr bool is_mcg = true; + + // Is never called, but is provided for symmetry with specific_stream + void set_stream(...) + { + abort(); + } + +public: + typedef itype state_type; + + static constexpr itype increment() { + return 0; + } + + static constexpr bool can_specify_stream = false; + + static constexpr size_t streams_pow2() + { + return 0u; + } + +protected: + constexpr no_stream() = default; +}; + + +/* + * single stream/sequence (oneseq) + */ + +template <typename itype> +class oneseq_stream : public default_increment<itype> { +protected: + static constexpr bool is_mcg = false; + + // Is never called, but is provided for symmetry with specific_stream + void set_stream(...) + { + abort(); + } + +public: + typedef itype state_type; + + static constexpr itype stream() + { + return default_increment<itype>::increment() >> 1; + } + + static constexpr bool can_specify_stream = false; + + static constexpr size_t streams_pow2() + { + return 0u; + } + +protected: + constexpr oneseq_stream() = default; +}; + + +/* + * specific stream + */ + +template <typename itype> +class specific_stream { +protected: + static constexpr bool is_mcg = false; + + itype inc_ = default_increment<itype>::increment(); + +public: + typedef itype state_type; + typedef itype stream_state; + + constexpr itype increment() const { + return inc_; + } + + itype stream() + { + return inc_ >> 1; + } + + void set_stream(itype specific_seq) + { + inc_ = (specific_seq << 1) | 1; + } + + static constexpr bool can_specify_stream = true; + + static constexpr size_t streams_pow2() + { + return (sizeof(itype)*8) - 1u; + } + +protected: + specific_stream() = default; + + specific_stream(itype specific_seq) + : inc_((specific_seq << 1) | itype(1U)) + { + // Nothing (else) to do. + } +}; + + +/* + * This is where it all comes together. This function joins together three + * mixin classes which define + * - the LCG additive constant (the stream) + * - the LCG multiplier + * - the output function + * in addition, we specify the type of the LCG state, and the result type, + * and whether to use the pre-advance version of the state for the output + * (increasing instruction-level parallelism) or the post-advance version + * (reducing register pressure). + * + * Given the high level of parameterization, the code has to use some + * template-metaprogramming tricks to handle some of the suble variations + * involved. + */ + +template <typename xtype, typename itype, + typename output_mixin, + bool output_previous = true, + typename stream_mixin = oneseq_stream<itype>, + typename multiplier_mixin = default_multiplier<itype> > +class engine : protected output_mixin, + public stream_mixin, + protected multiplier_mixin { +protected: + itype state_; + + struct can_specify_stream_tag {}; + struct no_specifiable_stream_tag {}; + + using stream_mixin::increment; + using multiplier_mixin::multiplier; + +public: + typedef xtype result_type; + typedef itype state_type; + + static constexpr size_t period_pow2() + { + return sizeof(state_type)*8 - 2*stream_mixin::is_mcg; + } + + // It would be nice to use std::numeric_limits for these, but + // we can't be sure that it'd be defined for the 128-bit types. + + static constexpr result_type min() + { + return result_type(0UL); + } + + static constexpr result_type max() + { + return ~result_type(0UL); + } + +protected: + itype bump(itype state) + { + return state * multiplier() + increment(); + } + + itype base_generate() + { + return state_ = bump(state_); + } + + itype base_generate0() + { + itype old_state = state_; + state_ = bump(state_); + return old_state; + } + +public: + result_type operator()() + { + if (output_previous) + return this->output(base_generate0()); + else + return this->output(base_generate()); + } + + result_type operator()(result_type upper_bound) + { + return bounded_rand(*this, upper_bound); + } + +protected: + static itype advance(itype state, itype delta, + itype cur_mult, itype cur_plus); + + static itype distance(itype cur_state, itype newstate, itype cur_mult, + itype cur_plus, itype mask = ~itype(0U)); + + itype distance(itype newstate, itype mask = ~itype(0U)) const + { + return distance(state_, newstate, multiplier(), increment(), mask); + } + +public: + void advance(itype delta) + { + state_ = advance(state_, delta, this->multiplier(), this->increment()); + } + + void backstep(itype delta) + { + advance(-delta); + } + + void discard(itype delta) + { + advance(delta); + } + + bool wrapped() + { + if (stream_mixin::is_mcg) { + // For MCGs, the low order two bits never change. In this + // implementation, we keep them fixed at 3 to make this test + // easier. + return state_ == 3; + } else { + return state_ == 0; + } + } + + engine(itype state = itype(0xcafef00dd15ea5e5ULL)) + : state_(this->is_mcg ? state|state_type(3U) + : bump(state + this->increment())) + { + // Nothing else to do. + } + + // This function may or may not exist. It thus has to be a template + // to use SFINAE; users don't have to worry about its template-ness. + + template <typename sm = stream_mixin> + engine(itype state, typename sm::stream_state stream_seed) + : stream_mixin(stream_seed), + state_(this->is_mcg ? state|state_type(3U) + : bump(state + this->increment())) + { + // Nothing else to do. + } + + template<typename SeedSeq> + engine(SeedSeq&& seedSeq, typename std::enable_if< + !stream_mixin::can_specify_stream + && !std::is_convertible<SeedSeq, itype>::value + && !std::is_convertible<SeedSeq, engine>::value, + no_specifiable_stream_tag>::type = {}) + : engine(generate_one<itype>(std::forward<SeedSeq>(seedSeq))) + { + // Nothing else to do. + } + + template<typename SeedSeq> + engine(SeedSeq&& seedSeq, typename std::enable_if< + stream_mixin::can_specify_stream + && !std::is_convertible<SeedSeq, itype>::value + && !std::is_convertible<SeedSeq, engine>::value, + can_specify_stream_tag>::type = {}) + : engine(generate_one<itype,1,2>(seedSeq), + generate_one<itype,0,2>(seedSeq)) + { + // Nothing else to do. + } + + + template<typename... Args> + void seed(Args&&... args) + { + new (this) engine(std::forward<Args>(args)...); + } + + template <typename xtype1, typename itype1, + typename output_mixin1, bool output_previous1, + typename stream_mixin_lhs, typename multiplier_mixin_lhs, + typename stream_mixin_rhs, typename multiplier_mixin_rhs> + friend bool operator==(const engine<xtype1,itype1, + output_mixin1,output_previous1, + stream_mixin_lhs, multiplier_mixin_lhs>&, + const engine<xtype1,itype1, + output_mixin1,output_previous1, + stream_mixin_rhs, multiplier_mixin_rhs>&); + + template <typename xtype1, typename itype1, + typename output_mixin1, bool output_previous1, + typename stream_mixin_lhs, typename multiplier_mixin_lhs, + typename stream_mixin_rhs, typename multiplier_mixin_rhs> + friend itype1 operator-(const engine<xtype1,itype1, + output_mixin1,output_previous1, + stream_mixin_lhs, multiplier_mixin_lhs>&, + const engine<xtype1,itype1, + output_mixin1,output_previous1, + stream_mixin_rhs, multiplier_mixin_rhs>&); + + template <typename CharT, typename Traits, + typename xtype1, typename itype1, + typename output_mixin1, bool output_previous1, + typename stream_mixin1, typename multiplier_mixin1> + friend std::basic_ostream<CharT,Traits>& + operator<<(std::basic_ostream<CharT,Traits>& out, + const engine<xtype1,itype1, + output_mixin1,output_previous1, + stream_mixin1, multiplier_mixin1>&); + + template <typename CharT, typename Traits, + typename xtype1, typename itype1, + typename output_mixin1, bool output_previous1, + typename stream_mixin1, typename multiplier_mixin1> + friend std::basic_istream<CharT,Traits>& + operator>>(std::basic_istream<CharT,Traits>& in, + engine<xtype1, itype1, + output_mixin1, output_previous1, + stream_mixin1, multiplier_mixin1>& rng); +}; + +template <typename CharT, typename Traits, + typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin, typename multiplier_mixin> +std::basic_ostream<CharT,Traits>& +operator<<(std::basic_ostream<CharT,Traits>& out, + const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin, multiplier_mixin>& rng) +{ + auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left); + auto space = out.widen(' '); + auto orig_fill = out.fill(); + + out << rng.multiplier() << space + << rng.increment() << space + << rng.state_; + + out.flags(orig_flags); + out.fill(orig_fill); + return out; +} + + +template <typename CharT, typename Traits, + typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin, typename multiplier_mixin> +std::basic_istream<CharT,Traits>& +operator>>(std::basic_istream<CharT,Traits>& in, + engine<xtype,itype, + output_mixin,output_previous, + stream_mixin, multiplier_mixin>& rng) +{ + auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws); + + itype multiplier, increment, state; + in >> multiplier >> increment >> state; + + if (!in.fail()) { + bool good = true; + if (multiplier != rng.multiplier()) { + good = false; + } else if (rng.can_specify_stream) { + rng.set_stream(increment >> 1); + } else if (increment != rng.increment()) { + good = false; + } + if (good) { + rng.state_ = state; + } else { + in.clear(std::ios::failbit); + } + } + + in.flags(orig_flags); + return in; +} + + +template <typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin, typename multiplier_mixin> +itype engine<xtype,itype,output_mixin,output_previous,stream_mixin, + multiplier_mixin>::advance( + itype state, itype delta, itype cur_mult, itype cur_plus) +{ + // The method used here is based on Brown, "Random Number Generation + // with Arbitrary Stride,", Transactions of the American Nuclear + // Society (Nov. 1994). The algorithm is very similar to fast + // exponentiation. + // + // Even though delta is an unsigned integer, we can pass a + // signed integer to go backwards, it just goes "the long way round". + + constexpr itype ZERO = 0u; // itype may be a non-trivial types, so + constexpr itype ONE = 1u; // we define some ugly constants. + itype acc_mult = 1; + itype acc_plus = 0; + while (delta > ZERO) { + if (delta & ONE) { + acc_mult *= cur_mult; + acc_plus = acc_plus*cur_mult + cur_plus; + } + cur_plus = (cur_mult+ONE)*cur_plus; + cur_mult *= cur_mult; + delta >>= 1; + } + return acc_mult * state + acc_plus; +} + +template <typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin, typename multiplier_mixin> +itype engine<xtype,itype,output_mixin,output_previous,stream_mixin, + multiplier_mixin>::distance( + itype cur_state, itype newstate, itype cur_mult, itype cur_plus, itype mask) +{ + constexpr itype ONE = 1u; // itype could be weird, so use constant + itype the_bit = stream_mixin::is_mcg ? itype(4u) : itype(1u); + itype distance = 0u; + while ((cur_state & mask) != (newstate & mask)) { + if ((cur_state & the_bit) != (newstate & the_bit)) { + cur_state = cur_state * cur_mult + cur_plus; + distance |= the_bit; + } + assert((cur_state & the_bit) == (newstate & the_bit)); + the_bit <<= 1; + cur_plus = (cur_mult+ONE)*cur_plus; + cur_mult *= cur_mult; + } + return stream_mixin::is_mcg ? distance >> 2 : distance; +} + +template <typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin_lhs, typename multiplier_mixin_lhs, + typename stream_mixin_rhs, typename multiplier_mixin_rhs> +itype operator-(const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin_lhs, multiplier_mixin_lhs>& lhs, + const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin_rhs, multiplier_mixin_rhs>& rhs) +{ + if (lhs.multiplier() != rhs.multiplier() + || lhs.increment() != rhs.increment()) + throw std::logic_error("incomparable generators"); + return rhs.distance(lhs.state_); +} + + +template <typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin_lhs, typename multiplier_mixin_lhs, + typename stream_mixin_rhs, typename multiplier_mixin_rhs> +bool operator==(const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin_lhs, multiplier_mixin_lhs>& lhs, + const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin_rhs, multiplier_mixin_rhs>& rhs) +{ + return (lhs.multiplier() == rhs.multiplier()) + && (lhs.increment() == rhs.increment()) + && (lhs.state_ == rhs.state_); +} + +template <typename xtype, typename itype, + typename output_mixin, bool output_previous, + typename stream_mixin_lhs, typename multiplier_mixin_lhs, + typename stream_mixin_rhs, typename multiplier_mixin_rhs> +inline bool operator!=(const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin_lhs, multiplier_mixin_lhs>& lhs, + const engine<xtype,itype, + output_mixin,output_previous, + stream_mixin_rhs, multiplier_mixin_rhs>& rhs) +{ + return !operator==(lhs,rhs); +} + + +template <typename xtype, typename itype, + template<typename XT,typename IT> class output_mixin, + bool output_previous = (sizeof(itype) <= 8)> +using oneseq_base = engine<xtype, itype, + output_mixin<xtype, itype>, output_previous, + oneseq_stream<itype> >; + +template <typename xtype, typename itype, + template<typename XT,typename IT> class output_mixin, + bool output_previous = (sizeof(itype) <= 8)> +using unique_base = engine<xtype, itype, + output_mixin<xtype, itype>, output_previous, + unique_stream<itype> >; + +template <typename xtype, typename itype, + template<typename XT,typename IT> class output_mixin, + bool output_previous = (sizeof(itype) <= 8)> +using setseq_base = engine<xtype, itype, + output_mixin<xtype, itype>, output_previous, + specific_stream<itype> >; + +template <typename xtype, typename itype, + template<typename XT,typename IT> class output_mixin, + bool output_previous = (sizeof(itype) <= 8)> +using mcg_base = engine<xtype, itype, + output_mixin<xtype, itype>, output_previous, + no_stream<itype> >; + +/* + * OUTPUT FUNCTIONS. + * + * These are the core of the PCG generation scheme. They specify how to + * turn the base LCG's internal state into the output value of the final + * generator. + * + * They're implemented as mixin classes. + * + * All of the classes have code that is written to allow it to be applied + * at *arbitrary* bit sizes, although in practice they'll only be used at + * standard sizes supported by C++. + */ + +/* + * XSH RS -- high xorshift, followed by a random shift + * + * Fast. A good performer. + */ + +template <typename xtype, typename itype> +struct xsh_rs_mixin { + static xtype output(itype internal) + { + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); + constexpr bitcount_t sparebits = bits - xtypebits; + constexpr bitcount_t opbits = + sparebits-5 >= 64 ? 5 + : sparebits-4 >= 32 ? 4 + : sparebits-3 >= 16 ? 3 + : sparebits-2 >= 4 ? 2 + : sparebits-1 >= 1 ? 1 + : 0; + constexpr bitcount_t mask = (1 << opbits) - 1; + constexpr bitcount_t maxrandshift = mask; + constexpr bitcount_t topspare = opbits; + constexpr bitcount_t bottomspare = sparebits - topspare; + constexpr bitcount_t xshift = topspare + (xtypebits+maxrandshift)/2; + bitcount_t rshift = + opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; + internal ^= internal >> xshift; + xtype result = xtype(internal >> (bottomspare - maxrandshift + rshift)); + return result; + } +}; + +/* + * XSH RR -- high xorshift, followed by a random rotate + * + * Fast. A good performer. Slightly better statistically than XSH RS. + */ + +template <typename xtype, typename itype> +struct xsh_rr_mixin { + static xtype output(itype internal) + { + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype)*8); + constexpr bitcount_t sparebits = bits - xtypebits; + constexpr bitcount_t wantedopbits = + xtypebits >= 128 ? 7 + : xtypebits >= 64 ? 6 + : xtypebits >= 32 ? 5 + : xtypebits >= 16 ? 4 + : 3; + constexpr bitcount_t opbits = + sparebits >= wantedopbits ? wantedopbits + : sparebits; + constexpr bitcount_t amplifier = wantedopbits - opbits; + constexpr bitcount_t mask = (1 << opbits) - 1; + constexpr bitcount_t topspare = opbits; + constexpr bitcount_t bottomspare = sparebits - topspare; + constexpr bitcount_t xshift = (topspare + xtypebits)/2; + bitcount_t rot = opbits ? bitcount_t(internal >> (bits - opbits)) & mask + : 0; + bitcount_t amprot = (rot << amplifier) & mask; + internal ^= internal >> xshift; + xtype result = xtype(internal >> bottomspare); + result = rotr(result, amprot); + return result; + } +}; + +/* + * RXS -- random xorshift + */ + +template <typename xtype, typename itype> +struct rxs_mixin { +static xtype output_rxs(itype internal) + { + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype)*8); + constexpr bitcount_t shift = bits - xtypebits; + constexpr bitcount_t extrashift = (xtypebits - shift)/2; + bitcount_t rshift = shift > 64+8 ? (internal >> (bits - 6)) & 63 + : shift > 32+4 ? (internal >> (bits - 5)) & 31 + : shift > 16+2 ? (internal >> (bits - 4)) & 15 + : shift > 8+1 ? (internal >> (bits - 3)) & 7 + : shift > 4+1 ? (internal >> (bits - 2)) & 3 + : shift > 2+1 ? (internal >> (bits - 1)) & 1 + : 0; + internal ^= internal >> (shift + extrashift - rshift); + xtype result = internal >> rshift; + return result; + } +}; + +/* + * RXS M XS -- random xorshift, mcg multiply, fixed xorshift + * + * The most statistically powerful generator, but all those steps + * make it slower than some of the others. We give it the rottenest jobs. + * + * Because it's usually used in contexts where the state type and the + * result type are the same, it is a permutation and is thus invertable. + * We thus provide a function to invert it. This function is used to + * for the "inside out" generator used by the extended generator. + */ + +/* Defined type-based concepts for the multiplication step. They're actually + * all derived by truncating the 128-bit, which was computed to be a good + * "universal" constant. + */ + +template <typename T> +struct mcg_multiplier { + // Not defined for an arbitrary type +}; + +template <typename T> +struct mcg_unmultiplier { + // Not defined for an arbitrary type +}; + +PCG_DEFINE_CONSTANT(uint8_t, mcg, multiplier, 217U) +PCG_DEFINE_CONSTANT(uint8_t, mcg, unmultiplier, 105U) + +PCG_DEFINE_CONSTANT(uint16_t, mcg, multiplier, 62169U) +PCG_DEFINE_CONSTANT(uint16_t, mcg, unmultiplier, 28009U) + +PCG_DEFINE_CONSTANT(uint32_t, mcg, multiplier, 277803737U) +PCG_DEFINE_CONSTANT(uint32_t, mcg, unmultiplier, 2897767785U) + +PCG_DEFINE_CONSTANT(uint64_t, mcg, multiplier, 12605985483714917081ULL) +PCG_DEFINE_CONSTANT(uint64_t, mcg, unmultiplier, 15009553638781119849ULL) + +PCG_DEFINE_CONSTANT(pcg128_t, mcg, multiplier, + PCG_128BIT_CONSTANT(17766728186571221404ULL, 12605985483714917081ULL)) +PCG_DEFINE_CONSTANT(pcg128_t, mcg, unmultiplier, + PCG_128BIT_CONSTANT(14422606686972528997ULL, 15009553638781119849ULL)) + + +template <typename xtype, typename itype> +struct rxs_m_xs_mixin { + static xtype output(itype internal) + { + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t opbits = xtypebits >= 128 ? 6 + : xtypebits >= 64 ? 5 + : xtypebits >= 32 ? 4 + : xtypebits >= 16 ? 3 + : 2; + constexpr bitcount_t shift = bits - xtypebits; + constexpr bitcount_t mask = (1 << opbits) - 1; + bitcount_t rshift = + opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; + internal ^= internal >> (opbits + rshift); + internal *= mcg_multiplier<itype>::multiplier(); + xtype result = internal >> shift; + result ^= result >> ((2U*xtypebits+2U)/3U); + return result; + } + + static itype unoutput(itype internal) + { + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t opbits = bits >= 128 ? 6 + : bits >= 64 ? 5 + : bits >= 32 ? 4 + : bits >= 16 ? 3 + : 2; + constexpr bitcount_t mask = (1 << opbits) - 1; + + internal = unxorshift(internal, bits, (2U*bits+2U)/3U); + + internal *= mcg_unmultiplier<itype>::unmultiplier(); + + bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0; + internal = unxorshift(internal, bits, opbits + rshift); + + return internal; + } +}; + + +/* + * RXS M -- random xorshift, mcg multiply + */ + +template <typename xtype, typename itype> +struct rxs_m_mixin { + static xtype output(itype internal) + { + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t opbits = xtypebits >= 128 ? 6 + : xtypebits >= 64 ? 5 + : xtypebits >= 32 ? 4 + : xtypebits >= 16 ? 3 + : 2; + constexpr bitcount_t shift = bits - xtypebits; + constexpr bitcount_t mask = (1 << opbits) - 1; + bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0; + internal ^= internal >> (opbits + rshift); + internal *= mcg_multiplier<itype>::multiplier(); + xtype result = internal >> shift; + return result; + } +}; + +/* + * XSL RR -- fixed xorshift (to low bits), random rotate + * + * Useful for 128-bit types that are split across two CPU registers. + */ + +template <typename xtype, typename itype> +struct xsl_rr_mixin { + static xtype output(itype internal) + { + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t sparebits = bits - xtypebits; + constexpr bitcount_t wantedopbits = xtypebits >= 128 ? 7 + : xtypebits >= 64 ? 6 + : xtypebits >= 32 ? 5 + : xtypebits >= 16 ? 4 + : 3; + constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits + : sparebits; + constexpr bitcount_t amplifier = wantedopbits - opbits; + constexpr bitcount_t mask = (1 << opbits) - 1; + constexpr bitcount_t topspare = sparebits; + constexpr bitcount_t bottomspare = sparebits - topspare; + constexpr bitcount_t xshift = (topspare + xtypebits) / 2; + + bitcount_t rot = + opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; + bitcount_t amprot = (rot << amplifier) & mask; + internal ^= internal >> xshift; + xtype result = xtype(internal >> bottomspare); + result = rotr(result, amprot); + return result; + } +}; + + +/* + * XSL RR RR -- fixed xorshift (to low bits), random rotate (both parts) + * + * Useful for 128-bit types that are split across two CPU registers. + * If you really want an invertable 128-bit RNG, I guess this is the one. + */ + +template <typename T> struct halfsize_trait {}; +template <> struct halfsize_trait<pcg128_t> { typedef uint64_t type; }; +template <> struct halfsize_trait<uint64_t> { typedef uint32_t type; }; +template <> struct halfsize_trait<uint32_t> { typedef uint16_t type; }; +template <> struct halfsize_trait<uint16_t> { typedef uint8_t type; }; + +template <typename xtype, typename itype> +struct xsl_rr_rr_mixin { + typedef typename halfsize_trait<itype>::type htype; + + static itype output(itype internal) + { + constexpr bitcount_t htypebits = bitcount_t(sizeof(htype) * 8); + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t sparebits = bits - htypebits; + constexpr bitcount_t wantedopbits = htypebits >= 128 ? 7 + : htypebits >= 64 ? 6 + : htypebits >= 32 ? 5 + : htypebits >= 16 ? 4 + : 3; + constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits + : sparebits; + constexpr bitcount_t amplifier = wantedopbits - opbits; + constexpr bitcount_t mask = (1 << opbits) - 1; + constexpr bitcount_t topspare = sparebits; + constexpr bitcount_t xshift = (topspare + htypebits) / 2; + + bitcount_t rot = + opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; + bitcount_t amprot = (rot << amplifier) & mask; + internal ^= internal >> xshift; + htype lowbits = htype(internal); + lowbits = rotr(lowbits, amprot); + htype highbits = htype(internal >> topspare); + bitcount_t rot2 = lowbits & mask; + bitcount_t amprot2 = (rot2 << amplifier) & mask; + highbits = rotr(highbits, amprot2); + return (itype(highbits) << topspare) ^ itype(lowbits); + } +}; + + +/* + * XSH -- fixed xorshift (to high bits) + * + * You shouldn't use this at 64-bits or less. + */ + +template <typename xtype, typename itype> +struct xsh_mixin { + static xtype output(itype internal) + { + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t sparebits = bits - xtypebits; + constexpr bitcount_t topspare = 0; + constexpr bitcount_t bottomspare = sparebits - topspare; + constexpr bitcount_t xshift = (topspare + xtypebits) / 2; + + internal ^= internal >> xshift; + xtype result = internal >> bottomspare; + return result; + } +}; + +/* + * XSL -- fixed xorshift (to low bits) + * + * You shouldn't use this at 64-bits or less. + */ + +template <typename xtype, typename itype> +struct xsl_mixin { + inline xtype output(itype internal) + { + constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); + constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); + constexpr bitcount_t sparebits = bits - xtypebits; + constexpr bitcount_t topspare = sparebits; + constexpr bitcount_t bottomspare = sparebits - topspare; + constexpr bitcount_t xshift = (topspare + xtypebits) / 2; + + internal ^= internal >> xshift; + xtype result = internal >> bottomspare; + return result; + } +}; + +/* ---- End of Output Functions ---- */ + + +template <typename baseclass> +struct inside_out : private baseclass { + inside_out() = delete; + + typedef typename baseclass::result_type result_type; + typedef typename baseclass::state_type state_type; + static_assert(sizeof(result_type) == sizeof(state_type), + "Require a RNG whose output function is a permutation"); + + static bool external_step(result_type& randval, size_t i) + { + state_type state = baseclass::unoutput(randval); + state = state * baseclass::multiplier() + baseclass::increment() + + state_type(i*2); + result_type result = baseclass::output(state); + randval = result; + state_type zero = + baseclass::is_mcg ? state & state_type(3U) : state_type(0U); + return result == zero; + } + + static bool external_advance(result_type& randval, size_t i, + result_type delta, bool forwards = true) + { + state_type state = baseclass::unoutput(randval); + state_type mult = baseclass::multiplier(); + state_type inc = baseclass::increment() + state_type(i*2); + state_type zero = + baseclass::is_mcg ? state & state_type(3U) : state_type(0U); + state_type dist_to_zero = baseclass::distance(state, zero, mult, inc); + bool crosses_zero = + forwards ? dist_to_zero <= delta + : (-dist_to_zero) <= delta; + if (!forwards) + delta = -delta; + state = baseclass::advance(state, delta, mult, inc); + randval = baseclass::output(state); + return crosses_zero; + } +}; + + +template <bitcount_t table_pow2, bitcount_t advance_pow2, typename baseclass, typename extvalclass, bool kdd = true> +class extended : public baseclass { +public: + typedef typename baseclass::state_type state_type; + typedef typename baseclass::result_type result_type; + typedef inside_out<extvalclass> insideout; + +private: + static constexpr bitcount_t rtypebits = sizeof(result_type)*8; + static constexpr bitcount_t stypebits = sizeof(state_type)*8; + + static constexpr bitcount_t tick_limit_pow2 = 64U; + + static constexpr size_t table_size = 1UL << table_pow2; + static constexpr size_t table_shift = stypebits - table_pow2; + static constexpr state_type table_mask = + (state_type(1U) << table_pow2) - state_type(1U); + + static constexpr bool may_tick = + (advance_pow2 < stypebits) && (advance_pow2 < tick_limit_pow2); + static constexpr size_t tick_shift = stypebits - advance_pow2; + static constexpr state_type tick_mask = + may_tick ? state_type( + (uint64_t(1) << (advance_pow2*may_tick)) - 1) + // ^-- stupidity to appease GCC warnings + : ~state_type(0U); + + static constexpr bool may_tock = stypebits < tick_limit_pow2; + + result_type data_[table_size]; + + PCG_NOINLINE void advance_table(); + + PCG_NOINLINE void advance_table(state_type delta, bool isForwards = true); + + result_type& get_extended_value() + { + state_type state = this->state_; + if (kdd && baseclass::is_mcg) { + // The low order bits of an MCG are constant, so drop them. + state >>= 2; + } + size_t index = kdd ? state & table_mask + : state >> table_shift; + + if (may_tick) { + bool tick = kdd ? (state & tick_mask) == state_type(0u) + : (state >> tick_shift) == state_type(0u); + if (tick) + advance_table(); + } + if (may_tock) { + bool tock = state == state_type(0u); + if (tock) + advance_table(); + } + return data_[index]; + } + +public: + static constexpr size_t period_pow2() + { + return baseclass::period_pow2() + table_size*extvalclass::period_pow2(); + } + + __attribute__((always_inline)) result_type operator()() + { + result_type rhs = get_extended_value(); + result_type lhs = this->baseclass::operator()(); + return lhs ^ rhs; + } + + result_type operator()(result_type upper_bound) + { + return bounded_rand(*this, upper_bound); + } + + void set(result_type wanted) + { + result_type& rhs = get_extended_value(); + result_type lhs = this->baseclass::operator()(); + rhs = lhs ^ wanted; + } + + void advance(state_type distance, bool forwards = true); + + void backstep(state_type distance) + { + advance(distance, false); + } + + extended(const result_type* data) + : baseclass() + { + datainit(data); + } + + extended(const result_type* data, state_type seed) + : baseclass(seed) + { + datainit(data); + } + + // This function may or may not exist. It thus has to be a template + // to use SFINAE; users don't have to worry about its template-ness. + + template <typename bc = baseclass> + extended(const result_type* data, state_type seed, + typename bc::stream_state stream_seed) + : baseclass(seed, stream_seed) + { + datainit(data); + } + + extended() + : baseclass() + { + selfinit(); + } + + extended(state_type seed) + : baseclass(seed) + { + selfinit(); + } + + // This function may or may not exist. It thus has to be a template + // to use SFINAE; users don't have to worry about its template-ness. + + template <typename bc = baseclass> + extended(state_type seed, typename bc::stream_state stream_seed) + : baseclass(seed, stream_seed) + { + selfinit(); + } + +private: + void selfinit(); + void datainit(const result_type* data); + +public: + + template<typename SeedSeq, typename = typename std::enable_if< + !std::is_convertible<SeedSeq, result_type>::value + && !std::is_convertible<SeedSeq, extended>::value>::type> + extended(SeedSeq&& seedSeq) + : baseclass(seedSeq) + { + generate_to<table_size>(seedSeq, data_); + } + + template<typename... Args> + void seed(Args&&... args) + { + new (this) extended(std::forward<Args>(args)...); + } + + template <bitcount_t table_pow2_, bitcount_t advance_pow2_, + typename baseclass_, typename extvalclass_, bool kdd_> + friend bool operator==(const extended<table_pow2_, advance_pow2_, + baseclass_, extvalclass_, kdd_>&, + const extended<table_pow2_, advance_pow2_, + baseclass_, extvalclass_, kdd_>&); + + template <typename CharT, typename Traits, + bitcount_t table_pow2_, bitcount_t advance_pow2_, + typename baseclass_, typename extvalclass_, bool kdd_> + friend std::basic_ostream<CharT,Traits>& + operator<<(std::basic_ostream<CharT,Traits>& out, + const extended<table_pow2_, advance_pow2_, + baseclass_, extvalclass_, kdd_>&); + + template <typename CharT, typename Traits, + bitcount_t table_pow2_, bitcount_t advance_pow2_, + typename baseclass_, typename extvalclass_, bool kdd_> + friend std::basic_istream<CharT,Traits>& + operator>>(std::basic_istream<CharT,Traits>& in, + extended<table_pow2_, advance_pow2_, + baseclass_, extvalclass_, kdd_>&); + +}; + + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +void extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::datainit( + const result_type* data) +{ + for (size_t i = 0; i < table_size; ++i) + data_[i] = data[i]; +} + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +void extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::selfinit() +{ + // We need to fill the extended table with something, and we have + // very little provided data, so we use the base generator to + // produce values. Although not ideal (use a seed sequence, folks!), + // unexpected correlations are mitigated by + // - using XOR differences rather than the number directly + // - the way the table is accessed, its values *won't* be accessed + // in the same order the were written. + // - any strange correlations would only be apparent if we + // were to backstep the generator so that the base generator + // was generating the same values again + result_type xdiff = baseclass::operator()() - baseclass::operator()(); + for (size_t i = 0; i < table_size; ++i) { + data_[i] = baseclass::operator()() ^ xdiff; + } +} + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +bool operator==(const extended<table_pow2, advance_pow2, + baseclass, extvalclass, kdd>& lhs, + const extended<table_pow2, advance_pow2, + baseclass, extvalclass, kdd>& rhs) +{ + auto& base_lhs = static_cast<const baseclass&>(lhs); + auto& base_rhs = static_cast<const baseclass&>(rhs); + return base_lhs == base_rhs + && !memcmp((void*) lhs.data_, (void*) rhs.data_, sizeof(lhs.data_)); +} + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +inline bool operator!=(const extended<table_pow2, advance_pow2, + baseclass, extvalclass, kdd>& lhs, + const extended<table_pow2, advance_pow2, + baseclass, extvalclass, kdd>& rhs) +{ + return lhs != rhs; +} + +template <typename CharT, typename Traits, + bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +std::basic_ostream<CharT,Traits>& +operator<<(std::basic_ostream<CharT,Traits>& out, + const extended<table_pow2, advance_pow2, + baseclass, extvalclass, kdd>& rng) +{ + auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left); + auto space = out.widen(' '); + auto orig_fill = out.fill(); + + out << rng.multiplier() << space + << rng.increment() << space + << rng.state_; + + for (const auto& datum : rng.data_) + out << space << datum; + + out.flags(orig_flags); + out.fill(orig_fill); + return out; +} + +template <typename CharT, typename Traits, + bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +std::basic_istream<CharT,Traits>& +operator>>(std::basic_istream<CharT,Traits>& in, + extended<table_pow2, advance_pow2, + baseclass, extvalclass, kdd>& rng) +{ + extended<table_pow2, advance_pow2, baseclass, extvalclass> new_rng; + auto& base_rng = static_cast<baseclass&>(new_rng); + in >> base_rng; + + if (in.fail()) + return in; + + auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws); + + for (auto& datum : new_rng.data_) { + in >> datum; + if (in.fail()) + goto bail; + } + + rng = new_rng; + +bail: + in.flags(orig_flags); + return in; +} + + + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +void +extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance_table() +{ + bool carry = false; + for (size_t i = 0; i < table_size; ++i) { + if (carry) { + carry = insideout::external_step(data_[i],i+1); + } + bool carry2 = insideout::external_step(data_[i],i+1); + carry = carry || carry2; + } +} + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +void +extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance_table( + state_type delta, bool isForwards) +{ + typedef typename baseclass::state_type base_state_t; + typedef typename extvalclass::state_type ext_state_t; + constexpr bitcount_t basebits = sizeof(base_state_t)*8; + constexpr bitcount_t extbits = sizeof(ext_state_t)*8; + static_assert(basebits <= extbits || advance_pow2 > 0, + "Current implementation might overflow its carry"); + + base_state_t carry = 0; + for (size_t i = 0; i < table_size; ++i) { + base_state_t total_delta = carry + delta; + ext_state_t trunc_delta = ext_state_t(total_delta); + if (basebits > extbits) { + carry = total_delta >> extbits; + } else { + carry = 0; + } + carry += + insideout::external_advance(data_[i],i+1, trunc_delta, isForwards); + } +} + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename baseclass, typename extvalclass, bool kdd> +void extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance( + state_type distance, bool forwards) +{ + static_assert(kdd, + "Efficient advance is too hard for non-kdd extension. " + "For a weak advance, cast to base class"); + state_type zero = + baseclass::is_mcg ? this->state_ & state_type(3U) : state_type(0U); + if (may_tick) { + state_type ticks = distance >> (advance_pow2*may_tick); + // ^-- stupidity to appease GCC + // warnings + state_type adv_mask = + baseclass::is_mcg ? tick_mask << 2 : tick_mask; + state_type next_advance_distance = this->distance(zero, adv_mask); + if (!forwards) + next_advance_distance = (-next_advance_distance) & tick_mask; + if (next_advance_distance < (distance & tick_mask)) { + ++ticks; + } + if (ticks) + advance_table(ticks, forwards); + } + if (forwards) { + if (may_tock && this->distance(zero) <= distance) + advance_table(); + baseclass::advance(distance); + } else { + if (may_tock && -(this->distance(zero)) <= distance) + advance_table(state_type(1U), false); + baseclass::advance(-distance); + } +} + +} // namespace pcg_detail + +namespace pcg_engines { + +using namespace pcg_detail; + +/* Predefined types for XSH RS */ + +typedef oneseq_base<uint8_t, uint16_t, xsh_rs_mixin> oneseq_xsh_rs_16_8; +typedef oneseq_base<uint16_t, uint32_t, xsh_rs_mixin> oneseq_xsh_rs_32_16; +typedef oneseq_base<uint32_t, uint64_t, xsh_rs_mixin> oneseq_xsh_rs_64_32; +typedef oneseq_base<uint64_t, pcg128_t, xsh_rs_mixin> oneseq_xsh_rs_128_64; + +typedef unique_base<uint8_t, uint16_t, xsh_rs_mixin> unique_xsh_rs_16_8; +typedef unique_base<uint16_t, uint32_t, xsh_rs_mixin> unique_xsh_rs_32_16; +typedef unique_base<uint32_t, uint64_t, xsh_rs_mixin> unique_xsh_rs_64_32; +typedef unique_base<uint64_t, pcg128_t, xsh_rs_mixin> unique_xsh_rs_128_64; + +typedef setseq_base<uint8_t, uint16_t, xsh_rs_mixin> setseq_xsh_rs_16_8; +typedef setseq_base<uint16_t, uint32_t, xsh_rs_mixin> setseq_xsh_rs_32_16; +typedef setseq_base<uint32_t, uint64_t, xsh_rs_mixin> setseq_xsh_rs_64_32; +typedef setseq_base<uint64_t, pcg128_t, xsh_rs_mixin> setseq_xsh_rs_128_64; + +typedef mcg_base<uint8_t, uint16_t, xsh_rs_mixin> mcg_xsh_rs_16_8; +typedef mcg_base<uint16_t, uint32_t, xsh_rs_mixin> mcg_xsh_rs_32_16; +typedef mcg_base<uint32_t, uint64_t, xsh_rs_mixin> mcg_xsh_rs_64_32; +typedef mcg_base<uint64_t, pcg128_t, xsh_rs_mixin> mcg_xsh_rs_128_64; + +/* Predefined types for XSH RR */ + +typedef oneseq_base<uint8_t, uint16_t, xsh_rr_mixin> oneseq_xsh_rr_16_8; +typedef oneseq_base<uint16_t, uint32_t, xsh_rr_mixin> oneseq_xsh_rr_32_16; +typedef oneseq_base<uint32_t, uint64_t, xsh_rr_mixin> oneseq_xsh_rr_64_32; +typedef oneseq_base<uint64_t, pcg128_t, xsh_rr_mixin> oneseq_xsh_rr_128_64; + +typedef unique_base<uint8_t, uint16_t, xsh_rr_mixin> unique_xsh_rr_16_8; +typedef unique_base<uint16_t, uint32_t, xsh_rr_mixin> unique_xsh_rr_32_16; +typedef unique_base<uint32_t, uint64_t, xsh_rr_mixin> unique_xsh_rr_64_32; +typedef unique_base<uint64_t, pcg128_t, xsh_rr_mixin> unique_xsh_rr_128_64; + +typedef setseq_base<uint8_t, uint16_t, xsh_rr_mixin> setseq_xsh_rr_16_8; +typedef setseq_base<uint16_t, uint32_t, xsh_rr_mixin> setseq_xsh_rr_32_16; +typedef setseq_base<uint32_t, uint64_t, xsh_rr_mixin> setseq_xsh_rr_64_32; +typedef setseq_base<uint64_t, pcg128_t, xsh_rr_mixin> setseq_xsh_rr_128_64; + +typedef mcg_base<uint8_t, uint16_t, xsh_rr_mixin> mcg_xsh_rr_16_8; +typedef mcg_base<uint16_t, uint32_t, xsh_rr_mixin> mcg_xsh_rr_32_16; +typedef mcg_base<uint32_t, uint64_t, xsh_rr_mixin> mcg_xsh_rr_64_32; +typedef mcg_base<uint64_t, pcg128_t, xsh_rr_mixin> mcg_xsh_rr_128_64; + + +/* Predefined types for RXS M XS */ + +typedef oneseq_base<uint8_t, uint8_t, rxs_m_xs_mixin> oneseq_rxs_m_xs_8_8; +typedef oneseq_base<uint16_t, uint16_t, rxs_m_xs_mixin> oneseq_rxs_m_xs_16_16; +typedef oneseq_base<uint32_t, uint32_t, rxs_m_xs_mixin> oneseq_rxs_m_xs_32_32; +typedef oneseq_base<uint64_t, uint64_t, rxs_m_xs_mixin> oneseq_rxs_m_xs_64_64; +typedef oneseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> oneseq_rxs_m_xs_128_128; + +typedef unique_base<uint8_t, uint8_t, rxs_m_xs_mixin> unique_rxs_m_xs_8_8; +typedef unique_base<uint16_t, uint16_t, rxs_m_xs_mixin> unique_rxs_m_xs_16_16; +typedef unique_base<uint32_t, uint32_t, rxs_m_xs_mixin> unique_rxs_m_xs_32_32; +typedef unique_base<uint64_t, uint64_t, rxs_m_xs_mixin> unique_rxs_m_xs_64_64; +typedef unique_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> unique_rxs_m_xs_128_128; + +typedef setseq_base<uint8_t, uint8_t, rxs_m_xs_mixin> setseq_rxs_m_xs_8_8; +typedef setseq_base<uint16_t, uint16_t, rxs_m_xs_mixin> setseq_rxs_m_xs_16_16; +typedef setseq_base<uint32_t, uint32_t, rxs_m_xs_mixin> setseq_rxs_m_xs_32_32; +typedef setseq_base<uint64_t, uint64_t, rxs_m_xs_mixin> setseq_rxs_m_xs_64_64; +typedef setseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> setseq_rxs_m_xs_128_128; + + // MCG versions don't make sense here, so aren't defined. + +/* Predefined types for XSL RR (only defined for "large" types) */ + +typedef oneseq_base<uint32_t, uint64_t, xsl_rr_mixin> oneseq_xsl_rr_64_32; +typedef oneseq_base<uint64_t, pcg128_t, xsl_rr_mixin> oneseq_xsl_rr_128_64; + +typedef unique_base<uint32_t, uint64_t, xsl_rr_mixin> unique_xsl_rr_64_32; +typedef unique_base<uint64_t, pcg128_t, xsl_rr_mixin> unique_xsl_rr_128_64; + +typedef setseq_base<uint32_t, uint64_t, xsl_rr_mixin> setseq_xsl_rr_64_32; +typedef setseq_base<uint64_t, pcg128_t, xsl_rr_mixin> setseq_xsl_rr_128_64; + +typedef mcg_base<uint32_t, uint64_t, xsl_rr_mixin> mcg_xsl_rr_64_32; +typedef mcg_base<uint64_t, pcg128_t, xsl_rr_mixin> mcg_xsl_rr_128_64; + + +/* Predefined types for XSL RR RR (only defined for "large" types) */ + +typedef oneseq_base<uint64_t, uint64_t, xsl_rr_rr_mixin> + oneseq_xsl_rr_rr_64_64; +typedef oneseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin> + oneseq_xsl_rr_rr_128_128; + +typedef unique_base<uint64_t, uint64_t, xsl_rr_rr_mixin> + unique_xsl_rr_rr_64_64; +typedef unique_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin> + unique_xsl_rr_rr_128_128; + +typedef setseq_base<uint64_t, uint64_t, xsl_rr_rr_mixin> + setseq_xsl_rr_rr_64_64; +typedef setseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin> + setseq_xsl_rr_rr_128_128; + + // MCG versions don't make sense here, so aren't defined. + +/* Extended generators */ + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename BaseRNG, bool kdd = true> +using ext_std8 = extended<table_pow2, advance_pow2, BaseRNG, + oneseq_rxs_m_xs_8_8, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename BaseRNG, bool kdd = true> +using ext_std16 = extended<table_pow2, advance_pow2, BaseRNG, + oneseq_rxs_m_xs_16_16, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename BaseRNG, bool kdd = true> +using ext_std32 = extended<table_pow2, advance_pow2, BaseRNG, + oneseq_rxs_m_xs_32_32, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, + typename BaseRNG, bool kdd = true> +using ext_std64 = extended<table_pow2, advance_pow2, BaseRNG, + oneseq_rxs_m_xs_64_64, kdd>; + + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_oneseq_rxs_m_xs_32_32 = + ext_std32<table_pow2, advance_pow2, oneseq_rxs_m_xs_32_32, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_mcg_xsh_rs_64_32 = + ext_std32<table_pow2, advance_pow2, mcg_xsh_rs_64_32, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_oneseq_xsh_rs_64_32 = + ext_std32<table_pow2, advance_pow2, oneseq_xsh_rs_64_32, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_setseq_xsh_rr_64_32 = + ext_std32<table_pow2, advance_pow2, setseq_xsh_rr_64_32, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_mcg_xsl_rr_128_64 = + ext_std64<table_pow2, advance_pow2, mcg_xsl_rr_128_64, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_oneseq_xsl_rr_128_64 = + ext_std64<table_pow2, advance_pow2, oneseq_xsl_rr_128_64, kdd>; + +template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true> +using ext_setseq_xsl_rr_128_64 = + ext_std64<table_pow2, advance_pow2, setseq_xsl_rr_128_64, kdd>; + +} // namespace pcg_engines + +typedef pcg_engines::setseq_xsh_rr_64_32 pcg32; +typedef pcg_engines::oneseq_xsh_rr_64_32 pcg32_oneseq; +typedef pcg_engines::unique_xsh_rr_64_32 pcg32_unique; +typedef pcg_engines::mcg_xsh_rs_64_32 pcg32_fast; + +typedef pcg_engines::setseq_xsl_rr_128_64 pcg64; +typedef pcg_engines::oneseq_xsl_rr_128_64 pcg64_oneseq; +typedef pcg_engines::unique_xsl_rr_128_64 pcg64_unique; +typedef pcg_engines::mcg_xsl_rr_128_64 pcg64_fast; + +typedef pcg_engines::setseq_rxs_m_xs_8_8 pcg8_once_insecure; +typedef pcg_engines::setseq_rxs_m_xs_16_16 pcg16_once_insecure; +typedef pcg_engines::setseq_rxs_m_xs_32_32 pcg32_once_insecure; +typedef pcg_engines::setseq_rxs_m_xs_64_64 pcg64_once_insecure; +typedef pcg_engines::setseq_xsl_rr_rr_128_128 pcg128_once_insecure; + +typedef pcg_engines::oneseq_rxs_m_xs_8_8 pcg8_oneseq_once_insecure; +typedef pcg_engines::oneseq_rxs_m_xs_16_16 pcg16_oneseq_once_insecure; +typedef pcg_engines::oneseq_rxs_m_xs_32_32 pcg32_oneseq_once_insecure; +typedef pcg_engines::oneseq_rxs_m_xs_64_64 pcg64_oneseq_once_insecure; +typedef pcg_engines::oneseq_xsl_rr_rr_128_128 pcg128_oneseq_once_insecure; + + +// These two extended RNGs provide two-dimensionally equidistributed +// 32-bit generators. pcg32_k2_fast occupies the same space as pcg64, +// and can be called twice to generate 64 bits, but does not required +// 128-bit math; on 32-bit systems, it's faster than pcg64 as well. + +typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true> pcg32_k2; +typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true> pcg32_k2_fast; + +// These eight extended RNGs have about as much state as arc4random +// +// - the k variants are k-dimensionally equidistributed +// - the c variants offer better crypographic security +// +// (just how good the cryptographic security is is an open question) + +typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true> pcg32_k64; +typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,true> pcg32_k64_oneseq; +typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true> pcg32_k64_fast; + +typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,false> pcg32_c64; +typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,false> pcg32_c64_oneseq; +typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,false> pcg32_c64_fast; + +typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,true> pcg64_k32; +typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,true> pcg64_k32_oneseq; +typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,true> pcg64_k32_fast; + +typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,false> pcg64_c32; +typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,false> pcg64_c32_oneseq; +typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,false> pcg64_c32_fast; + +// These eight extended RNGs have more state than the Mersenne twister +// +// - the k variants are k-dimensionally equidistributed +// - the c variants offer better crypographic security +// +// (just how good the cryptographic security is is an open question) + +typedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,true> pcg32_k1024; +typedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,true> pcg32_k1024_fast; + +typedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,false> pcg32_c1024; +typedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,false> pcg32_c1024_fast; + +typedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,true> pcg64_k1024; +typedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,true> pcg64_k1024_fast; + +typedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,false> pcg64_c1024; +typedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,false> pcg64_c1024_fast; + +// These generators have an insanely huge period (2^524352), and is suitable +// for silly party tricks, such as dumping out 64 KB ZIP files at an arbitrary +// point in the future. [Actually, over the full period of the generator, it +// will produce every 64 KB ZIP file 2^64 times!] + +typedef pcg_engines::ext_setseq_xsh_rr_64_32<14,16,true> pcg32_k16384; +typedef pcg_engines::ext_oneseq_xsh_rs_64_32<14,32,true> pcg32_k16384_fast; + +#endif // PCG_RAND_HPP_INCLUDED diff --git a/vendor/pcg-cpp-0.98/include/pcg_uint128.hpp b/vendor/pcg-cpp-0.98/include/pcg_uint128.hpp new file mode 100644 index 00000000..99b20e78 --- /dev/null +++ b/vendor/pcg-cpp-0.98/include/pcg_uint128.hpp @@ -0,0 +1,750 @@ +/* + * PCG Random Number Generation for C++ + * + * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + +/* + * This code provides a a C++ class that can provide 128-bit (or higher) + * integers. To produce 2K-bit integers, it uses two K-bit integers, + * placed in a union that allowes the code to also see them as four K/2 bit + * integers (and access them either directly name, or by index). + * + * It may seem like we're reinventing the wheel here, because several + * libraries already exist that support large integers, but most existing + * libraries provide a very generic multiprecision code, but here we're + * operating at a fixed size. Also, most other libraries are fairly + * heavyweight. So we use a direct implementation. Sadly, it's much slower + * than hand-coded assembly or direct CPU support. + */ + +#ifndef PCG_UINT128_HPP_INCLUDED +#define PCG_UINT128_HPP_INCLUDED 1 + +#include <cstdint> +#include <cstdio> +#include <cassert> +#include <climits> +#include <utility> +#include <initializer_list> +#include <type_traits> + +/* + * We want to lay the type out the same way that a native type would be laid + * out, which means we must know the machine's endian, at compile time. + * This ugliness attempts to do so. + */ + +#ifndef PCG_LITTLE_ENDIAN + #if defined(__BYTE_ORDER__) + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define PCG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define PCG_LITTLE_ENDIAN 0 + #else + #error __BYTE_ORDER__ does not match a standard endian, pick a side + #endif + #elif __LITTLE_ENDIAN__ || _LITTLE_ENDIAN + #define PCG_LITTLE_ENDIAN 1 + #elif __BIG_ENDIAN__ || _BIG_ENDIAN + #define PCG_LITTLE_ENDIAN 0 + #elif __x86_64 || __x86_64__ || __i386 || __i386__ + #define PCG_LITTLE_ENDIAN 1 + #elif __powerpc__ || __POWERPC__ || __ppc__ || __PPC__ \ + || __m68k__ || __mc68000__ + #define PCG_LITTLE_ENDIAN 0 + #else + #error Unable to determine target endianness + #endif +#endif + +namespace pcg_extras { + +// Recent versions of GCC have intrinsics we can use to quickly calculate +// the number of leading and trailing zeros in a number. If possible, we +// use them, otherwise we fall back to old-fashioned bit twiddling to figure +// them out. + +#ifndef PCG_BITCOUNT_T + typedef uint8_t bitcount_t; +#else + typedef PCG_BITCOUNT_T bitcount_t; +#endif + +/* + * Provide some useful helper functions + * * flog2 floor(log2(x)) + * * trailingzeros number of trailing zero bits + */ + +#ifdef __GNUC__ // Any GNU-compatible compiler supporting C++11 has + // some useful intrinsics we can use. + +inline bitcount_t flog2(uint32_t v) +{ + return 31 - __builtin_clz(v); +} + +inline bitcount_t trailingzeros(uint32_t v) +{ + return __builtin_ctz(v); +} + +inline bitcount_t flog2(uint64_t v) +{ +#if UINT64_MAX == ULONG_MAX + return 63 - __builtin_clzl(v); +#elif UINT64_MAX == ULLONG_MAX + return 63 - __builtin_clzll(v); +#else + #error Cannot find a function for uint64_t +#endif +} + +inline bitcount_t trailingzeros(uint64_t v) +{ +#if UINT64_MAX == ULONG_MAX + return __builtin_ctzl(v); +#elif UINT64_MAX == ULLONG_MAX + return __builtin_ctzll(v); +#else + #error Cannot find a function for uint64_t +#endif +} + +#else // Otherwise, we fall back to bit twiddling + // implementations + +inline bitcount_t flog2(uint32_t v) +{ + // Based on code by Eric Cole and Mark Dickinson, which appears at + // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn + + static const uint8_t multiplyDeBruijnBitPos[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }; + + v |= v >> 1; // first round down to one less than a power of 2 + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + return multiplyDeBruijnBitPos[(uint32_t)(v * 0x07C4ACDDU) >> 27]; +} + +inline bitcount_t trailingzeros(uint32_t v) +{ + static const uint8_t multiplyDeBruijnBitPos[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + + return multiplyDeBruijnBitPos[((uint32_t)((v & -v) * 0x077CB531U)) >> 27]; +} + +inline bitcount_t flog2(uint64_t v) +{ + uint32_t high = v >> 32; + uint32_t low = uint32_t(v); + + return high ? 32+flog2(high) : flog2(low); +} + +inline bitcount_t trailingzeros(uint64_t v) +{ + uint32_t high = v >> 32; + uint32_t low = uint32_t(v); + + return low ? trailingzeros(low) : trailingzeros(high)+32; +} + +#endif + +template <typename UInt> +inline bitcount_t clog2(UInt v) +{ + return flog2(v) + ((v & (-v)) != v); +} + +template <typename UInt> +inline UInt addwithcarry(UInt x, UInt y, bool carryin, bool* carryout) +{ + UInt half_result = y + carryin; + UInt result = x + half_result; + *carryout = (half_result < y) || (result < x); + return result; +} + +template <typename UInt> +inline UInt subwithcarry(UInt x, UInt y, bool carryin, bool* carryout) +{ + UInt half_result = y + carryin; + UInt result = x - half_result; + *carryout = (half_result < y) || (result > x); + return result; +} + + +template <typename UInt, typename UIntX2> +class uint_x4 { +// private: +public: + union { +#if PCG_LITTLE_ENDIAN + struct { + UInt v0, v1, v2, v3; + } w; + struct { + UIntX2 v01, v23; + } d; +#else + struct { + UInt v3, v2, v1, v0; + } w; + struct { + UIntX2 v23, v01; + } d; +#endif + // For the array access versions, the code that uses the array + // must handle endian itself. Yuck. + UInt wa[4]; + UIntX2 da[2]; + }; + +public: + uint_x4() = default; + + constexpr uint_x4(UInt v3, UInt v2, UInt v1, UInt v0) +#if PCG_LITTLE_ENDIAN + : w{v0, v1, v2, v3} +#else + : w{v3, v2, v1, v0} +#endif + { + // Nothing (else) to do + } + + constexpr uint_x4(UIntX2 v23, UIntX2 v01) +#if PCG_LITTLE_ENDIAN + : d{v01,v23} +#else + : d{v23,v01} +#endif + { + // Nothing (else) to do + } + + template<class Integral, + typename std::enable_if<(std::is_integral<Integral>::value + && sizeof(Integral) <= sizeof(UIntX2)) + >::type* = nullptr> + constexpr uint_x4(Integral v01) +#if PCG_LITTLE_ENDIAN + : d{UIntX2(v01),0UL} +#else + : d{0UL,UIntX2(v01)} +#endif + { + // Nothing (else) to do + } + + explicit constexpr operator uint64_t() const + { + return d.v01; + } + + explicit constexpr operator uint32_t() const + { + return w.v0; + } + + explicit constexpr operator int() const + { + return w.v0; + } + + explicit constexpr operator uint16_t() const + { + return w.v0; + } + + explicit constexpr operator uint8_t() const + { + return w.v0; + } + + typedef typename std::conditional<std::is_same<uint64_t, + unsigned long>::value, + unsigned long long, + unsigned long>::type + uint_missing_t; + + explicit constexpr operator uint_missing_t() const + { + return d.v01; + } + + explicit constexpr operator bool() const + { + return d.v01 || d.v23; + } + + template<typename U, typename V> + friend uint_x4<U,V> operator*(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend std::pair< uint_x4<U,V>,uint_x4<U,V> > + divmod(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator+(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator-(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator<<(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator>>(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator&(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator|(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator^(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend bool operator==(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend bool operator!=(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend bool operator<(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend bool operator<=(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend bool operator>(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend bool operator>=(const uint_x4<U,V>&, const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator~(const uint_x4<U,V>&); + + template<typename U, typename V> + friend uint_x4<U,V> operator-(const uint_x4<U,V>&); + + template<typename U, typename V> + friend bitcount_t flog2(const uint_x4<U,V>&); + + template<typename U, typename V> + friend bitcount_t trailingzeros(const uint_x4<U,V>&); + + uint_x4& operator*=(const uint_x4& rhs) + { + uint_x4 result = *this * rhs; + return *this = result; + } + + uint_x4& operator/=(const uint_x4& rhs) + { + uint_x4 result = *this / rhs; + return *this = result; + } + + uint_x4& operator%=(const uint_x4& rhs) + { + uint_x4 result = *this % rhs; + return *this = result; + } + + uint_x4& operator+=(const uint_x4& rhs) + { + uint_x4 result = *this + rhs; + return *this = result; + } + + uint_x4& operator-=(const uint_x4& rhs) + { + uint_x4 result = *this - rhs; + return *this = result; + } + + uint_x4& operator&=(const uint_x4& rhs) + { + uint_x4 result = *this & rhs; + return *this = result; + } + + uint_x4& operator|=(const uint_x4& rhs) + { + uint_x4 result = *this | rhs; + return *this = result; + } + + uint_x4& operator^=(const uint_x4& rhs) + { + uint_x4 result = *this ^ rhs; + return *this = result; + } + + uint_x4& operator>>=(bitcount_t shift) + { + uint_x4 result = *this >> shift; + return *this = result; + } + + uint_x4& operator<<=(bitcount_t shift) + { + uint_x4 result = *this << shift; + return *this = result; + } + +}; + +template<typename U, typename V> +bitcount_t flog2(const uint_x4<U,V>& v) +{ +#if PCG_LITTLE_ENDIAN + for (uint8_t i = 4; i !=0; /* dec in loop */) { + --i; +#else + for (uint8_t i = 0; i < 4; ++i) { +#endif + if (v.wa[i] == 0) + continue; + return flog2(v.wa[i]) + (sizeof(U)*CHAR_BIT)*i; + } + abort(); +} + +template<typename U, typename V> +bitcount_t trailingzeros(const uint_x4<U,V>& v) +{ +#if PCG_LITTLE_ENDIAN + for (uint8_t i = 0; i < 4; ++i) { +#else + for (uint8_t i = 4; i !=0; /* dec in loop */) { + --i; +#endif + if (v.wa[i] != 0) + return trailingzeros(v.wa[i]) + (sizeof(U)*CHAR_BIT)*i; + } + return (sizeof(U)*CHAR_BIT)*4; +} + +template <typename UInt, typename UIntX2> +std::pair< uint_x4<UInt,UIntX2>, uint_x4<UInt,UIntX2> > + divmod(const uint_x4<UInt,UIntX2>& orig_dividend, + const uint_x4<UInt,UIntX2>& divisor) +{ + // If the dividend is less than the divisor, the answer is always zero. + // This takes care of boundary cases like 0/x (which would otherwise be + // problematic because we can't take the log of zero. (The boundary case + // of division by zero is undefined.) + if (orig_dividend < divisor) + return { uint_x4<UInt,UIntX2>(0UL), orig_dividend }; + + auto dividend = orig_dividend; + + auto log2_divisor = flog2(divisor); + auto log2_dividend = flog2(dividend); + // assert(log2_dividend >= log2_divisor); + bitcount_t logdiff = log2_dividend - log2_divisor; + + constexpr uint_x4<UInt,UIntX2> ONE(1UL); + if (logdiff == 0) + return { ONE, dividend - divisor }; + + // Now we change the log difference to + // floor(log2(divisor)) - ceil(log2(dividend)) + // to ensure that we *underestimate* the result. + logdiff -= 1; + + uint_x4<UInt,UIntX2> quotient(0UL); + + auto qfactor = ONE << logdiff; + auto factor = divisor << logdiff; + + do { + dividend -= factor; + quotient += qfactor; + while (dividend < factor) { + factor >>= 1; + qfactor >>= 1; + } + } while (dividend >= divisor); + + return { quotient, dividend }; +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator/(const uint_x4<UInt,UIntX2>& dividend, + const uint_x4<UInt,UIntX2>& divisor) +{ + return divmod(dividend, divisor).first; +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator%(const uint_x4<UInt,UIntX2>& dividend, + const uint_x4<UInt,UIntX2>& divisor) +{ + return divmod(dividend, divisor).second; +} + + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator*(const uint_x4<UInt,UIntX2>& a, + const uint_x4<UInt,UIntX2>& b) +{ + uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U}; + bool carryin = false; + bool carryout; + UIntX2 a0b0 = UIntX2(a.w.v0) * UIntX2(b.w.v0); + r.w.v0 = UInt(a0b0); + r.w.v1 = UInt(a0b0 >> 32); + + UIntX2 a1b0 = UIntX2(a.w.v1) * UIntX2(b.w.v0); + r.w.v2 = UInt(a1b0 >> 32); + r.w.v1 = addwithcarry(r.w.v1, UInt(a1b0), carryin, &carryout); + carryin = carryout; + r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout); + carryin = carryout; + r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); + + UIntX2 a0b1 = UIntX2(a.w.v0) * UIntX2(b.w.v1); + carryin = false; + r.w.v2 = addwithcarry(r.w.v2, UInt(a0b1 >> 32), carryin, &carryout); + carryin = carryout; + r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); + + carryin = false; + r.w.v1 = addwithcarry(r.w.v1, UInt(a0b1), carryin, &carryout); + carryin = carryout; + r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout); + carryin = carryout; + r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); + + UIntX2 a1b1 = UIntX2(a.w.v1) * UIntX2(b.w.v1); + carryin = false; + r.w.v2 = addwithcarry(r.w.v2, UInt(a1b1), carryin, &carryout); + carryin = carryout; + r.w.v3 = addwithcarry(r.w.v3, UInt(a1b1 >> 32), carryin, &carryout); + + r.d.v23 += a.d.v01 * b.d.v23 + a.d.v23 * b.d.v01; + + return r; +} + + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator+(const uint_x4<UInt,UIntX2>& a, + const uint_x4<UInt,UIntX2>& b) +{ + uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U}; + + bool carryin = false; + bool carryout; + r.w.v0 = addwithcarry(a.w.v0, b.w.v0, carryin, &carryout); + carryin = carryout; + r.w.v1 = addwithcarry(a.w.v1, b.w.v1, carryin, &carryout); + carryin = carryout; + r.w.v2 = addwithcarry(a.w.v2, b.w.v2, carryin, &carryout); + carryin = carryout; + r.w.v3 = addwithcarry(a.w.v3, b.w.v3, carryin, &carryout); + + return r; +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator-(const uint_x4<UInt,UIntX2>& a, + const uint_x4<UInt,UIntX2>& b) +{ + uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U}; + + bool carryin = false; + bool carryout; + r.w.v0 = subwithcarry(a.w.v0, b.w.v0, carryin, &carryout); + carryin = carryout; + r.w.v1 = subwithcarry(a.w.v1, b.w.v1, carryin, &carryout); + carryin = carryout; + r.w.v2 = subwithcarry(a.w.v2, b.w.v2, carryin, &carryout); + carryin = carryout; + r.w.v3 = subwithcarry(a.w.v3, b.w.v3, carryin, &carryout); + + return r; +} + + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator&(const uint_x4<UInt,UIntX2>& a, + const uint_x4<UInt,UIntX2>& b) +{ + return uint_x4<UInt,UIntX2>(a.d.v23 & b.d.v23, a.d.v01 & b.d.v01); +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator|(const uint_x4<UInt,UIntX2>& a, + const uint_x4<UInt,UIntX2>& b) +{ + return uint_x4<UInt,UIntX2>(a.d.v23 | b.d.v23, a.d.v01 | b.d.v01); +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator^(const uint_x4<UInt,UIntX2>& a, + const uint_x4<UInt,UIntX2>& b) +{ + return uint_x4<UInt,UIntX2>(a.d.v23 ^ b.d.v23, a.d.v01 ^ b.d.v01); +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator~(const uint_x4<UInt,UIntX2>& v) +{ + return uint_x4<UInt,UIntX2>(~v.d.v23, ~v.d.v01); +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator-(const uint_x4<UInt,UIntX2>& v) +{ + return uint_x4<UInt,UIntX2>(0UL,0UL) - v; +} + +template <typename UInt, typename UIntX2> +bool operator==(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b) +{ + return (a.d.v01 == b.d.v01) && (a.d.v23 == b.d.v23); +} + +template <typename UInt, typename UIntX2> +bool operator!=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b) +{ + return !operator==(a,b); +} + + +template <typename UInt, typename UIntX2> +bool operator<(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b) +{ + return (a.d.v23 < b.d.v23) + || ((a.d.v23 == b.d.v23) && (a.d.v01 < b.d.v01)); +} + +template <typename UInt, typename UIntX2> +bool operator>(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b) +{ + return operator<(b,a); +} + +template <typename UInt, typename UIntX2> +bool operator<=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b) +{ + return !(operator<(b,a)); +} + +template <typename UInt, typename UIntX2> +bool operator>=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b) +{ + return !(operator<(a,b)); +} + + + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator<<(const uint_x4<UInt,UIntX2>& v, + const bitcount_t shift) +{ + uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U}; + const bitcount_t bits = sizeof(UInt) * CHAR_BIT; + const bitcount_t bitmask = bits - 1; + const bitcount_t shiftdiv = shift / bits; + const bitcount_t shiftmod = shift & bitmask; + + if (shiftmod) { + UInt carryover = 0; +#if PCG_LITTLE_ENDIAN + for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { +#else + for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { + --out, --in; +#endif + r.wa[out] = (v.wa[in] << shiftmod) | carryover; + carryover = (v.wa[in] >> (bits - shiftmod)); + } + } else { +#if PCG_LITTLE_ENDIAN + for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { +#else + for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { + --out, --in; +#endif + r.wa[out] = v.wa[in]; + } + } + + return r; +} + +template <typename UInt, typename UIntX2> +uint_x4<UInt,UIntX2> operator>>(const uint_x4<UInt,UIntX2>& v, + const bitcount_t shift) +{ + uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U}; + const bitcount_t bits = sizeof(UInt) * CHAR_BIT; + const bitcount_t bitmask = bits - 1; + const bitcount_t shiftdiv = shift / bits; + const bitcount_t shiftmod = shift & bitmask; + + if (shiftmod) { + UInt carryover = 0; +#if PCG_LITTLE_ENDIAN + for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { + --out, --in; +#else + for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { +#endif + r.wa[out] = (v.wa[in] >> shiftmod) | carryover; + carryover = (v.wa[in] << (bits - shiftmod)); + } + } else { +#if PCG_LITTLE_ENDIAN + for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { + --out, --in; +#else + for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { +#endif + r.wa[out] = v.wa[in]; + } + } + + return r; +} + +} // namespace pcg_extras + +#endif // PCG_UINT128_HPP_INCLUDED |