mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[upstream_utils] Add jart/json.cpp
This commit is contained in:
@@ -122,6 +122,7 @@ third_party_cc_lib_helper(
|
||||
third_party_cc_lib_helper(
|
||||
name = "json",
|
||||
include_root = "src/main/native/thirdparty/json/include",
|
||||
src_root = "src/main/native/thirdparty/json/src",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -189,13 +190,13 @@ wpilib_cc_library(
|
||||
third_party_header_only_libraries = [
|
||||
":argparse",
|
||||
":expected",
|
||||
":json",
|
||||
":sigslot",
|
||||
],
|
||||
third_party_libraries = [
|
||||
":debugging",
|
||||
":double-conversion",
|
||||
":fmtlib",
|
||||
":json",
|
||||
":llvm",
|
||||
":mpack",
|
||||
":nanopb",
|
||||
|
||||
@@ -114,7 +114,7 @@ file(
|
||||
src/main/native/cpp/*.cpp
|
||||
src/main/native/thirdparty/debugging/src/*.cpp
|
||||
src/main/native/thirdparty/double-conversion/src/*.cpp
|
||||
src/main/native/thirdparty/json/cpp/*.cpp
|
||||
src/main/native/thirdparty/json/src/*.cpp
|
||||
src/main/native/thirdparty/llvm/cpp/*.cpp
|
||||
src/main/native/thirdparty/mpack/src/*.cpp
|
||||
src/main/native/thirdparty/nanopb/src/*.cpp
|
||||
|
||||
@@ -44,11 +44,11 @@ ext {
|
||||
}
|
||||
jsonCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs 'src/main/native/thirdparty/json/cpp'
|
||||
include '*.cpp'
|
||||
srcDirs 'src/main/native/thirdparty/json/src'
|
||||
include '**/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDirs 'src/main/native/thirdparty/json/include'
|
||||
srcDirs 'src/main/native/include', 'src/main/native/thirdparty/double-conversion/include', 'src/main/native/thirdparty/expected/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/json/include'
|
||||
}
|
||||
}
|
||||
llvmCpp(CppSourceSet) {
|
||||
@@ -210,7 +210,7 @@ cppSourcesZip {
|
||||
from('src/main/native/thirdparty/fmtlib/src') {
|
||||
into '/'
|
||||
}
|
||||
from('src/main/native/thirdparty/json/cpp') {
|
||||
from('src/main/native/thirdparty/json/src') {
|
||||
into '/'
|
||||
}
|
||||
from('src/main/native/thirdparty/llvm/cpp') {
|
||||
|
||||
424
wpiutil/src/main/native/thirdparty/json/include/wpi/util/json.hpp
vendored
Normal file
424
wpiutil/src/main/native/thirdparty/json/include/wpi/util/json.hpp
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
// -*- mode:c++;indent-tabs-mode:nil;c-basic-offset:4;coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Mozilla Foundation
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <climits>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/util/StringMap.hpp"
|
||||
#include "wpi/util/expected"
|
||||
|
||||
namespace wpi::util {
|
||||
|
||||
class json;
|
||||
class raw_ostream;
|
||||
|
||||
template <typename T>
|
||||
struct json_serializer;
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
concept HasToJson = requires(json& j, const T& val) {
|
||||
{ to_json(j, val) };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasFromJson = requires(const json& j, T& val) {
|
||||
{ from_json(j, val) };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasJsonSerializer = requires (json& j, const json& cj, const T& val) {
|
||||
typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||
{ json_serializer<typename std::remove_cvref_t<T>>::to(j, val) };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept HasJsonDeserializer = requires (json& j, const json& cj, const T& val) {
|
||||
typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||
{ json_serializer<typename std::remove_cvref_t<T>>::from(cj) } -> std::convertible_to<typename std::remove_cvref_t<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept JsonConvertible =
|
||||
HasToJson<T> ||
|
||||
HasJsonSerializer<T> ||
|
||||
std::is_same_v<T, std::nullptr_t> ||
|
||||
std::is_same_v<T, bool> ||
|
||||
std::is_floating_point_v<T> ||
|
||||
std::is_integral_v<T> ||
|
||||
std::convertible_to<T, std::string> ||
|
||||
std::convertible_to<T, std::string_view> ||
|
||||
std::is_same_v<T, std::vector<json>> ||
|
||||
std::is_same_v<T, wpi::util::StringMap<json>>;
|
||||
|
||||
template <typename F, typename Tuple, size_t... I>
|
||||
void apply_pairs_helper(F&& f, Tuple&& t, std::index_sequence<I...>) {
|
||||
// This fold expression creates a sequence of calls to f for each pair
|
||||
(f(std::get<I * 2>(std::forward<Tuple>(t)),
|
||||
std::get<I * 2 + 1>(std::forward<Tuple>(t))), ...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class json
|
||||
{
|
||||
friend bool operator==(const json& lhs, const json& rhs);
|
||||
public:
|
||||
using array_t = std::vector<json>;
|
||||
using object_t = wpi::util::StringMap<json>;
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Null,
|
||||
Bool,
|
||||
Int,
|
||||
Uint,
|
||||
Float,
|
||||
Double,
|
||||
String,
|
||||
Array,
|
||||
Object
|
||||
};
|
||||
|
||||
private:
|
||||
enum Status
|
||||
{
|
||||
success,
|
||||
bad_double,
|
||||
absent_value,
|
||||
bad_negative,
|
||||
bad_exponent,
|
||||
missing_comma,
|
||||
missing_colon,
|
||||
malformed_utf8,
|
||||
depth_exceeded,
|
||||
stack_overflow,
|
||||
unexpected_eof,
|
||||
overlong_ascii,
|
||||
unexpected_comma,
|
||||
unexpected_colon,
|
||||
unexpected_octal,
|
||||
trailing_content,
|
||||
illegal_character,
|
||||
invalid_hex_escape,
|
||||
overlong_utf8_0x7ff,
|
||||
overlong_utf8_0xffff,
|
||||
object_missing_value,
|
||||
illegal_utf8_character,
|
||||
invalid_unicode_escape,
|
||||
utf16_surrogate_in_utf8,
|
||||
unexpected_end_of_array,
|
||||
hex_escape_not_printable,
|
||||
invalid_escape_character,
|
||||
utf8_exceeds_utf16_range,
|
||||
unexpected_end_of_string,
|
||||
unexpected_end_of_object,
|
||||
object_key_must_be_string,
|
||||
c1_control_code_in_string,
|
||||
non_del_c0_control_code_in_string,
|
||||
};
|
||||
|
||||
Type type_;
|
||||
union
|
||||
{
|
||||
bool bool_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
long long long_value;
|
||||
unsigned long long ulong_value;
|
||||
std::string string_value;
|
||||
array_t array_value;
|
||||
object_t object_value;
|
||||
};
|
||||
|
||||
public:
|
||||
static wpi::util::expected<json, const char*> parse(std::string_view);
|
||||
static json parse_or_throw(std::string_view);
|
||||
|
||||
json(const json&);
|
||||
json(json&&);
|
||||
json(const char*);
|
||||
json(const std::string&);
|
||||
json(std::string_view);
|
||||
~json();
|
||||
|
||||
constexpr json(const std::nullptr_t = nullptr) : type_(Type::Null)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(std::same_as<bool> auto value) : type_(Type::Bool), bool_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(int value) : type_(Type::Int), long_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(float value) : type_(Type::Float), float_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(unsigned value) : type_(Type::Int), long_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(long value) : type_(Type::Int), long_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(unsigned long value)
|
||||
{
|
||||
if (value <= LLONG_MAX) {
|
||||
type_ = Type::Int;
|
||||
long_value = value;
|
||||
} else {
|
||||
type_ = Type::Uint;
|
||||
ulong_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr json(long long value) : type_(Type::Int), long_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr json(unsigned long long value)
|
||||
{
|
||||
if (value <= LLONG_MAX) {
|
||||
type_ = Type::Int;
|
||||
long_value = value;
|
||||
} else {
|
||||
type_ = Type::Uint;
|
||||
ulong_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr json(double value) : type_(Type::Double), double_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
json(std::string&& value) : type_(Type::String), string_value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
json(array_t&& value) : type_(Type::Array), array_value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
json(object_t&& value) : type_(Type::Object), object_value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <std::ranges::input_range R>
|
||||
requires detail::JsonConvertible<std::ranges::range_value_t<R>>
|
||||
json(const R& range) : type_(Type::Array), array_value(std::ranges::cbegin(range), std::ranges::cend(range))
|
||||
{
|
||||
}
|
||||
|
||||
template <detail::HasToJson T>
|
||||
json(const T& value) : type_(Type::Null)
|
||||
{
|
||||
to_json(*this, value);
|
||||
}
|
||||
|
||||
template <detail::HasJsonSerializer T>
|
||||
json(const T& value) : type_(Type::Null)
|
||||
{
|
||||
json_serializer<T>::to(*this, value);
|
||||
}
|
||||
|
||||
constexpr Type type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
constexpr bool is_null() const
|
||||
{
|
||||
return type_ == Type::Null;
|
||||
}
|
||||
|
||||
constexpr bool is_bool() const
|
||||
{
|
||||
return type_ == Type::Bool;
|
||||
}
|
||||
|
||||
constexpr bool is_number() const
|
||||
{
|
||||
return is_float() || is_double() || is_int() || is_uint();
|
||||
}
|
||||
|
||||
constexpr bool is_int() const
|
||||
{
|
||||
return type_ == Type::Int;
|
||||
}
|
||||
|
||||
constexpr bool is_uint() const
|
||||
{
|
||||
return type_ == Type::Uint;
|
||||
}
|
||||
|
||||
constexpr bool is_float() const
|
||||
{
|
||||
return type_ == Type::Float;
|
||||
}
|
||||
|
||||
constexpr bool is_double() const
|
||||
{
|
||||
return type_ == Type::Double;
|
||||
}
|
||||
|
||||
bool is_string() const
|
||||
{
|
||||
return type_ == Type::String;
|
||||
}
|
||||
|
||||
bool is_array() const
|
||||
{
|
||||
return type_ == Type::Array;
|
||||
}
|
||||
|
||||
bool is_object() const
|
||||
{
|
||||
return type_ == Type::Object;
|
||||
}
|
||||
|
||||
bool get_bool() const;
|
||||
float get_float() const;
|
||||
double get_double() const;
|
||||
double get_number() const;
|
||||
long long get_int() const;
|
||||
unsigned long long get_uint() const;
|
||||
std::string& get_string();
|
||||
const std::string& get_string() const;
|
||||
array_t& get_array();
|
||||
const array_t& get_array() const;
|
||||
object_t& get_object();
|
||||
const object_t& get_object() const;
|
||||
|
||||
template <detail::HasFromJson T>
|
||||
T get() const {
|
||||
T value;
|
||||
from_json(*this, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <detail::HasJsonDeserializer T>
|
||||
T get() const {
|
||||
return json_serializer<T>::from(*this);
|
||||
}
|
||||
|
||||
bool contains(std::string_view) const;
|
||||
|
||||
json* lookup(std::string_view);
|
||||
const json* lookup(std::string_view) const;
|
||||
|
||||
void set_array();
|
||||
void set_object();
|
||||
|
||||
template <typename... Args>
|
||||
static json array(Args&&... args) {
|
||||
json j;
|
||||
j.set_array();
|
||||
(j.array_value.emplace_back(std::forward<Args>(args)), ...);
|
||||
return j;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static json object(Args&&... args) {
|
||||
json j;
|
||||
j.set_object();
|
||||
detail::apply_pairs_helper(
|
||||
[&](auto&& key, auto&& value) {
|
||||
j.object_value[std::forward<decltype(key)>(key)] = std::forward<decltype(value)>(value);
|
||||
},
|
||||
std::forward_as_tuple(args...),
|
||||
std::make_index_sequence<sizeof...(Args) / 2>{});
|
||||
return j;
|
||||
}
|
||||
|
||||
std::string to_string() const;
|
||||
std::string to_string_pretty() const;
|
||||
|
||||
json& operator=(const json&);
|
||||
json& operator=(json&&);
|
||||
|
||||
template <detail::HasToJson T>
|
||||
json& operator=(const T& value) {
|
||||
to_json(*this, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <detail::HasJsonSerializer T>
|
||||
json& operator=(const T& value) {
|
||||
json_serializer<T>::to(*this, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
json& operator[](size_t);
|
||||
json& operator[](std::string_view);
|
||||
|
||||
json& at(size_t);
|
||||
json& at(std::string_view);
|
||||
|
||||
const json& at(size_t) const;
|
||||
const json& at(std::string_view) const;
|
||||
|
||||
json value(size_t, json&&);
|
||||
json value(std::string_view, json&&);
|
||||
|
||||
void erase(std::string_view);
|
||||
|
||||
json& emplace_back(json&& value);
|
||||
|
||||
bool empty() const;
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return to_string();
|
||||
}
|
||||
|
||||
void marshal(wpi::util::raw_ostream& os, bool pretty = false, int indent = 0) const;
|
||||
|
||||
static void stringify_null(wpi::util::raw_ostream&);
|
||||
static void stringify_string(wpi::util::raw_ostream&, std::string_view);
|
||||
static void stringify_bool(wpi::util::raw_ostream&, bool);
|
||||
static void stringify_float(wpi::util::raw_ostream&, float);
|
||||
static void stringify_double(wpi::util::raw_ostream&, double);
|
||||
static void stringify_int(wpi::util::raw_ostream&, long long);
|
||||
static void stringify_uint(wpi::util::raw_ostream&, unsigned long long);
|
||||
static void stringify_array(wpi::util::raw_ostream&, const array_t&, bool pretty = false, int indent = 0);
|
||||
static void stringify_object(wpi::util::raw_ostream&, const object_t&, bool pretty = false, int indent = 0);
|
||||
|
||||
private:
|
||||
static const char* StatusToString(Status);
|
||||
void clear();
|
||||
static void serialize(wpi::util::raw_ostream&, std::string_view);
|
||||
static Status parse(json&, const char*&, const char*, int, int);
|
||||
};
|
||||
|
||||
bool operator==(const json& lhs, const json& rhs);
|
||||
inline bool operator!=(const json& lhs, const json& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace wpi::util
|
||||
1569
wpiutil/src/main/native/thirdparty/json/src/json.cpp
vendored
Normal file
1569
wpiutil/src/main/native/thirdparty/json/src/json.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
670
wpiutil/src/main/native/thirdparty/json/src/jtckdint.h
vendored
Normal file
670
wpiutil/src/main/native/thirdparty/json/src/jtckdint.h
vendored
Normal file
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright 2023 Justine Alexandra Roberts Tunney
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview C23 Checked Arithmetic
|
||||
*
|
||||
* This header defines three type generic functions:
|
||||
*
|
||||
* - `bool ckd_add(res, a, b)`
|
||||
* - `bool ckd_sub(res, a, b)`
|
||||
* - `bool ckd_mul(res, a, b)`
|
||||
*
|
||||
* Which allow integer arithmetic errors to be detected. There are many
|
||||
* kinds of integer errors, e.g. overflow, truncation, etc. These funcs
|
||||
* catch them all. Here's an example of how it works:
|
||||
*
|
||||
* uint32_t c;
|
||||
* int32_t a = 0x7fffffff;
|
||||
* int32_t b = 2;
|
||||
* assert(!ckd_add(&c, a, b));
|
||||
* assert(c == 0x80000001u);
|
||||
*
|
||||
* Experienced C / C++ users should find this example counter-intuitive
|
||||
* because the expression `0x7fffffff + 2` not only overflows it's also
|
||||
* undefined behavior. However here we see it's specified, and does not
|
||||
* result in an error. That's because C23 checked arithmetic is not the
|
||||
* arithmetic you're used to. The new standard changes the mathematics.
|
||||
*
|
||||
* C23 checked arithmetic is defined as performing the arithmetic using
|
||||
* infinite precision and then checking if the resulting value will fit
|
||||
* in the output type. Our example above did not result in an error due
|
||||
* to `0x80000001` being a legal value for `uint32_t`.
|
||||
*
|
||||
* This implementation will use the GNU compiler builtins, when they're
|
||||
* available, only if you don't use build flags like `-std=c11` because
|
||||
* they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI.
|
||||
* Instead, you'll get a pretty good pure C11 and C++11 implementation.
|
||||
*
|
||||
* @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf
|
||||
* @version 1.0 (2024-12-07)
|
||||
*/
|
||||
|
||||
#ifndef JTCKDINT_H_
|
||||
#define JTCKDINT_H_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#define __ckd_has_include(x) __has_include(x)
|
||||
#else
|
||||
#define __ckd_has_include(x) 0
|
||||
#endif
|
||||
|
||||
#if __ckd_has_include(<stdckdint.h>) && !defined(__cplusplus)
|
||||
#include <stdckdint.h>
|
||||
#else
|
||||
|
||||
#define __STDC_VERSION_STDCKDINT_H__ 202311L
|
||||
|
||||
#if (!defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__))
|
||||
#define __ckd_have_int128
|
||||
#define __ckd_intmax __int128
|
||||
#elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \
|
||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))
|
||||
#define __ckd_intmax long long
|
||||
#else
|
||||
#define __ckd_intmax long
|
||||
#endif
|
||||
|
||||
typedef signed __ckd_intmax __ckd_intmax_t;
|
||||
typedef unsigned __ckd_intmax __ckd_uintmax_t;
|
||||
|
||||
#ifdef __has_builtin
|
||||
#define __ckd_has_builtin(x) __has_builtin(x)
|
||||
#else
|
||||
#define __ckd_has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if (!defined(__STRICT_ANSI__) && \
|
||||
((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
|
||||
(__ckd_has_builtin(__builtin_add_overflow) && \
|
||||
__ckd_has_builtin(__builtin_sub_overflow) && \
|
||||
__ckd_has_builtin(__builtin_mul_overflow))))
|
||||
#define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res))
|
||||
#define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res))
|
||||
#define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res))
|
||||
|
||||
#elif (defined(__cplusplus) && \
|
||||
(__cplusplus >= 201103L || \
|
||||
(defined(_MSC_VER) && __cplusplus >= 199711L && \
|
||||
__ckd_has_include(<type_traits>) && __ckd_has_include(<limits>))))
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename __T, typename __U, typename __V>
|
||||
inline bool
|
||||
ckd_add(__T* __res, __U __a, __V __b)
|
||||
{
|
||||
static_assert(std::is_integral<__T>::value &&
|
||||
std::is_integral<__U>::value &&
|
||||
std::is_integral<__V>::value,
|
||||
"non-integral types not allowed");
|
||||
static_assert(!std::is_same<__T, bool>::value &&
|
||||
!std::is_same<__U, bool>::value &&
|
||||
!std::is_same<__V, bool>::value,
|
||||
"checked booleans not supported");
|
||||
static_assert(!std::is_same<__T, char>::value &&
|
||||
!std::is_same<__U, char>::value &&
|
||||
!std::is_same<__V, char>::value,
|
||||
"unqualified char type is ambiguous");
|
||||
__ckd_uintmax_t __x = __a;
|
||||
__ckd_uintmax_t __y = __b;
|
||||
__ckd_uintmax_t __z = __x + __y;
|
||||
*__res = __z;
|
||||
if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) {
|
||||
if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) {
|
||||
return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z);
|
||||
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
|
||||
return (
|
||||
__z != static_cast<__T>(__z) ||
|
||||
((std::is_signed<__U>::value || std::is_signed<__V>::value) &&
|
||||
static_cast<__ckd_intmax_t>(__z) < 0));
|
||||
}
|
||||
}
|
||||
bool __truncated = false;
|
||||
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
|
||||
__truncated =
|
||||
__z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
|
||||
}
|
||||
switch (std::is_signed<__T>::value << 2 | //
|
||||
std::is_signed<__U>::value << 1 | //
|
||||
std::is_signed<__V>::value) {
|
||||
case 0: // u = u + u
|
||||
return __truncated | (__z < __x);
|
||||
case 1: // u = u + s
|
||||
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>((__z ^ __x) & (__z ^ __y)) < 0);
|
||||
case 2: // u = s + u
|
||||
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>((__z ^ __x) & (__z ^ __y)) < 0);
|
||||
case 3: // u = s + s
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>(((__z | __x) & __y) |
|
||||
((__z & __x) & ~__y)) < 0);
|
||||
case 4: // s = u + u
|
||||
return __truncated | (__z < __x) |
|
||||
(static_cast<__ckd_intmax_t>(__z) < 0);
|
||||
case 5: // s = u + s
|
||||
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated | (__x + __y < __y);
|
||||
case 6: // s = s + u
|
||||
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated | (__x + __y < __x);
|
||||
case 7: // s = s + s
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>((__z ^ __x) & (__z ^ __y)) < 0);
|
||||
default:
|
||||
for (;;)
|
||||
(void)0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename __T, typename __U, typename __V>
|
||||
inline bool
|
||||
ckd_sub(__T* __res, __U __a, __V __b)
|
||||
{
|
||||
static_assert(std::is_integral<__T>::value &&
|
||||
std::is_integral<__U>::value &&
|
||||
std::is_integral<__V>::value,
|
||||
"non-integral types not allowed");
|
||||
static_assert(!std::is_same<__T, bool>::value &&
|
||||
!std::is_same<__U, bool>::value &&
|
||||
!std::is_same<__V, bool>::value,
|
||||
"checked booleans not supported");
|
||||
static_assert(!std::is_same<__T, char>::value &&
|
||||
!std::is_same<__U, char>::value &&
|
||||
!std::is_same<__V, char>::value,
|
||||
"unqualified char type is ambiguous");
|
||||
__ckd_uintmax_t __x = __a;
|
||||
__ckd_uintmax_t __y = __b;
|
||||
__ckd_uintmax_t __z = __x - __y;
|
||||
*__res = __z;
|
||||
bool __truncated = false;
|
||||
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
|
||||
__truncated =
|
||||
__z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
|
||||
}
|
||||
switch (std::is_signed<__T>::value << 2 | //
|
||||
std::is_signed<__U>::value << 1 | //
|
||||
std::is_signed<__V>::value) {
|
||||
case 0: // u = u - u
|
||||
return __truncated | (__x < __y);
|
||||
case 1: // u = u - s
|
||||
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>((__x ^ __y) & (__z ^ __x)) < 0);
|
||||
case 2: // u = s - u
|
||||
return __truncated | (__y > __x) |
|
||||
(static_cast<__ckd_intmax_t>(__x) < 0);
|
||||
case 3: // u = s - s
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>(((__z & __x) & __y) |
|
||||
((__z | __x) & ~__y)) < 0);
|
||||
case 4: // s = u - u
|
||||
return __truncated |
|
||||
((__x < __y) ^ (static_cast<__ckd_intmax_t>(__z) < 0));
|
||||
case 5: // s = u - s
|
||||
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated | (__x >= __y);
|
||||
case 6: // s = s - u
|
||||
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||
return __truncated | (__x < __y);
|
||||
case 7: // s = s - s
|
||||
return __truncated |
|
||||
(static_cast<__ckd_intmax_t>((__x ^ __y) & (__z ^ __x)) < 0);
|
||||
default:
|
||||
for (;;)
|
||||
(void)0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename __T, typename __U, typename __V>
|
||||
inline bool
|
||||
ckd_mul(__T* __res, __U __a, __V __b)
|
||||
{
|
||||
static_assert(std::is_integral<__T>::value &&
|
||||
std::is_integral<__U>::value &&
|
||||
std::is_integral<__V>::value,
|
||||
"non-integral types not allowed");
|
||||
static_assert(!std::is_same<__T, bool>::value &&
|
||||
!std::is_same<__U, bool>::value &&
|
||||
!std::is_same<__V, bool>::value,
|
||||
"checked booleans not supported");
|
||||
static_assert(!std::is_same<__T, char>::value &&
|
||||
!std::is_same<__U, char>::value &&
|
||||
!std::is_same<__V, char>::value,
|
||||
"unqualified char type is ambiguous");
|
||||
__ckd_uintmax_t __x = __a;
|
||||
__ckd_uintmax_t __y = __b;
|
||||
if ((sizeof(__U) * 8 - std::is_signed<__U>::value) +
|
||||
(sizeof(__V) * 8 - std::is_signed<__V>::value) <=
|
||||
(sizeof(__T) * 8 - std::is_signed<__T>::value)) {
|
||||
if (sizeof(__ckd_uintmax_t) > sizeof(__T) ||
|
||||
std::is_signed<__T>::value) {
|
||||
__ckd_intmax_t __z = __x * __y;
|
||||
return __z != (*__res = __z);
|
||||
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
*__res = __z;
|
||||
return (
|
||||
__z != static_cast<__T>(__z) ||
|
||||
((std::is_signed<__U>::value || std::is_signed<__V>::value) &&
|
||||
static_cast<__ckd_intmax_t>(__z) < 0));
|
||||
}
|
||||
}
|
||||
switch (std::is_signed<__T>::value << 2 | //
|
||||
std::is_signed<__U>::value << 1 | //
|
||||
std::is_signed<__V>::value) {
|
||||
case 0: { // u = u * u
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
int __o = __x && __z / __x != __y;
|
||||
*__res = __z;
|
||||
return __o | (sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res));
|
||||
}
|
||||
case 1: { // u = u * s
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
int __o = __x && __z / __x != __y;
|
||||
*__res = __z;
|
||||
return (__o | ((static_cast<__ckd_intmax_t>(__y) < 0) & !!__x) |
|
||||
(sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||
}
|
||||
case 2: { // u = s * u
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
int __o = __x && __z / __x != __y;
|
||||
*__res = __z;
|
||||
return (__o | ((static_cast<__ckd_intmax_t>(__x) < 0) & !!__y) |
|
||||
(sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||
}
|
||||
case 3: { // u = s * s
|
||||
int __o = false;
|
||||
if (static_cast<__ckd_intmax_t>(__x & __y) < 0) {
|
||||
__x = 0 - __x;
|
||||
__y = 0 - __y;
|
||||
} else if (static_cast<__ckd_intmax_t>(__x ^ __y) < 0) {
|
||||
__o = __x && __y;
|
||||
}
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
__o |= __x && __z / __x != __y;
|
||||
*__res = __z;
|
||||
return __o | (sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res));
|
||||
}
|
||||
case 4: { // s = u * u
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
int __o = __x && __z / __x != __y;
|
||||
*__res = __z;
|
||||
return (__o | (static_cast<__ckd_intmax_t>(__z) < 0) |
|
||||
(sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||
}
|
||||
case 5: { // s = u * s
|
||||
__ckd_uintmax_t __t = 0 - __y;
|
||||
__t = static_cast<__ckd_intmax_t>(__t) < 0 ? __y : __t;
|
||||
__ckd_uintmax_t __p = __t * __x;
|
||||
int __o = __t && __p / __t != __x;
|
||||
int __n = static_cast<__ckd_intmax_t>(__y) < 0;
|
||||
__ckd_uintmax_t __z = __n ? 0 - __p : __p;
|
||||
*__res = __z;
|
||||
__ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max();
|
||||
return (__o | (__p > __m + __n) |
|
||||
(sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||
}
|
||||
case 6: { // s = s * u
|
||||
__ckd_uintmax_t __t = 0 - __x;
|
||||
__t = static_cast<__ckd_intmax_t>(__t) < 0 ? __x : __t;
|
||||
__ckd_uintmax_t __p = __t * __y;
|
||||
int __o = __t && __p / __t != __y;
|
||||
int __n = static_cast<__ckd_intmax_t>(__x) < 0;
|
||||
__ckd_uintmax_t __z = __n ? 0 - __p : __p;
|
||||
*__res = __z;
|
||||
__ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max();
|
||||
return (__o | (__p > __m + __n) |
|
||||
(sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||
}
|
||||
case 7: { // s = s * s
|
||||
__ckd_uintmax_t __z = __x * __y;
|
||||
*__res = __z;
|
||||
return ((((static_cast<__ckd_intmax_t>(__y) < 0) &&
|
||||
(static_cast<__ckd_intmax_t>(__x) ==
|
||||
std::numeric_limits<__ckd_intmax_t>::min())) ||
|
||||
(__y && ((static_cast<__ckd_intmax_t>(__z) /
|
||||
static_cast<__ckd_intmax_t>(__y)) !=
|
||||
static_cast<__ckd_intmax_t>(__x)))) |
|
||||
(sizeof(__T) < sizeof(__z) &&
|
||||
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||
}
|
||||
default:
|
||||
for (;;)
|
||||
(void)0;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
|
||||
#define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b))
|
||||
#define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b))
|
||||
#define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b))
|
||||
|
||||
#if defined(__GNUC__) || defined(__llvm__)
|
||||
#define __ckd_inline \
|
||||
extern __inline \
|
||||
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
|
||||
#else
|
||||
#define __ckd_inline static inline
|
||||
#endif
|
||||
|
||||
#ifdef __ckd_have_int128
|
||||
#define __ckd_generic_int128(x, y) \
|
||||
, \
|
||||
signed __int128 \
|
||||
: x \
|
||||
, unsigned __int128 : y
|
||||
#else
|
||||
#define __ckd_generic_int128(x, y)
|
||||
#endif
|
||||
|
||||
#define __ckd_sign(T) ((T)1 << (sizeof(T) * 8 - 1))
|
||||
|
||||
#define __ckd_is_signed(x) \
|
||||
_Generic(x, \
|
||||
signed char: 1, \
|
||||
unsigned char: 0, \
|
||||
signed short: 1, \
|
||||
unsigned short: 0, \
|
||||
signed int: 1, \
|
||||
unsigned int: 0, \
|
||||
signed long: 1, \
|
||||
unsigned long: 0, \
|
||||
signed long long: 1, \
|
||||
unsigned long long: 0 __ckd_generic_int128(1, 0))
|
||||
|
||||
#define __ckd_expr(op, res, a, b) \
|
||||
(_Generic(*res, \
|
||||
signed char: __ckd_##op##_schar, \
|
||||
unsigned char: __ckd_##op##_uchar, \
|
||||
signed short: __ckd_##op##_sshort, \
|
||||
unsigned short: __ckd_##op##_ushort, \
|
||||
signed int: __ckd_##op##_sint, \
|
||||
unsigned int: __ckd_##op##_uint, \
|
||||
signed long: __ckd_##op##_slong, \
|
||||
unsigned long: __ckd_##op##_ulong, \
|
||||
signed long long: __ckd_##op##_slonger, \
|
||||
unsigned long long: __ckd_##op##_ulonger __ckd_generic_int128( \
|
||||
__ckd_##op##_sint128, __ckd_##op##_uint128))( \
|
||||
res, a, b, __ckd_is_signed(a), __ckd_is_signed(b)))
|
||||
|
||||
#define __ckd_declare_add(S, T) \
|
||||
__ckd_inline char S(void* __res, \
|
||||
__ckd_uintmax_t __x, \
|
||||
__ckd_uintmax_t __y, \
|
||||
char __a_signed, \
|
||||
char __b_signed) \
|
||||
{ \
|
||||
__ckd_uintmax_t __z = __x + __y; \
|
||||
*(T*)__res = __z; \
|
||||
char __truncated = 0; \
|
||||
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
||||
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
||||
} \
|
||||
switch (__ckd_is_signed((T)0) << 2 | __a_signed << 1 | __b_signed) { \
|
||||
case 0: /* u = u + u */ \
|
||||
return __truncated | (__z < __x); \
|
||||
case 1: /* u = u + s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__z ^ __x) & (__z ^ __y)) < 0); \
|
||||
case 2: /* u = s + u */ \
|
||||
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__z ^ __x) & (__z ^ __y)) < 0); \
|
||||
case 3: /* u = s + s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)(((__z | __x) & __y) | \
|
||||
((__z & __x) & ~__y)) < 0); \
|
||||
case 4: /* s = u + u */ \
|
||||
return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \
|
||||
case 5: /* s = u + s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x + __y < __y); \
|
||||
case 6: /* s = s + u */ \
|
||||
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x + __y < __x); \
|
||||
case 7: /* s = s + s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__z ^ __x) & (__z ^ __y)) < 0); \
|
||||
default: \
|
||||
for (;;) \
|
||||
(void)0; \
|
||||
} \
|
||||
}
|
||||
|
||||
__ckd_declare_add(__ckd_add_schar,
|
||||
signed char) __ckd_declare_add(__ckd_add_uchar, unsigned char)
|
||||
__ckd_declare_add(__ckd_add_sshort, signed short) __ckd_declare_add(
|
||||
__ckd_add_ushort,
|
||||
unsigned short) __ckd_declare_add(__ckd_add_sint, signed int)
|
||||
__ckd_declare_add(__ckd_add_uint, unsigned int) __ckd_declare_add(
|
||||
__ckd_add_slong,
|
||||
signed long) __ckd_declare_add(__ckd_add_ulong, unsigned long)
|
||||
__ckd_declare_add(__ckd_add_slonger,
|
||||
signed long long) __ckd_declare_add(__ckd_add_ulonger,
|
||||
unsigned long long)
|
||||
#ifdef __ckd_have_int128
|
||||
__ckd_declare_add(__ckd_add_sint128,
|
||||
signed __int128) __ckd_declare_add(__ckd_add_uint128,
|
||||
unsigned __int128)
|
||||
#endif
|
||||
|
||||
#define __ckd_declare_sub(S, T) \
|
||||
__ckd_inline char S(void* __res, \
|
||||
__ckd_uintmax_t __x, \
|
||||
__ckd_uintmax_t __y, \
|
||||
char __a_signed, \
|
||||
char __b_signed) \
|
||||
{ \
|
||||
__ckd_uintmax_t __z = __x - __y; \
|
||||
*(T*)__res = __z; \
|
||||
char __truncated = 0; \
|
||||
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
||||
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
||||
} \
|
||||
switch (__ckd_is_signed((T)0) << 2 | __a_signed << 1 | __b_signed) { \
|
||||
case 0: /* u = u - u */ \
|
||||
return __truncated | (__x < __y); \
|
||||
case 1: /* u = u - s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__x ^ __y) & (__z ^ __x)) < 0); \
|
||||
case 2: /* u = s - u */ \
|
||||
return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \
|
||||
case 3: /* u = s - s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)(((__z & __x) & __y) | \
|
||||
((__z | __x) & ~__y)) < 0); \
|
||||
case 4: /* s = u - u */ \
|
||||
return __truncated | \
|
||||
((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \
|
||||
case 5: /* s = u - s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x >= __y); \
|
||||
case 6: /* s = s - u */ \
|
||||
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x < __y); \
|
||||
case 7: /* s = s - s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__x ^ __y) & (__z ^ __x)) < 0); \
|
||||
default: \
|
||||
for (;;) \
|
||||
(void)0; \
|
||||
} \
|
||||
}
|
||||
|
||||
__ckd_declare_sub(__ckd_sub_schar, signed char) __ckd_declare_sub(
|
||||
__ckd_sub_uchar,
|
||||
unsigned char) __ckd_declare_sub(__ckd_sub_sshort, signed short)
|
||||
__ckd_declare_sub(__ckd_sub_ushort,
|
||||
unsigned short) __ckd_declare_sub(__ckd_sub_sint,
|
||||
signed int)
|
||||
__ckd_declare_sub(__ckd_sub_uint, unsigned int) __ckd_declare_sub(
|
||||
__ckd_sub_slong,
|
||||
signed long) __ckd_declare_sub(__ckd_sub_ulong, unsigned long)
|
||||
__ckd_declare_sub(__ckd_sub_slonger, signed long long)
|
||||
__ckd_declare_sub(__ckd_sub_ulonger, unsigned long long)
|
||||
#ifdef __ckd_have_int128
|
||||
__ckd_declare_sub(__ckd_sub_sint128, signed __int128)
|
||||
__ckd_declare_sub(__ckd_sub_uint128, unsigned __int128)
|
||||
#endif
|
||||
|
||||
#define __ckd_declare_mul(S, T) \
|
||||
__ckd_inline char S(void* __res, \
|
||||
__ckd_uintmax_t __x, \
|
||||
__ckd_uintmax_t __y, \
|
||||
char __a_signed, \
|
||||
char __b_signed) \
|
||||
{ \
|
||||
switch (__ckd_is_signed((T)0) << 2 | __a_signed << 1 | __b_signed) { \
|
||||
case 0: { /* u = u * u */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T*)__res = __z; \
|
||||
return __o | (sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res); \
|
||||
} \
|
||||
case 1: { /* u = u * s */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T*)__res = __z; \
|
||||
return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||
} \
|
||||
case 2: { /* u = s * u */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T*)__res = __z; \
|
||||
return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||
} \
|
||||
case 3: { /* u = s * s */ \
|
||||
int __o = 0; \
|
||||
if ((__ckd_intmax_t)(__x & __y) < 0) { \
|
||||
__x = 0 - __x; \
|
||||
__y = 0 - __y; \
|
||||
} else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \
|
||||
__o = __x && __y; \
|
||||
} \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
__o |= __x && __z / __x != __y; \
|
||||
*(T*)__res = __z; \
|
||||
return __o | (sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res); \
|
||||
} \
|
||||
case 4: { /* s = u * u */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T*)__res = __z; \
|
||||
return (__o | ((__ckd_intmax_t)(__z) < 0) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||
} \
|
||||
case 5: { /* s = u * s */ \
|
||||
__ckd_uintmax_t __t = 0 - __y; \
|
||||
__t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \
|
||||
__ckd_uintmax_t __p = __t * __x; \
|
||||
int __o = __t && __p / __t != __x; \
|
||||
int __n = (__ckd_intmax_t)__y < 0; \
|
||||
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
||||
*(T*)__res = __z; \
|
||||
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
||||
return (__o | (__p > __m + __n) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||
} \
|
||||
case 6: { /* s = s * u */ \
|
||||
__ckd_uintmax_t __t = 0 - __x; \
|
||||
__t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \
|
||||
__ckd_uintmax_t __p = __t * __y; \
|
||||
int __o = __t && __p / __t != __y; \
|
||||
int __n = (__ckd_intmax_t)__x < 0; \
|
||||
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
||||
*(T*)__res = __z; \
|
||||
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
||||
return (__o | (__p > __m + __n) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||
} \
|
||||
case 7: { /* s = s * s */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
*(T*)__res = __z; \
|
||||
return ( \
|
||||
((((__ckd_intmax_t)__y < 0) && \
|
||||
(__x == __ckd_sign(__ckd_uintmax_t))) || \
|
||||
(__y && (((__ckd_intmax_t)__z / (__ckd_intmax_t)__y) != \
|
||||
(__ckd_intmax_t)__x))) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||
} \
|
||||
default: \
|
||||
for (;;) \
|
||||
(void)0; \
|
||||
} \
|
||||
}
|
||||
|
||||
__ckd_declare_mul(__ckd_mul_schar, signed char)
|
||||
__ckd_declare_mul(__ckd_mul_uchar, unsigned char)
|
||||
__ckd_declare_mul(
|
||||
__ckd_mul_sshort,
|
||||
signed short) __ckd_declare_mul(__ckd_mul_ushort,
|
||||
unsigned short)
|
||||
__ckd_declare_mul(__ckd_mul_sint, signed int)
|
||||
__ckd_declare_mul(__ckd_mul_uint, unsigned int)
|
||||
__ckd_declare_mul(__ckd_mul_slong,
|
||||
signed long)
|
||||
__ckd_declare_mul(__ckd_mul_ulong,
|
||||
unsigned long)
|
||||
__ckd_declare_mul(__ckd_mul_slonger,
|
||||
signed long long)
|
||||
__ckd_declare_mul(__ckd_mul_ulonger,
|
||||
unsigned long long)
|
||||
#ifdef __ckd_have_int128
|
||||
__ckd_declare_mul(__ckd_mul_sint128,
|
||||
signed __int128)
|
||||
__ckd_declare_mul(__ckd_mul_uint128,
|
||||
unsigned __int128)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#pragma message "checked integer arithmetic unsupported in this environment"
|
||||
|
||||
#define ckd_add(res, x, y) (*(res) = (x) + (y), 0)
|
||||
#define ckd_sub(res, x, y) (*(res) = (x) - (y), 0)
|
||||
#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0)
|
||||
|
||||
#endif /* GNU */
|
||||
#endif /* stdckdint.h */
|
||||
#endif /* JTCKDINT_H_ */
|
||||
59
wpiutil/src/test/native/cpp/json_test.cpp
Normal file
59
wpiutil/src/test/native/cpp/json_test.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpi/util/json.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace wpi::util {
|
||||
|
||||
TEST(JsonTest, ParseMaxUint64) {
|
||||
auto j = json::parse_or_throw("18446744073709551615");
|
||||
EXPECT_TRUE(j.is_uint());
|
||||
EXPECT_EQ(j.get_uint(), 18446744073709551615ull);
|
||||
}
|
||||
|
||||
TEST(JsonTest, MarshalMaxUint64) {
|
||||
json j{18446744073709551615ull};
|
||||
EXPECT_EQ(j.to_string(), "18446744073709551615");
|
||||
}
|
||||
|
||||
TEST(JsonTest, AssignBool) {
|
||||
json j;
|
||||
j = true;
|
||||
ASSERT_TRUE(j.is_bool());
|
||||
EXPECT_TRUE(j.get_bool());
|
||||
}
|
||||
|
||||
TEST(JsonTest, AssignBoolToMap) {
|
||||
json j;
|
||||
j["key"] = true;
|
||||
ASSERT_TRUE(j["key"].is_bool());
|
||||
EXPECT_TRUE(j["key"].get_bool());
|
||||
}
|
||||
|
||||
TEST(JsonTest, AssignBoolToArray) {
|
||||
json j;
|
||||
j.emplace_back(true);
|
||||
ASSERT_TRUE(j[0].is_bool());
|
||||
EXPECT_TRUE(j[0].get_bool());
|
||||
}
|
||||
|
||||
TEST(JsonTest, BoolObject) {
|
||||
json j = json::object("key", true);
|
||||
ASSERT_TRUE(j["key"].is_bool());
|
||||
EXPECT_TRUE(j["key"].get_bool());
|
||||
}
|
||||
|
||||
TEST(JsonTest, BoolArray) {
|
||||
json j = json::array(true, false, true);
|
||||
ASSERT_TRUE(j[0].is_bool());
|
||||
EXPECT_TRUE(j[0].get_bool());
|
||||
ASSERT_TRUE(j[1].is_bool());
|
||||
EXPECT_FALSE(j[1].get_bool());
|
||||
ASSERT_TRUE(j[2].is_bool());
|
||||
EXPECT_TRUE(j[2].get_bool());
|
||||
}
|
||||
|
||||
} // namespace wpi::util
|
||||
Reference in New Issue
Block a user