mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
[wpiutil] Separate third party libraries (#4190)
This commit is contained in:
234
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
vendored
Normal file
234
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
// Formatting library for C++ - dynamic format arguments
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_ARGS_H_
|
||||
#define FMT_ARGS_H_
|
||||
|
||||
#include <functional> // std::reference_wrapper
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <vector>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T> struct is_reference_wrapper : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||
|
||||
template <typename T> const T& unwrap(const T& v) { return v; }
|
||||
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
|
||||
return static_cast<const T&>(v);
|
||||
}
|
||||
|
||||
class dynamic_arg_list {
|
||||
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
|
||||
// templates it doesn't complain about inability to deduce single translation
|
||||
// unit for placing vtable. So storage_node_base is made a fake template.
|
||||
template <typename = void> struct node {
|
||||
virtual ~node() = default;
|
||||
std::unique_ptr<node<>> next;
|
||||
};
|
||||
|
||||
template <typename T> struct typed_node : node<> {
|
||||
T value;
|
||||
|
||||
template <typename Arg>
|
||||
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
||||
: value(arg.data(), arg.size()) {}
|
||||
};
|
||||
|
||||
std::unique_ptr<node<>> head_;
|
||||
|
||||
public:
|
||||
template <typename T, typename Arg> const T& push(const Arg& arg) {
|
||||
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||
auto& value = new_node->value;
|
||||
new_node->next = std::move(head_);
|
||||
head_ = std::move(new_node);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
\rst
|
||||
A dynamic version of `fmt::format_arg_store`.
|
||||
It's equipped with a storage to potentially temporary objects which lifetimes
|
||||
could be shorter than the format arguments object.
|
||||
|
||||
It can be implicitly converted into `~fmt::basic_format_args` for passing
|
||||
into type-erased formatting functions such as `~fmt::vformat`.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Context>
|
||||
class dynamic_format_arg_store
|
||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||
// Workaround a GCC template argument substitution bug.
|
||||
: public basic_format_args<Context>
|
||||
#endif
|
||||
{
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
template <typename T> struct need_copy {
|
||||
static constexpr detail::type mapped_type =
|
||||
detail::mapped_type_constant<T, Context>::value;
|
||||
|
||||
enum {
|
||||
value = !(detail::is_reference_wrapper<T>::value ||
|
||||
std::is_same<T, basic_string_view<char_type>>::value ||
|
||||
std::is_same<T, detail::std_string_view<char_type>>::value ||
|
||||
(mapped_type != detail::type::cstring_type &&
|
||||
mapped_type != detail::type::string_type &&
|
||||
mapped_type != detail::type::custom_type))
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using stored_type = conditional_t<detail::is_string<T>::value &&
|
||||
!has_formatter<T, Context>::value &&
|
||||
!detail::is_reference_wrapper<T>::value,
|
||||
std::basic_string<char_type>, T>;
|
||||
|
||||
// Storage of basic_format_arg must be contiguous.
|
||||
std::vector<basic_format_arg<Context>> data_;
|
||||
std::vector<detail::named_arg_info<char_type>> named_info_;
|
||||
|
||||
// Storage of arguments not fitting into basic_format_arg must grow
|
||||
// without relocation because items in data_ refer to it.
|
||||
detail::dynamic_arg_list dynamic_args_;
|
||||
|
||||
friend class basic_format_args<Context>;
|
||||
|
||||
unsigned long long get_types() const {
|
||||
return detail::is_unpacked_bit | data_.size() |
|
||||
(named_info_.empty()
|
||||
? 0ULL
|
||||
: static_cast<unsigned long long>(detail::has_named_args_bit));
|
||||
}
|
||||
|
||||
const basic_format_arg<Context>* data() const {
|
||||
return named_info_.empty() ? data_.data() : data_.data() + 1;
|
||||
}
|
||||
|
||||
template <typename T> void emplace_arg(const T& arg) {
|
||||
data_.emplace_back(detail::make_arg<Context>(arg));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
|
||||
if (named_info_.empty()) {
|
||||
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
|
||||
data_.insert(data_.begin(), {zero_ptr, 0});
|
||||
}
|
||||
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
|
||||
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
|
||||
data->pop_back();
|
||||
};
|
||||
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
|
||||
guard{&data_, pop_one};
|
||||
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
|
||||
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
|
||||
guard.release();
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr dynamic_format_arg_store() = default;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Adds an argument into the dynamic store for later passing to a formatting
|
||||
function.
|
||||
|
||||
Note that custom types and string types (but not string views) are copied
|
||||
into the store dynamically allocating memory if necessary.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
store.push_back(42);
|
||||
store.push_back("abc");
|
||||
store.push_back(1.5f);
|
||||
std::string result = fmt::vformat("{} and {} and {}", store);
|
||||
\endrst
|
||||
*/
|
||||
template <typename T> void push_back(const T& arg) {
|
||||
if (detail::const_check(need_copy<T>::value))
|
||||
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
|
||||
else
|
||||
emplace_arg(detail::unwrap(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Adds a reference to the argument into the dynamic store for later passing to
|
||||
a formatting function.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
char band[] = "Rolling Stones";
|
||||
store.push_back(std::cref(band));
|
||||
band[9] = 'c'; // Changing str affects the output.
|
||||
std::string result = fmt::vformat("{}", store);
|
||||
// result == "Rolling Scones"
|
||||
\endrst
|
||||
*/
|
||||
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
||||
static_assert(
|
||||
need_copy<T>::value,
|
||||
"objects of built-in types and string views are always copied");
|
||||
emplace_arg(arg.get());
|
||||
}
|
||||
|
||||
/**
|
||||
Adds named argument into the dynamic store for later passing to a formatting
|
||||
function. ``std::reference_wrapper`` is supported to avoid copying of the
|
||||
argument. The name is always copied into the store.
|
||||
*/
|
||||
template <typename T>
|
||||
void push_back(const detail::named_arg<char_type, T>& arg) {
|
||||
const char_type* arg_name =
|
||||
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
|
||||
if (detail::const_check(need_copy<T>::value)) {
|
||||
emplace_arg(
|
||||
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
|
||||
} else {
|
||||
emplace_arg(fmt::arg(arg_name, arg.value));
|
||||
}
|
||||
}
|
||||
|
||||
/** Erase all elements from the store */
|
||||
void clear() {
|
||||
data_.clear();
|
||||
named_info_.clear();
|
||||
dynamic_args_ = detail::dynamic_arg_list();
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Reserves space to store at least *new_cap* arguments including
|
||||
*new_cap_named* named arguments.
|
||||
\endrst
|
||||
*/
|
||||
void reserve(size_t new_cap, size_t new_cap_named) {
|
||||
FMT_ASSERT(new_cap >= new_cap_named,
|
||||
"Set of arguments includes set of named arguments");
|
||||
data_.reserve(new_cap);
|
||||
named_info_.reserve(new_cap_named);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_ARGS_H_
|
||||
2067
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
vendored
Normal file
2067
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
638
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
vendored
Normal file
638
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
vendored
Normal file
@@ -0,0 +1,638 @@
|
||||
// Formatting library for C++ - color support
|
||||
//
|
||||
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COLOR_H_
|
||||
#define FMT_COLOR_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
// __declspec(deprecated) is broken in some MSVC versions.
|
||||
#if FMT_MSC_VER
|
||||
# define FMT_DEPRECATED_NONMSVC
|
||||
#else
|
||||
# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
enum class color : uint32_t {
|
||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||
black = 0x000000, // rgb(0,0,0)
|
||||
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||
blue = 0x0000FF, // rgb(0,0,255)
|
||||
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||
brown = 0xA52A2A, // rgb(165,42,42)
|
||||
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||
coral = 0xFF7F50, // rgb(255,127,80)
|
||||
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||
crimson = 0xDC143C, // rgb(220,20,60)
|
||||
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||
dark_green = 0x006400, // rgb(0,100,0)
|
||||
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||
dim_gray = 0x696969, // rgb(105,105,105)
|
||||
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||
forest_green = 0x228B22, // rgb(34,139,34)
|
||||
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||
gold = 0xFFD700, // rgb(255,215,0)
|
||||
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||
gray = 0x808080, // rgb(128,128,128)
|
||||
green = 0x008000, // rgb(0,128,0)
|
||||
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||
indigo = 0x4B0082, // rgb(75,0,130)
|
||||
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||
light_coral = 0xF08080, // rgb(240,128,128)
|
||||
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||
light_green = 0x90EE90, // rgb(144,238,144)
|
||||
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||
lime = 0x00FF00, // rgb(0,255,0)
|
||||
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||
maroon = 0x800000, // rgb(128,0,0)
|
||||
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||
navy = 0x000080, // rgb(0,0,128)
|
||||
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||
olive = 0x808000, // rgb(128,128,0)
|
||||
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||
orange = 0xFFA500, // rgb(255,165,0)
|
||||
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||
peru = 0xCD853F, // rgb(205,133,63)
|
||||
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||
purple = 0x800080, // rgb(128,0,128)
|
||||
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||
red = 0xFF0000, // rgb(255,0,0)
|
||||
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||
salmon = 0xFA8072, // rgb(250,128,114)
|
||||
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||
sienna = 0xA0522D, // rgb(160,82,45)
|
||||
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||
slate_gray = 0x708090, // rgb(112,128,144)
|
||||
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||
tan = 0xD2B48C, // rgb(210,180,140)
|
||||
teal = 0x008080, // rgb(0,128,128)
|
||||
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||
tomato = 0xFF6347, // rgb(255,99,71)
|
||||
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||
violet = 0xEE82EE, // rgb(238,130,238)
|
||||
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||
white = 0xFFFFFF, // rgb(255,255,255)
|
||||
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||
}; // enum class color
|
||||
|
||||
enum class terminal_color : uint8_t {
|
||||
black = 30,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
bright_black = 90,
|
||||
bright_red,
|
||||
bright_green,
|
||||
bright_yellow,
|
||||
bright_blue,
|
||||
bright_magenta,
|
||||
bright_cyan,
|
||||
bright_white
|
||||
};
|
||||
|
||||
enum class emphasis : uint8_t {
|
||||
bold = 1,
|
||||
faint = 1 << 1,
|
||||
italic = 1 << 2,
|
||||
underline = 1 << 3,
|
||||
blink = 1 << 4,
|
||||
reverse = 1 << 5,
|
||||
conceal = 1 << 6,
|
||||
strikethrough = 1 << 7,
|
||||
};
|
||||
|
||||
// rgb is a struct for red, green and blue colors.
|
||||
// Using the name "rgb" makes some editors show the color in a tooltip.
|
||||
struct rgb {
|
||||
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
|
||||
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
|
||||
FMT_CONSTEXPR rgb(uint32_t hex)
|
||||
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
|
||||
FMT_CONSTEXPR rgb(color hex)
|
||||
: r((uint32_t(hex) >> 16) & 0xFF),
|
||||
g((uint32_t(hex) >> 8) & 0xFF),
|
||||
b(uint32_t(hex) & 0xFF) {}
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
};
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
// color is a struct of either a rgb color or a terminal color.
|
||||
struct color_type {
|
||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
||||
value{} {
|
||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||
}
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||
}
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
||||
value{} {
|
||||
value.term_color = static_cast<uint8_t>(term_color);
|
||||
}
|
||||
bool is_rgb;
|
||||
union color_union {
|
||||
uint8_t term_color;
|
||||
uint32_t rgb_color;
|
||||
} value;
|
||||
};
|
||||
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
/** A text style consisting of foreground and background colors and emphasis. */
|
||||
class text_style {
|
||||
public:
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||
: set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems(em) {}
|
||||
|
||||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||
if (!set_foreground_color) {
|
||||
set_foreground_color = rhs.set_foreground_color;
|
||||
foreground_color = rhs.foreground_color;
|
||||
} else if (rhs.set_foreground_color) {
|
||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||
FMT_THROW(format_error("can't OR a terminal color"));
|
||||
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
|
||||
}
|
||||
|
||||
if (!set_background_color) {
|
||||
set_background_color = rhs.set_background_color;
|
||||
background_color = rhs.background_color;
|
||||
} else if (rhs.set_background_color) {
|
||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||
FMT_THROW(format_error("can't OR a terminal color"));
|
||||
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR text_style operator|(text_style lhs,
|
||||
const text_style& rhs) {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
|
||||
const text_style& rhs) {
|
||||
return and_assign(rhs);
|
||||
}
|
||||
|
||||
FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
|
||||
operator&(text_style lhs, const text_style& rhs) {
|
||||
return lhs.and_assign(rhs);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||
return set_foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
||||
return set_background_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||
return static_cast<uint8_t>(ems) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
|
||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||
return foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
|
||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||
return background_color;
|
||||
}
|
||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||
return ems;
|
||||
}
|
||||
|
||||
private:
|
||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||
detail::color_type text_color) FMT_NOEXCEPT
|
||||
: set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems() {
|
||||
if (is_foreground) {
|
||||
foreground_color = text_color;
|
||||
set_foreground_color = true;
|
||||
} else {
|
||||
background_color = text_color;
|
||||
set_background_color = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
|
||||
if (!set_foreground_color) {
|
||||
set_foreground_color = rhs.set_foreground_color;
|
||||
foreground_color = rhs.foreground_color;
|
||||
} else if (rhs.set_foreground_color) {
|
||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||
FMT_THROW(format_error("can't AND a terminal color"));
|
||||
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
||||
}
|
||||
|
||||
if (!set_background_color) {
|
||||
set_background_color = rhs.set_background_color;
|
||||
background_color = rhs.background_color;
|
||||
} else if (rhs.set_background_color) {
|
||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||
FMT_THROW(format_error("can't AND a terminal color"));
|
||||
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
detail::color_type foreground_color;
|
||||
detail::color_type background_color;
|
||||
bool set_foreground_color;
|
||||
bool set_background_color;
|
||||
emphasis ems;
|
||||
};
|
||||
|
||||
/** Creates a text style from the foreground (text) color. */
|
||||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
||||
return text_style(true, foreground);
|
||||
}
|
||||
|
||||
/** Creates a text style from the background color. */
|
||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
||||
return text_style(false, background);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
||||
emphasis rhs) FMT_NOEXCEPT {
|
||||
return text_style(lhs) | rhs;
|
||||
}
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
template <typename Char> struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
||||
const char* esc) FMT_NOEXCEPT {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
// sequence.
|
||||
if (!text_color.is_rgb) {
|
||||
bool is_background = esc == string_view("\x1b[48;2;");
|
||||
uint32_t value = text_color.value.term_color;
|
||||
// Background ASCII codes are the same as the foreground ones but with
|
||||
// 10 more.
|
||||
if (is_background) value += 10u;
|
||||
|
||||
size_t index = 0;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
|
||||
if (value >= 100u) {
|
||||
buffer[index++] = static_cast<Char>('1');
|
||||
value %= 100u;
|
||||
}
|
||||
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
buffer[index++] = static_cast<Char>('\0');
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
buffer[i] = static_cast<Char>(esc[i]);
|
||||
}
|
||||
rgb color(text_color.value.rgb_color);
|
||||
to_esc(color.r, buffer + 7, ';');
|
||||
to_esc(color.g, buffer + 11, ';');
|
||||
to_esc(color.b, buffer + 15, 'm');
|
||||
buffer[19] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
||||
uint8_t em_codes[num_emphases] = {};
|
||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
|
||||
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
|
||||
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
|
||||
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
|
||||
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
|
||||
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < num_emphases; ++i) {
|
||||
if (!em_codes[i]) continue;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
}
|
||||
buffer[index++] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
|
||||
return buffer + std::char_traits<Char>::length(buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t num_emphases = 8;
|
||||
Char buffer[7u + 3u * num_emphases + 1u];
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||
char delimiter) FMT_NOEXCEPT {
|
||||
out[0] = static_cast<Char>('0' + c / 100);
|
||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||
out[2] = static_cast<Char>('0' + c % 10);
|
||||
out[3] = static_cast<Char>(delimiter);
|
||||
}
|
||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em,
|
||||
emphasis mask) FMT_NOEXCEPT {
|
||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||
detail::color_type foreground) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||
detail::color_type background) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
||||
std::fputs(chars, stream);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
||||
std::fputws(chars, stream);
|
||||
}
|
||||
|
||||
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
||||
fputs("\x1b[0m", stream);
|
||||
}
|
||||
|
||||
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
||||
fputs(L"\x1b[0m", stream);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
buffer.append(reset_color.begin(), reset_color.end());
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||
buf.append(emphasis.begin(), emphasis.end());
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground());
|
||||
buf.append(foreground.begin(), foreground.end());
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
auto background = detail::make_background_color<Char>(ts.get_background());
|
||||
buf.append(background.begin(), background.end());
|
||||
}
|
||||
detail::vformat_to(buf, format_str, args, {});
|
||||
if (has_style) detail::reset_color<Char>(buf);
|
||||
}
|
||||
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
basic_memory_buffer<Char> buf;
|
||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
||||
buf.push_back(Char(0));
|
||||
detail::fputs(buf.data(), f);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats a string and prints it to the specified file stream using ANSI
|
||||
escape sequences to specify text formatting.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||
const Args&... args) {
|
||||
vprint(f, ts, format_str,
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||
specify text formatting.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||
void print(const text_style& ts, const S& format_str, const Args&... args) {
|
||||
return print(stdout, ts, format_str, args...);
|
||||
}
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
inline std::basic_string<Char> vformat(
|
||||
const text_style& ts, const S& format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
basic_memory_buffer<Char> buf;
|
||||
detail::vformat_to(buf, ts, to_string_view(format_str), args);
|
||||
return fmt::to_string(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments and returns the result as a string using ANSI
|
||||
escape sequences to specify text formatting.
|
||||
|
||||
**Example**::
|
||||
|
||||
#include <fmt/color.h>
|
||||
std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"The answer is {}", 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||
const Args&... args) {
|
||||
return fmt::vformat(ts, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
/**
|
||||
Formats a string with the given text_style and writes the output to ``out``.
|
||||
*/
|
||||
template <typename OutputIt, typename Char,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||
OutputIt vformat_to(
|
||||
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
detail::vformat_to(buf, ts, format_str, args);
|
||||
return detail::get_iterator(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments with the given text_style, writes the result to the output
|
||||
iterator ``out`` and returns the iterator past the end of the output range.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::vector<char> out;
|
||||
fmt::format_to(std::back_inserter(out),
|
||||
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&&
|
||||
detail::is_string<S>::value>
|
||||
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
||||
Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
return vformat_to(out, ts, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COLOR_H_
|
||||
642
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
vendored
Normal file
642
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
vendored
Normal file
@@ -0,0 +1,642 @@
|
||||
// Formatting library for C++ - experimental format string compilation
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COMPILE_H_
|
||||
#define FMT_COMPILE_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
// An output iterator that counts the number of objects written to it and
|
||||
// discards them.
|
||||
class counting_iterator {
|
||||
private:
|
||||
size_t count_;
|
||||
|
||||
public:
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
using _Unchecked_type = counting_iterator; // Mark iterator as checked.
|
||||
|
||||
struct value_type {
|
||||
template <typename T> void operator=(const T&) {}
|
||||
};
|
||||
|
||||
counting_iterator() : count_(0) {}
|
||||
|
||||
size_t count() const { return count_; }
|
||||
|
||||
counting_iterator& operator++() {
|
||||
++count_;
|
||||
return *this;
|
||||
}
|
||||
counting_iterator operator++(int) {
|
||||
auto it = *this;
|
||||
++*this;
|
||||
return it;
|
||||
}
|
||||
|
||||
friend counting_iterator operator+(counting_iterator it, difference_type n) {
|
||||
it.count_ += static_cast<size_t>(n);
|
||||
return it;
|
||||
}
|
||||
|
||||
value_type operator*() const { return {}; }
|
||||
};
|
||||
|
||||
template <typename Char, typename InputIt>
|
||||
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
||||
counting_iterator it) {
|
||||
return it + (end - begin);
|
||||
}
|
||||
|
||||
template <typename OutputIt> class truncating_iterator_base {
|
||||
protected:
|
||||
OutputIt out_;
|
||||
size_t limit_;
|
||||
size_t count_ = 0;
|
||||
|
||||
truncating_iterator_base() : out_(), limit_(0) {}
|
||||
|
||||
truncating_iterator_base(OutputIt out, size_t limit)
|
||||
: out_(out), limit_(limit) {}
|
||||
|
||||
public:
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = typename std::iterator_traits<OutputIt>::value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
using _Unchecked_type =
|
||||
truncating_iterator_base; // Mark iterator as checked.
|
||||
|
||||
OutputIt base() const { return out_; }
|
||||
size_t count() const { return count_; }
|
||||
};
|
||||
|
||||
// An output iterator that truncates the output and counts the number of objects
|
||||
// written to it.
|
||||
template <typename OutputIt,
|
||||
typename Enable = typename std::is_void<
|
||||
typename std::iterator_traits<OutputIt>::value_type>::type>
|
||||
class truncating_iterator;
|
||||
|
||||
template <typename OutputIt>
|
||||
class truncating_iterator<OutputIt, std::false_type>
|
||||
: public truncating_iterator_base<OutputIt> {
|
||||
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
|
||||
|
||||
public:
|
||||
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
|
||||
|
||||
truncating_iterator() = default;
|
||||
|
||||
truncating_iterator(OutputIt out, size_t limit)
|
||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||
|
||||
truncating_iterator& operator++() {
|
||||
if (this->count_++ < this->limit_) ++this->out_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
truncating_iterator operator++(int) {
|
||||
auto it = *this;
|
||||
++*this;
|
||||
return it;
|
||||
}
|
||||
|
||||
value_type& operator*() const {
|
||||
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OutputIt>
|
||||
class truncating_iterator<OutputIt, std::true_type>
|
||||
: public truncating_iterator_base<OutputIt> {
|
||||
public:
|
||||
truncating_iterator() = default;
|
||||
|
||||
truncating_iterator(OutputIt out, size_t limit)
|
||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||
|
||||
template <typename T> truncating_iterator& operator=(T val) {
|
||||
if (this->count_++ < this->limit_) *this->out_++ = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
truncating_iterator& operator++() { return *this; }
|
||||
truncating_iterator& operator++(int) { return *this; }
|
||||
truncating_iterator& operator*() { return *this; }
|
||||
};
|
||||
|
||||
// A compile-time string which is compiled into fast formatting code.
|
||||
class compiled_string {};
|
||||
|
||||
template <typename S>
|
||||
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Converts a string literal *s* into a format string that will be parsed at
|
||||
compile time and converted into efficient formatting code. Requires C++17
|
||||
``constexpr if`` compiler support.
|
||||
|
||||
**Example**::
|
||||
|
||||
// Converts 42 into std::string using the most efficient method and no
|
||||
// runtime format string processing.
|
||||
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||
\endrst
|
||||
*/
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
# define FMT_COMPILE(s) \
|
||||
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
|
||||
#else
|
||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||
#endif
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
template <typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct udl_compiled_string : compiled_string {
|
||||
using char_type = Char;
|
||||
constexpr operator basic_string_view<char_type>() const {
|
||||
return {Str.data, N - 1};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, typename... Tail>
|
||||
const T& first(const T& value, const Tail&...) {
|
||||
return value;
|
||||
}
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
template <typename... Args> struct type_list {};
|
||||
|
||||
// Returns a reference to the argument at index N from [first, rest...].
|
||||
template <int N, typename T, typename... Args>
|
||||
constexpr const auto& get([[maybe_unused]] const T& first,
|
||||
[[maybe_unused]] const Args&... rest) {
|
||||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||
if constexpr (N == 0)
|
||||
return first;
|
||||
else
|
||||
return detail::get<N - 1>(rest...);
|
||||
}
|
||||
|
||||
template <typename Char, typename... Args>
|
||||
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
|
||||
type_list<Args...>) {
|
||||
return get_arg_index_by_name<Args...>(name);
|
||||
}
|
||||
|
||||
template <int N, typename> struct get_type_impl;
|
||||
|
||||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||
using type =
|
||||
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
|
||||
};
|
||||
|
||||
template <int N, typename T>
|
||||
using get_type = typename get_type_impl<N, T>::type;
|
||||
|
||||
template <typename T> struct is_compiled_format : std::false_type {};
|
||||
|
||||
template <typename Char> struct text {
|
||||
basic_string_view<Char> data;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||
return write<Char>(out, data);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<text<Char>> : std::true_type {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
||||
size_t size) {
|
||||
return {{&s[pos], size}};
|
||||
}
|
||||
|
||||
template <typename Char> struct code_unit {
|
||||
Char value;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||
return write<Char>(out, value);
|
||||
}
|
||||
};
|
||||
|
||||
// This ensures that the argument type is convertible to `const T&`.
|
||||
template <typename T, int N, typename... Args>
|
||||
constexpr const T& get_arg_checked(const Args&... args) {
|
||||
const auto& arg = detail::get<N>(args...);
|
||||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||
return arg.value;
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<code_unit<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N.
|
||||
template <typename Char, typename T, int N> struct field {
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
return write<Char>(out, get_arg_checked<T, N>(args...));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument with name.
|
||||
template <typename Char> struct runtime_named_field {
|
||||
using char_type = Char;
|
||||
basic_string_view<Char> name;
|
||||
|
||||
template <typename OutputIt, typename T>
|
||||
constexpr static bool try_format_argument(
|
||||
OutputIt& out,
|
||||
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
|
||||
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
|
||||
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
|
||||
if (arg_name == arg.name) {
|
||||
out = write<Char>(out, arg.value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
bool found = (try_format_argument(out, name, args) || ...);
|
||||
if (!found) {
|
||||
FMT_THROW(format_error("argument with specified name is not found"));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N and has format specifiers.
|
||||
template <typename Char, typename T, int N> struct spec_field {
|
||||
using char_type = Char;
|
||||
formatter<T, Char> fmt;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr FMT_INLINE OutputIt format(OutputIt out,
|
||||
const Args&... args) const {
|
||||
const auto& vargs =
|
||||
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
|
||||
basic_format_context<OutputIt, Char> ctx(out, vargs);
|
||||
return fmt.format(get_arg_checked<T, N>(args...), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
|
||||
|
||||
template <typename L, typename R> struct concat {
|
||||
L lhs;
|
||||
R rhs;
|
||||
using char_type = typename L::char_type;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
out = lhs.format(out, args...);
|
||||
return rhs.format(out, args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct is_compiled_format<concat<L, R>> : std::true_type {};
|
||||
|
||||
template <typename L, typename R>
|
||||
constexpr concat<L, R> make_concat(L lhs, R rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
struct unknown_format {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
|
||||
for (size_t size = str.size(); pos != size; ++pos) {
|
||||
if (str[pos] == '{' || str[pos] == '}') break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
template <typename Args, size_t POS, int ID, typename S>
|
||||
constexpr auto compile_format_string(S format_str);
|
||||
|
||||
template <typename Args, size_t POS, int ID, typename T, typename S>
|
||||
constexpr auto parse_tail(T head, S format_str) {
|
||||
if constexpr (POS !=
|
||||
basic_string_view<typename S::char_type>(format_str).size()) {
|
||||
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
||||
unknown_format>())
|
||||
return tail;
|
||||
else
|
||||
return make_concat(head, tail);
|
||||
} else {
|
||||
return head;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Char> struct parse_specs_result {
|
||||
formatter<T, Char> fmt;
|
||||
size_t end;
|
||||
int next_arg_id;
|
||||
};
|
||||
|
||||
constexpr int manual_indexing_id = -1;
|
||||
|
||||
template <typename T, typename Char>
|
||||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||
size_t pos, int next_arg_id) {
|
||||
str.remove_prefix(pos);
|
||||
auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
|
||||
auto f = formatter<T, Char>();
|
||||
auto end = f.parse(ctx);
|
||||
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
|
||||
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
|
||||
}
|
||||
|
||||
template <typename Char> struct arg_id_handler {
|
||||
arg_ref<Char> arg_id;
|
||||
|
||||
constexpr int operator()() {
|
||||
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||
return 0;
|
||||
}
|
||||
constexpr int operator()(int id) {
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
constexpr int operator()(basic_string_view<Char> id) {
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr void on_error(const char* message) {
|
||||
FMT_THROW(format_error(message));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char> struct parse_arg_id_result {
|
||||
arg_ref<Char> arg_id;
|
||||
const Char* arg_id_end;
|
||||
};
|
||||
|
||||
template <int ID, typename Char>
|
||||
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
||||
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
|
||||
auto arg_id_end = parse_arg_id(begin, end, handler);
|
||||
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void> struct field_type {
|
||||
using type = remove_cvref_t<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
|
||||
using type = remove_cvref_t<decltype(T::value)>;
|
||||
};
|
||||
|
||||
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
|
||||
typename S>
|
||||
constexpr auto parse_replacement_field_then_tail(S format_str) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr auto str = basic_string_view<char_type>(format_str);
|
||||
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
|
||||
if constexpr (c == '}') {
|
||||
return parse_tail<Args, END_POS + 1, NEXT_ID>(
|
||||
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
|
||||
format_str);
|
||||
} else if constexpr (c == ':') {
|
||||
constexpr auto result = parse_specs<typename field_type<T>::type>(
|
||||
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
|
||||
return parse_tail<Args, result.end, result.next_arg_id>(
|
||||
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
|
||||
result.fmt},
|
||||
format_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Compiles a non-empty format string and returns the compiled representation
|
||||
// or unknown_format() on unrecognized input.
|
||||
template <typename Args, size_t POS, int ID, typename S>
|
||||
constexpr auto compile_format_string(S format_str) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr auto str = basic_string_view<char_type>(format_str);
|
||||
if constexpr (str[POS] == '{') {
|
||||
if constexpr (POS + 1 == str.size())
|
||||
FMT_THROW(format_error("unmatched '{' in format string"));
|
||||
if constexpr (str[POS + 1] == '{') {
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
|
||||
static_assert(ID != manual_indexing_id,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
|
||||
POS + 1, ID, next_id>(
|
||||
format_str);
|
||||
} else {
|
||||
constexpr auto arg_id_result =
|
||||
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
|
||||
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
|
||||
constexpr char_type c =
|
||||
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
|
||||
static_assert(c == '}' || c == ':', "missing '}' in format string");
|
||||
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
|
||||
static_assert(
|
||||
ID == manual_indexing_id || ID == 0,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
constexpr auto arg_index = arg_id_result.arg_id.val.index;
|
||||
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
|
||||
Args, arg_id_end_pos,
|
||||
arg_index, manual_indexing_id>(
|
||||
format_str);
|
||||
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
|
||||
constexpr auto arg_index =
|
||||
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
|
||||
if constexpr (arg_index != invalid_arg_index) {
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_replacement_field_then_tail<
|
||||
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
|
||||
arg_index, next_id>(format_str);
|
||||
} else {
|
||||
if constexpr (c == '}') {
|
||||
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
||||
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
|
||||
format_str);
|
||||
} else if constexpr (c == ':') {
|
||||
return unknown_format(); // no type info for specs parsing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if constexpr (str[POS] == '}') {
|
||||
if constexpr (POS + 1 == str.size())
|
||||
FMT_THROW(format_error("unmatched '}' in format string"));
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||
} else {
|
||||
constexpr auto end = parse_text(str, POS + 1);
|
||||
if constexpr (end - POS > 1) {
|
||||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
||||
format_str);
|
||||
} else {
|
||||
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
|
||||
format_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args, typename S,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
constexpr auto compile(S format_str) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(format_str);
|
||||
if constexpr (str.size() == 0) {
|
||||
return detail::make_text(str, 0, 0);
|
||||
} else {
|
||||
constexpr auto result =
|
||||
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
|
||||
format_str);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
} // namespace detail
|
||||
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
|
||||
template <typename CompiledFormat, typename... Args,
|
||||
typename Char = typename CompiledFormat::char_type,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
auto s = std::basic_string<Char>();
|
||||
cf.format(std::back_inserter(s), args...);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
return cf.format(out, args...);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
Args&&... args) {
|
||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(S());
|
||||
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
|
||||
const auto& first = detail::first(args...);
|
||||
if constexpr (detail::is_named_arg<
|
||||
remove_cvref_t<decltype(first)>>::value) {
|
||||
return fmt::to_string(first.value);
|
||||
} else {
|
||||
return fmt::to_string(first);
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return format(compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return format_to(out,
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return format_to(out, compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||
const S& format_str, Args&&... args) {
|
||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
|
||||
std::forward<Args>(args)...);
|
||||
return {it.base(), it.count()};
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
size_t formatted_size(const S& format_str, const Args&... args) {
|
||||
return format_to(detail::counting_iterator(), format_str, args...).count();
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
||||
memory_buffer buffer;
|
||||
format_to(std::back_inserter(buffer), format_str, args...);
|
||||
detail::print(f, {buffer.data(), buffer.size()});
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
void print(const S& format_str, const Args&... args) {
|
||||
print(stdout, format_str, args...);
|
||||
}
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
inline namespace literals {
|
||||
template <detail_exported::fixed_string Str>
|
||||
constexpr detail::udl_compiled_string<
|
||||
remove_cvref_t<decltype(Str.data[0])>,
|
||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
||||
operator""_cf() {
|
||||
return {};
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COMPILE_H_
|
||||
3236
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
vendored
Normal file
3236
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2642
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h
vendored
Normal file
2642
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3104
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
vendored
Normal file
3104
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/locale.h
vendored
Normal file
2
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/locale.h
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "xchar.h"
|
||||
#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead
|
||||
527
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
vendored
Normal file
527
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
vendored
Normal file
@@ -0,0 +1,527 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OS_H_
|
||||
#define FMT_OS_H_
|
||||
|
||||
#include <cerrno>
|
||||
#include <clocale> // locale_t
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib> // strtod_l
|
||||
#include <system_error> // std::system_error
|
||||
|
||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifndef FMT_USE_FCNTL
|
||||
// UWP doesn't provide _pipe.
|
||||
# if FMT_HAS_INCLUDE("winapifamily.h")
|
||||
# include <winapifamily.h>
|
||||
# endif
|
||||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || \
|
||||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
# include <fcntl.h> // for O_RDONLY
|
||||
# define FMT_USE_FCNTL 1
|
||||
# else
|
||||
# define FMT_USE_FCNTL 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
// 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)
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
/**
|
||||
\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 type aliases for common character types:
|
||||
|
||||
+---------------+-----------------------------+
|
||||
| Type | Definition |
|
||||
+===============+=============================+
|
||||
| cstring_view | basic_cstring_view<char> |
|
||||
+---------------+-----------------------------+
|
||||
| wcstring_view | basic_cstring_view<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(cstring_view format_str, const Args & ... args);
|
||||
|
||||
format("{}", 42);
|
||||
format(std::string("{}"), 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename Char> class basic_cstring_view {
|
||||
private:
|
||||
const Char* data_;
|
||||
|
||||
public:
|
||||
/** Constructs a string reference object from a C string. */
|
||||
basic_cstring_view(const Char* s) : data_(s) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs a string reference from an ``std::string`` object.
|
||||
\endrst
|
||||
*/
|
||||
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
||||
|
||||
/** Returns the pointer to a C string. */
|
||||
const Char* c_str() const { return data_; }
|
||||
};
|
||||
|
||||
using cstring_view = basic_cstring_view<char>;
|
||||
using wcstring_view = basic_cstring_view<wchar_t>;
|
||||
|
||||
template <typename Char> struct formatter<std::error_code, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::write_bytes(out, ec.category().name(),
|
||||
basic_format_specs<Char>());
|
||||
out = detail::write<Char>(out, Char(':'));
|
||||
out = detail::write<Char>(out, ec.value());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
// A converter from UTF-16 to UTF-8.
|
||||
// It is only provided for Windows since other systems support UTF-8 natively.
|
||||
class utf16_to_utf8 {
|
||||
private:
|
||||
memory_buffer buffer_;
|
||||
|
||||
public:
|
||||
utf16_to_utf8() {}
|
||||
FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s);
|
||||
operator string_view() const { return string_view(&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(basic_string_view<wchar_t> s);
|
||||
};
|
||||
|
||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||
const char* message) FMT_NOEXCEPT;
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
||||
format_args args);
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs a :class:`std::system_error` 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 system_error 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::windows_error(GetLastError(),
|
||||
"cannot open file '{}'", filename);
|
||||
}
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::system_error windows_error(int error_code, string_view message,
|
||||
const Args&... args) {
|
||||
return vwindows_error(error_code, message, fmt::make_format_args(args...));
|
||||
}
|
||||
|
||||
// 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,
|
||||
const char* message) FMT_NOEXCEPT;
|
||||
#else
|
||||
inline const std::error_category& system_category() FMT_NOEXCEPT {
|
||||
return std::system_category();
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// std::system is not available on some platforms such as iOS (#2248).
|
||||
#ifdef __OSX__
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
void say(const S& format_str, Args&&... args) {
|
||||
std::system(format("say \"{}\"", format(format_str, args...)).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// A buffered file.
|
||||
class buffered_file {
|
||||
private:
|
||||
FILE* file_;
|
||||
|
||||
friend class file;
|
||||
|
||||
explicit buffered_file(FILE* f) : file_(f) {}
|
||||
|
||||
public:
|
||||
buffered_file(const buffered_file&) = delete;
|
||||
void operator=(const buffered_file&) = delete;
|
||||
|
||||
// Constructs a buffered_file object which doesn't represent any file.
|
||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||
|
||||
public:
|
||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
|
||||
buffered_file& operator=(buffered_file&& other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Opens a file.
|
||||
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
||||
|
||||
// Closes the file.
|
||||
FMT_API 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.
|
||||
FMT_API int(fileno)() const;
|
||||
|
||||
void vprint(string_view format_str, format_args args) {
|
||||
fmt::vprint(file_, format_str, args);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void print(string_view format_str, const Args&... args) {
|
||||
vprint(format_str, fmt::make_format_args(args...));
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
// A file. Closed file is represented by a file object with descriptor -1.
|
||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||
// fmt::system_error 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.
|
||||
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
||||
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
|
||||
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
|
||||
};
|
||||
|
||||
// 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.
|
||||
FMT_API file(cstring_view path, int oflag);
|
||||
|
||||
public:
|
||||
file(const file&) = delete;
|
||||
void operator=(const file&) = delete;
|
||||
|
||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
||||
|
||||
// Move assignment is not noexcept because close may throw.
|
||||
file& operator=(file&& other) {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~file() FMT_NOEXCEPT;
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
FMT_API long long size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
FMT_API size_t read(void* buffer, size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
FMT_API size_t write(const void* buffer, size_t count);
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
FMT_API static file dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
FMT_API void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
FMT_API static void pipe(file& read_end, file& write_end);
|
||||
|
||||
// Creates a buffered_file object associated with this file and detaches
|
||||
// this file object from the file.
|
||||
FMT_API buffered_file fdopen(const char* mode);
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
long getpagesize();
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
struct buffer_size {
|
||||
buffer_size() = default;
|
||||
size_t value = 0;
|
||||
buffer_size operator=(size_t val) const {
|
||||
auto bs = buffer_size();
|
||||
bs.value = val;
|
||||
return bs;
|
||||
}
|
||||
};
|
||||
|
||||
struct ostream_params {
|
||||
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
|
||||
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
||||
|
||||
ostream_params() {}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
|
||||
oflag = new_oflag;
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, detail::buffer_size bs)
|
||||
: ostream_params(params...) {
|
||||
this->buffer_size = bs.value;
|
||||
}
|
||||
|
||||
// Intel has a bug that results in failure to deduce a constructor
|
||||
// for empty parameter packs.
|
||||
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
|
||||
ostream_params(int new_oflag) : oflag(new_oflag) {}
|
||||
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
|
||||
# endif
|
||||
};
|
||||
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
// Added {} below to work around default constructor error known to
|
||||
// occur in Xcode versions 7.2.1 and 8.2.1.
|
||||
constexpr detail::buffer_size buffer_size{};
|
||||
|
||||
/** A fast output stream which is not thread-safe. */
|
||||
class FMT_API ostream final : private detail::buffer<char> {
|
||||
private:
|
||||
file file_;
|
||||
|
||||
void grow(size_t) override;
|
||||
|
||||
ostream(cstring_view path, const detail::ostream_params& params)
|
||||
: file_(path, params.oflag) {
|
||||
set(new char[params.buffer_size], params.buffer_size);
|
||||
}
|
||||
|
||||
public:
|
||||
ostream(ostream&& other)
|
||||
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
|
||||
file_(std::move(other.file_)) {
|
||||
other.clear();
|
||||
other.set(nullptr, 0);
|
||||
}
|
||||
~ostream() {
|
||||
flush();
|
||||
delete[] data();
|
||||
}
|
||||
|
||||
void flush() {
|
||||
if (size() == 0) return;
|
||||
file_.write(data(), size());
|
||||
clear();
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
friend ostream output_file(cstring_view path, T... params);
|
||||
|
||||
void close() {
|
||||
flush();
|
||||
file_.close();
|
||||
}
|
||||
|
||||
/**
|
||||
Formats ``args`` according to specifications in ``fmt`` and writes the
|
||||
output to the file.
|
||||
*/
|
||||
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
||||
vformat_to(detail::buffer_appender<char>(*this), fmt,
|
||||
fmt::make_format_args(args...));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Opens a file for writing. Supported parameters passed in *params*:
|
||||
|
||||
* ``<integer>``: Flags passed to `open
|
||||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
||||
(``file::WRONLY | file::CREATE`` by default)
|
||||
* ``buffer_size=<integer>``: Output buffer size
|
||||
|
||||
**Example**::
|
||||
|
||||
auto out = fmt::output_file("guide.txt");
|
||||
out.print("Don't {}", "Panic");
|
||||
\endrst
|
||||
*/
|
||||
template <typename... T>
|
||||
inline ostream output_file(cstring_view path, T... params) {
|
||||
return {path, detail::ostream_params(params...)};
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
#ifdef FMT_LOCALE
|
||||
// A "C" numeric locale.
|
||||
class locale {
|
||||
private:
|
||||
# ifdef _WIN32
|
||||
using locale_t = _locale_t;
|
||||
|
||||
static void freelocale(locale_t loc) { _free_locale(loc); }
|
||||
|
||||
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
|
||||
return _strtod_l(nptr, endptr, loc);
|
||||
}
|
||||
# endif
|
||||
|
||||
locale_t locale_;
|
||||
|
||||
public:
|
||||
using type = locale_t;
|
||||
locale(const locale&) = delete;
|
||||
void operator=(const locale&) = delete;
|
||||
|
||||
locale() {
|
||||
# ifndef _WIN32
|
||||
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
|
||||
# else
|
||||
locale_ = _create_locale(LC_NUMERIC, "C");
|
||||
# endif
|
||||
if (!locale_) FMT_THROW(system_error(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.
|
||||
FMT_DEPRECATED double strtod(const char*& str) const {
|
||||
char* end = nullptr;
|
||||
double result = strtod_l(str, &end, locale_);
|
||||
str = end;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
using Locale FMT_DEPRECATED_ALIAS = locale;
|
||||
#endif // FMT_LOCALE
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OS_H_
|
||||
135
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
vendored
Normal file
135
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// Formatting library for C++ - std::ostream support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
#define FMT_OSTREAM_H_
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Checks if T has a user-defined operator<<.
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
class is_streamable {
|
||||
private:
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
|
||||
<< std::declval<U>()) != 0>;
|
||||
|
||||
template <typename> static auto test(...) -> std::false_type;
|
||||
|
||||
using result = decltype(test<T>(0));
|
||||
|
||||
public:
|
||||
is_streamable() = default;
|
||||
|
||||
static const bool value = result::value;
|
||||
};
|
||||
|
||||
// Formatting of built-in types and arrays is intentionally disabled because
|
||||
// it's handled by standard (non-ostream) formatters.
|
||||
template <typename T, typename Char>
|
||||
struct is_streamable<
|
||||
T, Char,
|
||||
enable_if_t<
|
||||
std::is_arithmetic<T>::value || std::is_array<T>::value ||
|
||||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
|
||||
std::is_same<T, std::basic_string<Char>>::value ||
|
||||
std::is_same<T, std_string_view<Char>>::value ||
|
||||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
|
||||
: std::false_type {};
|
||||
|
||||
// Write the content of buf to os.
|
||||
// It is a separate function rather than a part of vprint to simplify testing.
|
||||
template <typename Char>
|
||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||
const Char* buf_data = buf.data();
|
||||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||
unsigned_streamsize size = buf.size();
|
||||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||
do {
|
||||
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||
buf_data += n;
|
||||
size -= n;
|
||||
} while (size != 0);
|
||||
}
|
||||
|
||||
template <typename Char, typename T>
|
||||
void format_value(buffer<Char>& buf, const T& value,
|
||||
locale_ref loc = locale_ref()) {
|
||||
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
|
||||
auto&& output = std::basic_ostream<Char>(&format_buf);
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
if (loc) output.imbue(loc.get<std::locale>());
|
||||
#endif
|
||||
output << value;
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
buf.try_resize(buf.size());
|
||||
}
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename T, typename Char>
|
||||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||
: private formatter<basic_string_view<Char>, Char> {
|
||||
using formatter<basic_string_view<Char>, Char>::parse;
|
||||
|
||||
template <typename OutputIt>
|
||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
|
||||
-> OutputIt {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
format_value(buffer, value, ctx.locale());
|
||||
return formatter<basic_string_view<Char>, Char>::format(
|
||||
{buffer.data(), buffer.size()}, ctx);
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
template <typename OutputIt>
|
||||
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
|
||||
-> OutputIt {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
format_value(buffer, value, ctx.locale());
|
||||
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
FMT_MODULE_EXPORT
|
||||
template <typename Char>
|
||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(cerr, "Don't {}!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
FMT_MODULE_EXPORT
|
||||
template <typename S, typename... Args,
|
||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||
vprint(os, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OSTREAM_H_
|
||||
657
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
vendored
Normal file
657
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
vendored
Normal file
@@ -0,0 +1,657 @@
|
||||
// Formatting library for C++ - legacy printf implementation
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_PRINTF_H_
|
||||
#define FMT_PRINTF_H_
|
||||
|
||||
#include <algorithm> // std::max
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <ostream>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
template <typename T> struct printf_formatter { printf_formatter() = delete; };
|
||||
|
||||
template <typename Char>
|
||||
class basic_printf_parse_context : public basic_format_parse_context<Char> {
|
||||
using basic_format_parse_context<Char>::basic_format_parse_context;
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Char> class basic_printf_context {
|
||||
private:
|
||||
OutputIt out_;
|
||||
basic_format_args<basic_printf_context> args_;
|
||||
|
||||
public:
|
||||
using char_type = Char;
|
||||
using format_arg = basic_format_arg<basic_printf_context>;
|
||||
using parse_context_type = basic_printf_parse_context<Char>;
|
||||
template <typename T> using formatter_type = printf_formatter<T>;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs a ``printf_context`` object. References to the arguments are
|
||||
stored in the context object so make sure they have appropriate lifetimes.
|
||||
\endrst
|
||||
*/
|
||||
basic_printf_context(OutputIt out,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: out_(out), args_(args) {}
|
||||
|
||||
OutputIt out() { return out_; }
|
||||
void advance_to(OutputIt it) { out_ = it; }
|
||||
|
||||
detail::locale_ref locale() { return {}; }
|
||||
|
||||
format_arg arg(int id) const { return args_.get(id); }
|
||||
|
||||
FMT_CONSTEXPR void on_error(const char* message) {
|
||||
detail::error_handler().on_error(message);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned> struct int_checker {
|
||||
template <typename T> static bool fits_in_int(T value) {
|
||||
unsigned max = max_value<int>();
|
||||
return value <= max;
|
||||
}
|
||||
static bool fits_in_int(bool) { return true; }
|
||||
};
|
||||
|
||||
template <> struct int_checker<true> {
|
||||
template <typename T> static bool fits_in_int(T value) {
|
||||
return value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= max_value<int>();
|
||||
}
|
||||
static bool fits_in_int(int) { return true; }
|
||||
};
|
||||
|
||||
class printf_precision_handler {
|
||||
public:
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
int operator()(T value) {
|
||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
FMT_THROW(format_error("number is too big"));
|
||||
return (std::max)(static_cast<int>(value), 0);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
int operator()(T) {
|
||||
FMT_THROW(format_error("precision is not integer"));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// An argument visitor that returns true iff arg is a zero integer.
|
||||
class is_zero_int {
|
||||
public:
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
bool operator()(T value) {
|
||||
return value == 0;
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
bool operator()(T) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
||||
|
||||
template <> struct make_unsigned_or_bool<bool> { using type = bool; };
|
||||
|
||||
template <typename T, typename Context> class arg_converter {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
basic_format_arg<Context>& arg_;
|
||||
char_type type_;
|
||||
|
||||
public:
|
||||
arg_converter(basic_format_arg<Context>& arg, char_type type)
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void operator()(bool value) {
|
||||
if (type_ != 's') operator()<bool>(value);
|
||||
}
|
||||
|
||||
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
|
||||
void operator()(U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
|
||||
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
||||
// Extra casts are used to silence warnings.
|
||||
if (is_signed) {
|
||||
arg_ = detail::make_arg<Context>(
|
||||
static_cast<int>(static_cast<target_type>(value)));
|
||||
} else {
|
||||
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
||||
arg_ = detail::make_arg<Context>(
|
||||
static_cast<unsigned>(static_cast<unsigned_type>(value)));
|
||||
}
|
||||
} else {
|
||||
if (is_signed) {
|
||||
// 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_ = detail::make_arg<Context>(static_cast<long long>(value));
|
||||
} else {
|
||||
arg_ = detail::make_arg<Context>(
|
||||
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
|
||||
void operator()(U) {} // No conversion needed for non-integral types.
|
||||
};
|
||||
|
||||
// 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, typename Context, typename Char>
|
||||
void convert_arg(basic_format_arg<Context>& arg, Char type) {
|
||||
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
|
||||
}
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
template <typename Context> class char_converter {
|
||||
private:
|
||||
basic_format_arg<Context>& arg_;
|
||||
|
||||
public:
|
||||
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
void operator()(T value) {
|
||||
arg_ = detail::make_arg<Context>(
|
||||
static_cast<typename Context::char_type>(value));
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
void operator()(T) {} // No conversion needed for non-integral types.
|
||||
};
|
||||
|
||||
// An argument visitor that return a pointer to a C string if argument is a
|
||||
// string or null otherwise.
|
||||
template <typename Char> struct get_cstring {
|
||||
template <typename T> const Char* operator()(T) { return nullptr; }
|
||||
const Char* operator()(const Char* s) { return s; }
|
||||
};
|
||||
|
||||
// Checks if an argument is a valid printf width specifier and sets
|
||||
// left alignment if it is negative.
|
||||
template <typename Char> class printf_width_handler {
|
||||
private:
|
||||
using format_specs = basic_format_specs<Char>;
|
||||
|
||||
format_specs& specs_;
|
||||
|
||||
public:
|
||||
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
unsigned operator()(T value) {
|
||||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||
if (detail::is_negative(value)) {
|
||||
specs_.align = align::left;
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = max_value<int>();
|
||||
if (width > int_max) FMT_THROW(format_error("number is too big"));
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
unsigned operator()(T) {
|
||||
FMT_THROW(format_error("width is not integer"));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// The ``printf`` argument formatter.
|
||||
template <typename OutputIt, typename Char>
|
||||
class printf_arg_formatter : public arg_formatter<Char> {
|
||||
private:
|
||||
using base = arg_formatter<Char>;
|
||||
using context_type = basic_printf_context<OutputIt, Char>;
|
||||
using format_specs = basic_format_specs<Char>;
|
||||
|
||||
context_type& context_;
|
||||
|
||||
OutputIt write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs;
|
||||
s.type = presentation_type::none;
|
||||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
||||
}
|
||||
|
||||
public:
|
||||
printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
|
||||
: base{iter, s, locale_ref()}, context_(ctx) {}
|
||||
|
||||
OutputIt operator()(monostate value) { return base::operator()(value); }
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
|
||||
OutputIt operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||
// std::is_same instead.
|
||||
if (std::is_same<T, Char>::value) {
|
||||
format_specs fmt_specs = this->specs;
|
||||
if (fmt_specs.type != presentation_type::none &&
|
||||
fmt_specs.type != presentation_type::chr) {
|
||||
return (*this)(static_cast<int>(value));
|
||||
}
|
||||
fmt_specs.sign = sign::none;
|
||||
fmt_specs.alt = false;
|
||||
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
||||
// align::numeric needs to be overwritten here since the '0' flag is
|
||||
// ignored for non-numeric types
|
||||
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
||||
fmt_specs.align = align::right;
|
||||
return write<Char>(this->out, static_cast<Char>(value), fmt_specs);
|
||||
}
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||
OutputIt operator()(T value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated C string. */
|
||||
OutputIt operator()(const char* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated wide C string. */
|
||||
OutputIt operator()(const wchar_t* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
}
|
||||
|
||||
OutputIt operator()(basic_string_view<Char> value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
/** Formats a pointer. */
|
||||
OutputIt operator()(const void* value) {
|
||||
return value ? base::operator()(value) : write_null_pointer();
|
||||
}
|
||||
|
||||
/** Formats an argument of a custom (user-defined) type. */
|
||||
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
auto parse_ctx =
|
||||
basic_printf_parse_context<Char>(basic_string_view<Char>());
|
||||
handle.format(parse_ctx, context_);
|
||||
return this->out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
|
||||
const Char* end) {
|
||||
for (; it != end; ++it) {
|
||||
switch (*it) {
|
||||
case '-':
|
||||
specs.align = align::left;
|
||||
break;
|
||||
case '+':
|
||||
specs.sign = sign::plus;
|
||||
break;
|
||||
case '0':
|
||||
specs.fill[0] = '0';
|
||||
break;
|
||||
case ' ':
|
||||
if (specs.sign != sign::plus) {
|
||||
specs.sign = sign::space;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
specs.alt = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename GetArg>
|
||||
int parse_header(const Char*& it, const Char* end,
|
||||
basic_format_specs<Char>& specs, GetArg get_arg) {
|
||||
int arg_index = -1;
|
||||
Char c = *it;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
int value = parse_nonnegative_int(it, end, -1);
|
||||
if (it != end && *it == '$') { // value is an argument index
|
||||
++it;
|
||||
arg_index = value != -1 ? value : max_value<int>();
|
||||
} else {
|
||||
if (c == '0') specs.fill[0] = '0';
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
if (value == -1) FMT_THROW(format_error("number is too big"));
|
||||
specs.width = value;
|
||||
return arg_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_flags(specs, it, end);
|
||||
// Parse width.
|
||||
if (it != end) {
|
||||
if (*it >= '0' && *it <= '9') {
|
||||
specs.width = parse_nonnegative_int(it, end, -1);
|
||||
if (specs.width == -1) FMT_THROW(format_error("number is too big"));
|
||||
} else if (*it == '*') {
|
||||
++it;
|
||||
specs.width = static_cast<int>(visit_format_arg(
|
||||
detail::printf_width_handler<Char>(specs), get_arg(-1)));
|
||||
}
|
||||
}
|
||||
return arg_index;
|
||||
}
|
||||
|
||||
template <typename Char, typename Context>
|
||||
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
basic_format_args<Context> args) {
|
||||
using OutputIt = buffer_appender<Char>;
|
||||
auto out = OutputIt(buf);
|
||||
auto context = basic_printf_context<OutputIt, Char>(out, args);
|
||||
auto parse_ctx = basic_printf_parse_context<Char>(format);
|
||||
|
||||
// Returns the argument with specified index or, if arg_index is -1, the next
|
||||
// argument.
|
||||
auto get_arg = [&](int arg_index) {
|
||||
if (arg_index < 0)
|
||||
arg_index = parse_ctx.next_arg_id();
|
||||
else
|
||||
parse_ctx.check_arg_id(--arg_index);
|
||||
return detail::get_arg(context, arg_index);
|
||||
};
|
||||
|
||||
const Char* start = parse_ctx.begin();
|
||||
const Char* end = parse_ctx.end();
|
||||
auto it = start;
|
||||
while (it != end) {
|
||||
if (!detail::find<false, Char>(it, end, '%', it)) {
|
||||
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
|
||||
break;
|
||||
}
|
||||
Char c = *it++;
|
||||
if (it != end && *it == c) {
|
||||
out = detail::write(
|
||||
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
|
||||
start = ++it;
|
||||
continue;
|
||||
}
|
||||
out = detail::write(out, basic_string_view<Char>(
|
||||
start, detail::to_unsigned(it - 1 - start)));
|
||||
|
||||
basic_format_specs<Char> specs;
|
||||
specs.align = align::right;
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
int arg_index = parse_header(it, end, specs, get_arg);
|
||||
if (arg_index == 0) parse_ctx.on_error("argument not found");
|
||||
|
||||
// Parse precision.
|
||||
if (it != end && *it == '.') {
|
||||
++it;
|
||||
c = it != end ? *it : 0;
|
||||
if ('0' <= c && c <= '9') {
|
||||
specs.precision = parse_nonnegative_int(it, end, 0);
|
||||
} else if (c == '*') {
|
||||
++it;
|
||||
specs.precision = static_cast<int>(
|
||||
visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
|
||||
} else {
|
||||
specs.precision = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto arg = get_arg(arg_index);
|
||||
// For d, i, o, u, x, and X conversion specifiers, if a precision is
|
||||
// specified, the '0' flag is ignored
|
||||
if (specs.precision >= 0 && arg.is_integral())
|
||||
specs.fill[0] =
|
||||
' '; // Ignore '0' flag for non-numeric types or if '-' present.
|
||||
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
|
||||
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
|
||||
auto str_end = str + specs.precision;
|
||||
auto nul = std::find(str, str_end, Char());
|
||||
arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
|
||||
basic_string_view<Char>(
|
||||
str, detail::to_unsigned(nul != str_end ? nul - str
|
||||
: specs.precision)));
|
||||
}
|
||||
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
|
||||
specs.alt = false;
|
||||
if (specs.fill[0] == '0') {
|
||||
if (arg.is_arithmetic() && specs.align != align::left)
|
||||
specs.align = align::numeric;
|
||||
else
|
||||
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
|
||||
// flag is also present.
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
c = it != end ? *it++ : 0;
|
||||
Char t = it != end ? *it : 0;
|
||||
using detail::convert_arg;
|
||||
switch (c) {
|
||||
case 'h':
|
||||
if (t == 'h') {
|
||||
++it;
|
||||
t = it != end ? *it : 0;
|
||||
convert_arg<signed char>(arg, t);
|
||||
} else {
|
||||
convert_arg<short>(arg, t);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (t == 'l') {
|
||||
++it;
|
||||
t = it != end ? *it : 0;
|
||||
convert_arg<long long>(arg, t);
|
||||
} else {
|
||||
convert_arg<long>(arg, t);
|
||||
}
|
||||
break;
|
||||
case 'j':
|
||||
convert_arg<intmax_t>(arg, t);
|
||||
break;
|
||||
case 'z':
|
||||
convert_arg<size_t>(arg, t);
|
||||
break;
|
||||
case 't':
|
||||
convert_arg<std::ptrdiff_t>(arg, t);
|
||||
break;
|
||||
case 'L':
|
||||
// printf produces garbage when 'L' is omitted for long double, no
|
||||
// need to do the same.
|
||||
break;
|
||||
default:
|
||||
--it;
|
||||
convert_arg<void>(arg, c);
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
||||
char type = static_cast<char>(*it++);
|
||||
if (arg.is_integral()) {
|
||||
// Normalize type.
|
||||
switch (type) {
|
||||
case 'i':
|
||||
case 'u':
|
||||
type = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
visit_format_arg(
|
||||
detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
|
||||
arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
specs.type = parse_presentation_type(type);
|
||||
if (specs.type == presentation_type::none)
|
||||
parse_ctx.on_error("invalid type specifier");
|
||||
|
||||
start = it;
|
||||
|
||||
// Format argument.
|
||||
out = visit_format_arg(
|
||||
detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
|
||||
}
|
||||
detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||
}
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
template <typename Char>
|
||||
using basic_printf_context_t =
|
||||
basic_printf_context<detail::buffer_appender<Char>, Char>;
|
||||
|
||||
using printf_context = basic_printf_context_t<char>;
|
||||
using wprintf_context = basic_printf_context_t<wchar_t>;
|
||||
|
||||
using printf_args = basic_format_args<printf_context>;
|
||||
using wprintf_args = basic_format_args<wprintf_context>;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||
arguments and can be implicitly converted to `~fmt::printf_args`.
|
||||
\endrst
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto make_printf_args(const T&... args)
|
||||
-> format_arg_store<printf_context, T...> {
|
||||
return {args...};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||
arguments and can be implicitly converted to `~fmt::wprintf_args`.
|
||||
\endrst
|
||||
*/
|
||||
template <typename... T>
|
||||
inline auto make_wprintf_args(const T&... args)
|
||||
-> format_arg_store<wprintf_context, T...> {
|
||||
return {args...};
|
||||
}
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
inline auto vsprintf(
|
||||
const S& fmt,
|
||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||
-> std::basic_string<Char> {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
vprintf(buffer, to_string_view(fmt), args);
|
||||
return to_string(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments and returns the result as a string.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... T,
|
||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
||||
using context = basic_printf_context_t<Char>;
|
||||
return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
inline auto vfprintf(
|
||||
std::FILE* f, const S& fmt,
|
||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||
-> int {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
vprintf(buffer, to_string_view(fmt), args);
|
||||
size_t size = buffer.size();
|
||||
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
|
||||
? -1
|
||||
: static_cast<int>(size);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the file *f*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... T, typename Char = char_t<S>>
|
||||
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
||||
using context = basic_printf_context_t<Char>;
|
||||
return vfprintf(f, to_string_view(fmt),
|
||||
fmt::make_format_args<context>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
inline auto vprintf(
|
||||
const S& fmt,
|
||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||
-> int {
|
||||
return vfprintf(stdout, to_string_view(fmt), args);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to ``stdout``.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||
inline auto printf(const S& fmt, const T&... args) -> int {
|
||||
return vprintf(
|
||||
to_string_view(fmt),
|
||||
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
FMT_DEPRECATED auto vfprintf(
|
||||
std::basic_ostream<Char>& os, const S& fmt,
|
||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||
-> int {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
vprintf(buffer, to_string_view(fmt), args);
|
||||
os.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
||||
return static_cast<int>(buffer.size());
|
||||
}
|
||||
template <typename S, typename... T, typename Char = char_t<S>>
|
||||
FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt,
|
||||
const T&... args) -> int {
|
||||
return vfprintf(os, to_string_view(fmt),
|
||||
fmt::make_format_args<basic_printf_context_t<Char>>(args...));
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_PRINTF_H_
|
||||
793
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
vendored
Normal file
793
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
vendored
Normal file
@@ -0,0 +1,793 @@
|
||||
// Formatting library for C++ - experimental range support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
//
|
||||
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
|
||||
// All Rights Reserved
|
||||
// {fmt} support for ranges, containers and types tuple interface.
|
||||
|
||||
#ifndef FMT_RANGES_H_
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename RangeT, typename OutputIterator>
|
||||
OutputIterator copy(const RangeT& range, OutputIterator out) {
|
||||
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
||||
*out++ = *it;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
OutputIterator copy(const char* str, OutputIterator out) {
|
||||
while (*str) *out++ = *str++;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
OutputIterator copy(char ch, OutputIterator out) {
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
OutputIterator copy(wchar_t ch, OutputIterator out) {
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Returns true if T has a std::string-like interface, like std::string_view.
|
||||
template <typename T> class is_std_string_like {
|
||||
template <typename U>
|
||||
static auto check(U* p)
|
||||
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
is_string<T>::value ||
|
||||
std::is_convertible<T, std_string_view<char>>::value ||
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||
|
||||
template <typename T> class is_map {
|
||||
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
#ifdef FMT_FORMAT_MAP_AS_LIST
|
||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||
#else
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T> class is_set {
|
||||
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
#ifdef FMT_FORMAT_SET_AS_LIST
|
||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||
#else
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename... Ts> struct conditional_helper {};
|
||||
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
|
||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
||||
|
||||
# define FMT_DECLTYPE_RETURN(val) \
|
||||
->decltype(val) { return val; } \
|
||||
static_assert( \
|
||||
true, "") // This makes it so that a semicolon is required after the
|
||||
// macro, which helps clang-format handle the formatting.
|
||||
|
||||
// C array overload
|
||||
template <typename T, std::size_t N>
|
||||
auto range_begin(const T (&arr)[N]) -> const T* {
|
||||
return arr;
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
auto range_end(const T (&arr)[N]) -> const T* {
|
||||
return arr + N;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_member_fn_begin_end_t : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>>
|
||||
: std::true_type {};
|
||||
|
||||
// Member function overload
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
|
||||
|
||||
// ADL overload. Only participates in overload resolution if member functions
|
||||
// are not found.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng)
|
||||
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(begin(static_cast<T&&>(rng)))> {
|
||||
return begin(static_cast<T&&>(rng));
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(end(static_cast<T&&>(rng)))> {
|
||||
return end(static_cast<T&&>(rng));
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_const_begin_end : std::false_type {};
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_mutable_begin_end : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_const_begin_end<
|
||||
T,
|
||||
void_t<
|
||||
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
|
||||
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_mutable_begin_end<
|
||||
T, void_t<decltype(detail::range_begin(std::declval<T>())),
|
||||
decltype(detail::range_end(std::declval<T>())),
|
||||
enable_if_t<std::is_copy_constructible<T>::value>>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_range_<T, void>
|
||||
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
|
||||
has_mutable_begin_end<T>::value)> {};
|
||||
# undef FMT_DECLTYPE_RETURN
|
||||
#endif
|
||||
|
||||
// tuple_size and tuple_element check.
|
||||
template <typename T> class is_tuple_like_ {
|
||||
template <typename U>
|
||||
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
||||
template <typename T, T... N>
|
||||
using integer_sequence = std::integer_sequence<T, N...>;
|
||||
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
|
||||
#else
|
||||
template <typename T, T... N> struct integer_sequence {
|
||||
using value_type = T;
|
||||
|
||||
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
|
||||
};
|
||||
|
||||
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
|
||||
|
||||
template <typename T, size_t N, T... Ns>
|
||||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||
template <typename T, T... Ns>
|
||||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||
|
||||
template <size_t N>
|
||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||
#endif
|
||||
|
||||
template <class Tuple, class F, size_t... Is>
|
||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
||||
using std::get;
|
||||
// using free function get<I>(T) now.
|
||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||
(void)_; // blocks warnings
|
||||
}
|
||||
|
||||
template <class T>
|
||||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
|
||||
T const&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
||||
const auto indexes = get_indexes(tup);
|
||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
using value_type =
|
||||
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
||||
|
||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||
*out++ = ',';
|
||||
*out++ = ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
struct singleton {
|
||||
unsigned char upper;
|
||||
unsigned char lower_count;
|
||||
};
|
||||
|
||||
inline auto is_printable(uint16_t x, const singleton* singletons,
|
||||
size_t singletons_size,
|
||||
const unsigned char* singleton_lowers,
|
||||
const unsigned char* normal, size_t normal_size)
|
||||
-> bool {
|
||||
auto upper = x >> 8;
|
||||
auto lower_start = 0;
|
||||
for (size_t i = 0; i < singletons_size; ++i) {
|
||||
auto s = singletons[i];
|
||||
auto lower_end = lower_start + s.lower_count;
|
||||
if (upper < s.upper) break;
|
||||
if (upper == s.upper) {
|
||||
for (auto j = lower_start; j < lower_end; ++j) {
|
||||
if (singleton_lowers[j] == (x & 0xff)) return false;
|
||||
}
|
||||
}
|
||||
lower_start = lower_end;
|
||||
}
|
||||
|
||||
auto xsigned = static_cast<int>(x);
|
||||
auto current = true;
|
||||
for (size_t i = 0; i < normal_size; ++i) {
|
||||
auto v = static_cast<int>(normal[i]);
|
||||
auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v;
|
||||
xsigned -= len;
|
||||
if (xsigned < 0) break;
|
||||
current = !current;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
// Returns true iff the code point cp is printable.
|
||||
// This code is generated by support/printable.py.
|
||||
inline auto is_printable(uint32_t cp) -> bool {
|
||||
static constexpr singleton singletons0[] = {
|
||||
{0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
|
||||
{0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
|
||||
{0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
|
||||
{0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
|
||||
{0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
|
||||
{0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
|
||||
{0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
|
||||
};
|
||||
static constexpr unsigned char singletons0_lower[] = {
|
||||
0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
|
||||
0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
|
||||
0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
|
||||
0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
|
||||
0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
|
||||
0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
|
||||
0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
||||
0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
|
||||
0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
|
||||
0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
|
||||
0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
|
||||
0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
|
||||
0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
|
||||
0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
|
||||
0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
|
||||
0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
|
||||
0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
|
||||
0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
|
||||
0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
|
||||
0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
|
||||
0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
|
||||
0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
|
||||
0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
|
||||
0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
|
||||
0xfe, 0xff,
|
||||
};
|
||||
static constexpr singleton singletons1[] = {
|
||||
{0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
|
||||
{0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
|
||||
{0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
|
||||
{0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
|
||||
{0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
|
||||
{0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
|
||||
{0xfa, 2}, {0xfb, 1},
|
||||
};
|
||||
static constexpr unsigned char singletons1_lower[] = {
|
||||
0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
|
||||
0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
|
||||
0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
|
||||
0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
||||
0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
|
||||
0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
|
||||
0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
|
||||
0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
|
||||
0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
|
||||
0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
|
||||
0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
|
||||
0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
|
||||
0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
|
||||
0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
|
||||
0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
|
||||
};
|
||||
static constexpr unsigned char normal0[] = {
|
||||
0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
|
||||
0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
|
||||
0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
|
||||
0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
|
||||
0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
|
||||
0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
|
||||
0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
|
||||
0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
|
||||
0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
|
||||
0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
|
||||
0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
|
||||
0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
|
||||
0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
|
||||
0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
|
||||
0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
|
||||
0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
|
||||
0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
|
||||
0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
|
||||
0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
|
||||
0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
|
||||
0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
|
||||
0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
|
||||
0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
|
||||
0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
|
||||
0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
|
||||
0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
|
||||
};
|
||||
static constexpr unsigned char normal1[] = {
|
||||
0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
|
||||
0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
|
||||
0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
|
||||
0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
|
||||
0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
|
||||
0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
|
||||
0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
|
||||
0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
|
||||
0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
|
||||
0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
|
||||
0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
|
||||
0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
|
||||
0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
|
||||
0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
|
||||
0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
|
||||
0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
|
||||
0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
|
||||
0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
|
||||
0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
|
||||
0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
|
||||
0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
|
||||
0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
|
||||
0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
|
||||
0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
|
||||
0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
|
||||
0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
|
||||
0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
|
||||
0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
|
||||
0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
|
||||
0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
|
||||
0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
|
||||
0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
|
||||
0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
|
||||
0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
|
||||
0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
|
||||
};
|
||||
auto lower = static_cast<uint16_t>(cp);
|
||||
if (cp < 0x10000) {
|
||||
return is_printable(lower, singletons0,
|
||||
sizeof(singletons0) / sizeof(*singletons0),
|
||||
singletons0_lower, normal0, sizeof(normal0));
|
||||
}
|
||||
if (cp < 0x20000) {
|
||||
return is_printable(lower, singletons1,
|
||||
sizeof(singletons1) / sizeof(*singletons1),
|
||||
singletons1_lower, normal1, sizeof(normal1));
|
||||
}
|
||||
if (0x2a6de <= cp && cp < 0x2a700) return false;
|
||||
if (0x2b735 <= cp && cp < 0x2b740) return false;
|
||||
if (0x2b81e <= cp && cp < 0x2b820) return false;
|
||||
if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
|
||||
if (0x2ebe1 <= cp && cp < 0x2f800) return false;
|
||||
if (0x2fa1e <= cp && cp < 0x30000) return false;
|
||||
if (0x3134b <= cp && cp < 0xe0100) return false;
|
||||
if (0xe01f0 <= cp && cp < 0x110000) return false;
|
||||
return cp < 0x110000;
|
||||
}
|
||||
|
||||
inline auto needs_escape(uint32_t cp) -> bool {
|
||||
return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
|
||||
!is_printable(cp);
|
||||
}
|
||||
|
||||
template <typename Char> struct find_escape_result {
|
||||
const Char* begin;
|
||||
const Char* end;
|
||||
uint32_t cp;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
auto find_escape(const Char* begin, const Char* end)
|
||||
-> find_escape_result<Char> {
|
||||
for (; begin != end; ++begin) {
|
||||
auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin);
|
||||
if (sizeof(Char) == 1 && cp >= 0x80) continue;
|
||||
if (needs_escape(cp)) return {begin, begin + 1, cp};
|
||||
}
|
||||
return {begin, nullptr, 0};
|
||||
}
|
||||
|
||||
inline auto find_escape(const char* begin, const char* end)
|
||||
-> find_escape_result<char> {
|
||||
if (!is_utf8()) return find_escape<char>(begin, end);
|
||||
auto result = find_escape_result<char>{end, nullptr, 0};
|
||||
for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
|
||||
[&](uint32_t cp, string_view sv) {
|
||||
if (needs_escape(cp)) {
|
||||
result = {sv.begin(), sv.end(), cp};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
||||
*out++ = '"';
|
||||
auto begin = str.begin(), end = str.end();
|
||||
do {
|
||||
auto escape = find_escape(begin, end);
|
||||
out = copy_str<Char>(begin, escape.begin, out);
|
||||
begin = escape.end;
|
||||
if (!begin) break;
|
||||
auto c = static_cast<Char>(escape.cp);
|
||||
switch (escape.cp) {
|
||||
case '\n':
|
||||
*out++ = '\\';
|
||||
c = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*out++ = '\\';
|
||||
c = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*out++ = '\\';
|
||||
c = 't';
|
||||
break;
|
||||
case '"':
|
||||
FMT_FALLTHROUGH;
|
||||
case '\\':
|
||||
*out++ = '\\';
|
||||
break;
|
||||
default:
|
||||
if (is_utf8()) {
|
||||
if (escape.cp < 0x100) {
|
||||
out = format_to(out, "\\x{:02x}", escape.cp);
|
||||
continue;
|
||||
}
|
||||
if (escape.cp < 0x10000) {
|
||||
out = format_to(out, "\\u{:04x}", escape.cp);
|
||||
continue;
|
||||
}
|
||||
if (escape.cp < 0x110000) {
|
||||
out = format_to(out, "\\U{:08x}", escape.cp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (Char escape_char : basic_string_view<Char>(
|
||||
escape.begin, to_unsigned(escape.end - escape.begin))) {
|
||||
out = format_to(
|
||||
out, "\\x{:02x}",
|
||||
static_cast<typename std::make_unsigned<Char>::type>(escape_char));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*out++ = c;
|
||||
} while (begin != end);
|
||||
*out++ = '"';
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
|
||||
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
|
||||
auto sv = std_string_view<Char>(str);
|
||||
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename Arg,
|
||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||
*out++ = '\'';
|
||||
*out++ = v;
|
||||
*out++ = '\'';
|
||||
return out;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Char, typename OutputIt, typename Arg,
|
||||
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
|
||||
!std::is_same<Arg, Char>::value)>
|
||||
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_tuple_like {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||
};
|
||||
|
||||
template <typename TupleT, typename Char>
|
||||
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
||||
private:
|
||||
// C++11 generic lambda for format().
|
||||
template <typename FormatContext> struct format_each {
|
||||
template <typename T> void operator()(const T& v) {
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, v);
|
||||
++i;
|
||||
}
|
||||
int i;
|
||||
typename FormatContext::iterator& out;
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext = format_context>
|
||||
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
*out++ = '(';
|
||||
detail::for_each(values, format_each<FormatContext>{0, out});
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||
!detail::is_map<T>::value &&
|
||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<
|
||||
fmt::is_range<T, Char>::value
|
||||
// Workaround a bug in MSVC 2019 and earlier.
|
||||
#if !FMT_MSC_VER
|
||||
&& (is_formattable<detail::value_type<T>, Char>::value ||
|
||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
||||
#endif
|
||||
>> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <
|
||||
typename FormatContext, typename U,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||
const T, T>>::value)>
|
||||
auto format(U& range, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
||||
Char prefix = '{';
|
||||
Char postfix = '}';
|
||||
#else
|
||||
Char prefix = detail::is_set<T>::value ? '{' : '[';
|
||||
Char postfix = detail::is_set<T>::value ? '}' : ']';
|
||||
#endif
|
||||
auto out = ctx.out();
|
||||
*out++ = prefix;
|
||||
int i = 0;
|
||||
auto it = std::begin(range);
|
||||
auto end = std::end(range);
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, *it);
|
||||
++i;
|
||||
}
|
||||
*out++ = postfix;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<
|
||||
detail::is_map<T>::value
|
||||
// Workaround a bug in MSVC 2019 and earlier.
|
||||
#if !FMT_MSC_VER
|
||||
&& (is_formattable<detail::value_type<T>, Char>::value ||
|
||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
||||
#endif
|
||||
>> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <
|
||||
typename FormatContext, typename U,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||
const T, T>>::value)>
|
||||
auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
*out++ = '{';
|
||||
int i = 0;
|
||||
for (const auto& item : map) {
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, item.first);
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
out = detail::write_range_entry<Char>(out, item.second);
|
||||
++i;
|
||||
}
|
||||
*out++ = '}';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
||||
const std::tuple<T...>& tuple;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
|
||||
: tuple(t), sep{s} {}
|
||||
};
|
||||
|
||||
template <typename Char, typename... T>
|
||||
using tuple_arg_join = tuple_join_view<Char, T...>;
|
||||
|
||||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||
// support in tuple_join. It is disabled by default because of issues with
|
||||
// the dynamic width and precision.
|
||||
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
|
||||
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||
#endif
|
||||
|
||||
template <typename Char, typename... T>
|
||||
struct formatter<tuple_join_view<Char, T...>, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Char, T...>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
return do_format(value, ctx,
|
||||
std::integral_constant<size_t, sizeof...(T)>());
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||
std::integral_constant<size_t, 0>)
|
||||
-> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename ParseContext, size_t N>
|
||||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||
std::integral_constant<size_t, N>)
|
||||
-> decltype(ctx.begin()) {
|
||||
auto end = ctx.begin();
|
||||
#if FMT_TUPLE_JOIN_SPECIFIERS
|
||||
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
|
||||
if (N > 1) {
|
||||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||
if (end != end1)
|
||||
FMT_THROW(format_error("incompatible format specs for tuple elements"));
|
||||
}
|
||||
#endif
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
typename FormatContext::iterator {
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename FormatContext, size_t N>
|
||||
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
auto out = std::get<sizeof...(T) - N>(formatters_)
|
||||
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
|
||||
if (N > 1) {
|
||||
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||
ctx.advance_to(out);
|
||||
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns an object that formats `tuple` with elements separated by `sep`.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::tuple<int, char> t = {1, 'a'};
|
||||
fmt::print("{}", fmt::join(t, ", "));
|
||||
// Output: "1, a"
|
||||
\endrst
|
||||
*/
|
||||
template <typename... T>
|
||||
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
|
||||
-> tuple_join_view<char, T...> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
|
||||
basic_string_view<wchar_t> sep)
|
||||
-> tuple_join_view<wchar_t, T...> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns an object that formats `initializer_list` with elements separated by
|
||||
`sep`.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
|
||||
// Output: "1, 2, 3"
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, string_view sep)
|
||||
-> join_view<const T*, const T*> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_RANGES_H_
|
||||
235
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
vendored
Normal file
235
wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
// Formatting library for C++ - optional wchar_t and exotic character support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_XCHAR_H_
|
||||
#define FMT_XCHAR_H_
|
||||
|
||||
#include <cwchar>
|
||||
#include <tuple>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
using wstring_view = basic_string_view<wchar_t>;
|
||||
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||
using wformat_context = buffer_context<wchar_t>;
|
||||
using wformat_args = basic_format_args<wformat_context>;
|
||||
using wmemory_buffer = basic_memory_buffer<wchar_t>;
|
||||
|
||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||
// Workaround broken conversion on older gcc.
|
||||
template <typename... Args> using wformat_string = wstring_view;
|
||||
#else
|
||||
template <typename... Args>
|
||||
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||
#endif
|
||||
|
||||
template <> struct is_char<wchar_t> : std::true_type {};
|
||||
template <> struct is_char<detail::char8_type> : std::true_type {};
|
||||
template <> struct is_char<char16_t> : std::true_type {};
|
||||
template <> struct is_char<char32_t> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
|
||||
const Args&... args) {
|
||||
return {args...};
|
||||
}
|
||||
|
||||
inline namespace literals {
|
||||
constexpr auto operator"" _format(const wchar_t* s, size_t n)
|
||||
-> detail::udl_formatter<wchar_t> {
|
||||
return {{s, n}};
|
||||
}
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
|
||||
return {s};
|
||||
}
|
||||
#endif
|
||||
} // namespace literals
|
||||
|
||||
template <typename It, typename Sentinel>
|
||||
auto join(It begin, Sentinel end, wstring_view sep)
|
||||
-> join_view<It, Sentinel, wchar_t> {
|
||||
return {begin, end, sep};
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
auto join(Range&& range, wstring_view sep)
|
||||
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
|
||||
wchar_t> {
|
||||
return join(std::begin(range), std::end(range), sep);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, wstring_view sep)
|
||||
-> join_view<const T*, const T*, wchar_t> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
auto vformat(basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||
-> std::basic_string<Char> {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
return to_string(buffer);
|
||||
}
|
||||
|
||||
// Pass char_t as a default template parameter instead of using
|
||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return vformat(to_string_view(format_str), vargs);
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat(
|
||||
const Locale& loc, const S& format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||
-> std::basic_string<Char> {
|
||||
return detail::vformat(loc, to_string_view(format_str), args);
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename... Args,
|
||||
typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
||||
-> std::basic_string<Char> {
|
||||
return detail::vformat(loc, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
auto vformat_to(OutputIt out, const S& format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||
-> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
detail::vformat_to(buf, to_string_view(format_str), args);
|
||||
return detail::get_iterator(buf);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
||||
return vformat_to(out, to_string_view(fmt), vargs);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args, typename Char, size_t SIZE,
|
||||
typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
|
||||
const S& format_str, Args&&... args) ->
|
||||
typename buffer_context<Char>::iterator {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
detail::vformat_to(buf, to_string_view(format_str), vargs, {});
|
||||
return detail::buffer_appender<Char>(buf);
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||
typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_locale<Locale>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to(
|
||||
OutputIt out, const Locale& loc, const S& format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
||||
return detail::get_iterator(buf);
|
||||
}
|
||||
|
||||
template <
|
||||
typename OutputIt, typename Locale, typename S, typename... Args,
|
||||
typename Char = char_t<S>,
|
||||
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
|
||||
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
||||
Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to_n(
|
||||
OutputIt out, size_t n, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
|
||||
n);
|
||||
detail::vformat_to(buf, format_str, args);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
||||
const Args&... args) -> format_to_n_result<OutputIt> {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
||||
return vformat_to_n(out, n, to_string_view(fmt), vargs);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
||||
detail::counting_buffer<Char> buf;
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
||||
detail::vformat_to(buf, to_string_view(fmt), vargs);
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
||||
wmemory_buffer buffer;
|
||||
detail::vformat_to(buffer, fmt, args);
|
||||
buffer.push_back(L'\0');
|
||||
std::fputws(buffer.data(), f);
|
||||
}
|
||||
|
||||
inline void vprint(wstring_view fmt, wformat_args args) {
|
||||
vprint(stdout, fmt, args);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
||||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
/**
|
||||
Converts *value* to ``std::wstring`` using the default format for type *T*.
|
||||
*/
|
||||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
||||
return format(FMT_STRING(L"{}"), value);
|
||||
}
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_XCHAR_H_
|
||||
124
wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
vendored
Normal file
124
wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
// Formatting library for C++
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/format-inl.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
// DEPRECATED!
|
||||
template <typename T = void> struct basic_data {
|
||||
FMT_API static constexpr const char digits[100][2] = {
|
||||
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
|
||||
{'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
|
||||
{'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
|
||||
{'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
|
||||
{'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
|
||||
{'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
|
||||
{'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
|
||||
{'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
|
||||
{'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
|
||||
{'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
|
||||
{'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
|
||||
{'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
|
||||
{'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
|
||||
{'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
|
||||
{'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
|
||||
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
|
||||
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
||||
FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
|
||||
FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
|
||||
FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1,
|
||||
0};
|
||||
FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1,
|
||||
0};
|
||||
FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
|
||||
0x1000000u | ' '};
|
||||
};
|
||||
|
||||
#ifdef FMT_SHARED
|
||||
// Required for -flto, -fivisibility=hidden and -shared to work
|
||||
extern template struct basic_data<void>;
|
||||
#endif
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
// DEPRECATED! These are here only for ABI compatiblity.
|
||||
template <typename T> constexpr const char basic_data<T>::digits[][2];
|
||||
template <typename T> constexpr const char basic_data<T>::hex_digits[];
|
||||
template <typename T> constexpr const char basic_data<T>::signs[];
|
||||
template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
|
||||
template <typename T>
|
||||
constexpr const char basic_data<T>::right_padding_shifts[];
|
||||
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
int format_float(char* buf, std::size_t size, const char* format, int precision,
|
||||
T value) {
|
||||
#ifdef FMT_FUZZ
|
||||
if (precision > 100000)
|
||||
throw std::runtime_error(
|
||||
"fuzz mode - avoid large allocation inside snprintf");
|
||||
#endif
|
||||
// Suppress the warning about nonliteral format string.
|
||||
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
|
||||
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
||||
: snprintf_ptr(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
|
||||
FMT_NOEXCEPT;
|
||||
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
|
||||
FMT_NOEXCEPT;
|
||||
} // namespace detail
|
||||
|
||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
||||
int (*instantiate_format_float)(double, int, detail::float_specs,
|
||||
detail::buffer<char>&) = detail::format_float;
|
||||
|
||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||
template FMT_API detail::locale_ref::locale_ref(const std::locale& loc);
|
||||
template FMT_API std::locale detail::locale_ref::get<std::locale>() const;
|
||||
#endif
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template FMT_API auto detail::thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<char>;
|
||||
template FMT_API char detail::decimal_point_impl(locale_ref);
|
||||
|
||||
template FMT_API void detail::buffer<char>::append(const char*, const char*);
|
||||
|
||||
// DEPRECATED!
|
||||
// There is no correspondent extern template in format.h because of
|
||||
// incompatibility between clang and gcc (#2377).
|
||||
template FMT_API void detail::vformat_to(
|
||||
detail::buffer<char>&, string_view,
|
||||
basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
|
||||
|
||||
template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
|
||||
detail::buffer<char>&);
|
||||
template FMT_API int detail::snprintf_float(long double, int,
|
||||
detail::float_specs,
|
||||
detail::buffer<char>&);
|
||||
template FMT_API int detail::format_float(double, int, detail::float_specs,
|
||||
detail::buffer<char>&);
|
||||
template FMT_API int detail::format_float(long double, int, detail::float_specs,
|
||||
detail::buffer<char>&);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template FMT_API auto detail::thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<wchar_t>;
|
||||
template FMT_API wchar_t detail::decimal_point_impl(locale_ref);
|
||||
|
||||
template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*,
|
||||
const wchar_t*);
|
||||
|
||||
template struct detail::basic_data<void>;
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
360
wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
vendored
Normal file
360
wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
// Disable bogus MSVC warnings.
|
||||
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "fmt/os.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
|
||||
# ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# else
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <io.h>
|
||||
|
||||
# ifndef S_IRUSR
|
||||
# define S_IRUSR _S_IREAD
|
||||
# endif
|
||||
# ifndef S_IWUSR
|
||||
# define S_IWUSR _S_IWRITE
|
||||
# endif
|
||||
# ifndef S_IRGRP
|
||||
# define S_IRGRP 0
|
||||
# endif
|
||||
# ifndef S_IROTH
|
||||
# define S_IROTH 0
|
||||
# endif
|
||||
# endif // _WIN32
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef fileno
|
||||
# undef fileno
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
// Return type of read and write functions.
|
||||
using rwresult = int;
|
||||
|
||||
// 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;
|
||||
}
|
||||
#elif FMT_USE_FCNTL
|
||||
// Return type of read and write functions.
|
||||
using rwresult = ssize_t;
|
||||
|
||||
inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef _WIN32
|
||||
detail::utf16_to_utf8::utf16_to_utf8(basic_string_view<wchar_t> s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(windows_error(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
int detail::utf16_to_utf8::convert(basic_string_view<wchar_t> s) {
|
||||
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
if (s_size == 0) {
|
||||
// WideCharToMultiByte does not support zero length, handle separately.
|
||||
buffer_.resize(1);
|
||||
buffer_[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
|
||||
nullptr, nullptr);
|
||||
if (length == 0) return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
|
||||
length, nullptr, nullptr);
|
||||
if (length == 0) return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
class system_message {
|
||||
system_message(const system_message&) = delete;
|
||||
void operator=(const system_message&) = delete;
|
||||
|
||||
unsigned long result_;
|
||||
wchar_t* message_;
|
||||
|
||||
static bool is_whitespace(wchar_t c) FMT_NOEXCEPT {
|
||||
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
||||
}
|
||||
|
||||
public:
|
||||
explicit system_message(unsigned long error_code)
|
||||
: result_(0), message_(nullptr) {
|
||||
result_ = FormatMessageW(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<wchar_t*>(&message_), 0, nullptr);
|
||||
if (result_ != 0) {
|
||||
while (result_ != 0 && is_whitespace(message_[result_ - 1])) {
|
||||
--result_;
|
||||
}
|
||||
}
|
||||
}
|
||||
~system_message() { LocalFree(message_); }
|
||||
explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; }
|
||||
operator basic_string_view<wchar_t>() const FMT_NOEXCEPT {
|
||||
return basic_string_view<wchar_t>(message_, result_);
|
||||
}
|
||||
};
|
||||
|
||||
class utf8_system_category final : public std::error_category {
|
||||
public:
|
||||
const char* name() const FMT_NOEXCEPT override { return "system"; }
|
||||
std::string message(int error_code) const override {
|
||||
system_message msg(error_code);
|
||||
if (msg) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
|
||||
return utf8_message.str();
|
||||
}
|
||||
}
|
||||
return "unknown error";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT {
|
||||
static const detail::utf8_system_category category;
|
||||
return category;
|
||||
}
|
||||
|
||||
std::system_error vwindows_error(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
auto ec = std::error_code(err_code, system_category());
|
||||
return std::system_error(ec, vformat(format_str, args));
|
||||
}
|
||||
|
||||
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||
const char* message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
system_message msg(error_code);
|
||||
if (msg) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
|
||||
format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
void report_windows_error(int error_code, const char* message) FMT_NOEXCEPT {
|
||||
report_error(detail::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
buffered_file::~buffered_file() FMT_NOEXCEPT {
|
||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||
report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
|
||||
nullptr);
|
||||
if (!file_)
|
||||
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
|
||||
}
|
||||
|
||||
void buffered_file::close() {
|
||||
if (!file_) return;
|
||||
int result = FMT_SYSTEM(fclose(file_));
|
||||
file_ = nullptr;
|
||||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
||||
}
|
||||
|
||||
// A macro used to prevent expansion of fileno on broken versions of MinGW.
|
||||
#define FMT_ARGS
|
||||
|
||||
int buffered_file::fileno() const {
|
||||
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
|
||||
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
|
||||
return fd;
|
||||
}
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
file::file(cstring_view path, int oflag) {
|
||||
# ifdef _WIN32
|
||||
using mode_t = int;
|
||||
# endif
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
# 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(system_error(errno, "cannot open file {}", path.c_str()));
|
||||
}
|
||||
|
||||
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)
|
||||
report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
void 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(system_error(errno, "cannot close file"));
|
||||
}
|
||||
|
||||
long long 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(windows_error(GetLastError(), "cannot get file size"));
|
||||
}
|
||||
unsigned long long long_size = size_upper;
|
||||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||
# else
|
||||
using Stat = struct stat;
|
||||
Stat file_stat = Stat();
|
||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||
FMT_THROW(system_error(errno, "cannot get file attributes"));
|
||||
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
||||
"return type of file::size is not large enough");
|
||||
return file_stat.st_size;
|
||||
# endif
|
||||
}
|
||||
|
||||
std::size_t 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(system_error(errno, "cannot read from file"));
|
||||
return detail::to_unsigned(result);
|
||||
}
|
||||
|
||||
std::size_t file::write(const void* buffer, std::size_t count) {
|
||||
rwresult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||
return count;
|
||||
}
|
||||
|
||||
file 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(system_error(errno, "cannot duplicate file descriptor {}", fd));
|
||||
return file(new_fd);
|
||||
}
|
||||
|
||||
void file::dup2(int fd) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) {
|
||||
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
|
||||
fd_, fd));
|
||||
}
|
||||
}
|
||||
|
||||
void file::dup2(int fd, std::error_code& ec) FMT_NOEXCEPT {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
||||
}
|
||||
|
||||
void 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(system_error(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]);
|
||||
}
|
||||
|
||||
buffered_file file::fdopen(const char* mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
# if defined(__MINGW32__) && defined(_POSIX_)
|
||||
FILE* f = ::fdopen(fd_, mode);
|
||||
# else
|
||||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
# endif
|
||||
if (!f)
|
||||
FMT_THROW(
|
||||
system_error(errno, "cannot associate stream with file descriptor"));
|
||||
buffered_file bf(f);
|
||||
fd_ = -1;
|
||||
return bf;
|
||||
}
|
||||
|
||||
long 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(system_error(errno, "cannot get memory page size"));
|
||||
return size;
|
||||
# endif
|
||||
}
|
||||
|
||||
FMT_API void ostream::grow(size_t) {
|
||||
if (this->size() == this->capacity()) flush();
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
FMT_END_NAMESPACE
|
||||
5942
wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp
vendored
Normal file
5942
wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1505
wpiutil/src/main/native/thirdparty/json/cpp/json.cpp
vendored
Normal file
1505
wpiutil/src/main/native/thirdparty/json/cpp/json.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1415
wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
vendored
Normal file
1415
wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1091
wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
vendored
Normal file
1091
wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1968
wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
vendored
Normal file
1968
wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
540
wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp
vendored
Normal file
540
wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp
vendored
Normal file
@@ -0,0 +1,540 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++
|
||||
| | |__ | | | | | | version 3.1.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#define WPI_JSON_IMPLEMENTATION
|
||||
#include "wpi/json.h"
|
||||
|
||||
#include <numeric> // accumulate
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
std::string json_pointer::to_string() const noexcept
|
||||
{
|
||||
return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
|
||||
std::string{},
|
||||
[](const std::string & a, const std::string & b)
|
||||
{
|
||||
return a + "/" + escape(b);
|
||||
});
|
||||
}
|
||||
|
||||
int json_pointer::array_index(std::string_view s)
|
||||
{
|
||||
SmallString<128> str{s};
|
||||
std::size_t processed_chars = 0;
|
||||
const int res = std::stoi(str.c_str(), &processed_chars);
|
||||
|
||||
// check if the string was completely read
|
||||
if (JSON_UNLIKELY(processed_chars != str.size()))
|
||||
{
|
||||
JSON_THROW(detail::out_of_range::create(404, fmt::format("unresolved reference token '{}'", s)));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
json& json_pointer::get_and_create(json& j) const
|
||||
{
|
||||
using size_type = typename json::size_type;
|
||||
auto result = &j;
|
||||
|
||||
// in case no reference tokens exist, return a reference to the JSON value
|
||||
// j which will be overwritten by a primitive value
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
switch (result->m_type)
|
||||
{
|
||||
case detail::value_t::null:
|
||||
{
|
||||
if (reference_token == "0")
|
||||
{
|
||||
// start a new array if reference token is 0
|
||||
result = &result->operator[](0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// start a new object otherwise
|
||||
result = &result->operator[](reference_token);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// create an entry in the object
|
||||
result = &result->operator[](reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
// create an entry in the array
|
||||
JSON_TRY
|
||||
{
|
||||
result = &result->operator[](static_cast<size_type>(array_index(reference_token)));
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0, fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
The following code is only reached if there exists a reference
|
||||
token _and_ the current value is primitive. In this case, we have
|
||||
an error situation, because primitive values may only occur as
|
||||
single value; that is, with an empty list of reference tokens.
|
||||
*/
|
||||
default:
|
||||
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten"));
|
||||
}
|
||||
}
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
json& json_pointer::get_unchecked(json* ptr) const
|
||||
{
|
||||
using size_type = typename json::size_type;
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
// convert null values to arrays or objects before continuing
|
||||
if (ptr->m_type == detail::value_t::null)
|
||||
{
|
||||
// check if reference token is a number
|
||||
const bool nums =
|
||||
std::all_of(reference_token.begin(), reference_token.end(),
|
||||
[](const char x)
|
||||
{
|
||||
return (x >= '0' and x <= '9');
|
||||
});
|
||||
|
||||
// change value to array for numbers or "-" or to object otherwise
|
||||
*ptr = (nums or reference_token == "-")
|
||||
? detail::value_t::array
|
||||
: detail::value_t::object;
|
||||
}
|
||||
|
||||
switch (ptr->m_type)
|
||||
{
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// use unchecked object access
|
||||
ptr = &ptr->operator[](reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
if (reference_token == "-")
|
||||
{
|
||||
// explicitly treat "-" as index beyond the end
|
||||
ptr = &ptr->operator[](ptr->m_value.array->size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// convert array index to number; unchecked access
|
||||
JSON_TRY
|
||||
{
|
||||
ptr = &ptr->operator[](
|
||||
static_cast<size_type>(array_index(reference_token)));
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
json& json_pointer::get_checked(json* ptr) const
|
||||
{
|
||||
using size_type = typename json::size_type;
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
switch (ptr->m_type)
|
||||
{
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// note: at performs range check
|
||||
ptr = &ptr->at(reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
if (JSON_UNLIKELY(reference_token == "-"))
|
||||
{
|
||||
// "-" always fails the range check
|
||||
JSON_THROW(detail::out_of_range::create(402,
|
||||
fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
|
||||
}
|
||||
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
// note: at performs range check
|
||||
JSON_TRY
|
||||
{
|
||||
ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
const json& json_pointer::get_unchecked(const json* ptr) const
|
||||
{
|
||||
using size_type = typename json::size_type;
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
switch (ptr->m_type)
|
||||
{
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// use unchecked object access
|
||||
ptr = &ptr->operator[](reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
if (JSON_UNLIKELY(reference_token == "-"))
|
||||
{
|
||||
// "-" cannot be used for const access
|
||||
JSON_THROW(detail::out_of_range::create(402,
|
||||
fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
|
||||
}
|
||||
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
// use unchecked array access
|
||||
JSON_TRY
|
||||
{
|
||||
ptr = &ptr->operator[](
|
||||
static_cast<size_type>(array_index(reference_token)));
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
const json& json_pointer::get_checked(const json* ptr) const
|
||||
{
|
||||
using size_type = typename json::size_type;
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
switch (ptr->m_type)
|
||||
{
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// note: at performs range check
|
||||
ptr = &ptr->at(reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
if (JSON_UNLIKELY(reference_token == "-"))
|
||||
{
|
||||
// "-" always fails the range check
|
||||
JSON_THROW(detail::out_of_range::create(402,
|
||||
fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
|
||||
}
|
||||
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
// note: at performs range check
|
||||
JSON_TRY
|
||||
{
|
||||
ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> json_pointer::split(std::string_view ref_str)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
// special case: empty reference string -> no reference tokens
|
||||
if (ref_str.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// check if nonempty reference string begins with slash
|
||||
if (JSON_UNLIKELY(ref_str[0] != '/'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(107, 1,
|
||||
fmt::format("JSON pointer must be empty or begin with '/' - was: '{}'", ref_str)));
|
||||
}
|
||||
|
||||
// extract the reference tokens:
|
||||
// - slash: position of the last read slash (or end of string)
|
||||
// - start: position after the previous slash
|
||||
for (
|
||||
// search for the first slash after the first character
|
||||
std::size_t slash = ref_str.find_first_of('/', 1),
|
||||
// set the beginning of the first reference token
|
||||
start = 1;
|
||||
// we can stop if start == string::npos+1 = 0
|
||||
start != 0;
|
||||
// set the beginning of the next reference token
|
||||
// (will eventually be 0 if slash == std::string::npos)
|
||||
start = slash + 1,
|
||||
// find next slash
|
||||
slash = ref_str.find_first_of('/', start))
|
||||
{
|
||||
// use the text between the beginning of the reference token
|
||||
// (start) and the last slash (slash).
|
||||
auto reference_token = slice(ref_str, start, slash);
|
||||
|
||||
// check reference tokens are properly escaped
|
||||
for (std::size_t pos = reference_token.find_first_of('~');
|
||||
pos != std::string_view::npos;
|
||||
pos = reference_token.find_first_of('~', pos + 1))
|
||||
{
|
||||
assert(reference_token[pos] == '~');
|
||||
|
||||
// ~ must be followed by 0 or 1
|
||||
if (JSON_UNLIKELY(pos == reference_token.size() - 1 or
|
||||
(reference_token[pos + 1] != '0' and
|
||||
reference_token[pos + 1] != '1')))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
|
||||
}
|
||||
}
|
||||
|
||||
// finally, store the reference token
|
||||
std::string ref_tok{reference_token};
|
||||
unescape(ref_tok);
|
||||
result.emplace_back(std::move(ref_tok));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void json_pointer::replace_substring(std::string& s, const std::string& f,
|
||||
const std::string& t)
|
||||
{
|
||||
assert(not f.empty());
|
||||
for (auto pos = s.find(f); // find first occurrence of f
|
||||
pos != std::string::npos; // make sure f was found
|
||||
s.replace(pos, f.size(), t), // replace with t, and
|
||||
pos = s.find(f, pos + t.size())) // find next occurrence of f
|
||||
{}
|
||||
}
|
||||
|
||||
std::string json_pointer::escape(std::string s)
|
||||
{
|
||||
replace_substring(s, "~", "~0");
|
||||
replace_substring(s, "/", "~1");
|
||||
return s;
|
||||
}
|
||||
|
||||
/// unescape "~1" to tilde and "~0" to slash (order is important!)
|
||||
void json_pointer::unescape(std::string& s)
|
||||
{
|
||||
replace_substring(s, "~1", "/");
|
||||
replace_substring(s, "~0", "~");
|
||||
}
|
||||
|
||||
void json_pointer::flatten(std::string_view reference_string,
|
||||
const json& value,
|
||||
json& result)
|
||||
{
|
||||
switch (value.m_type)
|
||||
{
|
||||
case detail::value_t::array:
|
||||
{
|
||||
if (value.m_value.array->empty())
|
||||
{
|
||||
// flatten empty array as null
|
||||
result[reference_string] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate array and use index as reference string
|
||||
for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
|
||||
{
|
||||
flatten(fmt::format("{}/{}", reference_string, i),
|
||||
value.m_value.array->operator[](i), result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::object:
|
||||
{
|
||||
if (value.m_value.object->empty())
|
||||
{
|
||||
// flatten empty object as null
|
||||
result[reference_string] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate object and use keys as reference string
|
||||
for (const auto& element : *value.m_value.object)
|
||||
{
|
||||
flatten(fmt::format("{}/{}", reference_string, escape(std::string{element.first()})), element.second, result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// add primitive value with its reference string
|
||||
result[reference_string] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json
|
||||
json_pointer::unflatten(const json& value)
|
||||
{
|
||||
if (JSON_UNLIKELY(not value.is_object()))
|
||||
{
|
||||
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
|
||||
}
|
||||
|
||||
// we need to iterate over the object values in sorted key order
|
||||
SmallVector<StringMapConstIterator<json>, 64> sorted;
|
||||
for (auto i = value.m_value.object->begin(),
|
||||
end = value.m_value.object->end(); i != end; ++i)
|
||||
{
|
||||
if (!i->second.is_primitive())
|
||||
{
|
||||
JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
|
||||
}
|
||||
sorted.push_back(i);
|
||||
}
|
||||
std::sort(sorted.begin(), sorted.end(),
|
||||
[](const StringMapConstIterator<json>& a,
|
||||
const StringMapConstIterator<json>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
json result;
|
||||
|
||||
// iterate the sorted JSON object values
|
||||
for (const auto& element : sorted)
|
||||
{
|
||||
|
||||
// assign value to reference pointed to by JSON pointer; Note
|
||||
// that if the JSON pointer is "" (i.e., points to the whole
|
||||
// value), function get_and_create returns a reference to
|
||||
// result itself. An assignment will then create a primitive
|
||||
// value.
|
||||
json_pointer(element->first()).get_and_create(result) = element->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
1531
wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp
vendored
Normal file
1531
wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8120
wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
vendored
Normal file
8120
wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
207
wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h
vendored
Normal file
207
wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++
|
||||
| | |__ | | | | | | version 3.1.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "wpi/json.h"
|
||||
|
||||
#include <clocale> // lconv, localeconv
|
||||
#include <cmath> // labs, isfinite, isnan, signbit, ldexp
|
||||
#include <type_traits>
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class json::serializer
|
||||
{
|
||||
static constexpr uint8_t UTF8_ACCEPT = 0;
|
||||
static constexpr uint8_t UTF8_REJECT = 1;
|
||||
|
||||
public:
|
||||
/*!
|
||||
@param[in] s output stream to serialize to
|
||||
@param[in] ichar indentation character to use
|
||||
@param[in] indent_init_len initial length of indentation string buffer
|
||||
*/
|
||||
serializer(raw_ostream& s, const char ichar, size_t indent_init_len = 512)
|
||||
: o(s), indent_char(ichar),
|
||||
indent_string(indent_init_len, indent_char)
|
||||
{}
|
||||
|
||||
// delete because of pointer members
|
||||
serializer(const serializer&) = delete;
|
||||
serializer& operator=(const serializer&) = delete;
|
||||
|
||||
/*!
|
||||
@brief internal implementation of the serialization function
|
||||
|
||||
This function is called by the public member function dump and organizes
|
||||
the serialization internally. The indentation level is propagated as
|
||||
additional parameter. In case of arrays and objects, the function is
|
||||
called recursively.
|
||||
|
||||
- strings and object keys are escaped using `escape_string()`
|
||||
- integer numbers are converted implicitly via `operator<<`
|
||||
- floating-point numbers are converted to a string using `"%g"` format
|
||||
|
||||
@param[in] val value to serialize
|
||||
@param[in] pretty_print whether the output shall be pretty-printed
|
||||
@param[in] ensure_ascii whether the output shall only use ASCII chars
|
||||
@param[in] indent_step the indent level
|
||||
@param[in] current_indent the current indent level (only used internally)
|
||||
*/
|
||||
void dump(const json& val, const bool pretty_print,
|
||||
const bool ensure_ascii,
|
||||
const unsigned int indent_step,
|
||||
const unsigned int current_indent = 0);
|
||||
|
||||
/*!
|
||||
@brief dump escaped string
|
||||
|
||||
Escape a string by replacing certain special characters by a sequence of an
|
||||
escape character (backslash) and another character and other control
|
||||
characters by a sequence of "\u" followed by a four-digit hex
|
||||
representation. The escaped string is written to output stream @a o.
|
||||
|
||||
@param[in] s the string to escape
|
||||
@param[in] ensure_ascii whether to escape non-ASCII characters with
|
||||
"\uXXXX" sequences
|
||||
|
||||
Complexity: Linear in the length of string @a s.
|
||||
*/
|
||||
void dump_escaped(std::string_view s, const bool ensure_ascii);
|
||||
|
||||
template <typename NumberType,
|
||||
detail::enable_if_t<std::is_same_v<NumberType, uint64_t>, int> = 0>
|
||||
bool is_negative_integer(NumberType x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename NumberType,
|
||||
detail::enable_if_t<std::is_same_v<NumberType, int64_t>, int> = 0>
|
||||
bool is_negative_integer(NumberType x) {
|
||||
return x < 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief dump an integer
|
||||
|
||||
Dump a given integer to output stream @a o. Works internally with
|
||||
@a number_buffer.
|
||||
|
||||
@param[in] x integer number (signed or unsigned) to dump
|
||||
@tparam NumberType either @a int64_t or @a uint64_t
|
||||
*/
|
||||
template<typename NumberType, detail::enable_if_t<
|
||||
std::is_same<NumberType, uint64_t>::value or
|
||||
std::is_same<NumberType, int64_t>::value,
|
||||
int> = 0>
|
||||
void dump_integer(NumberType x)
|
||||
{
|
||||
// special case for "0"
|
||||
if (x == 0)
|
||||
{
|
||||
o << '0';
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_negative = is_negative_integer(x); // see issue #755
|
||||
std::size_t i = 0;
|
||||
|
||||
while (x != 0)
|
||||
{
|
||||
// spare 1 byte for '\0'
|
||||
assert(i < number_buffer.size() - 1);
|
||||
|
||||
const auto digit = std::labs(static_cast<long>(x % 10));
|
||||
number_buffer[i++] = static_cast<char>('0' + digit);
|
||||
x /= 10;
|
||||
}
|
||||
|
||||
if (is_negative)
|
||||
{
|
||||
// make sure there is capacity for the '-'
|
||||
assert(i < number_buffer.size() - 2);
|
||||
number_buffer[i++] = '-';
|
||||
}
|
||||
|
||||
std::reverse(number_buffer.begin(), number_buffer.begin() + i);
|
||||
o.write(number_buffer.data(), i);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief dump a floating-point number
|
||||
|
||||
Dump a given floating-point number to output stream @a o. Works internally
|
||||
with @a number_buffer.
|
||||
|
||||
@param[in] x floating-point number to dump
|
||||
*/
|
||||
void dump_float(double x);
|
||||
|
||||
/*!
|
||||
@brief check whether a string is UTF-8 encoded
|
||||
|
||||
The function checks each byte of a string whether it is UTF-8 encoded. The
|
||||
result of the check is stored in the @a state parameter. The function must
|
||||
be called initially with state 0 (accept). State 1 means the string must
|
||||
be rejected, because the current byte is not allowed. If the string is
|
||||
completely processed, but the state is non-zero, the string ended
|
||||
prematurely; that is, the last byte indicated more bytes should have
|
||||
followed.
|
||||
|
||||
@param[in,out] state the state of the decoding
|
||||
@param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT)
|
||||
@param[in] byte next byte to decode
|
||||
@return new state
|
||||
|
||||
@note The function has been edited: a std::array is used.
|
||||
|
||||
@copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
@sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
*/
|
||||
static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept;
|
||||
|
||||
private:
|
||||
/// the output of the serializer
|
||||
raw_ostream& o;
|
||||
|
||||
/// a (hopefully) large enough character buffer
|
||||
std::array<char, 64> number_buffer{{}};
|
||||
|
||||
/// the indentation character
|
||||
const char indent_char;
|
||||
/// the indentation string
|
||||
std::string indent_string;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
833
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
vendored
Normal file
833
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
vendored
Normal file
@@ -0,0 +1,833 @@
|
||||
/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
|
||||
*
|
||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://llvm.org/LICENSE.txt for license information.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*
|
||||
*===------------------------------------------------------------------------=*/
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Sept 2001: fixed const & error conditions per
|
||||
mods suggested by S. Parent & A. Lillich.
|
||||
June 2002: Tim Dodd added detection and handling of incomplete
|
||||
source sequences, enhanced error detection, added casts
|
||||
to eliminate compiler warnings.
|
||||
July 2003: slight mods to back out aggressive FFFE detection.
|
||||
Jan 2004: updated switches in from-UTF8 conversions.
|
||||
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
|
||||
|
||||
See the header file "ConvertUTF.h" for complete documentation.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#ifdef CVTUTF_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "Windows/WindowsSupport.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This code extensively uses fall-through switches.
|
||||
* Keep the compiler from warning about that.
|
||||
*/
|
||||
#if defined(__clang__) && defined(__has_warning)
|
||||
# if __has_warning("-Wimplicit-fallthrough")
|
||||
# define ConvertUTF_DISABLE_WARNINGS \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
# define ConvertUTF_RESTORE_WARNINGS \
|
||||
_Pragma("clang diagnostic pop")
|
||||
# endif
|
||||
#elif defined(__GNUC__) && __GNUC__ > 6
|
||||
# define ConvertUTF_DISABLE_WARNINGS \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
# define ConvertUTF_RESTORE_WARNINGS \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#ifndef ConvertUTF_DISABLE_WARNINGS
|
||||
# define ConvertUTF_DISABLE_WARNINGS
|
||||
#endif
|
||||
#ifndef ConvertUTF_RESTORE_WARNINGS
|
||||
# define ConvertUTF_RESTORE_WARNINGS
|
||||
#endif
|
||||
|
||||
ConvertUTF_DISABLE_WARNINGS
|
||||
|
||||
namespace wpi {
|
||||
|
||||
static const int halfShift = 10; /* used for shifting by 10 bits */
|
||||
|
||||
static const UTF32 halfBase = 0x0010000UL;
|
||||
static const UTF32 halfMask = 0x3FFUL;
|
||||
|
||||
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||
* left as-is for anyone who may want to do such conversion, which was
|
||||
* allowed in earlier algorithms.
|
||||
*/
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||
|
||||
/*
|
||||
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||
* into the first byte, depending on how many bytes follow. There are
|
||||
* as many entries in this table as there are UTF-8 sequence types.
|
||||
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
|
||||
* for *legal* UTF-8 will be 4 or fewer bytes total.
|
||||
*/
|
||||
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||
* Constants have been gathered. Loops & conditionals have been removed as
|
||||
* much as possible for efficiency, in favor of drop-through switches.
|
||||
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch = *source++;
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_LEGAL_UTF32) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
UTF32 ch, ch2;
|
||||
while (source < sourceEnd) {
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
*target++ = ch;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
#ifdef CVTUTF_DEBUG
|
||||
if (result == sourceIllegal) {
|
||||
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
UTF32 ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
ch = *source++;
|
||||
if (flags == strictConversion ) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Figure out how many bytes the result will require. Turn any
|
||||
* illegally large UTF32 things (> Plane 17) into replacement chars.
|
||||
*/
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
result = sourceIllegal;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||
* This must be called with the length pre-determined by the first byte.
|
||||
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||
* length = trailingBytesForUTF8[*source]+1;
|
||||
* and the sequence is illegal right away if there aren't that many bytes
|
||||
* available.
|
||||
* If presented with a length > 4, this returns false. The Unicode
|
||||
* definition of UTF-8 goes up to 4-byte sequences.
|
||||
*/
|
||||
|
||||
static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
UTF8 a;
|
||||
const UTF8 *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return false; break;
|
||||
case 0xED: if (a > 0x9F) return false; break;
|
||||
case 0xF0: if (a < 0x90) return false; break;
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
}
|
||||
if (*source > 0xF4) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||
int length = trailingBytesForUTF8[*source]+1;
|
||||
if (length > sourceEnd - source) {
|
||||
return false;
|
||||
}
|
||||
return isLegalUTF8(source, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static unsigned
|
||||
findMaximalSubpartOfIllFormedUTF8Sequence(const UTF8 *source,
|
||||
const UTF8 *sourceEnd) {
|
||||
UTF8 b1, b2, b3;
|
||||
|
||||
assert(!isLegalUTF8Sequence(source, sourceEnd));
|
||||
|
||||
/*
|
||||
* Unicode 6.3.0, D93b:
|
||||
*
|
||||
* Maximal subpart of an ill-formed subsequence: The longest code unit
|
||||
* subsequence starting at an unconvertible offset that is either:
|
||||
* a. the initial subsequence of a well-formed code unit sequence, or
|
||||
* b. a subsequence of length one.
|
||||
*/
|
||||
|
||||
if (source == sourceEnd)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Perform case analysis. See Unicode 6.3.0, Table 3-7. Well-Formed UTF-8
|
||||
* Byte Sequences.
|
||||
*/
|
||||
|
||||
b1 = *source;
|
||||
++source;
|
||||
if (b1 >= 0xC2 && b1 <= 0xDF) {
|
||||
/*
|
||||
* First byte is valid, but we know that this code unit sequence is
|
||||
* invalid, so the maximal subpart has to end after the first byte.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (source == sourceEnd)
|
||||
return 1;
|
||||
|
||||
b2 = *source;
|
||||
++source;
|
||||
|
||||
if (b1 == 0xE0) {
|
||||
return (b2 >= 0xA0 && b2 <= 0xBF) ? 2 : 1;
|
||||
}
|
||||
if (b1 >= 0xE1 && b1 <= 0xEC) {
|
||||
return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
|
||||
}
|
||||
if (b1 == 0xED) {
|
||||
return (b2 >= 0x80 && b2 <= 0x9F) ? 2 : 1;
|
||||
}
|
||||
if (b1 >= 0xEE && b1 <= 0xEF) {
|
||||
return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
|
||||
}
|
||||
if (b1 == 0xF0) {
|
||||
if (b2 >= 0x90 && b2 <= 0xBF) {
|
||||
if (source == sourceEnd)
|
||||
return 2;
|
||||
|
||||
b3 = *source;
|
||||
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (b1 >= 0xF1 && b1 <= 0xF3) {
|
||||
if (b2 >= 0x80 && b2 <= 0xBF) {
|
||||
if (source == sourceEnd)
|
||||
return 2;
|
||||
|
||||
b3 = *source;
|
||||
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (b1 == 0xF4) {
|
||||
if (b2 >= 0x80 && b2 <= 0x8F) {
|
||||
if (source == sourceEnd)
|
||||
return 2;
|
||||
|
||||
b3 = *source;
|
||||
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert((b1 >= 0x80 && b1 <= 0xC1) || b1 >= 0xF5);
|
||||
/*
|
||||
* There are no valid sequences that start with these bytes. Maximal subpart
|
||||
* is defined to have length 1 in these cases.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return the total number of bytes in a codepoint
|
||||
* represented in UTF-8, given the value of the first byte.
|
||||
*/
|
||||
unsigned getNumBytesForUTF8(UTF8 first) {
|
||||
return trailingBytesForUTF8[first] + 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 string is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) {
|
||||
while (*source != sourceEnd) {
|
||||
int length = trailingBytesForUTF8[**source] + 1;
|
||||
if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
|
||||
return false;
|
||||
*source += length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (extraBytesToRead >= sourceEnd - source) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (!isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_UTF16) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
source -= (extraBytesToRead+1); /* return to the start */
|
||||
break; /* Bail out; shouldn't continue */
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static ConversionResult ConvertUTF8toUTF32Impl(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags,
|
||||
Boolean InputIsPartial) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (extraBytesToRead >= sourceEnd - source) {
|
||||
if (flags == strictConversion || InputIsPartial) {
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
} else {
|
||||
result = sourceIllegal;
|
||||
|
||||
/*
|
||||
* Replace the maximal subpart of ill-formed sequence with
|
||||
* replacement character.
|
||||
*/
|
||||
source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
|
||||
sourceEnd);
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
|
||||
/* Do this check whether lenient or strict */
|
||||
if (!isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
if (flags == strictConversion) {
|
||||
/* Abort conversion. */
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Replace the maximal subpart of ill-formed sequence with
|
||||
* replacement character.
|
||||
*/
|
||||
source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
|
||||
sourceEnd);
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6;
|
||||
case 4: ch += *source++; ch <<= 6;
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
/*
|
||||
* UTF-16 surrogate values are illegal in UTF-32, and anything
|
||||
* over Plane 17 (> 0x10FFFF) is illegal.
|
||||
*/
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = ch;
|
||||
}
|
||||
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
|
||||
result = sourceIllegal;
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32Partial(const UTF8 **sourceStart,
|
||||
const UTF8 *sourceEnd,
|
||||
UTF32 **targetStart,
|
||||
UTF32 *targetEnd,
|
||||
ConversionFlags flags) {
|
||||
return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
|
||||
flags, /*InputIsPartial=*/true);
|
||||
}
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
|
||||
const UTF8 *sourceEnd, UTF32 **targetStart,
|
||||
UTF32 *targetEnd, ConversionFlags flags) {
|
||||
return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
|
||||
flags, /*InputIsPartial=*/false);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
The fall-through switches in UTF-8 reading code save a
|
||||
temp variable, some decrements & conditionals. The switches
|
||||
are equivalent to the following loop:
|
||||
{
|
||||
int tmpBytesToRead = extraBytesToRead+1;
|
||||
do {
|
||||
ch += *source++;
|
||||
--tmpBytesToRead;
|
||||
if (tmpBytesToRead) ch <<= 6;
|
||||
} while (tmpBytesToRead > 0);
|
||||
}
|
||||
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code CodePageToUTF16(unsigned codepage,
|
||||
std::string_view original,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
if (!original.empty()) {
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), 0);
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
|
||||
utf16.reserve(len + 1);
|
||||
utf16.set_size(len);
|
||||
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), utf16.size());
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Make utf16 null terminated.
|
||||
utf16.push_back(0);
|
||||
utf16.pop_back();
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_UTF8, utf8, utf16);
|
||||
}
|
||||
|
||||
std::error_code CurCPToUTF16(std::string_view curcp,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_ACP, curcp, utf16);
|
||||
}
|
||||
|
||||
static
|
||||
std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16,
|
||||
size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &converted) {
|
||||
if (utf16_len) {
|
||||
// Get length.
|
||||
int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(),
|
||||
0, NULL, NULL);
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
|
||||
converted.reserve(len);
|
||||
converted.set_size(len);
|
||||
|
||||
// Now do the actual conversion.
|
||||
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(),
|
||||
converted.size(), NULL, NULL);
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Make the new string null terminated.
|
||||
converted.push_back(0);
|
||||
converted.pop_back();
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &utf8) {
|
||||
return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8);
|
||||
}
|
||||
|
||||
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &curcp) {
|
||||
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp);
|
||||
}
|
||||
|
||||
} // end namespace windows
|
||||
} // end namespace sys
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
ConvertUTF_RESTORE_WARNINGS
|
||||
253
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
vendored
Normal file
253
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/span.h"
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
|
||||
char *&ResultPtr, const UTF8 *&ErrorPtr) {
|
||||
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
|
||||
ConversionResult result = conversionOK;
|
||||
// Copy the character span over.
|
||||
if (WideCharWidth == 1) {
|
||||
const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.data());
|
||||
if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.data() + Source.size()))) {
|
||||
result = sourceIllegal;
|
||||
ErrorPtr = Pos;
|
||||
} else {
|
||||
memcpy(ResultPtr, Source.data(), Source.size());
|
||||
ResultPtr += Source.size();
|
||||
}
|
||||
} else if (WideCharWidth == 2) {
|
||||
const UTF8 *sourceStart = (const UTF8*)Source.data();
|
||||
// FIXME: Make the type of the result buffer correct instead of
|
||||
// using reinterpret_cast.
|
||||
UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
|
||||
ConversionFlags flags = strictConversion;
|
||||
result = ConvertUTF8toUTF16(
|
||||
&sourceStart, sourceStart + Source.size(),
|
||||
&targetStart, targetStart + Source.size(), flags);
|
||||
if (result == conversionOK)
|
||||
ResultPtr = reinterpret_cast<char*>(targetStart);
|
||||
else
|
||||
ErrorPtr = sourceStart;
|
||||
} else if (WideCharWidth == 4) {
|
||||
const UTF8 *sourceStart = (const UTF8*)Source.data();
|
||||
// FIXME: Make the type of the result buffer correct instead of
|
||||
// using reinterpret_cast.
|
||||
UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
|
||||
ConversionFlags flags = strictConversion;
|
||||
result = ConvertUTF8toUTF32(
|
||||
&sourceStart, sourceStart + Source.size(),
|
||||
&targetStart, targetStart + Source.size(), flags);
|
||||
if (result == conversionOK)
|
||||
ResultPtr = reinterpret_cast<char*>(targetStart);
|
||||
else
|
||||
ErrorPtr = sourceStart;
|
||||
}
|
||||
assert((result != targetExhausted)
|
||||
&& "ConvertUTF8toUTFXX exhausted target buffer");
|
||||
return result == conversionOK;
|
||||
}
|
||||
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
|
||||
const UTF32 *SourceStart = &Source;
|
||||
const UTF32 *SourceEnd = SourceStart + 1;
|
||||
UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
|
||||
UTF8 *TargetEnd = TargetStart + 4;
|
||||
ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
|
||||
&TargetStart, TargetEnd,
|
||||
strictConversion);
|
||||
if (CR != conversionOK)
|
||||
return false;
|
||||
|
||||
ResultPtr = reinterpret_cast<char*>(TargetStart);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasUTF16ByteOrderMark(span<const char> S) {
|
||||
return (S.size() >= 2 &&
|
||||
((S[0] == '\xff' && S[1] == '\xfe') ||
|
||||
(S[0] == '\xfe' && S[1] == '\xff')));
|
||||
}
|
||||
|
||||
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
|
||||
assert(Out.empty());
|
||||
|
||||
// Error out on an uneven byte count.
|
||||
if (SrcBytes.size() % 2)
|
||||
return false;
|
||||
|
||||
// Avoid OOB by returning early on empty input.
|
||||
if (SrcBytes.empty())
|
||||
return true;
|
||||
|
||||
const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin());
|
||||
const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end());
|
||||
|
||||
assert((uintptr_t)Src % sizeof(UTF16) == 0);
|
||||
|
||||
// Byteswap if necessary.
|
||||
std::vector<UTF16> ByteSwapped;
|
||||
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
|
||||
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
|
||||
for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I)
|
||||
ByteSwapped[I] = wpi::ByteSwap_16(ByteSwapped[I]);
|
||||
Src = &ByteSwapped[0];
|
||||
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
|
||||
}
|
||||
|
||||
// Skip the BOM for conversion.
|
||||
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE)
|
||||
Src++;
|
||||
|
||||
// Just allocate enough space up front. We'll shrink it later. Allocate
|
||||
// enough that we can fit a null terminator without reallocating.
|
||||
Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
|
||||
UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]);
|
||||
UTF8 *DstEnd = Dst + Out.size();
|
||||
|
||||
ConversionResult CR =
|
||||
ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
|
||||
assert(CR != targetExhausted);
|
||||
|
||||
if (CR != conversionOK) {
|
||||
Out.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]);
|
||||
Out.push_back(0);
|
||||
Out.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out)
|
||||
{
|
||||
return convertUTF16ToUTF8String(
|
||||
span<const char>(reinterpret_cast<const char *>(Src.data()),
|
||||
Src.size() * sizeof(UTF16)), Out);
|
||||
}
|
||||
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16) {
|
||||
assert(DstUTF16.empty());
|
||||
|
||||
// Avoid OOB by returning early on empty input.
|
||||
if (SrcUTF8.empty()) {
|
||||
DstUTF16.push_back(0);
|
||||
DstUTF16.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.data());
|
||||
const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.data() + SrcUTF8.size());
|
||||
|
||||
// Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding
|
||||
// as UTF-16 should always require the same amount or less code units than the
|
||||
// UTF-8 encoding. Allocate one extra byte for the null terminator though,
|
||||
// so that someone calling DstUTF16.data() gets a null terminated string.
|
||||
// We resize down later so we don't have to worry that this over allocates.
|
||||
DstUTF16.resize(SrcUTF8.size()+1);
|
||||
UTF16 *Dst = &DstUTF16[0];
|
||||
UTF16 *DstEnd = Dst + DstUTF16.size();
|
||||
|
||||
ConversionResult CR =
|
||||
ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
|
||||
assert(CR != targetExhausted);
|
||||
|
||||
if (CR != conversionOK) {
|
||||
DstUTF16.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
DstUTF16.resize(Dst - &DstUTF16[0]);
|
||||
DstUTF16.push_back(0);
|
||||
DstUTF16.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(sizeof(wchar_t) == 1 || sizeof(wchar_t) == 2 ||
|
||||
sizeof(wchar_t) == 4,
|
||||
"Expected wchar_t to be 1, 2, or 4 bytes");
|
||||
|
||||
template <typename TResult>
|
||||
static inline bool ConvertUTF8toWideInternal(std::string_view Source,
|
||||
TResult &Result) {
|
||||
// Even in the case of UTF-16, the number of bytes in a UTF-8 string is
|
||||
// at least as large as the number of elements in the resulting wide
|
||||
// string, because surrogate pairs take at least 4 bytes in UTF-8.
|
||||
Result.resize(Source.size() + 1);
|
||||
char *ResultPtr = reinterpret_cast<char *>(&Result[0]);
|
||||
const UTF8 *ErrorPtr;
|
||||
if (!ConvertUTF8toWide(sizeof(wchar_t), Source, ResultPtr, ErrorPtr)) {
|
||||
Result.clear();
|
||||
return false;
|
||||
}
|
||||
Result.resize(reinterpret_cast<wchar_t *>(ResultPtr) - &Result[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result) {
|
||||
return ConvertUTF8toWideInternal(Source, Result);
|
||||
}
|
||||
|
||||
bool ConvertUTF8toWide(const char *Source, std::wstring &Result) {
|
||||
if (!Source) {
|
||||
Result.clear();
|
||||
return true;
|
||||
}
|
||||
return ConvertUTF8toWide(std::string_view(Source), Result);
|
||||
}
|
||||
|
||||
bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result) {
|
||||
if (sizeof(wchar_t) == 1) {
|
||||
const UTF8 *Start = reinterpret_cast<const UTF8 *>(Source.data());
|
||||
const UTF8 *End =
|
||||
reinterpret_cast<const UTF8 *>(Source.data() + Source.size());
|
||||
if (!isLegalUTF8String(&Start, End))
|
||||
return false;
|
||||
Result.resize(Source.size());
|
||||
memcpy(&Result[0], Source.data(), Source.size());
|
||||
return true;
|
||||
} else if (sizeof(wchar_t) == 2) {
|
||||
return convertUTF16ToUTF8String(
|
||||
span<const UTF16>(reinterpret_cast<const UTF16 *>(Source.data()),
|
||||
Source.size()),
|
||||
Result);
|
||||
} else if (sizeof(wchar_t) == 4) {
|
||||
const UTF32 *Start = reinterpret_cast<const UTF32 *>(Source.data());
|
||||
const UTF32 *End =
|
||||
reinterpret_cast<const UTF32 *>(Source.data() + Source.size());
|
||||
Result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * Source.size());
|
||||
UTF8 *ResultPtr = reinterpret_cast<UTF8 *>(&Result[0]);
|
||||
UTF8 *ResultEnd = reinterpret_cast<UTF8 *>(&Result[0] + Result.size());
|
||||
if (ConvertUTF32toUTF8(&Start, End, &ResultPtr, ResultEnd,
|
||||
strictConversion) == conversionOK) {
|
||||
Result.resize(reinterpret_cast<char *>(ResultPtr) - &Result[0]);
|
||||
return true;
|
||||
} else {
|
||||
Result.clear();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
wpi_unreachable(
|
||||
"Control should never reach this point; see static_assert further up");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
240
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
vendored
Normal file
240
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an API used to indicate fatal error conditions. Non-fatal
|
||||
// errors (most of them) should be handled through LLVMContext.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Errc.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "fmt/format.h"
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
static fatal_error_handler_t ErrorHandler = nullptr;
|
||||
static void *ErrorHandlerUserData = nullptr;
|
||||
|
||||
static fatal_error_handler_t BadAllocErrorHandler = nullptr;
|
||||
static void *BadAllocErrorHandlerUserData = nullptr;
|
||||
|
||||
// Mutexes to synchronize installing error handlers and calling error handlers.
|
||||
// Do not use ManagedStatic, or that may allocate memory while attempting to
|
||||
// report an OOM.
|
||||
//
|
||||
// This usage of std::mutex has to be conditionalized behind ifdefs because
|
||||
// of this script:
|
||||
// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
|
||||
// That script attempts to statically link the LLVM symbolizer library with the
|
||||
// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
|
||||
// cuts out the threading portions of the hermetic copy of libc++ that it
|
||||
// builds. We can remove these ifdefs if that script goes away.
|
||||
static std::mutex ErrorHandlerMutex;
|
||||
static std::mutex BadAllocErrorHandlerMutex;
|
||||
|
||||
void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Error handler already registered!\n");
|
||||
ErrorHandler = handler;
|
||||
ErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void wpi::remove_fatal_error_handler() {
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
ErrorHandler = nullptr;
|
||||
ErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
|
||||
wpi::fatal_error_handler_t handler = nullptr;
|
||||
void* handlerData = nullptr;
|
||||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
handler = ErrorHandler;
|
||||
handlerData = ErrorHandlerUserData;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(handlerData, std::string{Reason}, GenCrashDiag);
|
||||
} else {
|
||||
fmt::print(stderr, "LLVM ERROR: {}\n", Reason);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
|
||||
BadAllocErrorHandler = handler;
|
||||
BadAllocErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void wpi::remove_bad_alloc_error_handler() {
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
BadAllocErrorHandler = nullptr;
|
||||
BadAllocErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
||||
void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
|
||||
fatal_error_handler_t Handler = nullptr;
|
||||
void *HandlerData = nullptr;
|
||||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
Handler = BadAllocErrorHandler;
|
||||
HandlerData = BadAllocErrorHandlerUserData;
|
||||
}
|
||||
|
||||
if (Handler) {
|
||||
Handler(HandlerData, Reason, GenCrashDiag);
|
||||
wpi_unreachable("bad alloc handler should not return");
|
||||
}
|
||||
|
||||
// Don't call the normal error handler. It may allocate memory. Directly write
|
||||
// an OOM to stderr and abort.
|
||||
const char *OOMMessage = "LLVM ERROR: out of memory\n";
|
||||
const char *Newline = "\n";
|
||||
#ifdef _WIN32
|
||||
(void)!::_write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::_write(2, Reason, strlen(Reason));
|
||||
(void)!::_write(2, Newline, strlen(Newline));
|
||||
#else
|
||||
(void)!::write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::write(2, Reason, strlen(Reason));
|
||||
(void)!::write(2, Newline, strlen(Newline));
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
// Causes crash on allocation failure. It is called prior to the handler set by
|
||||
// 'install_bad_alloc_error_handler'.
|
||||
static void out_of_memory_new_handler() {
|
||||
wpi::report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
|
||||
// Installs new handler that causes crash on allocation failure. It is called by
|
||||
// InitLLVM.
|
||||
void wpi::install_out_of_memory_new_handler() {
|
||||
std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
|
||||
(void)old;
|
||||
assert((old == nullptr || old == out_of_memory_new_handler) &&
|
||||
"new-handler already installed");
|
||||
}
|
||||
|
||||
void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
unsigned line) {
|
||||
// This code intentionally doesn't call the ErrorHandler callback, because
|
||||
// wpi_unreachable is intended to be used to indicate "impossible"
|
||||
// situations, and not legitimate runtime errors.
|
||||
if (msg)
|
||||
fmt::print(stderr, "{}\n", msg);
|
||||
std::fputs("UNREACHABLE executed", stderr);
|
||||
if (file)
|
||||
fmt::print(stderr, " at {}:{}", file, line);
|
||||
fmt::print(stderr, "{}", "!\n");
|
||||
abort();
|
||||
#ifdef LLVM_BUILTIN_UNREACHABLE
|
||||
// Windows systems and possibly others don't declare abort() to be noreturn,
|
||||
// so use the unreachable builtin to avoid a Clang self-host warning.
|
||||
LLVM_BUILTIN_UNREACHABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <winerror.h>
|
||||
|
||||
// I'd rather not double the line count of the following.
|
||||
#define MAP_ERR_TO_COND(x, y) \
|
||||
case x: \
|
||||
return std::make_error_code(std::errc::y)
|
||||
|
||||
std::error_code wpi::mapWindowsError(unsigned EV) {
|
||||
switch (EV) {
|
||||
MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
|
||||
MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
|
||||
MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
|
||||
MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
|
||||
MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
|
||||
MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
|
||||
MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
|
||||
MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
|
||||
MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
|
||||
MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
|
||||
MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
|
||||
MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
|
||||
MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
|
||||
MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
|
||||
MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
|
||||
MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
|
||||
MAP_ERR_TO_COND(ERROR_SEEK, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
|
||||
MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
|
||||
MAP_ERR_TO_COND(WSAEACCES, permission_denied);
|
||||
MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
|
||||
MAP_ERR_TO_COND(WSAEFAULT, bad_address);
|
||||
MAP_ERR_TO_COND(WSAEINTR, interrupted);
|
||||
MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
|
||||
MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
|
||||
MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
|
||||
default:
|
||||
return std::error_code(EV, std::system_category());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
28
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
vendored
Normal file
28
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
//===-------------- lib/Support/Hashing.cpp -------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides implementation bits for the LLVM common hashing
|
||||
// infrastructure. Documentation and most of the other information is in the
|
||||
// header file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/Hashing.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
// Provide a definition and static initializer for the fixed seed. This
|
||||
// initializer should always be zero to ensure its value can never appear to be
|
||||
// non-zero, even during dynamic initialization.
|
||||
uint64_t wpi::hashing::detail::fixed_seed_override = 0;
|
||||
|
||||
// Implement the function for forced setting of the fixed seed.
|
||||
// FIXME: Use atomic operations here so that there is no data race.
|
||||
void wpi::set_fixed_execution_hash_seed(uint64_t fixed_value) {
|
||||
hashing::detail::fixed_seed_override = fixed_value;
|
||||
}
|
||||
77
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ManagedStatic.cpp
vendored
Normal file
77
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ManagedStatic.cpp
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the ManagedStatic class and wpi_shutdown().
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/ManagedStatic.h"
|
||||
#include "wpi/mutex.h"
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
using namespace wpi;
|
||||
|
||||
static const ManagedStaticBase *StaticList = nullptr;
|
||||
|
||||
static wpi::mutex *getManagedStaticMutex() {
|
||||
static wpi::mutex m;
|
||||
return &m;
|
||||
}
|
||||
|
||||
void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
|
||||
void (*Deleter)(void*)) const {
|
||||
assert(Creator);
|
||||
if (1) {
|
||||
std::scoped_lock Lock(*getManagedStaticMutex());
|
||||
|
||||
if (!Ptr.load(std::memory_order_relaxed)) {
|
||||
void *Tmp = Creator();
|
||||
|
||||
Ptr.store(Tmp, std::memory_order_release);
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
Next = StaticList;
|
||||
StaticList = this;
|
||||
}
|
||||
} else {
|
||||
assert(!Ptr && !DeleterFn && !Next &&
|
||||
"Partially initialized ManagedStatic!?");
|
||||
Ptr = Creator();
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
Next = StaticList;
|
||||
StaticList = this;
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedStaticBase::destroy() const {
|
||||
assert(DeleterFn && "ManagedStatic not initialized correctly!");
|
||||
assert(StaticList == this &&
|
||||
"Not destroyed in reverse order of construction?");
|
||||
// Unlink from list.
|
||||
StaticList = Next;
|
||||
Next = nullptr;
|
||||
|
||||
// Destroy memory.
|
||||
DeleterFn(Ptr);
|
||||
|
||||
// Cleanup.
|
||||
Ptr = nullptr;
|
||||
DeleterFn = nullptr;
|
||||
}
|
||||
|
||||
/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
|
||||
/// IMPORTANT: it's only safe to call wpi_shutdown() in single thread,
|
||||
/// without any other threads executing LLVM APIs.
|
||||
/// wpi_shutdown() should be the last use of LLVM APIs.
|
||||
void wpi::wpi_shutdown() {
|
||||
while (StaticList)
|
||||
StaticList->destroy();
|
||||
}
|
||||
34
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp
vendored
Normal file
34
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
// These are out of line to have __cpp_aligned_new not affect ABI.
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
|
||||
wpi::allocate_buffer(size_t Size, size_t Alignment) {
|
||||
return ::operator new(Size
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
void wpi::deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
|
||||
::operator delete(Ptr
|
||||
#ifdef __cpp_sized_deallocation
|
||||
,
|
||||
Size
|
||||
#endif
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
523
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
vendored
Normal file
523
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
// 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.
|
||||
|
||||
//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MemoryBuffer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/MemoryBuffer.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// no matching operator delete
|
||||
#pragma warning(disable : 4291)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h> // NOLINT(build/include_order)
|
||||
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <system_error>
|
||||
|
||||
#include "wpi/Errc.h"
|
||||
#include "wpi/Errno.h"
|
||||
#include "wpi/MappedFileRegion.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/SmallVectorMemoryBuffer.h"
|
||||
#include "wpi/fs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wpi/WindowsError.h"
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBuffer implementation itself.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MemoryBuffer::~MemoryBuffer() {}
|
||||
|
||||
/// init - Initialize this MemoryBuffer as a reference to externally allocated
|
||||
/// memory.
|
||||
void MemoryBuffer::Init(const uint8_t* bufStart, const uint8_t* bufEnd) {
|
||||
m_bufferStart = bufStart;
|
||||
m_bufferEnd = bufEnd;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBufferMem implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// CopyStringRef - Copies contents of a StringRef into a block of memory and
|
||||
/// null-terminates it.
|
||||
static void CopyStringView(uint8_t* memory, std::string_view data) {
|
||||
if (!data.empty()) {
|
||||
std::memcpy(memory, data.data(), data.size());
|
||||
}
|
||||
memory[data.size()] = 0; // Null terminate string.
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct NamedBufferAlloc {
|
||||
std::string_view name;
|
||||
explicit NamedBufferAlloc(std::string_view name) : name(name) {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void* operator new(size_t N, NamedBufferAlloc alloc) {
|
||||
uint8_t* mem = static_cast<uint8_t*>(operator new(N + alloc.name.size() + 1));
|
||||
CopyStringView(mem + N, alloc.name);
|
||||
return mem;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
|
||||
template <typename MB>
|
||||
class MemoryBufferMem : public MB {
|
||||
public:
|
||||
explicit MemoryBufferMem(span<const uint8_t> inputData) {
|
||||
MemoryBuffer::Init(inputData.begin(), inputData.end());
|
||||
}
|
||||
|
||||
/// Disable sized deallocation for MemoryBufferMem, because it has
|
||||
/// tail-allocated data.
|
||||
void operator delete(void* p) { ::operator delete(p); } // NOLINT
|
||||
|
||||
std::string_view GetBufferIdentifier() const override {
|
||||
// The name is stored after the class itself.
|
||||
return std::string_view(reinterpret_cast<const char*>(this + 1));
|
||||
}
|
||||
|
||||
MemoryBuffer::BufferKind GetBufferKind() const override {
|
||||
return MemoryBuffer::MemoryBuffer_Malloc;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetFileAux(std::string_view filename,
|
||||
std::error_code& ec, int64_t fileSize,
|
||||
uint64_t mapSize, uint64_t offset);
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(
|
||||
span<const uint8_t> inputData, std::string_view bufferName) {
|
||||
auto* ret = new (NamedBufferAlloc(bufferName))
|
||||
MemoryBufferMem<MemoryBuffer>(inputData);
|
||||
return std::unique_ptr<MemoryBuffer>(ret);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(MemoryBufferRef ref) {
|
||||
return std::unique_ptr<MemoryBuffer>(
|
||||
GetMemBuffer(ref.GetBuffer(), ref.GetBufferIdentifier()));
|
||||
}
|
||||
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetMemBufferCopyImpl(
|
||||
span<const uint8_t> inputData, std::string_view bufferName,
|
||||
std::error_code& ec) {
|
||||
auto buf =
|
||||
WritableMemoryBuffer::GetNewUninitMemBuffer(inputData.size(), bufferName);
|
||||
if (!buf) {
|
||||
ec = make_error_code(errc::not_enough_memory);
|
||||
return nullptr;
|
||||
}
|
||||
std::memcpy(buf->begin(), inputData.data(), inputData.size());
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBufferCopy(
|
||||
span<const uint8_t> inputData, std::string_view bufferName) {
|
||||
std::error_code ec;
|
||||
return GetMemBufferCopyImpl(inputData, bufferName, ec);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFileSlice(
|
||||
std::string_view filePath, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset) {
|
||||
return GetFileAux<MemoryBuffer>(filePath, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBuffer::getFile implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename MB>
|
||||
constexpr auto kMapMode = MappedFileRegion::kReadOnly;
|
||||
template <>
|
||||
constexpr auto kMapMode<MemoryBuffer> = MappedFileRegion::kReadOnly;
|
||||
template <>
|
||||
constexpr auto kMapMode<WritableMemoryBuffer> = MappedFileRegion::kPriv;
|
||||
template <>
|
||||
constexpr auto kMapMode<WriteThroughMemoryBuffer> =
|
||||
MappedFileRegion::kReadWrite;
|
||||
|
||||
/// Memory maps a file descriptor using MappedFileRegion.
|
||||
///
|
||||
/// This handles converting the offset into a legal offset on the platform.
|
||||
template <typename MB>
|
||||
class MemoryBufferMMapFile : public MB {
|
||||
MappedFileRegion m_mfr;
|
||||
|
||||
static uint64_t getLegalMapOffset(uint64_t offset) {
|
||||
return offset & ~(MappedFileRegion::GetAlignment() - 1);
|
||||
}
|
||||
|
||||
static uint64_t getLegalMapSize(uint64_t len, uint64_t offset) {
|
||||
return len + (offset - getLegalMapOffset(offset));
|
||||
}
|
||||
|
||||
const uint8_t* getStart(uint64_t len, uint64_t offset) {
|
||||
return m_mfr.const_data() + (offset - getLegalMapOffset(offset));
|
||||
}
|
||||
|
||||
public:
|
||||
MemoryBufferMMapFile(fs::file_t f, uint64_t len, uint64_t offset,
|
||||
std::error_code& ec)
|
||||
: m_mfr(f, getLegalMapSize(len, offset), getLegalMapOffset(offset),
|
||||
kMapMode<MB>, ec) {
|
||||
if (!ec) {
|
||||
const uint8_t* Start = getStart(len, offset);
|
||||
MemoryBuffer::Init(Start, Start + len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Disable sized deallocation for MemoryBufferMMapFile, because it has
|
||||
/// tail-allocated data.
|
||||
void operator delete(void* p) { ::operator delete(p); } // NOLINT
|
||||
|
||||
std::string_view GetBufferIdentifier() const override {
|
||||
// The name is stored after the class itself.
|
||||
return std::string_view(reinterpret_cast<const char*>(this + 1));
|
||||
}
|
||||
|
||||
MemoryBuffer::BufferKind GetBufferKind() const override {
|
||||
return MemoryBuffer::MemoryBuffer_MMap;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetMemoryBufferForStream(
|
||||
fs::file_t f, std::string_view bufferName, std::error_code& ec) {
|
||||
constexpr size_t ChunkSize = 4096 * 4;
|
||||
SmallVector<uint8_t, ChunkSize> buffer;
|
||||
#ifdef _WIN32
|
||||
DWORD readBytes;
|
||||
#else
|
||||
ssize_t readBytes;
|
||||
#endif
|
||||
// Read into Buffer until we hit EOF.
|
||||
do {
|
||||
buffer.reserve(buffer.size() + ChunkSize);
|
||||
#ifdef _WIN32
|
||||
if (!ReadFile(f, buffer.end(), ChunkSize, &readBytes, nullptr)) {
|
||||
ec = mapWindowsError(GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
readBytes = sys::RetryAfterSignal(-1, ::read, f, buffer.end(), ChunkSize);
|
||||
if (readBytes == -1) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
buffer.set_size(buffer.size() + readBytes);
|
||||
} while (readBytes != 0);
|
||||
|
||||
return GetMemBufferCopyImpl(buffer, bufferName, ec);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFile(std::string_view filename,
|
||||
std::error_code& ec,
|
||||
int64_t fileSize) {
|
||||
return GetFileAux<MemoryBuffer>(filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetOpenFileImpl(fs::file_t f,
|
||||
std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t fileSize, uint64_t mapSize,
|
||||
int64_t offset);
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetFileAux(std::string_view filename,
|
||||
std::error_code& ec, int64_t fileSize,
|
||||
uint64_t mapSize, uint64_t offset) {
|
||||
fs::file_t F = fs::OpenFileForRead(filename, ec, fs::OF_None);
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto Ret = GetOpenFileImpl<MB>(F, filename, ec, fileSize, mapSize, offset);
|
||||
fs::CloseFile(F);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize) {
|
||||
return GetFileAux<WritableMemoryBuffer>(filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetFileSlice(
|
||||
std::string_view filename, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset) {
|
||||
return GetFileAux<WritableMemoryBuffer>(filename, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer>
|
||||
WritableMemoryBuffer::GetNewUninitMemBuffer(size_t size,
|
||||
std::string_view bufferName) {
|
||||
using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>;
|
||||
// Allocate space for the MemoryBuffer, the data and the name. It is important
|
||||
// that MemoryBuffer and data are aligned so PointerIntPair works with them.
|
||||
// TODO: Is 16-byte alignment enough? We copy small object files with large
|
||||
// alignment expectations into this buffer.
|
||||
size_t alignedStringLen =
|
||||
alignTo(sizeof(MemBuffer) + bufferName.size() + 1, 16);
|
||||
size_t realLen = alignedStringLen + size + 1;
|
||||
uint8_t* mem = static_cast<uint8_t*>(operator new(realLen, std::nothrow));
|
||||
if (!mem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The name is stored after the class itself.
|
||||
CopyStringView(mem + sizeof(MemBuffer), bufferName);
|
||||
|
||||
// The buffer begins after the name and must be aligned.
|
||||
uint8_t* buf = mem + alignedStringLen;
|
||||
buf[size] = 0; // Null terminate buffer.
|
||||
|
||||
auto* ret = new (mem) MemBuffer({buf, size});
|
||||
return std::unique_ptr<WritableMemoryBuffer>(ret);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetNewMemBuffer(
|
||||
size_t size, std::string_view bufferName) {
|
||||
auto sb = WritableMemoryBuffer::GetNewUninitMemBuffer(size, bufferName);
|
||||
if (!sb) {
|
||||
return nullptr;
|
||||
}
|
||||
std::memset(sb->begin(), 0, size);
|
||||
return sb;
|
||||
}
|
||||
|
||||
static std::unique_ptr<WriteThroughMemoryBuffer> GetReadWriteFile(
|
||||
std::string_view filename, std::error_code& ec, uint64_t fileSize,
|
||||
uint64_t mapSize, uint64_t offset) {
|
||||
fs::file_t f =
|
||||
fs::OpenFileForReadWrite(filename, ec, fs::CD_OpenExisting, fs::OF_None);
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Default is to map the full file.
|
||||
if (mapSize == uint64_t(-1)) {
|
||||
// If we don't know the file size, use fstat to find out. fstat on an open
|
||||
// file descriptor is cheaper than stat on a random path.
|
||||
if (fileSize == uint64_t(-1)) {
|
||||
#ifdef _WIN32
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't mmap it, so error out.
|
||||
if (GetFileType(f) != FILE_TYPE_DISK) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LARGE_INTEGER fileSizeWin;
|
||||
if (!GetFileSizeEx(f, &fileSizeWin)) {
|
||||
ec = wpi::mapWindowsError(GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
fileSize = fileSizeWin.QuadPart;
|
||||
#else
|
||||
struct stat status;
|
||||
if (fstat(f, &status) < 0) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't mmap it, so error out.
|
||||
if (status.st_mode != S_IFREG && status.st_mode != S_IFBLK) {
|
||||
ec = make_error_code(errc::invalid_argument);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fileSize = status.st_size;
|
||||
#endif
|
||||
}
|
||||
mapSize = fileSize;
|
||||
}
|
||||
|
||||
std::unique_ptr<WriteThroughMemoryBuffer> result(new (NamedBufferAlloc(
|
||||
filename)) MemoryBufferMMapFile<WriteThroughMemoryBuffer>(f, mapSize,
|
||||
offset, ec));
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<WriteThroughMemoryBuffer> WriteThroughMemoryBuffer::GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize) {
|
||||
return GetReadWriteFile(filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
/// Map a subrange of the specified file as a WritableMemoryBuffer.
|
||||
std::unique_ptr<WriteThroughMemoryBuffer>
|
||||
WriteThroughMemoryBuffer::GetFileSlice(std::string_view filename,
|
||||
std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset) {
|
||||
return GetReadWriteFile(filename, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetOpenFileImpl(fs::file_t f,
|
||||
std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t fileSize, uint64_t mapSize,
|
||||
int64_t offset) {
|
||||
// Default is to map the full file.
|
||||
if (mapSize == uint64_t(-1)) {
|
||||
// If we don't know the file size, use fstat to find out. fstat on an open
|
||||
// file descriptor is cheaper than stat on a random path.
|
||||
if (fileSize == uint64_t(-1)) {
|
||||
#ifdef _WIN32
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't trust the size. Create the memory
|
||||
// buffer by copying off the stream.
|
||||
LARGE_INTEGER fileSizeWin;
|
||||
if (GetFileType(f) != FILE_TYPE_DISK || !GetFileSizeEx(f, &fileSizeWin)) {
|
||||
return GetMemoryBufferForStream(f, filename, ec);
|
||||
}
|
||||
fileSize = fileSizeWin.QuadPart;
|
||||
#else
|
||||
struct stat status;
|
||||
if (fstat(f, &status) < 0) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't trust the size. Create the memory
|
||||
// buffer by copying off the stream.
|
||||
if (status.st_mode != S_IFREG && status.st_mode != S_IFBLK) {
|
||||
return GetMemoryBufferForStream(f, filename, ec);
|
||||
}
|
||||
|
||||
fileSize = status.st_size;
|
||||
#endif
|
||||
}
|
||||
mapSize = fileSize;
|
||||
}
|
||||
|
||||
// Don't use mmap for small files
|
||||
if (mapSize >= 4 * 4096) {
|
||||
std::unique_ptr<MB> result(new (NamedBufferAlloc(
|
||||
filename)) MemoryBufferMMapFile<MB>(f, mapSize, offset, ec));
|
||||
if (!ec) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
auto buf = WritableMemoryBuffer::GetNewUninitMemBuffer(mapSize, filename);
|
||||
if (!buf) {
|
||||
// Failed to create a buffer. The only way it can fail is if
|
||||
// new(std::nothrow) returns 0.
|
||||
ec = make_error_code(errc::not_enough_memory);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* bufPtr = buf.get()->begin();
|
||||
|
||||
size_t bytesLeft = mapSize;
|
||||
while (bytesLeft) {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER offsetWin;
|
||||
offsetWin.QuadPart = offset;
|
||||
DWORD numRead;
|
||||
if (!SetFilePointerEx(f, offsetWin, nullptr, FILE_BEGIN) ||
|
||||
!ReadFile(f, bufPtr, bytesLeft, &numRead, nullptr)) {
|
||||
ec = mapWindowsError(GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
// TODO
|
||||
#else
|
||||
ssize_t numRead = sys::RetryAfterSignal(-1, ::pread, f, bufPtr, bytesLeft,
|
||||
mapSize - bytesLeft + offset);
|
||||
if (numRead == -1) {
|
||||
// Error while reading.
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
if (numRead == 0) {
|
||||
std::memset(bufPtr, 0, bytesLeft); // zero-initialize rest of the buffer.
|
||||
break;
|
||||
}
|
||||
bytesLeft -= numRead;
|
||||
bufPtr += numRead;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetOpenFile(
|
||||
fs::file_t f, std::string_view filename, std::error_code& ec,
|
||||
uint64_t fileSize) {
|
||||
return GetOpenFileImpl<MemoryBuffer>(f, filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetOpenFileSlice(
|
||||
fs::file_t f, std::string_view filename, std::error_code& ec,
|
||||
uint64_t mapSize, int64_t offset) {
|
||||
assert(mapSize != uint64_t(-1));
|
||||
return GetOpenFileImpl<MemoryBuffer>(f, filename, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFileAsStream(
|
||||
std::string_view filename, std::error_code& ec) {
|
||||
fs::file_t f = fs::OpenFileForRead(filename, ec, fs::OF_None);
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<MemoryBuffer> ret = GetMemoryBufferForStream(f, filename, ec);
|
||||
fs::CloseFile(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MemoryBufferRef MemoryBuffer::GetMemBufferRef() const {
|
||||
return MemoryBufferRef(GetBuffer(), GetBufferIdentifier());
|
||||
}
|
||||
|
||||
SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() {}
|
||||
271
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
vendored
Normal file
271
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SmallPtrSet class. See SmallPtrSet.h for an
|
||||
// overview of the algorithm.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
void SmallPtrSetImplBase::shrink_and_clear() {
|
||||
assert(!isSmall() && "Can't shrink a small set!");
|
||||
free(CurArray);
|
||||
|
||||
// Reduce the number of buckets.
|
||||
unsigned Size = size();
|
||||
CurArraySize = Size > 16 ? 1 << (Log2_32_Ceil(Size) + 1) : 32;
|
||||
NumNonEmpty = NumTombstones = 0;
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
|
||||
|
||||
memset(CurArray, -1, CurArraySize*sizeof(void*));
|
||||
}
|
||||
|
||||
std::pair<const void *const *, bool>
|
||||
SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
|
||||
if (LLVM_UNLIKELY(size() * 4 >= CurArraySize * 3)) {
|
||||
// If more than 3/4 of the array is full, grow.
|
||||
Grow(CurArraySize < 64 ? 128 : CurArraySize * 2);
|
||||
} else if (LLVM_UNLIKELY(CurArraySize - NumNonEmpty < CurArraySize / 8)) {
|
||||
// If fewer of 1/8 of the array is empty (meaning that many are filled with
|
||||
// tombstones), rehash.
|
||||
Grow(CurArraySize);
|
||||
}
|
||||
|
||||
// Okay, we know we have space. Find a hash bucket.
|
||||
const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));
|
||||
if (*Bucket == Ptr)
|
||||
return std::make_pair(Bucket, false); // Already inserted, good.
|
||||
|
||||
// Otherwise, insert it!
|
||||
if (*Bucket == getTombstoneMarker())
|
||||
--NumTombstones;
|
||||
else
|
||||
++NumNonEmpty; // Track density.
|
||||
*Bucket = Ptr;
|
||||
incrementEpoch();
|
||||
return std::make_pair(Bucket, true);
|
||||
}
|
||||
|
||||
const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
|
||||
unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & (CurArraySize-1);
|
||||
unsigned ArraySize = CurArraySize;
|
||||
unsigned ProbeAmt = 1;
|
||||
const void *const *Array = CurArray;
|
||||
const void *const *Tombstone = nullptr;
|
||||
while (true) {
|
||||
// If we found an empty bucket, the pointer doesn't exist in the set.
|
||||
// Return a tombstone if we've seen one so far, or the empty bucket if
|
||||
// not.
|
||||
if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker()))
|
||||
return Tombstone ? Tombstone : Array+Bucket;
|
||||
|
||||
// Found Ptr's bucket?
|
||||
if (LLVM_LIKELY(Array[Bucket] == Ptr))
|
||||
return Array+Bucket;
|
||||
|
||||
// If this is a tombstone, remember it. If Ptr ends up not in the set, we
|
||||
// prefer to return it than something that would require more probing.
|
||||
if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
|
||||
Tombstone = Array+Bucket; // Remember the first tombstone found.
|
||||
|
||||
// It's a hash collision or a tombstone. Reprobe.
|
||||
Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
///
|
||||
void SmallPtrSetImplBase::Grow(unsigned NewSize) {
|
||||
const void **OldBuckets = CurArray;
|
||||
const void **OldEnd = EndPointer();
|
||||
bool WasSmall = isSmall();
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
|
||||
|
||||
// Reset member only if memory was allocated successfully
|
||||
CurArray = NewBuckets;
|
||||
CurArraySize = NewSize;
|
||||
memset(CurArray, -1, NewSize*sizeof(void*));
|
||||
|
||||
// Copy over all valid entries.
|
||||
for (const void **BucketPtr = OldBuckets; BucketPtr != OldEnd; ++BucketPtr) {
|
||||
// Copy over the element if it is valid.
|
||||
const void *Elt = *BucketPtr;
|
||||
if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
|
||||
*const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt);
|
||||
}
|
||||
|
||||
if (!WasSmall)
|
||||
free(OldBuckets);
|
||||
NumNonEmpty -= NumTombstones;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase &that) {
|
||||
SmallArray = SmallStorage;
|
||||
|
||||
// If we're becoming small, prepare to insert into our stack space
|
||||
if (that.isSmall()) {
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else {
|
||||
CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
|
||||
}
|
||||
|
||||
// Copy over the that array.
|
||||
CopyHelper(that);
|
||||
}
|
||||
|
||||
SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
|
||||
unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that) {
|
||||
SmallArray = SmallStorage;
|
||||
MoveHelper(SmallSize, std::move(that));
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {
|
||||
assert(&RHS != this && "Self-copy should be handled by the caller.");
|
||||
|
||||
if (isSmall() && RHS.isSmall())
|
||||
assert(CurArraySize == RHS.CurArraySize &&
|
||||
"Cannot assign sets with different small sizes");
|
||||
|
||||
// If we're becoming small, prepare to insert into our stack space
|
||||
if (RHS.isSmall()) {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else if (CurArraySize != RHS.CurArraySize) {
|
||||
if (isSmall())
|
||||
CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
|
||||
else {
|
||||
const void **T = (const void**)safe_realloc(CurArray,
|
||||
sizeof(void*) * RHS.CurArraySize);
|
||||
CurArray = T;
|
||||
}
|
||||
}
|
||||
|
||||
CopyHelper(RHS);
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::CopyHelper(const SmallPtrSetImplBase &RHS) {
|
||||
// Copy over the new array size
|
||||
CurArraySize = RHS.CurArraySize;
|
||||
|
||||
// Copy over the contents from the other set
|
||||
std::copy(RHS.CurArray, RHS.EndPointer(), CurArray);
|
||||
|
||||
NumNonEmpty = RHS.NumNonEmpty;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&RHS) {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
MoveHelper(SmallSize, std::move(RHS));
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::MoveHelper(unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&RHS) {
|
||||
assert(&RHS != this && "Self-move should be handled by the caller.");
|
||||
|
||||
if (RHS.isSmall()) {
|
||||
// Copy a small RHS rather than moving.
|
||||
CurArray = SmallArray;
|
||||
std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, CurArray);
|
||||
} else {
|
||||
CurArray = RHS.CurArray;
|
||||
RHS.CurArray = RHS.SmallArray;
|
||||
}
|
||||
|
||||
// Copy the rest of the trivial members.
|
||||
CurArraySize = RHS.CurArraySize;
|
||||
NumNonEmpty = RHS.NumNonEmpty;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
|
||||
// Make the RHS small and empty.
|
||||
RHS.CurArraySize = SmallSize;
|
||||
assert(RHS.CurArray == RHS.SmallArray);
|
||||
RHS.NumNonEmpty = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {
|
||||
if (this == &RHS) return;
|
||||
|
||||
// We can only avoid copying elements if neither set is small.
|
||||
if (!this->isSmall() && !RHS.isSmall()) {
|
||||
std::swap(this->CurArray, RHS.CurArray);
|
||||
std::swap(this->CurArraySize, RHS.CurArraySize);
|
||||
std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap(this->NumTombstones, RHS.NumTombstones);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: From here on we assume that both sets have the same small size.
|
||||
|
||||
// If only RHS is small, copy the small elements into LHS and move the pointer
|
||||
// from LHS to RHS.
|
||||
if (!this->isSmall() && RHS.isSmall()) {
|
||||
assert(RHS.CurArray == RHS.SmallArray);
|
||||
std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, this->SmallArray);
|
||||
std::swap(RHS.CurArraySize, this->CurArraySize);
|
||||
std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap(this->NumTombstones, RHS.NumTombstones);
|
||||
RHS.CurArray = this->CurArray;
|
||||
this->CurArray = this->SmallArray;
|
||||
return;
|
||||
}
|
||||
|
||||
// If only LHS is small, copy the small elements into RHS and move the pointer
|
||||
// from RHS to LHS.
|
||||
if (this->isSmall() && !RHS.isSmall()) {
|
||||
assert(this->CurArray == this->SmallArray);
|
||||
std::copy(this->CurArray, this->CurArray + this->NumNonEmpty,
|
||||
RHS.SmallArray);
|
||||
std::swap(RHS.CurArraySize, this->CurArraySize);
|
||||
std::swap(RHS.NumNonEmpty, this->NumNonEmpty);
|
||||
std::swap(RHS.NumTombstones, this->NumTombstones);
|
||||
this->CurArray = RHS.CurArray;
|
||||
RHS.CurArray = RHS.SmallArray;
|
||||
return;
|
||||
}
|
||||
|
||||
// Both a small, just swap the small elements.
|
||||
assert(this->isSmall() && RHS.isSmall());
|
||||
unsigned MinNonEmpty = std::min(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap_ranges(this->SmallArray, this->SmallArray + MinNonEmpty,
|
||||
RHS.SmallArray);
|
||||
if (this->NumNonEmpty > MinNonEmpty) {
|
||||
std::copy(this->SmallArray + MinNonEmpty,
|
||||
this->SmallArray + this->NumNonEmpty,
|
||||
RHS.SmallArray + MinNonEmpty);
|
||||
} else {
|
||||
std::copy(RHS.SmallArray + MinNonEmpty, RHS.SmallArray + RHS.NumNonEmpty,
|
||||
this->SmallArray + MinNonEmpty);
|
||||
}
|
||||
assert(this->CurArraySize == RHS.CurArraySize);
|
||||
std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap(this->NumTombstones, RHS.NumTombstones);
|
||||
}
|
||||
120
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
vendored
Normal file
120
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SmallVector class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <cstdint>
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
using namespace wpi;
|
||||
|
||||
// Check that no bytes are wasted and everything is well-aligned.
|
||||
namespace {
|
||||
struct Struct16B {
|
||||
alignas(16) void *X;
|
||||
};
|
||||
struct Struct32B {
|
||||
alignas(32) void *X;
|
||||
};
|
||||
}
|
||||
static_assert(sizeof(SmallVector<void *, 0>) ==
|
||||
sizeof(unsigned) * 2 + sizeof(void *),
|
||||
"wasted space in SmallVector size 0");
|
||||
static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
|
||||
"wrong alignment for 16-byte aligned T");
|
||||
static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
|
||||
"wrong alignment for 32-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
|
||||
"missing padding for 16-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
|
||||
"missing padding for 32-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<void *, 1>) ==
|
||||
sizeof(unsigned) * 2 + sizeof(void *) * 2,
|
||||
"wasted space in SmallVector size 1");
|
||||
|
||||
/// Report that MinSize doesn't fit into this vector's size type. Throws
|
||||
/// std::length_error or calls report_fatal_error.
|
||||
LLVM_ATTRIBUTE_NORETURN
|
||||
static void report_size_overflow(size_t MinSize, size_t MaxSize);
|
||||
static void report_size_overflow(size_t MinSize, size_t MaxSize) {
|
||||
std::string Reason = "SmallVector unable to grow. Requested capacity (" +
|
||||
std::to_string(MinSize) +
|
||||
") is larger than maximum value for size type (" +
|
||||
std::to_string(MaxSize) + ")";
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
throw std::length_error(Reason);
|
||||
#else
|
||||
report_fatal_error(Reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Report that this vector is already at maximum capacity. Throws
|
||||
/// std::length_error or calls report_fatal_error.
|
||||
LLVM_ATTRIBUTE_NORETURN static void report_at_maximum_capacity(size_t MaxSize);
|
||||
static void report_at_maximum_capacity(size_t MaxSize) {
|
||||
std::string Reason =
|
||||
"SmallVector capacity unable to grow. Already at maximum size " +
|
||||
std::to_string(MaxSize);
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
throw std::length_error(Reason);
|
||||
#else
|
||||
report_fatal_error(Reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
|
||||
constexpr size_t MaxSize = std::numeric_limits<unsigned>::max();
|
||||
|
||||
// Ensure we can fit the new capacity.
|
||||
// This is only going to be applicable when the capacity is 32 bit.
|
||||
if (MinSize > MaxSize)
|
||||
report_size_overflow(MinSize, MaxSize);
|
||||
|
||||
// Ensure we can meet the guarantee of space for at least one more element.
|
||||
// The above check alone will not catch the case where grow is called with a
|
||||
// default MinSize of 0, but the current capacity cannot be increased.
|
||||
// This is only going to be applicable when the capacity is 32 bit.
|
||||
if (OldCapacity == MaxSize)
|
||||
report_at_maximum_capacity(MaxSize);
|
||||
|
||||
// In theory 2*capacity can overflow if the capacity is 64 bit, but the
|
||||
// original capacity would never be large enough for this to be a problem.
|
||||
size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
|
||||
return (std::min)((std::max)(NewCapacity, MinSize), MaxSize);
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
void *SmallVectorBase::mallocForGrow(size_t MinSize, size_t TSize,
|
||||
size_t &NewCapacity) {
|
||||
NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
|
||||
return wpi::safe_malloc(NewCapacity * TSize);
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSize,
|
||||
size_t TSize) {
|
||||
size_t NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
|
||||
void *NewElts;
|
||||
if (BeginX == FirstEl) {
|
||||
NewElts = safe_malloc(NewCapacity * TSize);
|
||||
|
||||
// Copy the elements over. No need to run dtors on PODs.
|
||||
memcpy(NewElts, this->BeginX, size() * TSize);
|
||||
} else {
|
||||
// If this wasn't grown from the inline copy, grow the allocated space.
|
||||
NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
|
||||
}
|
||||
|
||||
this->BeginX = NewElts;
|
||||
this->Capacity = NewCapacity;
|
||||
}
|
||||
360
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
vendored
Normal file
360
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
// 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.
|
||||
|
||||
//===-- StringExtras.cpp - Implement the StringExtras header --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the StringExtras.h header
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringExtras.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
|
||||
// strncasecmp() is not available on non-POSIX systems, so define an
|
||||
// alternative function here.
|
||||
static int ascii_strncasecmp(const char* lhs, const char* rhs,
|
||||
size_t length) noexcept {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
unsigned char lhc = wpi::toLower(lhs[i]);
|
||||
unsigned char rhc = wpi::toLower(rhs[i]);
|
||||
if (lhc != rhc) {
|
||||
return lhc < rhc ? -1 : 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wpi::compare_lower(std::string_view lhs, std::string_view rhs) noexcept {
|
||||
if (int Res = ascii_strncasecmp(lhs.data(), rhs.data(),
|
||||
(std::min)(lhs.size(), rhs.size()))) {
|
||||
return Res;
|
||||
}
|
||||
if (lhs.size() == rhs.size()) {
|
||||
return 0;
|
||||
}
|
||||
return lhs.size() < rhs.size() ? -1 : 1;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::find_lower(
|
||||
std::string_view str, char ch, std::string_view::size_type from) noexcept {
|
||||
char lch = toLower(ch);
|
||||
auto s = drop_front(str, from);
|
||||
while (!s.empty()) {
|
||||
if (toLower(s.front()) == lch) {
|
||||
return str.size() - s.size();
|
||||
}
|
||||
s.remove_prefix(1);
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::find_lower(
|
||||
std::string_view str, std::string_view other,
|
||||
std::string_view::size_type from) noexcept {
|
||||
auto s = substr(str, from);
|
||||
while (s.size() >= other.size()) {
|
||||
if (starts_with_lower(s, other)) {
|
||||
return from;
|
||||
}
|
||||
s.remove_prefix(1);
|
||||
++from;
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::rfind_lower(
|
||||
std::string_view str, char ch, std::string_view::size_type from) noexcept {
|
||||
from = (std::min)(from, str.size());
|
||||
auto data = str.data();
|
||||
std::string_view::size_type i = from;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (toLower(data[i]) == toLower(ch)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::rfind_lower(std::string_view str,
|
||||
std::string_view other) noexcept {
|
||||
std::string_view::size_type n = other.size();
|
||||
if (n > str.size()) {
|
||||
return std::string_view::npos;
|
||||
}
|
||||
for (size_t i = str.size() - n + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (equals_lower(substr(str, i, n), other)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
bool wpi::starts_with_lower(std::string_view str,
|
||||
std::string_view prefix) noexcept {
|
||||
return str.size() >= prefix.size() &&
|
||||
ascii_strncasecmp(str.data(), prefix.data(), prefix.size()) == 0;
|
||||
}
|
||||
|
||||
bool wpi::ends_with_lower(std::string_view str,
|
||||
std::string_view suffix) noexcept {
|
||||
return str.size() >= suffix.size() &&
|
||||
ascii_strncasecmp(str.data() + str.size() - suffix.size(),
|
||||
suffix.data(), suffix.size()) == 0;
|
||||
}
|
||||
|
||||
void wpi::split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
std::string_view separator, int maxSplit,
|
||||
bool keepEmpty) noexcept {
|
||||
std::string_view s = str;
|
||||
|
||||
// Count down from maxSplit. When maxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make maxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (maxSplit-- != 0) {
|
||||
auto idx = s.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Push this split.
|
||||
if (keepEmpty || idx > 0) {
|
||||
arr.push_back(slice(s, 0, idx));
|
||||
}
|
||||
|
||||
// Jump forward.
|
||||
s = slice(s, idx + separator.size(), std::string_view::npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (keepEmpty || !s.empty()) {
|
||||
arr.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
void wpi::split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
char separator, int maxSplit, bool keepEmpty) noexcept {
|
||||
std::string_view s = str;
|
||||
|
||||
// Count down from maxSplit. When maxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make maxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (maxSplit-- != 0) {
|
||||
size_t idx = s.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Push this split.
|
||||
if (keepEmpty || idx > 0) {
|
||||
arr.push_back(slice(s, 0, idx));
|
||||
}
|
||||
|
||||
// Jump forward.
|
||||
s = slice(s, idx + 1, std::string_view::npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (keepEmpty || !s.empty()) {
|
||||
arr.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned GetAutoSenseRadix(std::string_view& str) noexcept {
|
||||
if (str.empty()) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0x") || wpi::starts_with(str, "0X")) {
|
||||
str.remove_prefix(2);
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0b") || wpi::starts_with(str, "0B")) {
|
||||
str.remove_prefix(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0o")) {
|
||||
str.remove_prefix(2);
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (str[0] == '0' && str.size() > 1 && wpi::isDigit(str[1])) {
|
||||
str.remove_prefix(1);
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool wpi::detail::ConsumeUnsignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
// Autosense radix if not specified.
|
||||
if (radix == 0) {
|
||||
radix = GetAutoSenseRadix(str);
|
||||
}
|
||||
|
||||
// Empty strings (after the radix autosense) are invalid.
|
||||
if (str.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse all the bytes of the string given this radix. Watch for overflow.
|
||||
std::string_view str2 = str;
|
||||
result = 0;
|
||||
while (!str2.empty()) {
|
||||
unsigned charVal;
|
||||
if (str2[0] >= '0' && str2[0] <= '9') {
|
||||
charVal = str2[0] - '0';
|
||||
} else if (str2[0] >= 'a' && str2[0] <= 'z') {
|
||||
charVal = str2[0] - 'a' + 10;
|
||||
} else if (str2[0] >= 'A' && str2[0] <= 'Z') {
|
||||
charVal = str2[0] - 'A' + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// If the parsed value is larger than the integer radix, we cannot
|
||||
// consume any more characters.
|
||||
if (charVal >= radix) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add in this character.
|
||||
unsigned long long prevResult = result; // NOLINT(runtime/int)
|
||||
result = result * radix + charVal;
|
||||
|
||||
// Check for overflow by shifting back and seeing if bits were lost.
|
||||
if (result / radix < prevResult) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str2.remove_prefix(1);
|
||||
}
|
||||
|
||||
// We consider the operation a failure if no characters were consumed
|
||||
// successfully.
|
||||
if (str.size() == str2.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str = str2;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::detail::ConsumeSignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
unsigned long long ullVal; // NOLINT(runtime/int)
|
||||
|
||||
// Handle positive strings first.
|
||||
if (str.empty() || str.front() != '-') {
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str, radix, ullVal) ||
|
||||
// Check for value so large it overflows a signed value.
|
||||
static_cast<long long>(ullVal) < 0) { // NOLINT(runtime/int)
|
||||
return true;
|
||||
}
|
||||
result = ullVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the positive part of the value.
|
||||
std::string_view str2 = wpi::drop_front(str, 1);
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str2, radix, ullVal) ||
|
||||
// Reject values so large they'd overflow as negative signed, but allow
|
||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||
// on signed overflow.
|
||||
static_cast<long long>(-ullVal) > 0) { // NOLINT(runtime/int)
|
||||
return true;
|
||||
}
|
||||
|
||||
str = str2;
|
||||
result = -ullVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsUnsignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str, radix, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For getAsUnsignedInteger, we require the whole string to be consumed or
|
||||
// else we consider it a failure.
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsSignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
if (wpi::detail::ConsumeSignedInteger(str, radix, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For getAsSignedInteger, we require the whole string to be consumed or else
|
||||
// we consider it a failure.
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<float> wpi::parse_float<float>(std::string_view str) noexcept {
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wpi::SmallString<32> storage{str};
|
||||
char* end;
|
||||
float val = std::strtof(storage.c_str(), &end);
|
||||
if (*end != '\0') {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<double> wpi::parse_float<double>(std::string_view str) noexcept {
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wpi::SmallString<32> storage{str};
|
||||
char* end;
|
||||
double val = std::strtod(storage.c_str(), &end);
|
||||
if (*end != '\0') {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<long double> wpi::parse_float<long double>(
|
||||
std::string_view str) noexcept {
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wpi::SmallString<32> storage{str};
|
||||
char* end;
|
||||
long double val = std::strtold(storage.c_str(), &end);
|
||||
if (*end != '\0') {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
261
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
vendored
Normal file
261
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
//===--- StringMap.cpp - String Hash table map implementation -------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the StringMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringMap.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/DJB.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
/// Returns the number of buckets to allocate to ensure that the DenseMap can
|
||||
/// accommodate \p NumEntries without need to grow().
|
||||
static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
|
||||
// Ensure that "NumEntries * 4 < NumBuckets * 3"
|
||||
if (NumEntries == 0)
|
||||
return 0;
|
||||
// +1 is required because of the strict equality.
|
||||
// For example if NumEntries is 48, we need to return 401.
|
||||
return NextPowerOf2(NumEntries * 4 / 3 + 1);
|
||||
}
|
||||
|
||||
StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
|
||||
ItemSize = itemSize;
|
||||
|
||||
// If a size is specified, initialize the table with that many buckets.
|
||||
if (InitSize) {
|
||||
// The table will grow when the number of entries reach 3/4 of the number of
|
||||
// buckets. To guarantee that "InitSize" number of entries can be inserted
|
||||
// in the table without growing, we allocate just what is needed here.
|
||||
init(getMinBucketToReserveForEntries(InitSize));
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, initialize it with zero buckets to avoid the allocation.
|
||||
TheTable = nullptr;
|
||||
NumBuckets = 0;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
void StringMapImpl::init(unsigned InitSize) {
|
||||
assert((InitSize & (InitSize - 1)) == 0 &&
|
||||
"Init Size must be a power of 2 or zero!");
|
||||
|
||||
unsigned NewNumBuckets = InitSize ? InitSize : 16;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
|
||||
TheTable = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
|
||||
|
||||
// Set the member only if TheTable was successfully allocated
|
||||
NumBuckets = NewNumBuckets;
|
||||
|
||||
// Allocate one extra bucket, set it to look filled so the iterators stop at
|
||||
// end.
|
||||
TheTable[NumBuckets] = (StringMapEntryBase *)2;
|
||||
}
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) { // Hash table unallocated so far?
|
||||
init(16);
|
||||
HTSize = NumBuckets;
|
||||
}
|
||||
unsigned FullHashValue = djbHash(Name, 0);
|
||||
unsigned BucketNo = FullHashValue & (HTSize - 1);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
int FirstTombstone = -1;
|
||||
while (true) {
|
||||
StringMapEntryBase *BucketItem = TheTable[BucketNo];
|
||||
// If we found an empty bucket, this key isn't in the table yet, return it.
|
||||
if (LLVM_LIKELY(!BucketItem)) {
|
||||
// If we found a tombstone, we want to reuse the tombstone instead of an
|
||||
// empty bucket. This reduces probing.
|
||||
if (FirstTombstone != -1) {
|
||||
HashTable[FirstTombstone] = FullHashValue;
|
||||
return FirstTombstone;
|
||||
}
|
||||
|
||||
HashTable[BucketNo] = FullHashValue;
|
||||
return BucketNo;
|
||||
}
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Skip over tombstones. However, remember the first one we see.
|
||||
if (FirstTombstone == -1)
|
||||
FirstTombstone = BucketNo;
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
// being non-null and for the full hash value) not at the items. This
|
||||
// is important for cache locality.
|
||||
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
++ProbeAmt;
|
||||
}
|
||||
}
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0)
|
||||
return -1; // Really empty table?
|
||||
unsigned FullHashValue = djbHash(Key, 0);
|
||||
unsigned BucketNo = FullHashValue & (HTSize - 1);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
while (true) {
|
||||
StringMapEntryBase *BucketItem = TheTable[BucketNo];
|
||||
// If we found an empty bucket, this key isn't in the table yet, return.
|
||||
if (LLVM_LIKELY(!BucketItem))
|
||||
return -1;
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Ignore tombstones.
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
// being non-null and for the full hash value) not at the items. This
|
||||
// is important for cache locality.
|
||||
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
++ProbeAmt;
|
||||
}
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char *)V + ItemSize;
|
||||
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return nullptr;
|
||||
|
||||
StringMapEntryBase *Result = TheTable[Bucket];
|
||||
TheTable[Bucket] = getTombstoneVal();
|
||||
--NumItems;
|
||||
++NumTombstones;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// RehashTable - Grow the table, redistributing values into the buckets with
|
||||
/// the appropriate mod-of-hashtable-size.
|
||||
unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
unsigned NewSize;
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
// If the hash table is now more than 3/4 full, or if fewer than 1/8 of
|
||||
// the buckets are empty (meaning that many are filled with tombstones),
|
||||
// grow/rehash the table.
|
||||
if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
|
||||
NewSize = NumBuckets * 2;
|
||||
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
|
||||
NumBuckets / 8)) {
|
||||
NewSize = NumBuckets;
|
||||
} else {
|
||||
return BucketNo;
|
||||
}
|
||||
|
||||
unsigned NewBucketNo = BucketNo;
|
||||
// Allocate one extra bucket which will always be non-empty. This allows the
|
||||
// iterators to stop at end.
|
||||
auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
|
||||
|
||||
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
|
||||
NewTableArray[NewSize] = (StringMapEntryBase *)2;
|
||||
|
||||
// Rehash all the items into their new buckets. Luckily :) we already have
|
||||
// the hash values available, so we don't have to rehash any strings.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
// Fast case, bucket available.
|
||||
unsigned FullHash = HashTable[I];
|
||||
unsigned NewBucket = FullHash & (NewSize - 1);
|
||||
if (!NewTableArray[NewBucket]) {
|
||||
NewTableArray[FullHash & (NewSize - 1)] = Bucket;
|
||||
NewHashArray[FullHash & (NewSize - 1)] = FullHash;
|
||||
if (I == BucketNo)
|
||||
NewBucketNo = NewBucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise probe for a spot.
|
||||
unsigned ProbeSize = 1;
|
||||
do {
|
||||
NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
|
||||
} while (NewTableArray[NewBucket]);
|
||||
|
||||
// Finally found a slot. Fill it in.
|
||||
NewTableArray[NewBucket] = Bucket;
|
||||
NewHashArray[NewBucket] = FullHash;
|
||||
if (I == BucketNo)
|
||||
NewBucketNo = NewBucket;
|
||||
}
|
||||
}
|
||||
|
||||
free(TheTable);
|
||||
|
||||
TheTable = NewTableArray;
|
||||
NumBuckets = NewSize;
|
||||
NumTombstones = 0;
|
||||
return NewBucketNo;
|
||||
}
|
||||
260
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
vendored
Normal file
260
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines things specific to Windows implementations. In addition to
|
||||
// providing some helpers for working with win32 APIs, this header wraps
|
||||
// <windows.h> with some portability macros. Always include WindowsSupport.h
|
||||
// instead of including <windows.h> directly.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only generic Win32 code that
|
||||
//=== is guaranteed to work on *all* Win32 variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_WINDOWSSUPPORT_H
|
||||
#define WPIUTIL_WPI_WINDOWSSUPPORT_H
|
||||
|
||||
// mingw-w64 tends to define it as 0x0502 in its headers.
|
||||
#undef _WIN32_WINNT
|
||||
#undef _WIN32_IE
|
||||
|
||||
// Require at least Windows 7 API.
|
||||
#define _WIN32_WINNT 0x0601
|
||||
#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Chrono.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/VersionTuple.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
#include <winternl.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
// Must be included after windows.h
|
||||
#include <wincrypt.h>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
|
||||
/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
|
||||
/// GetVersionEx is deprecated, but this API exposes the build number which can
|
||||
/// be useful for working around certain kernel bugs.
|
||||
inline wpi::VersionTuple GetWindowsOSVersion() {
|
||||
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
||||
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
|
||||
if (hMod) {
|
||||
auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
|
||||
if (getVer) {
|
||||
RTL_OSVERSIONINFOEXW info{};
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (getVer((PRTL_OSVERSIONINFOW)&info) == ((NTSTATUS)0x00000000L)) {
|
||||
return wpi::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0,
|
||||
info.dwBuildNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
return wpi::VersionTuple(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// Determines if the program is running on Windows 8 or newer. This
|
||||
/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
|
||||
/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't
|
||||
/// yet have VersionHelpers.h, so we have our own helper.
|
||||
inline bool RunningWindows8OrGreater() {
|
||||
// Windows 8 is version 6.2, service pack 0.
|
||||
return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
|
||||
}
|
||||
|
||||
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
|
||||
/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
|
||||
/// GetVersionEx is deprecated, but this API exposes the build number which can
|
||||
/// be useful for working around certain kernel bugs.
|
||||
wpi::VersionTuple GetWindowsOSVersion();
|
||||
|
||||
bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix);
|
||||
|
||||
// Include GetLastError() in a fatal error message.
|
||||
LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) {
|
||||
std::string ErrMsg;
|
||||
MakeErrMsg(&ErrMsg, Msg);
|
||||
wpi::report_fatal_error(ErrMsg);
|
||||
}
|
||||
|
||||
template <typename HandleTraits>
|
||||
class ScopedHandle {
|
||||
typedef typename HandleTraits::handle_type handle_type;
|
||||
handle_type Handle;
|
||||
|
||||
ScopedHandle(const ScopedHandle &other) = delete;
|
||||
void operator=(const ScopedHandle &other) = delete;
|
||||
public:
|
||||
ScopedHandle()
|
||||
: Handle(HandleTraits::GetInvalid()) {}
|
||||
|
||||
explicit ScopedHandle(handle_type h)
|
||||
: Handle(h) {}
|
||||
|
||||
~ScopedHandle() {
|
||||
if (HandleTraits::IsValid(Handle))
|
||||
HandleTraits::Close(Handle);
|
||||
}
|
||||
|
||||
handle_type take() {
|
||||
handle_type t = Handle;
|
||||
Handle = HandleTraits::GetInvalid();
|
||||
return t;
|
||||
}
|
||||
|
||||
ScopedHandle &operator=(handle_type h) {
|
||||
if (HandleTraits::IsValid(Handle))
|
||||
HandleTraits::Close(Handle);
|
||||
Handle = h;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// True if Handle is valid.
|
||||
explicit operator bool() const {
|
||||
return HandleTraits::IsValid(Handle) ? true : false;
|
||||
}
|
||||
|
||||
operator handle_type() const {
|
||||
return Handle;
|
||||
}
|
||||
};
|
||||
|
||||
struct CommonHandleTraits {
|
||||
typedef HANDLE handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::CloseHandle(h);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct JobHandleTraits : CommonHandleTraits {
|
||||
static handle_type GetInvalid() {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct CryptContextTraits : CommonHandleTraits {
|
||||
typedef HCRYPTPROV handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::CryptReleaseContext(h, 0);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct RegTraits : CommonHandleTraits {
|
||||
typedef HKEY handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::RegCloseKey(h);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct FindHandleTraits : CommonHandleTraits {
|
||||
static void Close(handle_type h) {
|
||||
::FindClose(h);
|
||||
}
|
||||
};
|
||||
|
||||
struct FileHandleTraits : CommonHandleTraits {};
|
||||
|
||||
typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
|
||||
typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
|
||||
typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
|
||||
typedef ScopedHandle<RegTraits> ScopedRegHandle;
|
||||
typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
|
||||
typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
|
||||
|
||||
template <class T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
template <class T>
|
||||
typename SmallVectorImpl<T>::const_pointer
|
||||
c_str(SmallVectorImpl<T> &str) {
|
||||
str.push_back(0);
|
||||
str.pop_back();
|
||||
return str.data();
|
||||
}
|
||||
|
||||
namespace sys {
|
||||
|
||||
inline std::chrono::nanoseconds toDuration(FILETIME Time) {
|
||||
ULARGE_INTEGER TimeInteger;
|
||||
TimeInteger.LowPart = Time.dwLowDateTime;
|
||||
TimeInteger.HighPart = Time.dwHighDateTime;
|
||||
|
||||
// FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
|
||||
return std::chrono::nanoseconds(100 * TimeInteger.QuadPart);
|
||||
}
|
||||
|
||||
inline TimePoint<> toTimePoint(FILETIME Time) {
|
||||
ULARGE_INTEGER TimeInteger;
|
||||
TimeInteger.LowPart = Time.dwLowDateTime;
|
||||
TimeInteger.HighPart = Time.dwHighDateTime;
|
||||
|
||||
// Adjust for different epoch
|
||||
TimeInteger.QuadPart -= 11644473600ll * 10000000;
|
||||
|
||||
// FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
|
||||
return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart));
|
||||
}
|
||||
|
||||
inline FILETIME toFILETIME(TimePoint<> TP) {
|
||||
ULARGE_INTEGER TimeInteger;
|
||||
TimeInteger.QuadPart = TP.time_since_epoch().count() / 100;
|
||||
TimeInteger.QuadPart += 11644473600ll * 10000000;
|
||||
|
||||
FILETIME Time;
|
||||
Time.dwLowDateTime = TimeInteger.LowPart;
|
||||
Time.dwHighDateTime = TimeInteger.HighPart;
|
||||
return Time;
|
||||
}
|
||||
|
||||
} // end namespace sys
|
||||
} // end namespace wpi.
|
||||
|
||||
#endif
|
||||
29
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
vendored
Normal file
29
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This implements support adapting raw_ostream to std::ostream.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/raw_os_ostream.h"
|
||||
#include <ostream>
|
||||
using namespace wpi;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_os_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_os_ostream::~raw_os_ostream() {
|
||||
flush();
|
||||
}
|
||||
|
||||
void raw_os_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.write(Ptr, Size);
|
||||
}
|
||||
|
||||
uint64_t raw_os_ostream::current_pos() const { return OS.tellp(); }
|
||||
737
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
vendored
Normal file
737
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
vendored
Normal file
@@ -0,0 +1,737 @@
|
||||
//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This implements support for bulk buffered stream output.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _CRT_NONSTDC_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/fs.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
|
||||
// <fcntl.h> may provide O_BINARY.
|
||||
# include <fcntl.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#ifndef STDIN_FILENO
|
||||
# define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
# define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
# define STDERR_FILENO 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "Windows/WindowsSupport.h"
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
constexpr raw_ostream::Colors raw_ostream::BLACK;
|
||||
constexpr raw_ostream::Colors raw_ostream::RED;
|
||||
constexpr raw_ostream::Colors raw_ostream::GREEN;
|
||||
constexpr raw_ostream::Colors raw_ostream::YELLOW;
|
||||
constexpr raw_ostream::Colors raw_ostream::BLUE;
|
||||
constexpr raw_ostream::Colors raw_ostream::MAGENTA;
|
||||
constexpr raw_ostream::Colors raw_ostream::CYAN;
|
||||
constexpr raw_ostream::Colors raw_ostream::WHITE;
|
||||
constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR;
|
||||
constexpr raw_ostream::Colors raw_ostream::RESET;
|
||||
|
||||
namespace {
|
||||
// Find the length of an array.
|
||||
template <class T, std::size_t N>
|
||||
constexpr inline size_t array_lengthof(T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
raw_ostream::~raw_ostream() {
|
||||
// raw_ostream's subclasses should take care to flush the buffer
|
||||
// in their destructors.
|
||||
assert(OutBufCur == OutBufStart &&
|
||||
"raw_ostream destructor called with non-empty buffer!");
|
||||
|
||||
if (BufferMode == BufferKind::InternalBuffer)
|
||||
delete [] OutBufStart;
|
||||
}
|
||||
|
||||
size_t raw_ostream::preferred_buffer_size() const {
|
||||
// BUFSIZ is intended to be a reasonable default.
|
||||
return BUFSIZ;
|
||||
}
|
||||
|
||||
void raw_ostream::SetBuffered() {
|
||||
// Ask the subclass to determine an appropriate buffer size.
|
||||
if (size_t Size = preferred_buffer_size())
|
||||
SetBufferSize(Size);
|
||||
else
|
||||
// It may return 0, meaning this stream should be unbuffered.
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
||||
BufferKind Mode) {
|
||||
assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) ||
|
||||
(Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) &&
|
||||
"stream must be unbuffered or have at least one byte");
|
||||
// Make sure the current buffer is free of content (we can't flush here; the
|
||||
// child buffer management logic will be in write_impl).
|
||||
assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
|
||||
|
||||
if (BufferMode == BufferKind::InternalBuffer)
|
||||
delete [] OutBufStart;
|
||||
OutBufStart = BufferStart;
|
||||
OutBufEnd = OutBufStart+Size;
|
||||
OutBufCur = OutBufStart;
|
||||
BufferMode = Mode;
|
||||
|
||||
assert(OutBufStart <= OutBufEnd && "Invalid size!");
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_escaped(std::string_view Str,
|
||||
bool UseHexEscapes) {
|
||||
for (unsigned char c : Str) {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
*this << '\\' << '\\';
|
||||
break;
|
||||
case '\t':
|
||||
*this << '\\' << 't';
|
||||
break;
|
||||
case '\n':
|
||||
*this << '\\' << 'n';
|
||||
break;
|
||||
case '"':
|
||||
*this << '\\' << '"';
|
||||
break;
|
||||
default:
|
||||
if (isPrint(c)) {
|
||||
*this << c;
|
||||
break;
|
||||
}
|
||||
|
||||
// Write out the escaped representation.
|
||||
if (UseHexEscapes) {
|
||||
*this << '\\' << 'x';
|
||||
*this << hexdigit((c >> 4 & 0xF));
|
||||
*this << hexdigit((c >> 0) & 0xF);
|
||||
} else {
|
||||
// Always use a full 3-character octal escape.
|
||||
*this << '\\';
|
||||
*this << char('0' + ((c >> 6) & 7));
|
||||
*this << char('0' + ((c >> 3) & 7));
|
||||
*this << char('0' + ((c >> 0) & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_nonempty() {
|
||||
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
||||
size_t Length = OutBufCur - OutBufStart;
|
||||
OutBufCur = OutBufStart;
|
||||
flush_tied_then_write(OutBufStart, Length);
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write(unsigned char C) {
|
||||
// Group exceptional cases into a single branch.
|
||||
if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
|
||||
if (LLVM_UNLIKELY(!OutBufStart)) {
|
||||
if (BufferMode == BufferKind::Unbuffered) {
|
||||
flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
|
||||
return *this;
|
||||
}
|
||||
// Set up a buffer and start over.
|
||||
SetBuffered();
|
||||
return write(C);
|
||||
}
|
||||
|
||||
flush_nonempty();
|
||||
}
|
||||
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
|
||||
// Group exceptional cases into a single branch.
|
||||
if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
|
||||
if (LLVM_UNLIKELY(!OutBufStart)) {
|
||||
if (BufferMode == BufferKind::Unbuffered) {
|
||||
flush_tied_then_write(Ptr, Size);
|
||||
return *this;
|
||||
}
|
||||
// Set up a buffer and start over.
|
||||
SetBuffered();
|
||||
return write(Ptr, Size);
|
||||
}
|
||||
|
||||
size_t NumBytes = OutBufEnd - OutBufCur;
|
||||
|
||||
// If the buffer is empty at this point we have a string that is larger
|
||||
// than the buffer. Directly write the chunk that is a multiple of the
|
||||
// preferred buffer size and put the remainder in the buffer.
|
||||
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
|
||||
assert(NumBytes != 0 && "undefined behavior");
|
||||
size_t BytesToWrite = Size - (Size % NumBytes);
|
||||
flush_tied_then_write(Ptr, BytesToWrite);
|
||||
size_t BytesRemaining = Size - BytesToWrite;
|
||||
if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
|
||||
// Too much left over to copy into our buffer.
|
||||
return write(Ptr + BytesToWrite, BytesRemaining);
|
||||
}
|
||||
copy_to_buffer(Ptr + BytesToWrite, BytesRemaining);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// We don't have enough space in the buffer to fit the string in. Insert as
|
||||
// much as possible, flush and start over with the remainder.
|
||||
copy_to_buffer(Ptr, NumBytes);
|
||||
flush_nonempty();
|
||||
return write(Ptr + NumBytes, Size - NumBytes);
|
||||
}
|
||||
|
||||
copy_to_buffer(Ptr, Size);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
||||
assert(Size <= size_t(OutBufEnd - OutBufCur) && "Buffer overrun!");
|
||||
|
||||
// Handle short strings specially, memcpy isn't very good at very short
|
||||
// strings.
|
||||
switch (Size) {
|
||||
case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH;
|
||||
case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH;
|
||||
case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH;
|
||||
case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH;
|
||||
case 0: break;
|
||||
default:
|
||||
memcpy(OutBufCur, Ptr, Size);
|
||||
break;
|
||||
}
|
||||
|
||||
OutBufCur += Size;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
|
||||
if (TiedStream)
|
||||
TiedStream->flush();
|
||||
write_impl(Ptr, Size);
|
||||
}
|
||||
|
||||
|
||||
template <char C>
|
||||
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
|
||||
static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
|
||||
|
||||
// Usually the indentation is small, handle it with a fastpath.
|
||||
if (NumChars < array_lengthof(Chars))
|
||||
return OS.write(Chars, NumChars);
|
||||
|
||||
while (NumChars) {
|
||||
unsigned NumToWrite = std::min(NumChars,
|
||||
(unsigned)array_lengthof(Chars)-1);
|
||||
OS.write(Chars, NumToWrite);
|
||||
NumChars -= NumToWrite;
|
||||
}
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
|
||||
return write_padding<' '>(*this, NumSpaces);
|
||||
}
|
||||
|
||||
/// write_zeros - Insert 'NumZeros' nulls.
|
||||
raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
|
||||
return write_padding<'\0'>(*this, NumZeros);
|
||||
}
|
||||
|
||||
void raw_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_fd_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static int getFD(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags) {
|
||||
assert((Access & fs::FA_Write) &&
|
||||
"Cannot make a raw_ostream from a read-only descriptor!");
|
||||
|
||||
// Handle "-" as stdout. Note that when we do this, we consider ourself
|
||||
// the owner of stdout and may set the "binary" flag globally based on Flags.
|
||||
if (Filename == "-") {
|
||||
EC = std::error_code();
|
||||
// Change stdout's text/binary mode based on the Flags.
|
||||
if (!(Flags & fs::OF_Text)) {
|
||||
#if defined(_WIN32)
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
}
|
||||
return STDOUT_FILENO;
|
||||
}
|
||||
|
||||
fs::file_t F;
|
||||
if (Access & fs::FA_Read)
|
||||
F = fs::OpenFileForReadWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
|
||||
else
|
||||
F = fs::OpenFileForWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
|
||||
if (EC)
|
||||
return -1;
|
||||
int FD = fs::FileToFd(F, EC, Flags);
|
||||
if (EC)
|
||||
return -1;
|
||||
|
||||
return FD;
|
||||
}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp)
|
||||
: raw_fd_ostream(Filename, EC, Disp, fs::FA_Write, fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, Access,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
Flags) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp,
|
||||
fs::FileAccess Access,
|
||||
fs::OpenFlags Flags)
|
||||
: raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
|
||||
|
||||
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
|
||||
/// closes the file when the stream is destroyed.
|
||||
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
|
||||
OStreamKind K)
|
||||
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
|
||||
if (FD < 0 ) {
|
||||
ShouldClose = false;
|
||||
return;
|
||||
}
|
||||
|
||||
enable_colors(true);
|
||||
|
||||
// Do not attempt to close stdout or stderr. We used to try to maintain the
|
||||
// property that tools that support writing file to stdout should not also
|
||||
// write informational output to stdout, but in practice we were never able to
|
||||
// maintain this invariant. Many features have been added to LLVM and clang
|
||||
// (-fdump-record-layouts, optimization remarks, etc) that print to stdout, so
|
||||
// users must simply be aware that mixed output and remarks is a possibility.
|
||||
if (FD <= STDERR_FILENO)
|
||||
ShouldClose = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Check if this is a console device. This is not equivalent to isatty.
|
||||
IsWindowsConsole =
|
||||
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
|
||||
#endif
|
||||
|
||||
// Get the starting position.
|
||||
off_t loc = ::lseek(FD, 0, SEEK_CUR);
|
||||
#ifdef _WIN32
|
||||
SupportsSeeking = loc != (off_t)-1 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(FD))) != FILE_TYPE_PIPE;
|
||||
#else
|
||||
SupportsSeeking = loc != (off_t)-1;
|
||||
#endif
|
||||
if (!SupportsSeeking)
|
||||
pos = 0;
|
||||
else
|
||||
pos = static_cast<uint64_t>(loc);
|
||||
}
|
||||
|
||||
raw_fd_ostream::~raw_fd_ostream() {
|
||||
if (FD >= 0) {
|
||||
flush();
|
||||
if (ShouldClose && ::close(FD) < 0)
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// On mingw, global dtors should not call exit().
|
||||
// report_fatal_error() invokes exit(). We know report_fatal_error()
|
||||
// might not write messages to stderr when any errors were detected
|
||||
// on FD == 2.
|
||||
if (FD == 2) return;
|
||||
#endif
|
||||
|
||||
// If there are any pending errors, report them now. Clients wishing
|
||||
// to avoid report_fatal_error calls should check for errors with
|
||||
// has_error() and clear the error flag with clear_error() before
|
||||
// destructing raw_ostream objects which may have errors.
|
||||
if (has_error())
|
||||
report_fatal_error("IO failure on output stream: " + error().message(),
|
||||
/*gen_crash_diag=*/false);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
// The most reliable way to print unicode in a Windows console is with
|
||||
// WriteConsoleW. To use that, first transcode from UTF-8 to UTF-16. This
|
||||
// assumes that LLVM programs always print valid UTF-8 to the console. The data
|
||||
// might not be UTF-8 for two major reasons:
|
||||
// 1. The program is printing binary (-filetype=obj -o -), in which case it
|
||||
// would have been gibberish anyway.
|
||||
// 2. The program is printing text in a semi-ascii compatible codepage like
|
||||
// shift-jis or cp1252.
|
||||
//
|
||||
// Most LLVM programs don't produce non-ascii text unless they are quoting
|
||||
// user source input. A well-behaved LLVM program should either validate that
|
||||
// the input is UTF-8 or transcode from the local codepage to UTF-8 before
|
||||
// quoting it. If they don't, this may mess up the encoding, but this is still
|
||||
// probably the best compromise we can make.
|
||||
static bool write_console_impl(int FD, std::string_view Data) {
|
||||
SmallVector<wchar_t, 256> WideText;
|
||||
|
||||
// Fall back to ::write if it wasn't valid UTF-8.
|
||||
if (auto EC = sys::windows::UTF8ToUTF16(Data, WideText))
|
||||
return false;
|
||||
|
||||
// On Windows 7 and earlier, WriteConsoleW has a low maximum amount of data
|
||||
// that can be written to the console at a time.
|
||||
size_t MaxWriteSize = WideText.size();
|
||||
if (!RunningWindows8OrGreater())
|
||||
MaxWriteSize = 32767;
|
||||
|
||||
size_t WCharsWritten = 0;
|
||||
do {
|
||||
size_t WCharsToWrite =
|
||||
std::min(MaxWriteSize, WideText.size() - WCharsWritten);
|
||||
DWORD ActuallyWritten;
|
||||
bool Success =
|
||||
::WriteConsoleW((HANDLE)::_get_osfhandle(FD), &WideText[WCharsWritten],
|
||||
WCharsToWrite, &ActuallyWritten,
|
||||
/*Reserved=*/nullptr);
|
||||
|
||||
// The most likely reason for WriteConsoleW to fail is that FD no longer
|
||||
// points to a console. Fall back to ::write. If this isn't the first loop
|
||||
// iteration, something is truly wrong.
|
||||
if (!Success)
|
||||
return false;
|
||||
|
||||
WCharsWritten += ActuallyWritten;
|
||||
} while (WCharsWritten != WideText.size());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
assert(FD >= 0 && "File already closed.");
|
||||
pos += Size;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
|
||||
// and using WriteConsoleW. If that fails, fall back to plain write().
|
||||
if (IsWindowsConsole)
|
||||
if (write_console_impl(FD, std::string_view(Ptr, Size)))
|
||||
return;
|
||||
#endif
|
||||
|
||||
// The maximum write size is limited to INT32_MAX. A write
|
||||
// greater than SSIZE_MAX is implementation-defined in POSIX,
|
||||
// and Windows _write requires 32 bit input.
|
||||
size_t MaxWriteSize = INT32_MAX;
|
||||
|
||||
#if defined(__linux__)
|
||||
// It is observed that Linux returns EINVAL for a very large write (>2G).
|
||||
// Make it a reasonably small value.
|
||||
MaxWriteSize = 1024 * 1024 * 1024;
|
||||
#endif
|
||||
|
||||
do {
|
||||
size_t ChunkSize = std::min(Size, MaxWriteSize);
|
||||
#ifdef _WIN32
|
||||
int ret = ::_write(FD, Ptr, ChunkSize);
|
||||
#else
|
||||
ssize_t ret = ::write(FD, Ptr, ChunkSize);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
// If it's a recoverable error, swallow it and retry the write.
|
||||
//
|
||||
// Ideally we wouldn't ever see EAGAIN or EWOULDBLOCK here, since
|
||||
// raw_ostream isn't designed to do non-blocking I/O. However, some
|
||||
// programs, such as old versions of bjam, have mistakenly used
|
||||
// O_NONBLOCK. For compatibility, emulate blocking semantics by
|
||||
// spinning until the write succeeds. If you don't want spinning,
|
||||
// don't use O_NONBLOCK file descriptors with raw_ostream.
|
||||
if (errno == EINTR || errno == EAGAIN
|
||||
#ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
// Otherwise it's a non-recoverable error. Note it and quit.
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
break;
|
||||
}
|
||||
|
||||
// The write may have written some or all of the data. Update the
|
||||
// size and buffer pointer to reflect the remainder that needs
|
||||
// to be written. If there are no bytes left, we're done.
|
||||
Ptr += ret;
|
||||
Size -= ret;
|
||||
} while (Size > 0);
|
||||
}
|
||||
|
||||
void raw_fd_ostream::close() {
|
||||
assert(ShouldClose);
|
||||
ShouldClose = false;
|
||||
flush();
|
||||
if (::close(FD) < 0)
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
FD = -1;
|
||||
}
|
||||
|
||||
uint64_t raw_fd_ostream::seek(uint64_t off) {
|
||||
assert(SupportsSeeking && "Stream does not support seeking!");
|
||||
flush();
|
||||
#ifdef _WIN32
|
||||
pos = ::_lseeki64(FD, off, SEEK_SET);
|
||||
#else
|
||||
pos = ::lseek(FD, off, SEEK_SET);
|
||||
#endif
|
||||
if (pos == (uint64_t)-1)
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
return pos;
|
||||
}
|
||||
|
||||
void raw_fd_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
uint64_t Pos = tell();
|
||||
seek(Offset);
|
||||
write(Ptr, Size);
|
||||
seek(Pos);
|
||||
}
|
||||
|
||||
size_t raw_fd_ostream::preferred_buffer_size() const {
|
||||
#if defined(_WIN32)
|
||||
// Disable buffering for console devices. Console output is re-encoded from
|
||||
// UTF-8 to UTF-16 on Windows, and buffering it would require us to split the
|
||||
// buffer on a valid UTF-8 codepoint boundary. Terminal buffering is disabled
|
||||
// below on most other OSs, so do the same thing on Windows and avoid that
|
||||
// complexity.
|
||||
if (IsWindowsConsole)
|
||||
return 0;
|
||||
return raw_ostream::preferred_buffer_size();
|
||||
#elif !defined(__minix)
|
||||
// Minix has no st_blksize.
|
||||
assert(FD >= 0 && "File not yet open!");
|
||||
struct stat statbuf;
|
||||
if (fstat(FD, &statbuf) != 0)
|
||||
return 0;
|
||||
|
||||
// If this is a terminal, don't use buffering. Line buffering
|
||||
// would be a more traditional thing to do, but it's not worth
|
||||
// the complexity.
|
||||
if (S_ISCHR(statbuf.st_mode) && is_displayed())
|
||||
return 0;
|
||||
// Return the preferred block size.
|
||||
return statbuf.st_blksize;
|
||||
#else
|
||||
return raw_ostream::preferred_buffer_size();
|
||||
#endif
|
||||
}
|
||||
|
||||
void raw_fd_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// outs(), errs(), nulls()
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_fd_ostream &wpi::outs() {
|
||||
// Set buffer settings to model stdout behavior.
|
||||
std::error_code EC;
|
||||
static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::OF_None);
|
||||
assert(!EC);
|
||||
return *S;
|
||||
}
|
||||
|
||||
raw_fd_ostream &wpi::errs() {
|
||||
// Set standard error to be unbuffered and tied to outs() by default.
|
||||
static raw_fd_ostream* S = new raw_fd_ostream(STDERR_FILENO, false, true);
|
||||
return *S;
|
||||
}
|
||||
|
||||
/// nulls() - This returns a reference to a raw_ostream which discards output.
|
||||
raw_ostream &wpi::nulls() {
|
||||
static raw_null_ostream S;
|
||||
return S;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_fd_stream::raw_fd_stream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(getFD(Filename, EC, fs::CD_CreateAlways,
|
||||
fs::FA_Write | fs::FA_Read,
|
||||
fs::OF_None),
|
||||
true, false, OStreamKind::OK_FDStream) {
|
||||
if (EC)
|
||||
return;
|
||||
|
||||
// Do not support non-seekable files.
|
||||
if (!supportsSeeking())
|
||||
EC = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
bool raw_fd_stream::classof(const raw_ostream *OS) {
|
||||
return OS->get_kind() == OStreamKind::OK_FDStream;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_string_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_string_ostream::~raw_string_ostream() {
|
||||
flush();
|
||||
}
|
||||
|
||||
void raw_string_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.append(Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_svector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_svector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_svector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.append(Ptr, Ptr + Size);
|
||||
}
|
||||
|
||||
void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_vector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_vector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_vector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.insert(OS.end(), Ptr, Ptr + Size);
|
||||
}
|
||||
|
||||
void raw_vector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_usvector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_usvector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_usvector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.append(reinterpret_cast<const uint8_t *>(Ptr),
|
||||
reinterpret_cast<const uint8_t *>(Ptr) + Size);
|
||||
}
|
||||
|
||||
void raw_usvector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_uvector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_uvector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_uvector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.insert(OS.end(), reinterpret_cast<const uint8_t *>(Ptr),
|
||||
reinterpret_cast<const uint8_t *>(Ptr) + Size);
|
||||
}
|
||||
|
||||
void raw_uvector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_null_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_null_ostream::~raw_null_ostream() {
|
||||
#ifndef NDEBUG
|
||||
// ~raw_ostream asserts that the buffer is empty. This isn't necessary
|
||||
// with raw_null_ostream, but it's better to have raw_null_ostream follow
|
||||
// the rules than to change the rules just for raw_null_ostream.
|
||||
flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
void raw_null_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
}
|
||||
|
||||
uint64_t raw_null_ostream::current_pos() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {}
|
||||
|
||||
void raw_pwrite_stream::anchor() {}
|
||||
|
||||
void buffer_ostream::anchor() {}
|
||||
|
||||
void buffer_unique_ostream::anchor() {}
|
||||
34
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h
vendored
Normal file
34
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the AlignedCharArrayUnion class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ALIGNOF_H
|
||||
#define WPIUTIL_WPI_ALIGNOF_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// A suitably aligned and sized character array member which can hold elements
|
||||
/// of any type.
|
||||
///
|
||||
/// This template is equivalent to std::aligned_union_t<1, ...>, but we cannot
|
||||
/// use it due to a bug in the MSVC x86 compiler:
|
||||
/// https://github.com/microsoft/STL/issues/1533
|
||||
/// Using `alignas` here works around the bug.
|
||||
template <typename T, typename... Ts> struct AlignedCharArrayUnion {
|
||||
using AlignedUnion = std::aligned_union_t<1, T, Ts...>;
|
||||
alignas(alignof(AlignedUnion)) char buffer[sizeof(AlignedUnion)];
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ALIGNOF_H
|
||||
103
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
vendored
Normal file
103
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
//===- AllocatorBase.h - Simple memory allocation abstraction ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This file defines MallocAllocator. MallocAllocator conforms to the LLVM
|
||||
/// "Allocator" concept which consists of an Allocate method accepting a size
|
||||
/// and alignment, and a Deallocate accepting a pointer and size. Further, the
|
||||
/// LLVM "Allocator" concept has overloads of Allocate and Deallocate for
|
||||
/// setting size and alignment based on the final type. These overloads are
|
||||
/// typically provided by a base class template \c AllocatorBase.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
#define WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// CRTP base class providing obvious overloads for the core \c
|
||||
/// Allocate() methods of LLVM-style allocators.
|
||||
///
|
||||
/// This base class both documents the full public interface exposed by all
|
||||
/// LLVM-style allocators, and redirects all of the overloads to a single core
|
||||
/// set of methods which the derived class must define.
|
||||
template <typename DerivedT> class AllocatorBase {
|
||||
public:
|
||||
/// Allocate \a Size bytes of \a Alignment aligned memory. This method
|
||||
/// must be implemented by \c DerivedT.
|
||||
void *Allocate(size_t Size, size_t Alignment) {
|
||||
#ifdef __clang__
|
||||
static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>(
|
||||
&AllocatorBase::Allocate) !=
|
||||
static_cast<void *(DerivedT::*)(size_t, size_t)>(
|
||||
&DerivedT::Allocate),
|
||||
"Class derives from AllocatorBase without implementing the "
|
||||
"core Allocate(size_t, size_t) overload!");
|
||||
#endif
|
||||
return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
|
||||
}
|
||||
|
||||
/// Deallocate \a Ptr to \a Size bytes of memory allocated by this
|
||||
/// allocator.
|
||||
void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
|
||||
#ifdef __clang__
|
||||
static_assert(
|
||||
static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>(
|
||||
&AllocatorBase::Deallocate) !=
|
||||
static_cast<void (DerivedT::*)(const void *, size_t, size_t)>(
|
||||
&DerivedT::Deallocate),
|
||||
"Class derives from AllocatorBase without implementing the "
|
||||
"core Deallocate(void *) overload!");
|
||||
#endif
|
||||
return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment);
|
||||
}
|
||||
|
||||
// The rest of these methods are helpers that redirect to one of the above
|
||||
// core methods.
|
||||
|
||||
/// Allocate space for a sequence of objects without constructing them.
|
||||
template <typename T> T *Allocate(size_t Num = 1) {
|
||||
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
/// Deallocate space for a sequence of objects without constructing them.
|
||||
template <typename T>
|
||||
std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void>
|
||||
Deallocate(T *Ptr, size_t Num = 1) {
|
||||
Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
|
||||
}
|
||||
};
|
||||
|
||||
class MallocAllocator : public AllocatorBase<MallocAllocator> {
|
||||
public:
|
||||
void Reset() {}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) {
|
||||
return allocate_buffer(Size, Alignment);
|
||||
}
|
||||
|
||||
// Pull in base class overloads.
|
||||
using AllocatorBase<MallocAllocator>::Allocate;
|
||||
|
||||
void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
|
||||
deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment);
|
||||
}
|
||||
|
||||
// Pull in base class overloads.
|
||||
using AllocatorBase<MallocAllocator>::Deallocate;
|
||||
|
||||
void PrintStats() const {}
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
62
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
vendored
Normal file
62
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_CHRONO_H
|
||||
#define WPIUTIL_WPI_CHRONO_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
namespace sys {
|
||||
|
||||
/// A time point on the system clock. This is provided for two reasons:
|
||||
/// - to insulate us against subtle differences in behavior to differences in
|
||||
/// system clock precision (which is implementation-defined and differs between
|
||||
/// platforms).
|
||||
/// - to shorten the type name
|
||||
/// The default precision is nanoseconds. If need a specific precision specify
|
||||
/// it explicitly. If unsure, use the default. If you need a time point on a
|
||||
/// clock other than the system_clock, use std::chrono directly.
|
||||
template <typename D = std::chrono::nanoseconds>
|
||||
using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
|
||||
|
||||
/// Convert a TimePoint to std::time_t
|
||||
inline std::time_t toTimeT(TimePoint<> TP) {
|
||||
using namespace std::chrono;
|
||||
return system_clock::to_time_t(
|
||||
time_point_cast<system_clock::time_point::duration>(TP));
|
||||
}
|
||||
|
||||
/// Convert a std::time_t to a TimePoint
|
||||
inline TimePoint<std::chrono::seconds>
|
||||
toTimePoint(std::time_t T) {
|
||||
using namespace std::chrono;
|
||||
return time_point_cast<seconds>(system_clock::from_time_t(T));
|
||||
}
|
||||
|
||||
/// Convert a std::time_t + nanoseconds to a TimePoint
|
||||
inline TimePoint<>
|
||||
toTimePoint(std::time_t T, uint32_t nsec) {
|
||||
using namespace std::chrono;
|
||||
return time_point_cast<nanoseconds>(system_clock::from_time_t(T))
|
||||
+ nanoseconds(nsec);
|
||||
}
|
||||
|
||||
} // namespace sys
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_CHRONO_H
|
||||
599
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
vendored
Normal file
599
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
vendored
Normal file
@@ -0,0 +1,599 @@
|
||||
//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines several macros, based on the current compiler. This allows
|
||||
// use of compiler-specific features in a way that remains portable. This header
|
||||
// can be included from either C or C++.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_COMPILER_H
|
||||
#define WPIUTIL_WPI_COMPILER_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_extension
|
||||
# define __has_extension(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
|
||||
// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
|
||||
#ifndef LLVM_HAS_CPP_ATTRIBUTE
|
||||
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
||||
# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
||||
#else
|
||||
# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_GNUC_PREREQ
|
||||
/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
|
||||
/// available.
|
||||
#ifndef LLVM_GNUC_PREREQ
|
||||
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
|
||||
((maj) << 20) + ((min) << 10) + (patch))
|
||||
# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
|
||||
# else
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_MSC_PREREQ
|
||||
/// Is the compiler MSVC of at least the specified version?
|
||||
/// The common \param version values to check for are:
|
||||
/// * 1910: VS2017, version 15.1 & 15.2
|
||||
/// * 1911: VS2017, version 15.3 & 15.4
|
||||
/// * 1912: VS2017, version 15.5
|
||||
/// * 1913: VS2017, version 15.6
|
||||
/// * 1914: VS2017, version 15.7
|
||||
/// * 1915: VS2017, version 15.8
|
||||
/// * 1916: VS2017, version 15.9
|
||||
/// * 1920: VS2019, version 16.0
|
||||
/// * 1921: VS2019, version 16.1
|
||||
#ifndef LLVM_MSC_PREREQ
|
||||
#ifdef _MSC_VER
|
||||
#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
|
||||
|
||||
// We require at least MSVC 2017.
|
||||
#if !LLVM_MSC_PREREQ(1910)
|
||||
#error LLVM requires at least MSVC 2017.
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define LLVM_MSC_PREREQ(version) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Does the compiler support ref-qualifiers for *this?
|
||||
///
|
||||
/// Sadly, this is separate from just rvalue reference support because GCC
|
||||
/// and MSVC implemented this later than everything else. This appears to be
|
||||
/// corrected in MSVC 2019 but not MSVC 2017.
|
||||
#ifndef LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \
|
||||
LLVM_MSC_PREREQ(1920)
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
|
||||
#else
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Expands to '&' if ref-qualifiers for *this are supported.
|
||||
///
|
||||
/// This can be used to provide lvalue/rvalue overrides of member functions.
|
||||
/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#ifndef LLVM_LVALUE_FUNCTION
|
||||
#if LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#define LLVM_LVALUE_FUNCTION &
|
||||
#else
|
||||
#define LLVM_LVALUE_FUNCTION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
|
||||
/// into a shared library, then the class should be private to the library and
|
||||
/// not accessible from outside it. Can also be used to mark variables and
|
||||
/// functions, making them private to any shared library they are linked into.
|
||||
/// On PE/COFF targets, library visibility is the default, so this isn't needed.
|
||||
///
|
||||
/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
|
||||
/// this attribute will be made public and visible outside of any shared library
|
||||
/// they are linked in to.
|
||||
#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
|
||||
!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
|
||||
#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
|
||||
#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define LLVM_LIBRARY_VISIBILITY
|
||||
#define LLVM_EXTERNAL_VISIBILITY
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_PREFETCH
|
||||
#if defined(__GNUC__)
|
||||
#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
|
||||
#else
|
||||
#define LLVM_PREFETCH(addr, rw, locality)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_USED
|
||||
#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
|
||||
#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_NODISCARD - Warn if a type or return value is discarded.
|
||||
|
||||
// Use the 'nodiscard' attribute in C++17 or newer mode.
|
||||
#ifndef LLVM_NODISCARD
|
||||
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
|
||||
#define LLVM_NODISCARD [[nodiscard]]
|
||||
#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
|
||||
#define LLVM_NODISCARD [[clang::warn_unused_result]]
|
||||
// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
|
||||
// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
|
||||
// Use the 'nodiscard' attribute in C++14 mode only with GCC.
|
||||
// TODO: remove this workaround when PR33518 is resolved.
|
||||
#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
|
||||
#define LLVM_NODISCARD [[nodiscard]]
|
||||
#else
|
||||
#define LLVM_NODISCARD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Indicate that a non-static, non-const C++ member function reinitializes
|
||||
// the entire object to a known state, independent of the previous state of
|
||||
// the object.
|
||||
//
|
||||
// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
|
||||
// marker that a moved-from object has left the indeterminate state and can be
|
||||
// reused.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
|
||||
#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_REINITIALIZES
|
||||
#endif
|
||||
|
||||
// Some compilers warn about unused functions. When a function is sometimes
|
||||
// used or not depending on build settings (e.g. a function only called from
|
||||
// within "assert"), this attribute can be used to suppress such warnings.
|
||||
//
|
||||
// However, it shouldn't be used for unused *variables*, as those have a much
|
||||
// more portable solution:
|
||||
// (void)unused_var_name;
|
||||
// Prefer cast-to-void wherever it is sufficient.
|
||||
#ifndef LLVM_ATTRIBUTE_UNUSED
|
||||
#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
|
||||
#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// FIXME: Provide this for PE/COFF targets.
|
||||
#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
|
||||
(!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32))
|
||||
#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_WEAK
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_READNONE
|
||||
// Prior to clang 3.2, clang did not accept any spelling of
|
||||
// __has_attribute(const), so assume it is supported.
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
// aka 'CONST' but following LLVM Conventions.
|
||||
#define LLVM_READNONE __attribute__((__const__))
|
||||
#else
|
||||
#define LLVM_READNONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_READONLY
|
||||
#if __has_attribute(pure) || defined(__GNUC__)
|
||||
// aka 'PURE' but following LLVM Conventions.
|
||||
#define LLVM_READONLY __attribute__((__pure__))
|
||||
#else
|
||||
#define LLVM_READONLY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_LIKELY
|
||||
#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
|
||||
#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
|
||||
#else
|
||||
#define LLVM_LIKELY(EXPR) (EXPR)
|
||||
#define LLVM_UNLIKELY(EXPR) (EXPR)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
|
||||
/// mark a method "not for inlining".
|
||||
#ifndef LLVM_ATTRIBUTE_NOINLINE
|
||||
#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
|
||||
#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
|
||||
/// so, mark a method "always inline" because it is performance sensitive. GCC
|
||||
/// 3.4 supported this but is buggy in various cases and produces unimplemented
|
||||
/// errors, just use it in GCC 4.0 and later.
|
||||
#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_NORETURN
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_NORETURN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
|
||||
/// pointer that does not alias any other valid pointer.
|
||||
#ifndef LLVM_ATTRIBUTE_RETURNS_NOALIAS
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
|
||||
#ifndef LLVM_FALLTHROUGH
|
||||
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[fallthrough]]
|
||||
#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
|
||||
#elif __has_attribute(fallthrough)
|
||||
#define LLVM_FALLTHROUGH __attribute__((fallthrough))
|
||||
#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
#define LLVM_FALLTHROUGH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
|
||||
/// they are constant initialized.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
||||
#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
|
||||
[[clang::require_constant_initialization]]
|
||||
#else
|
||||
#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
|
||||
#endif
|
||||
|
||||
/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
|
||||
/// lifetime warnings.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
|
||||
#define LLVM_GSL_OWNER [[gsl::Owner]]
|
||||
#else
|
||||
#define LLVM_GSL_OWNER
|
||||
#endif
|
||||
|
||||
/// LLVM_GSL_POINTER - Apply this to non-owning classes like
|
||||
/// std::string_view to enable lifetime warnings.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
|
||||
#define LLVM_GSL_POINTER [[gsl::Pointer]]
|
||||
#else
|
||||
#define LLVM_GSL_POINTER
|
||||
#endif
|
||||
|
||||
/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
|
||||
/// pedantic diagnostics.
|
||||
#ifndef LLVM_EXTENSION
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_EXTENSION __extension__
|
||||
#else
|
||||
#define LLVM_EXTENSION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
|
||||
// This macro will be removed.
|
||||
// Use C++14's attribute instead: [[deprecated("message")]]
|
||||
#ifndef LLVM_ATTRIBUTE_DEPRECATED
|
||||
#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
|
||||
/// to an expression which states that it is undefined behavior for the
|
||||
/// compiler to reach this point. Otherwise is not defined.
|
||||
#ifndef LLVM_BUILTIN_UNREACHABLE
|
||||
#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
|
||||
#elif defined(_MSC_VER)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __assume(false)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
|
||||
/// which causes the program to exit abnormally.
|
||||
#ifndef LLVM_BUILTIN_TRAP
|
||||
#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0)
|
||||
# define LLVM_BUILTIN_TRAP __builtin_trap()
|
||||
#elif defined(_MSC_VER)
|
||||
// The __debugbreak intrinsic is supported by MSVC, does not require forward
|
||||
// declarations involving platform-specific typedefs (unlike RaiseException),
|
||||
// results in a call to vectored exception handlers, and encodes to a short
|
||||
// instruction that still causes the trapping behavior we want.
|
||||
# define LLVM_BUILTIN_TRAP __debugbreak()
|
||||
#else
|
||||
# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
|
||||
/// an expression which causes the program to break while running
|
||||
/// under a debugger.
|
||||
#ifndef LLVM_BUILTIN_DEBUGTRAP
|
||||
#if __has_builtin(__builtin_debugtrap)
|
||||
# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
|
||||
#elif defined(_MSC_VER)
|
||||
// The __debugbreak intrinsic is supported by MSVC and breaks while
|
||||
// running under the debugger, and also supports invoking a debugger
|
||||
// when the OS is configured appropriately.
|
||||
# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
|
||||
#else
|
||||
// Just continue execution when built with compilers that have no
|
||||
// support. This is a debugging aid and not intended to force the
|
||||
// program to abort if encountered.
|
||||
# define LLVM_BUILTIN_DEBUGTRAP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ASSUME_ALIGNED
|
||||
/// Returns a pointer with an assumed alignment.
|
||||
#ifndef LLVM_ASSUME_ALIGNED
|
||||
#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
|
||||
#elif defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) \
|
||||
(((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
|
||||
#else
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) (p)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PACKED
|
||||
/// Used to specify a packed structure.
|
||||
/// LLVM_PACKED(
|
||||
/// struct A {
|
||||
/// int i;
|
||||
/// int j;
|
||||
/// int k;
|
||||
/// long long l;
|
||||
/// });
|
||||
///
|
||||
/// LLVM_PACKED_START
|
||||
/// struct B {
|
||||
/// int i;
|
||||
/// int j;
|
||||
/// int k;
|
||||
/// long long l;
|
||||
/// };
|
||||
/// LLVM_PACKED_END
|
||||
#ifndef LLVM_PACKED
|
||||
#ifdef _MSC_VER
|
||||
# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
|
||||
# define LLVM_PACKED_START __pragma(pack(push, 1))
|
||||
# define LLVM_PACKED_END __pragma(pack(pop))
|
||||
#else
|
||||
# define LLVM_PACKED(d) d __attribute__((packed))
|
||||
# define LLVM_PACKED_START _Pragma("pack(push, 1)")
|
||||
# define LLVM_PACKED_END _Pragma("pack(pop)")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PTR_SIZE
|
||||
/// A constant integer equivalent to the value of sizeof(void*).
|
||||
/// Generally used in combination with alignas or when doing computation in the
|
||||
/// preprocessor.
|
||||
#ifndef LLVM_PTR_SIZE
|
||||
#ifdef __SIZEOF_POINTER__
|
||||
# define LLVM_PTR_SIZE __SIZEOF_POINTER__
|
||||
#elif defined(_WIN64)
|
||||
# define LLVM_PTR_SIZE 8
|
||||
#elif defined(_WIN32)
|
||||
# define LLVM_PTR_SIZE 4
|
||||
#elif defined(_MSC_VER)
|
||||
# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
|
||||
#else
|
||||
# define LLVM_PTR_SIZE sizeof(void *)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_MEMORY_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with MemorySanitizer instrumentation.
|
||||
#if __has_feature(memory_sanitizer)
|
||||
# define LLVM_MEMORY_SANITIZER_BUILD 1
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
|
||||
#else
|
||||
# define LLVM_MEMORY_SANITIZER_BUILD 0
|
||||
# define __msan_allocated_memory(p, size)
|
||||
# define __msan_unpoison(p, size)
|
||||
# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ADDRESS_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with AddressSanitizer instrumentation.
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
# define LLVM_ADDRESS_SANITIZER_BUILD 1
|
||||
# include <sanitizer/asan_interface.h>
|
||||
#else
|
||||
# define LLVM_ADDRESS_SANITIZER_BUILD 0
|
||||
# define __asan_poison_memory_region(p, size)
|
||||
# define __asan_unpoison_memory_region(p, size)
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_THREAD_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
|
||||
#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
|
||||
# define LLVM_THREAD_SANITIZER_BUILD 1
|
||||
#else
|
||||
# define LLVM_THREAD_SANITIZER_BUILD 0
|
||||
#endif
|
||||
|
||||
#if LLVM_THREAD_SANITIZER_BUILD
|
||||
// Thread Sanitizer is a tool that finds races in code.
|
||||
// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
|
||||
// tsan detects these exact functions by name.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
|
||||
void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
|
||||
void AnnotateIgnoreWritesBegin(const char *file, int line);
|
||||
void AnnotateIgnoreWritesEnd(const char *file, int line);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// This marker is used to define a happens-before arc. The race detector will
|
||||
// infer an arc from the begin to the end when they share the same pointer
|
||||
// argument.
|
||||
# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
|
||||
|
||||
// This marker defines the destination of a happens-before arc.
|
||||
# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
|
||||
|
||||
// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
|
||||
# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
||||
|
||||
// Resume checking for racy writes.
|
||||
# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
||||
#else
|
||||
# define TsanHappensBefore(cv)
|
||||
# define TsanHappensAfter(cv)
|
||||
# define TsanIgnoreWritesBegin()
|
||||
# define TsanIgnoreWritesEnd()
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_NO_SANITIZE
|
||||
/// Disable a particular sanitizer for a function.
|
||||
#ifndef LLVM_NO_SANITIZE
|
||||
#if __has_attribute(no_sanitize)
|
||||
#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
|
||||
#else
|
||||
#define LLVM_NO_SANITIZE(KIND)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Mark debug helper function definitions like dump() that should not be
|
||||
/// stripped from debug builds.
|
||||
/// Note that you should also surround dump() functions with
|
||||
/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
|
||||
/// get stripped in release builds.
|
||||
// FIXME: Move this to a private config.h as it's not usable in public headers.
|
||||
#ifndef LLVM_DUMP_METHOD
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
|
||||
#else
|
||||
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PRETTY_FUNCTION
|
||||
/// Gets a user-friendly looking function signature for the current scope
|
||||
/// using the best available method on each platform. The exact format of the
|
||||
/// resulting string is implementation specific and non-portable, so this should
|
||||
/// only be used, for example, for logging or diagnostics.
|
||||
#ifndef LLVM_PRETTY_FUNCTION
|
||||
#if defined(_MSC_VER)
|
||||
#define LLVM_PRETTY_FUNCTION __FUNCSIG__
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define LLVM_PRETTY_FUNCTION __func__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_THREAD_LOCAL
|
||||
/// A thread-local storage specifier which can be used with globals,
|
||||
/// extern globals, and static globals.
|
||||
///
|
||||
/// This is essentially an extremely restricted analog to C++11's thread_local
|
||||
/// support. It uses thread_local if available, falling back on gcc __thread
|
||||
/// if not. __thread doesn't support many of the C++11 thread_local's
|
||||
/// features. You should only use this for PODs that you can statically
|
||||
/// initialize to some constant value. In almost all circumstances this is most
|
||||
/// appropriate for use with a pointer, integer, or small aggregation of
|
||||
/// pointers and integers.
|
||||
#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
|
||||
#define LLVM_THREAD_LOCAL thread_local
|
||||
#else
|
||||
// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
|
||||
// we only need the restricted functionality that provides.
|
||||
#define LLVM_THREAD_LOCAL __thread
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ENABLE_EXCEPTIONS
|
||||
/// Whether LLVM is built with exception support.
|
||||
#if __has_feature(cxx_exceptions)
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#elif defined(__GNUC__) && defined(__EXCEPTIONS)
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#elif defined(_MSC_VER) && defined(_CPPUNWIND)
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
307
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
vendored
Normal file
307
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
|
||||
*
|
||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://llvm.org/LICENSE.txt for license information.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*
|
||||
*==------------------------------------------------------------------------==*/
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
|
||||
Several funtions are included here, forming a complete set of
|
||||
conversions between the three formats. UTF-7 is not included
|
||||
here, but is handled in a separate source file.
|
||||
|
||||
Each of these routines takes pointers to input buffers and output
|
||||
buffers. The input buffers are const.
|
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd,
|
||||
putting the result into the buffer between *targetStart and
|
||||
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||
*(sourceEnd - 1) is the last item.
|
||||
|
||||
The return result indicates whether the conversion was successful,
|
||||
and if not, whether the problem was in the source or target buffers.
|
||||
(Only the first encountered problem is indicated.)
|
||||
|
||||
After the conversion, *sourceStart and *targetStart are both
|
||||
updated to point to the end of last text successfully converted in
|
||||
the respective buffers.
|
||||
|
||||
Input parameters:
|
||||
sourceStart - pointer to a pointer to the source buffer.
|
||||
The contents of this are modified on return so that
|
||||
it points at the next thing to be converted.
|
||||
targetStart - similarly, pointer to pointer to the target buffer.
|
||||
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||
two buffers, for overflow checking only.
|
||||
|
||||
These conversion functions take a ConversionFlags argument. When this
|
||||
flag is set to strict, both irregular sequences and isolated surrogates
|
||||
will cause an error. When the flag is set to lenient, both irregular
|
||||
sequences and isolated surrogates are converted.
|
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||
must check for illegal sequences.
|
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||
to the replacement character; otherwise (when the flag is set to strict)
|
||||
they constitute an error.
|
||||
|
||||
Output parameters:
|
||||
The value "sourceIllegal" is returned from some routines if the input
|
||||
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||
value will point to the illegal value that caused the problem. E.g.,
|
||||
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||
malformed sequence.
|
||||
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Fixes & updates, Sept 2001.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
#ifndef WPIUTIL_WPI_CONVERTUTF_H
|
||||
#define WPIUTIL_WPI_CONVERTUTF_H
|
||||
|
||||
#include "wpi/span.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
// Wrap everything in namespace wpi so that programs can link with llvm and
|
||||
// their own version of the unicode libraries.
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
16 bits, so wchar_t is no less portable than unsigned short!
|
||||
All should be unsigned values to avoid sign extension during
|
||||
bit mask & shift operations.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
typedef unsigned int UTF32; /* at least 32 bits */
|
||||
typedef unsigned short UTF16; /* at least 16 bits */
|
||||
typedef unsigned char UTF8; /* typically 8 bits */
|
||||
typedef bool Boolean; /* 0 or 1 */
|
||||
|
||||
/* Some fundamental constants */
|
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
|
||||
|
||||
#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4
|
||||
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
|
||||
|
||||
typedef enum {
|
||||
conversionOK, /* conversion successful */
|
||||
sourceExhausted, /* partial character in source, but hit end */
|
||||
targetExhausted, /* insuff. room in target for conversion */
|
||||
sourceIllegal /* source sequence is illegal/malformed */
|
||||
} ConversionResult;
|
||||
|
||||
typedef enum {
|
||||
strictConversion = 0,
|
||||
lenientConversion
|
||||
} ConversionFlags;
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
/**
|
||||
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
|
||||
* incomplete code unit sequence, returns \c sourceExhausted.
|
||||
*/
|
||||
ConversionResult ConvertUTF8toUTF32Partial(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
/**
|
||||
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
|
||||
* incomplete code unit sequence, returns \c sourceIllegal.
|
||||
*/
|
||||
ConversionResult ConvertUTF8toUTF32(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getNumBytesForUTF8(UTF8 firstByte);
|
||||
|
||||
/*************************************************************************/
|
||||
/* Below are LLVM-specific wrappers of the functions above. */
|
||||
|
||||
template <typename T> class SmallVectorImpl;
|
||||
|
||||
/**
|
||||
* Convert an UTF8 string_view to UTF8, UTF16, or UTF32 depending on
|
||||
* WideCharWidth. The converted data is written to ResultPtr, which needs to
|
||||
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
|
||||
* ResultPtr will point one after the end of the copied string. On failure,
|
||||
* ResultPtr will not be changed, and ErrorPtr will be set to the location of
|
||||
* the first character which could not be converted.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
|
||||
char *&ResultPtr, const UTF8 *&ErrorPtr);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string_view to a std::wstring.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 C-string to a std::wstring.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(const char *Source, std::wstring &Result);
|
||||
|
||||
/**
|
||||
* Converts a std::wstring to a UTF-8 encoded std::string.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result);
|
||||
|
||||
|
||||
/**
|
||||
* Convert an Unicode code point to UTF8 sequence.
|
||||
*
|
||||
* \param Source a Unicode code point.
|
||||
* \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
|
||||
* \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is
|
||||
* updated one past end of the converted sequence.
|
||||
*
|
||||
* \returns true on success.
|
||||
*/
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
|
||||
|
||||
/**
|
||||
* Convert the first UTF8 sequence in the given source buffer to a UTF32
|
||||
* code point.
|
||||
*
|
||||
* \param [in,out] source A pointer to the source buffer. If the conversion
|
||||
* succeeds, this pointer will be updated to point to the byte just past the
|
||||
* end of the converted sequence.
|
||||
* \param sourceEnd A pointer just past the end of the source buffer.
|
||||
* \param [out] target The converted code
|
||||
* \param flags Whether the conversion is strict or lenient.
|
||||
*
|
||||
* \returns conversionOK on success
|
||||
*
|
||||
* \sa ConvertUTF8toUTF32
|
||||
*/
|
||||
inline ConversionResult convertUTF8Sequence(const UTF8 **source,
|
||||
const UTF8 *sourceEnd,
|
||||
UTF32 *target,
|
||||
ConversionFlags flags) {
|
||||
if (*source == sourceEnd)
|
||||
return sourceExhausted;
|
||||
unsigned size = getNumBytesForUTF8(**source);
|
||||
if ((ptrdiff_t)size > sourceEnd - *source)
|
||||
return sourceExhausted;
|
||||
return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a blob of text starts with a UTF-16 big or little endian byte
|
||||
* order mark.
|
||||
*/
|
||||
bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
|
||||
|
||||
/**
|
||||
* Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
|
||||
*
|
||||
* \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
|
||||
* \param [out] Out Converted UTF-8 is stored here on success.
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out);
|
||||
|
||||
/**
|
||||
* Converts a UTF16 string into a UTF8 std::string.
|
||||
*
|
||||
* \param [in] Src A buffer of UTF-16 encoded text.
|
||||
* \param [out] Out Converted UTF-8 is stored here on success.
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string into a UTF-16 string with native endianness.
|
||||
*
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16);
|
||||
|
||||
#if defined(_WIN32)
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
/// Convert to UTF16 from the current code page used in the system
|
||||
std::error_code CurCPToUTF16(std::string_view utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
|
||||
SmallVectorImpl<char> &utf8);
|
||||
/// Convert from UTF16 to the current code page used in the system
|
||||
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
|
||||
SmallVectorImpl<char> &utf8);
|
||||
} // namespace windows
|
||||
} // namespace sys
|
||||
#endif
|
||||
|
||||
} /* end namespace wpi */
|
||||
|
||||
#endif
|
||||
29
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
vendored
Normal file
29
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for the DJ Bernstein hash function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_DJB_H
|
||||
#define WPIUTIL_WPI_DJB_H
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// The Bernstein hash function used by the DWARF accelerator tables.
|
||||
inline uint32_t djbHash(std::string_view Buffer, uint32_t H = 5381) {
|
||||
for (unsigned char C : Buffer)
|
||||
H = (H << 5) + H + C;
|
||||
return H;
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_DJB_H
|
||||
1308
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
vendored
Normal file
1308
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
294
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
vendored
Normal file
294
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines DenseMapInfo traits for DenseMap.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
#define WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
|
||||
#include "wpi/Hashing.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Simplistic combination of 32-bit hash values into 32-bit hash values.
|
||||
static inline unsigned combineHashValue(unsigned a, unsigned b) {
|
||||
uint64_t key = (uint64_t)a << 32 | (uint64_t)b;
|
||||
key += ~(key << 32);
|
||||
key ^= (key >> 22);
|
||||
key += ~(key << 13);
|
||||
key ^= (key >> 8);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 15);
|
||||
key += ~(key << 27);
|
||||
key ^= (key >> 31);
|
||||
return (unsigned)key;
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template<typename T>
|
||||
struct DenseMapInfo {
|
||||
//static inline T getEmptyKey();
|
||||
//static inline T getTombstoneKey();
|
||||
//static unsigned getHashValue(const T &Val);
|
||||
//static bool isEqual(const T &LHS, const T &RHS);
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values
|
||||
// that are aligned to alignof(T) bytes, but try to avoid requiring T to be
|
||||
// complete. This allows clients to instantiate DenseMap<T*, ...> with forward
|
||||
// declared key types. Assume that no pointer key type requires more than 4096
|
||||
// bytes of alignment.
|
||||
template<typename T>
|
||||
struct DenseMapInfo<T*> {
|
||||
// The following should hold, but it would require T to be complete:
|
||||
// static_assert(alignof(T) <= (1 << Log2MaxAlign),
|
||||
// "DenseMap does not support pointer keys requiring more than "
|
||||
// "Log2MaxAlign bits of alignment");
|
||||
static constexpr uintptr_t Log2MaxAlign = 12;
|
||||
|
||||
static inline T* getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= Log2MaxAlign;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
|
||||
static inline T* getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= Log2MaxAlign;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const T *PtrVal) {
|
||||
return (unsigned((uintptr_t)PtrVal) >> 4) ^
|
||||
(unsigned((uintptr_t)PtrVal) >> 9);
|
||||
}
|
||||
|
||||
static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for chars.
|
||||
template<> struct DenseMapInfo<char> {
|
||||
static inline char getEmptyKey() { return ~0; }
|
||||
static inline char getTombstoneKey() { return ~0 - 1; }
|
||||
static unsigned getHashValue(const char& Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const char &LHS, const char &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned chars.
|
||||
template <> struct DenseMapInfo<unsigned char> {
|
||||
static inline unsigned char getEmptyKey() { return ~0; }
|
||||
static inline unsigned char getTombstoneKey() { return ~0 - 1; }
|
||||
static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned shorts.
|
||||
template <> struct DenseMapInfo<unsigned short> {
|
||||
static inline unsigned short getEmptyKey() { return 0xFFFF; }
|
||||
static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
|
||||
static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned ints.
|
||||
template<> struct DenseMapInfo<unsigned> {
|
||||
static inline unsigned getEmptyKey() { return ~0U; }
|
||||
static inline unsigned getTombstoneKey() { return ~0U - 1; }
|
||||
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned longs.
|
||||
template<> struct DenseMapInfo<unsigned long> {
|
||||
static inline unsigned long getEmptyKey() { return ~0UL; }
|
||||
static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
|
||||
|
||||
static unsigned getHashValue(const unsigned long& Val) {
|
||||
return (unsigned)(Val * 37UL);
|
||||
}
|
||||
|
||||
static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned long longs.
|
||||
template<> struct DenseMapInfo<unsigned long long> {
|
||||
static inline unsigned long long getEmptyKey() { return ~0ULL; }
|
||||
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
|
||||
|
||||
static unsigned getHashValue(const unsigned long long& Val) {
|
||||
return (unsigned)(Val * 37ULL);
|
||||
}
|
||||
|
||||
static bool isEqual(const unsigned long long& LHS,
|
||||
const unsigned long long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for shorts.
|
||||
template <> struct DenseMapInfo<short> {
|
||||
static inline short getEmptyKey() { return 0x7FFF; }
|
||||
static inline short getTombstoneKey() { return -0x7FFF - 1; }
|
||||
static unsigned getHashValue(const short &Val) { return Val * 37U; }
|
||||
static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for ints.
|
||||
template<> struct DenseMapInfo<int> {
|
||||
static inline int getEmptyKey() { return 0x7fffffff; }
|
||||
static inline int getTombstoneKey() { return -0x7fffffff - 1; }
|
||||
static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
|
||||
|
||||
static bool isEqual(const int& LHS, const int& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for longs.
|
||||
template<> struct DenseMapInfo<long> {
|
||||
static inline long getEmptyKey() {
|
||||
return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
|
||||
}
|
||||
|
||||
static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
|
||||
|
||||
static unsigned getHashValue(const long& Val) {
|
||||
return (unsigned)(Val * 37UL);
|
||||
}
|
||||
|
||||
static bool isEqual(const long& LHS, const long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for long longs.
|
||||
template<> struct DenseMapInfo<long long> {
|
||||
static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
|
||||
static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
|
||||
|
||||
static unsigned getHashValue(const long long& Val) {
|
||||
return (unsigned)(Val * 37ULL);
|
||||
}
|
||||
|
||||
static bool isEqual(const long long& LHS,
|
||||
const long long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pairs whose members have info.
|
||||
template<typename T, typename U>
|
||||
struct DenseMapInfo<std::pair<T, U>> {
|
||||
using Pair = std::pair<T, U>;
|
||||
using FirstInfo = DenseMapInfo<T>;
|
||||
using SecondInfo = DenseMapInfo<U>;
|
||||
|
||||
static inline Pair getEmptyKey() {
|
||||
return std::make_pair(FirstInfo::getEmptyKey(),
|
||||
SecondInfo::getEmptyKey());
|
||||
}
|
||||
|
||||
static inline Pair getTombstoneKey() {
|
||||
return std::make_pair(FirstInfo::getTombstoneKey(),
|
||||
SecondInfo::getTombstoneKey());
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const Pair& PairVal) {
|
||||
return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first),
|
||||
SecondInfo::getHashValue(PairVal.second));
|
||||
}
|
||||
|
||||
static bool isEqual(const Pair &LHS, const Pair &RHS) {
|
||||
return FirstInfo::isEqual(LHS.first, RHS.first) &&
|
||||
SecondInfo::isEqual(LHS.second, RHS.second);
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all tuples whose members have info.
|
||||
template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
|
||||
using Tuple = std::tuple<Ts...>;
|
||||
|
||||
static inline Tuple getEmptyKey() {
|
||||
return Tuple(DenseMapInfo<Ts>::getEmptyKey()...);
|
||||
}
|
||||
|
||||
static inline Tuple getTombstoneKey() {
|
||||
return Tuple(DenseMapInfo<Ts>::getTombstoneKey()...);
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static unsigned getHashValueImpl(const Tuple &values, std::false_type) {
|
||||
using EltType = typename std::tuple_element<I, Tuple>::type;
|
||||
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
|
||||
return detail::combineHashValue(
|
||||
DenseMapInfo<EltType>::getHashValue(std::get<I>(values)),
|
||||
getHashValueImpl<I + 1>(values, atEnd));
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static unsigned getHashValueImpl(const Tuple &, std::true_type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const std::tuple<Ts...> &values) {
|
||||
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
|
||||
return getHashValueImpl<0>(values, atEnd);
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::false_type) {
|
||||
using EltType = typename std::tuple_element<I, Tuple>::type;
|
||||
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
|
||||
return DenseMapInfo<EltType>::isEqual(std::get<I>(lhs), std::get<I>(rhs)) &&
|
||||
isEqualImpl<I + 1>(lhs, rhs, atEnd);
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static bool isEqualImpl(const Tuple &, const Tuple &, std::true_type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isEqual(const Tuple &lhs, const Tuple &rhs) {
|
||||
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
|
||||
return isEqualImpl<0>(lhs, rhs, atEnd);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<hash_code> {
|
||||
static inline hash_code getEmptyKey() { return hash_code(-1); }
|
||||
static inline hash_code getTombstoneKey() { return hash_code(-2); }
|
||||
static unsigned getHashValue(hash_code val) { return static_cast<unsigned>(val); }
|
||||
static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
429
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
vendored
Normal file
429
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
vendored
Normal file
@@ -0,0 +1,429 @@
|
||||
//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares generic functions to read and write endian specific data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ENDIAN_H
|
||||
#define WPIUTIL_WPI_ENDIAN_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
namespace support {
|
||||
|
||||
enum endianness {big, little, native};
|
||||
|
||||
// These are named values for common alignments.
|
||||
enum {aligned = 0, unaligned = 1};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// ::value is either alignment, or alignof(T) if alignment is 0.
|
||||
template<class T, int alignment>
|
||||
struct PickAlignment {
|
||||
enum { value = alignment == 0 ? alignof(T) : alignment };
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
namespace endian {
|
||||
|
||||
constexpr endianness system_endianness() {
|
||||
return sys::IsBigEndianHost ? big : little;
|
||||
}
|
||||
|
||||
template <typename value_type>
|
||||
inline value_type byte_swap(value_type value, endianness endian) {
|
||||
if ((endian != native) && (endian != system_endianness()))
|
||||
sys::swapByteOrder(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Swap the bytes of value to match the given endianness.
|
||||
template<typename value_type, endianness endian>
|
||||
inline value_type byte_swap(value_type value) {
|
||||
if constexpr ((endian != native) && (endian != system_endianness()))
|
||||
sys::swapByteOrder(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Read a value of a particular endianness from memory.
|
||||
template <typename value_type, std::size_t alignment>
|
||||
inline value_type read(const void *memory, endianness endian) {
|
||||
value_type ret;
|
||||
|
||||
memcpy(&ret,
|
||||
LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
sizeof(value_type));
|
||||
return byte_swap<value_type>(ret, endian);
|
||||
}
|
||||
|
||||
template<typename value_type,
|
||||
endianness endian,
|
||||
std::size_t alignment>
|
||||
inline value_type read(const void *memory) {
|
||||
return read<value_type, alignment>(memory, endian);
|
||||
}
|
||||
|
||||
/// Read a value of a particular endianness from a buffer, and increment the
|
||||
/// buffer past that value.
|
||||
template <typename value_type, std::size_t alignment, typename CharT>
|
||||
inline value_type readNext(const CharT *&memory, endianness endian) {
|
||||
value_type ret = read<value_type, alignment>(memory, endian);
|
||||
memory += sizeof(value_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename value_type, endianness endian, std::size_t alignment,
|
||||
typename CharT>
|
||||
inline value_type readNext(const CharT *&memory) {
|
||||
return readNext<value_type, alignment, CharT>(memory, endian);
|
||||
}
|
||||
|
||||
/// Write a value to memory with a particular endianness.
|
||||
template <typename value_type, std::size_t alignment>
|
||||
inline void write(void *memory, value_type value, endianness endian) {
|
||||
value = byte_swap<value_type>(value, endian);
|
||||
memcpy(LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
&value, sizeof(value_type));
|
||||
}
|
||||
|
||||
template<typename value_type,
|
||||
endianness endian,
|
||||
std::size_t alignment>
|
||||
inline void write(void *memory, value_type value) {
|
||||
write<value_type, alignment>(memory, value, endian);
|
||||
}
|
||||
|
||||
template <typename value_type>
|
||||
using make_unsigned_t = std::make_unsigned_t<value_type>;
|
||||
|
||||
/// Read a value of a particular endianness from memory, for a location
|
||||
/// that starts at the given bit offset within the first byte.
|
||||
template <typename value_type, endianness endian, std::size_t alignment>
|
||||
inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
|
||||
assert(startBit < 8);
|
||||
if (startBit == 0)
|
||||
return read<value_type, endian, alignment>(memory);
|
||||
else {
|
||||
// Read two values and compose the result from them.
|
||||
value_type val[2];
|
||||
memcpy(&val[0],
|
||||
LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
sizeof(value_type) * 2);
|
||||
val[0] = byte_swap<value_type, endian>(val[0]);
|
||||
val[1] = byte_swap<value_type, endian>(val[1]);
|
||||
|
||||
// Shift bits from the lower value into place.
|
||||
make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
|
||||
// Mask off upper bits after right shift in case of signed type.
|
||||
make_unsigned_t<value_type> numBitsFirstVal =
|
||||
(sizeof(value_type) * 8) - startBit;
|
||||
lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
|
||||
|
||||
// Get the bits from the upper value.
|
||||
make_unsigned_t<value_type> upperVal =
|
||||
val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
|
||||
// Shift them in to place.
|
||||
upperVal <<= numBitsFirstVal;
|
||||
|
||||
return lowerVal | upperVal;
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a value to memory with a particular endianness, for a location
|
||||
/// that starts at the given bit offset within the first byte.
|
||||
template <typename value_type, endianness endian, std::size_t alignment>
|
||||
inline void writeAtBitAlignment(void *memory, value_type value,
|
||||
uint64_t startBit) {
|
||||
assert(startBit < 8);
|
||||
if (startBit == 0)
|
||||
write<value_type, endian, alignment>(memory, value);
|
||||
else {
|
||||
// Read two values and shift the result into them.
|
||||
value_type val[2];
|
||||
memcpy(&val[0],
|
||||
LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
sizeof(value_type) * 2);
|
||||
val[0] = byte_swap<value_type, endian>(val[0]);
|
||||
val[1] = byte_swap<value_type, endian>(val[1]);
|
||||
|
||||
// Mask off any existing bits in the upper part of the lower value that
|
||||
// we want to replace.
|
||||
val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
|
||||
make_unsigned_t<value_type> numBitsFirstVal =
|
||||
(sizeof(value_type) * 8) - startBit;
|
||||
make_unsigned_t<value_type> lowerVal = value;
|
||||
if (startBit > 0) {
|
||||
// Mask off the upper bits in the new value that are not going to go into
|
||||
// the lower value. This avoids a left shift of a negative value, which
|
||||
// is undefined behavior.
|
||||
lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
|
||||
// Now shift the new bits into place
|
||||
lowerVal <<= startBit;
|
||||
}
|
||||
val[0] |= lowerVal;
|
||||
|
||||
// Mask off any existing bits in the lower part of the upper value that
|
||||
// we want to replace.
|
||||
val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
|
||||
// Next shift the bits that go into the upper value into position.
|
||||
make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
|
||||
// Mask off upper bits after right shift in case of signed type.
|
||||
upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
|
||||
val[1] |= upperVal;
|
||||
|
||||
// Finally, rewrite values.
|
||||
val[0] = byte_swap<value_type, endian>(val[0]);
|
||||
val[1] = byte_swap<value_type, endian>(val[1]);
|
||||
memcpy(LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
&val[0], sizeof(value_type) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace endian
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename ValueType, endianness Endian, std::size_t Alignment,
|
||||
std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
|
||||
struct packed_endian_specific_integral {
|
||||
using value_type = ValueType;
|
||||
static constexpr endianness endian = Endian;
|
||||
static constexpr std::size_t alignment = Alignment;
|
||||
|
||||
packed_endian_specific_integral() = default;
|
||||
|
||||
explicit packed_endian_specific_integral(value_type val) { *this = val; }
|
||||
|
||||
operator value_type() const {
|
||||
return endian::read<value_type, endian, alignment>(
|
||||
(const void*)Value.buffer);
|
||||
}
|
||||
|
||||
void operator=(value_type newValue) {
|
||||
endian::write<value_type, endian, alignment>(
|
||||
(void*)Value.buffer, newValue);
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator+=(value_type newValue) {
|
||||
*this = *this + newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator-=(value_type newValue) {
|
||||
*this = *this - newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator|=(value_type newValue) {
|
||||
*this = *this | newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator&=(value_type newValue) {
|
||||
*this = *this & newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
struct {
|
||||
alignas(ALIGN) char buffer[sizeof(value_type)];
|
||||
} Value;
|
||||
|
||||
public:
|
||||
struct ref {
|
||||
explicit ref(void *Ptr) : Ptr(Ptr) {}
|
||||
|
||||
operator value_type() const {
|
||||
return endian::read<value_type, endian, alignment>(Ptr);
|
||||
}
|
||||
|
||||
void operator=(value_type NewValue) {
|
||||
endian::write<value_type, endian, alignment>(Ptr, NewValue);
|
||||
}
|
||||
|
||||
private:
|
||||
void *Ptr;
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
using ulittle16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
|
||||
using ulittle32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
|
||||
using ulittle64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
|
||||
|
||||
using little16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, little, unaligned>;
|
||||
using little32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, little, unaligned>;
|
||||
using little64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, little, unaligned>;
|
||||
|
||||
using aligned_ulittle16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, little, aligned>;
|
||||
using aligned_ulittle32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, little, aligned>;
|
||||
using aligned_ulittle64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, little, aligned>;
|
||||
|
||||
using aligned_little16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, little, aligned>;
|
||||
using aligned_little32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, little, aligned>;
|
||||
using aligned_little64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, little, aligned>;
|
||||
|
||||
using ubig16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
|
||||
using ubig32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
|
||||
using ubig64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
|
||||
|
||||
using big16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, big, unaligned>;
|
||||
using big32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, big, unaligned>;
|
||||
using big64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, big, unaligned>;
|
||||
|
||||
using aligned_ubig16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, big, aligned>;
|
||||
using aligned_ubig32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, big, aligned>;
|
||||
using aligned_ubig64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, big, aligned>;
|
||||
|
||||
using aligned_big16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, big, aligned>;
|
||||
using aligned_big32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, big, aligned>;
|
||||
using aligned_big64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, big, aligned>;
|
||||
|
||||
using unaligned_uint16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
|
||||
using unaligned_uint32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
|
||||
using unaligned_uint64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
|
||||
|
||||
using unaligned_int16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, native, unaligned>;
|
||||
using unaligned_int32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, native, unaligned>;
|
||||
using unaligned_int64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, native, unaligned>;
|
||||
|
||||
template <typename T>
|
||||
using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
|
||||
template <typename T>
|
||||
using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
|
||||
|
||||
template <typename T>
|
||||
using aligned_little_t =
|
||||
detail::packed_endian_specific_integral<T, little, aligned>;
|
||||
template <typename T>
|
||||
using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
|
||||
|
||||
namespace endian {
|
||||
|
||||
template <typename T> inline T read(const void *P, endianness E) {
|
||||
return read<T, unaligned>(P, E);
|
||||
}
|
||||
|
||||
template <typename T, endianness E> inline T read(const void *P) {
|
||||
return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
|
||||
}
|
||||
|
||||
inline uint16_t read16(const void *P, endianness E) {
|
||||
return read<uint16_t>(P, E);
|
||||
}
|
||||
inline uint32_t read32(const void *P, endianness E) {
|
||||
return read<uint32_t>(P, E);
|
||||
}
|
||||
inline uint64_t read64(const void *P, endianness E) {
|
||||
return read<uint64_t>(P, E);
|
||||
}
|
||||
|
||||
template <endianness E> inline uint16_t read16(const void *P) {
|
||||
return read<uint16_t, E>(P);
|
||||
}
|
||||
template <endianness E> inline uint32_t read32(const void *P) {
|
||||
return read<uint32_t, E>(P);
|
||||
}
|
||||
template <endianness E> inline uint64_t read64(const void *P) {
|
||||
return read<uint64_t, E>(P);
|
||||
}
|
||||
|
||||
inline uint16_t read16le(const void *P) { return read16<little>(P); }
|
||||
inline uint32_t read32le(const void *P) { return read32<little>(P); }
|
||||
inline uint64_t read64le(const void *P) { return read64<little>(P); }
|
||||
inline uint16_t read16be(const void *P) { return read16<big>(P); }
|
||||
inline uint32_t read32be(const void *P) { return read32<big>(P); }
|
||||
inline uint64_t read64be(const void *P) { return read64<big>(P); }
|
||||
|
||||
template <typename T> inline void write(void *P, T V, endianness E) {
|
||||
write<T, unaligned>(P, V, E);
|
||||
}
|
||||
|
||||
template <typename T, endianness E> inline void write(void *P, T V) {
|
||||
*(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
|
||||
}
|
||||
|
||||
inline void write16(void *P, uint16_t V, endianness E) {
|
||||
write<uint16_t>(P, V, E);
|
||||
}
|
||||
inline void write32(void *P, uint32_t V, endianness E) {
|
||||
write<uint32_t>(P, V, E);
|
||||
}
|
||||
inline void write64(void *P, uint64_t V, endianness E) {
|
||||
write<uint64_t>(P, V, E);
|
||||
}
|
||||
|
||||
template <endianness E> inline void write16(void *P, uint16_t V) {
|
||||
write<uint16_t, E>(P, V);
|
||||
}
|
||||
template <endianness E> inline void write32(void *P, uint32_t V) {
|
||||
write<uint32_t, E>(P, V);
|
||||
}
|
||||
template <endianness E> inline void write64(void *P, uint64_t V) {
|
||||
write<uint64_t, E>(P, V);
|
||||
}
|
||||
|
||||
inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
|
||||
inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
|
||||
inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
|
||||
inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
|
||||
inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
|
||||
inline void write64be(void *P, uint64_t V) { write64<big>(P, V); }
|
||||
|
||||
} // end namespace endian
|
||||
|
||||
} // end namespace support
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ENDIAN_H
|
||||
97
wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
vendored
Normal file
97
wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes.
|
||||
// These can be used to write iterators that are fail-fast when LLVM is built
|
||||
// with asserts enabled.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_EPOCHTRACKER_H
|
||||
#define WPIUTIL_WPI_EPOCHTRACKER_H
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifndef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
/// A base class for data structure classes wishing to make iterators
|
||||
/// ("handles") pointing into themselves fail-fast. When building without
|
||||
/// asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// DebugEpochBase does not by itself track handles pointing into itself. The
|
||||
/// expectation is that routines touching the handles will poll on
|
||||
/// isHandleInSync at appropriate points to assert that the handle they're using
|
||||
/// is still valid.
|
||||
///
|
||||
class DebugEpochBase {
|
||||
uint64_t Epoch;
|
||||
|
||||
public:
|
||||
DebugEpochBase() : Epoch(0) {}
|
||||
|
||||
/// Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// calling instance.
|
||||
void incrementEpoch() { ++Epoch; }
|
||||
|
||||
/// The destructor calls incrementEpoch to make use-after-free bugs
|
||||
/// more likely to crash deterministically.
|
||||
~DebugEpochBase() { incrementEpoch(); }
|
||||
|
||||
/// A base class for iterator classes ("handles") that wish to poll for
|
||||
/// iterator invalidating modifications in the underlying data structure.
|
||||
/// When LLVM is built without asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// HandleBase does not track the parent data structure by itself. It expects
|
||||
/// the routines modifying the data structure to call incrementEpoch when they
|
||||
/// make an iterator-invalidating modification.
|
||||
///
|
||||
class HandleBase {
|
||||
const uint64_t *EpochAddress;
|
||||
uint64_t EpochAtCreation;
|
||||
|
||||
public:
|
||||
HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
|
||||
|
||||
explicit HandleBase(const DebugEpochBase *Parent)
|
||||
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
|
||||
|
||||
/// Returns true if the DebugEpochBase this Handle is linked to has
|
||||
/// not called incrementEpoch on itself since the creation of this
|
||||
/// HandleBase instance.
|
||||
bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
|
||||
|
||||
/// Returns a pointer to the epoch word stored in the data structure
|
||||
/// this handle points into. Can be used to check if two iterators point
|
||||
/// into the same data structure.
|
||||
const void *getEpochAddress() const { return EpochAddress; }
|
||||
};
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class DebugEpochBase {
|
||||
public:
|
||||
void incrementEpoch() {}
|
||||
|
||||
class HandleBase {
|
||||
public:
|
||||
HandleBase() = default;
|
||||
explicit HandleBase(const DebugEpochBase *) {}
|
||||
bool isHandleInSync() const { return true; }
|
||||
const void *getEpochAddress() const { return nullptr; }
|
||||
};
|
||||
};
|
||||
|
||||
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif
|
||||
86
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
vendored
Normal file
86
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
//===- llvm/Support/Errc.h - Defines the wpi::errc enum --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// While std::error_code works OK on all platforms we use, there are some
|
||||
// some problems with std::errc that can be avoided by using our own
|
||||
// enumeration:
|
||||
//
|
||||
// * std::errc is a namespace in some implementations. That means that ADL
|
||||
// doesn't work and it is sometimes necessary to write std::make_error_code
|
||||
// or in templates:
|
||||
// using std::make_error_code;
|
||||
// make_error_code(...);
|
||||
//
|
||||
// with this enum it is safe to always just use make_error_code.
|
||||
//
|
||||
// * Some implementations define fewer names than others. This header has
|
||||
// the intersection of all the ones we support.
|
||||
//
|
||||
// * std::errc is just marked with is_error_condition_enum. This means that
|
||||
// common patterns like AnErrorCode == errc::no_such_file_or_directory take
|
||||
// 4 virtual calls instead of two comparisons.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERRC_H
|
||||
#define WPIUTIL_WPI_ERRC_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace wpi {
|
||||
enum class errc {
|
||||
argument_list_too_long = int(std::errc::argument_list_too_long),
|
||||
argument_out_of_domain = int(std::errc::argument_out_of_domain),
|
||||
bad_address = int(std::errc::bad_address),
|
||||
bad_file_descriptor = int(std::errc::bad_file_descriptor),
|
||||
broken_pipe = int(std::errc::broken_pipe),
|
||||
device_or_resource_busy = int(std::errc::device_or_resource_busy),
|
||||
directory_not_empty = int(std::errc::directory_not_empty),
|
||||
executable_format_error = int(std::errc::executable_format_error),
|
||||
file_exists = int(std::errc::file_exists),
|
||||
file_too_large = int(std::errc::file_too_large),
|
||||
filename_too_long = int(std::errc::filename_too_long),
|
||||
function_not_supported = int(std::errc::function_not_supported),
|
||||
illegal_byte_sequence = int(std::errc::illegal_byte_sequence),
|
||||
inappropriate_io_control_operation =
|
||||
int(std::errc::inappropriate_io_control_operation),
|
||||
interrupted = int(std::errc::interrupted),
|
||||
invalid_argument = int(std::errc::invalid_argument),
|
||||
invalid_seek = int(std::errc::invalid_seek),
|
||||
io_error = int(std::errc::io_error),
|
||||
is_a_directory = int(std::errc::is_a_directory),
|
||||
no_child_process = int(std::errc::no_child_process),
|
||||
no_lock_available = int(std::errc::no_lock_available),
|
||||
no_space_on_device = int(std::errc::no_space_on_device),
|
||||
no_such_device_or_address = int(std::errc::no_such_device_or_address),
|
||||
no_such_device = int(std::errc::no_such_device),
|
||||
no_such_file_or_directory = int(std::errc::no_such_file_or_directory),
|
||||
no_such_process = int(std::errc::no_such_process),
|
||||
not_a_directory = int(std::errc::not_a_directory),
|
||||
not_enough_memory = int(std::errc::not_enough_memory),
|
||||
not_supported = int(std::errc::not_supported),
|
||||
operation_not_permitted = int(std::errc::operation_not_permitted),
|
||||
permission_denied = int(std::errc::permission_denied),
|
||||
read_only_file_system = int(std::errc::read_only_file_system),
|
||||
resource_deadlock_would_occur = int(std::errc::resource_deadlock_would_occur),
|
||||
resource_unavailable_try_again =
|
||||
int(std::errc::resource_unavailable_try_again),
|
||||
result_out_of_range = int(std::errc::result_out_of_range),
|
||||
too_many_files_open_in_system = int(std::errc::too_many_files_open_in_system),
|
||||
too_many_files_open = int(std::errc::too_many_files_open),
|
||||
too_many_links = int(std::errc::too_many_links)
|
||||
};
|
||||
|
||||
inline std::error_code make_error_code(errc E) {
|
||||
return std::error_code(static_cast<int>(E), std::generic_category());
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <> struct is_error_code_enum<wpi::errc> : std::true_type {};
|
||||
}
|
||||
#endif
|
||||
37
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
vendored
Normal file
37
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares some portable and convenient functions to deal with errno.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERRNO_H
|
||||
#define WPIUTIL_WPI_ERRNO_H
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
namespace sys {
|
||||
|
||||
template <typename FailT, typename Fun, typename... Args>
|
||||
inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
|
||||
const Args &... As) {
|
||||
decltype(F(As...)) Res;
|
||||
do {
|
||||
errno = 0;
|
||||
Res = F(As...);
|
||||
} while (Res == Fail && errno == EINTR);
|
||||
return Res;
|
||||
}
|
||||
|
||||
} // namespace sys
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ERRNO_H
|
||||
141
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
vendored
Normal file
141
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an API used to indicate fatal error conditions. Non-fatal
|
||||
// errors (most of them) should be handled through LLVMContext.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERRORHANDLING_H
|
||||
#define WPIUTIL_WPI_ERRORHANDLING_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// An error handler callback.
|
||||
typedef void (*fatal_error_handler_t)(void *user_data,
|
||||
const std::string& reason,
|
||||
bool gen_crash_diag);
|
||||
|
||||
/// install_fatal_error_handler - Installs a new error handler to be used
|
||||
/// whenever a serious (non-recoverable) error is encountered by LLVM.
|
||||
///
|
||||
/// If no error handler is installed the default is to print the error message
|
||||
/// to stderr, and call exit(1). If an error handler is installed then it is
|
||||
/// the handler's responsibility to log the message, it will no longer be
|
||||
/// printed to stderr. If the error handler returns, then exit(1) will be
|
||||
/// called.
|
||||
///
|
||||
/// It is dangerous to naively use an error handler which throws an exception.
|
||||
/// Even though some applications desire to gracefully recover from arbitrary
|
||||
/// faults, blindly throwing exceptions through unfamiliar code isn't a way to
|
||||
/// achieve this.
|
||||
///
|
||||
/// \param user_data - An argument which will be passed to the install error
|
||||
/// handler.
|
||||
void install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data = nullptr);
|
||||
|
||||
/// Restores default error handling behavior.
|
||||
void remove_fatal_error_handler();
|
||||
|
||||
/// ScopedFatalErrorHandler - This is a simple helper class which just
|
||||
/// calls install_fatal_error_handler in its constructor and
|
||||
/// remove_fatal_error_handler in its destructor.
|
||||
struct ScopedFatalErrorHandler {
|
||||
explicit ScopedFatalErrorHandler(fatal_error_handler_t handler,
|
||||
void *user_data = nullptr) {
|
||||
install_fatal_error_handler(handler, user_data);
|
||||
}
|
||||
|
||||
~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
|
||||
};
|
||||
|
||||
/// Reports a serious error, calling any installed error handler. These
|
||||
/// functions are intended to be used for error conditions which are outside
|
||||
/// the control of the compiler (I/O errors, invalid user input, etc.)
|
||||
///
|
||||
/// If no error handler is installed the default is to print the message to
|
||||
/// standard error, followed by a newline.
|
||||
/// After the error handler is called this function will call abort(), it
|
||||
/// does not return.
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(std::string_view reason,
|
||||
bool gen_crash_diag = true);
|
||||
|
||||
/// Installs a new bad alloc error handler that should be used whenever a
|
||||
/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
|
||||
///
|
||||
/// The user can install a bad alloc handler, in order to define the behavior
|
||||
/// in case of failing allocations, e.g. throwing an exception. Note that this
|
||||
/// handler must not trigger any additional allocations itself.
|
||||
///
|
||||
/// If no error handler is installed the default is to print the error message
|
||||
/// to stderr, and call exit(1). If an error handler is installed then it is
|
||||
/// the handler's responsibility to log the message, it will no longer be
|
||||
/// printed to stderr. If the error handler returns, then exit(1) will be
|
||||
/// called.
|
||||
///
|
||||
///
|
||||
/// \param user_data - An argument which will be passed to the installed error
|
||||
/// handler.
|
||||
void install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data = nullptr);
|
||||
|
||||
/// Restores default bad alloc error handling behavior.
|
||||
void remove_bad_alloc_error_handler();
|
||||
|
||||
void install_out_of_memory_new_handler();
|
||||
|
||||
/// Reports a bad alloc error, calling any user defined bad alloc
|
||||
/// error handler. In contrast to the generic 'report_fatal_error'
|
||||
/// functions, this function might not terminate, e.g. the user
|
||||
/// defined error handler throws an exception, but it won't return.
|
||||
///
|
||||
/// Note: When throwing an exception in the bad alloc handler, make sure that
|
||||
/// the following unwind succeeds, e.g. do not trigger additional allocations
|
||||
/// in the unwind chain.
|
||||
///
|
||||
/// If no error handler is installed (default), throws a bad_alloc exception
|
||||
/// if LLVM is compiled with exception support. Otherwise prints the error
|
||||
/// to standard error and calls abort().
|
||||
LLVM_ATTRIBUTE_NORETURN void report_bad_alloc_error(const char *Reason,
|
||||
bool GenCrashDiag = true);
|
||||
|
||||
/// This function calls abort(), and prints the optional message to stderr.
|
||||
/// Use the wpi_unreachable macro (that adds location info), instead of
|
||||
/// calling this function directly.
|
||||
LLVM_ATTRIBUTE_NORETURN void
|
||||
wpi_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
|
||||
unsigned line = 0);
|
||||
}
|
||||
|
||||
/// Marks that the current location is not supposed to be reachable.
|
||||
/// In !NDEBUG builds, prints the message and location info to stderr.
|
||||
/// In NDEBUG builds, becomes an optimizer hint that the current location
|
||||
/// is not supposed to be reachable. On compilers that don't support
|
||||
/// such hints, prints a reduced message instead and aborts the program.
|
||||
///
|
||||
/// Use this instead of assert(0). It conveys intent more clearly and
|
||||
/// allows compilers to omit some unnecessary code.
|
||||
#ifndef NDEBUG
|
||||
#define wpi_unreachable(msg) \
|
||||
::wpi::wpi_unreachable_internal(msg, __FILE__, __LINE__)
|
||||
#elif defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
#define wpi_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
|
||||
#else
|
||||
#define wpi_unreachable(msg) ::wpi::wpi_unreachable_internal()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
420
wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
vendored
Normal file
420
wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file provides a collection of function (or more generally, callable)
|
||||
/// type erasure utilities supplementing those provided by the standard library
|
||||
/// in `<function>`.
|
||||
///
|
||||
/// It provides `unique_function`, which works like `std::function` but supports
|
||||
/// move-only callable objects and const-qualification.
|
||||
///
|
||||
/// Future plans:
|
||||
/// - Add a `function` that provides ref-qualified support, which doesn't work
|
||||
/// with `std::function`.
|
||||
/// - Provide support for specifying multiple signatures to type erase callable
|
||||
/// objects with an overload set, such as those produced by generic lambdas.
|
||||
/// - Expand to include a copyable utility that directly replaces std::function
|
||||
/// but brings the above improvements.
|
||||
///
|
||||
/// Note that LLVM's utilities are greatly simplified by not supporting
|
||||
/// allocators.
|
||||
///
|
||||
/// If the standard library ever begins to provide comparable facilities we can
|
||||
/// consider switching to those.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_FUNCTIONEXTRAS_H
|
||||
#define WPIUTIL_WPI_FUNCTIONEXTRAS_H
|
||||
|
||||
#include "wpi/PointerIntPair.h"
|
||||
#include "wpi/PointerUnion.h"
|
||||
#include "wpi/STLForwardCompat.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// unique_function is a type-erasing functor similar to std::function.
|
||||
///
|
||||
/// It can hold move-only function objects, like lambdas capturing unique_ptrs.
|
||||
/// Accordingly, it is movable but not copyable.
|
||||
///
|
||||
/// It supports const-qualification:
|
||||
/// - unique_function<int() const> has a const operator().
|
||||
/// It can only hold functions which themselves have a const operator().
|
||||
/// - unique_function<int()> has a non-const operator().
|
||||
/// It can hold functions with a non-const operator(), like mutable lambdas.
|
||||
template <typename FunctionT> class unique_function;
|
||||
|
||||
// GCC warns on OutOfLineStorage
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using EnableIfTrivial =
|
||||
std::enable_if_t<wpi::is_trivially_move_constructible<T>::value &&
|
||||
std::is_trivially_destructible<T>::value>;
|
||||
template <typename CallableT, typename ThisT>
|
||||
using EnableUnlessSameType =
|
||||
std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>::value>;
|
||||
template <typename CallableT, typename Ret, typename... Params>
|
||||
using EnableIfCallable =
|
||||
std::enable_if_t<std::is_void<Ret>::value ||
|
||||
std::is_convertible<decltype(std::declval<CallableT>()(
|
||||
std::declval<Params>()...)),
|
||||
Ret>::value>;
|
||||
|
||||
template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
|
||||
protected:
|
||||
static constexpr size_t InlineStorageSize = sizeof(void *) * 4;
|
||||
|
||||
template <typename T, class = void>
|
||||
struct IsSizeLessThanThresholdT : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsSizeLessThanThresholdT<
|
||||
T, std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
|
||||
|
||||
// Provide a type function to map parameters that won't observe extra copies
|
||||
// or moves and which are small enough to likely pass in register to values
|
||||
// and all other types to l-value reference types. We use this to compute the
|
||||
// types used in our erased call utility to minimize copies and moves unless
|
||||
// doing so would force things unnecessarily into memory.
|
||||
//
|
||||
// The heuristic used is related to common ABI register passing conventions.
|
||||
// It doesn't have to be exact though, and in one way it is more strict
|
||||
// because we want to still be able to observe either moves *or* copies.
|
||||
template <typename T> struct AdjustedParamTBase {
|
||||
static_assert(!std::is_reference<T>::value,
|
||||
"references should be handled by template specialization");
|
||||
using type = typename std::conditional<
|
||||
wpi::is_trivially_copy_constructible<T>::value &&
|
||||
wpi::is_trivially_move_constructible<T>::value &&
|
||||
IsSizeLessThanThresholdT<T>::value,
|
||||
T, T &>::type;
|
||||
};
|
||||
|
||||
// This specialization ensures that 'AdjustedParam<V<T>&>' or
|
||||
// 'AdjustedParam<V<T>&&>' does not trigger a compile-time error when 'T' is
|
||||
// an incomplete type and V a templated type.
|
||||
template <typename T> struct AdjustedParamTBase<T &> { using type = T &; };
|
||||
template <typename T> struct AdjustedParamTBase<T &&> { using type = T &; };
|
||||
|
||||
template <typename T>
|
||||
using AdjustedParamT = typename AdjustedParamTBase<T>::type;
|
||||
|
||||
// The type of the erased function pointer we use as a callback to dispatch to
|
||||
// the stored callable when it is trivial to move and destroy.
|
||||
using CallPtrT = ReturnT (*)(void *CallableAddr,
|
||||
AdjustedParamT<ParamTs>... Params);
|
||||
using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
|
||||
using DestroyPtrT = void (*)(void *CallableAddr);
|
||||
|
||||
/// A struct to hold a single trivial callback with sufficient alignment for
|
||||
/// our bitpacking.
|
||||
struct alignas(8) TrivialCallback {
|
||||
CallPtrT CallPtr;
|
||||
};
|
||||
|
||||
/// A struct we use to aggregate three callbacks when we need full set of
|
||||
/// operations.
|
||||
struct alignas(8) NonTrivialCallbacks {
|
||||
CallPtrT CallPtr;
|
||||
MovePtrT MovePtr;
|
||||
DestroyPtrT DestroyPtr;
|
||||
};
|
||||
|
||||
// Create a pointer union between either a pointer to a static trivial call
|
||||
// pointer in a struct or a pointer to a static struct of the call, move, and
|
||||
// destroy pointers.
|
||||
using CallbackPointerUnionT =
|
||||
PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
|
||||
|
||||
// The main storage buffer. This will either have a pointer to out-of-line
|
||||
// storage or an inline buffer storing the callable.
|
||||
union StorageUnionT {
|
||||
// For out-of-line storage we keep a pointer to the underlying storage and
|
||||
// the size. This is enough to deallocate the memory.
|
||||
struct OutOfLineStorageT {
|
||||
void *StoragePtr;
|
||||
size_t Size;
|
||||
size_t Alignment;
|
||||
} OutOfLineStorage;
|
||||
static_assert(
|
||||
sizeof(OutOfLineStorageT) <= InlineStorageSize,
|
||||
"Should always use all of the out-of-line storage for inline storage!");
|
||||
|
||||
// For in-line storage, we just provide an aligned character buffer. We
|
||||
// provide four pointers worth of storage here.
|
||||
// This is mutable as an inlined `const unique_function<void() const>` may
|
||||
// still modify its own mutable members.
|
||||
mutable
|
||||
typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
|
||||
InlineStorage;
|
||||
} StorageUnion;
|
||||
|
||||
// A compressed pointer to either our dispatching callback or our table of
|
||||
// dispatching callbacks and the flag for whether the callable itself is
|
||||
// stored inline or not.
|
||||
PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
|
||||
|
||||
bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
|
||||
|
||||
bool isTrivialCallback() const {
|
||||
return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
|
||||
}
|
||||
|
||||
CallPtrT getTrivialCallback() const {
|
||||
return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
|
||||
}
|
||||
|
||||
NonTrivialCallbacks *getNonTrivialCallbacks() const {
|
||||
return CallbackAndInlineFlag.getPointer()
|
||||
.template get<NonTrivialCallbacks *>();
|
||||
}
|
||||
|
||||
CallPtrT getCallPtr() const {
|
||||
return isTrivialCallback() ? getTrivialCallback()
|
||||
: getNonTrivialCallbacks()->CallPtr;
|
||||
}
|
||||
|
||||
// These three functions are only const in the narrow sense. They return
|
||||
// mutable pointers to function state.
|
||||
// This allows unique_function<T const>::operator() to be const, even if the
|
||||
// underlying functor may be internally mutable.
|
||||
//
|
||||
// const callers must ensure they're only used in const-correct ways.
|
||||
void *getCalleePtr() const {
|
||||
return isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
|
||||
}
|
||||
void *getInlineStorage() const { return &StorageUnion.InlineStorage; }
|
||||
void *getOutOfLineStorage() const {
|
||||
return StorageUnion.OutOfLineStorage.StoragePtr;
|
||||
}
|
||||
|
||||
size_t getOutOfLineStorageSize() const {
|
||||
return StorageUnion.OutOfLineStorage.Size;
|
||||
}
|
||||
size_t getOutOfLineStorageAlignment() const {
|
||||
return StorageUnion.OutOfLineStorage.Alignment;
|
||||
}
|
||||
|
||||
void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
|
||||
StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
|
||||
}
|
||||
|
||||
template <typename CalledAsT>
|
||||
static ReturnT CallImpl(void *CallableAddr,
|
||||
AdjustedParamT<ParamTs>... Params) {
|
||||
auto &Func = *reinterpret_cast<CalledAsT *>(CallableAddr);
|
||||
return Func(std::forward<ParamTs>(Params)...);
|
||||
}
|
||||
|
||||
template <typename CallableT>
|
||||
static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
|
||||
new (LHSCallableAddr)
|
||||
CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
|
||||
}
|
||||
|
||||
template <typename CallableT>
|
||||
static void DestroyImpl(void *CallableAddr) noexcept {
|
||||
reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
|
||||
}
|
||||
|
||||
// The pointers to call/move/destroy functions are determined for each
|
||||
// callable type (and called-as type, which determines the overload chosen).
|
||||
// (definitions are out-of-line).
|
||||
|
||||
// By default, we need an object that contains all the different
|
||||
// type erased behaviors needed. Create a static instance of the struct type
|
||||
// here and each instance will contain a pointer to it.
|
||||
// Wrap in a struct to avoid https://gcc.gnu.org/PR71954
|
||||
template <typename CallableT, typename CalledAs, typename Enable = void>
|
||||
struct CallbacksHolder {
|
||||
static NonTrivialCallbacks Callbacks;
|
||||
};
|
||||
// See if we can create a trivial callback. We need the callable to be
|
||||
// trivially moved and trivially destroyed so that we don't have to store
|
||||
// type erased callbacks for those operations.
|
||||
template <typename CallableT, typename CalledAs>
|
||||
struct CallbacksHolder<CallableT, CalledAs, EnableIfTrivial<CallableT>> {
|
||||
static TrivialCallback Callbacks;
|
||||
};
|
||||
|
||||
// A simple tag type so the call-as type to be passed to the constructor.
|
||||
template <typename T> struct CalledAs {};
|
||||
|
||||
// Essentially the "main" unique_function constructor, but subclasses
|
||||
// provide the qualified type to be used for the call.
|
||||
// (We always store a T, even if the call will use a pointer to const T).
|
||||
template <typename CallableT, typename CalledAsT>
|
||||
UniqueFunctionBase(CallableT Callable, CalledAs<CalledAsT>) {
|
||||
bool IsInlineStorage = true;
|
||||
void *CallableAddr = getInlineStorage();
|
||||
if (sizeof(CallableT) > InlineStorageSize ||
|
||||
alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
|
||||
IsInlineStorage = false;
|
||||
// Allocate out-of-line storage. FIXME: Use an explicit alignment
|
||||
// parameter in C++17 mode.
|
||||
auto Size = sizeof(CallableT);
|
||||
auto Alignment = alignof(CallableT);
|
||||
CallableAddr = allocate_buffer(Size, Alignment);
|
||||
setOutOfLineStorage(CallableAddr, Size, Alignment);
|
||||
}
|
||||
|
||||
// Now move into the storage.
|
||||
new (CallableAddr) CallableT(std::move(Callable));
|
||||
CallbackAndInlineFlag.setPointerAndInt(
|
||||
&CallbacksHolder<CallableT, CalledAsT>::Callbacks, IsInlineStorage);
|
||||
}
|
||||
|
||||
~UniqueFunctionBase() {
|
||||
if (!CallbackAndInlineFlag.getPointer())
|
||||
return;
|
||||
|
||||
// Cache this value so we don't re-check it after type-erased operations.
|
||||
bool IsInlineStorage = isInlineStorage();
|
||||
|
||||
if (!isTrivialCallback())
|
||||
getNonTrivialCallbacks()->DestroyPtr(
|
||||
IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
|
||||
|
||||
if (!IsInlineStorage)
|
||||
deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
|
||||
getOutOfLineStorageAlignment());
|
||||
}
|
||||
|
||||
UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
|
||||
// Copy the callback and inline flag.
|
||||
CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
|
||||
|
||||
// If the RHS is empty, just copying the above is sufficient.
|
||||
if (!RHS)
|
||||
return;
|
||||
|
||||
if (!isInlineStorage()) {
|
||||
// The out-of-line case is easiest to move.
|
||||
StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
|
||||
} else if (isTrivialCallback()) {
|
||||
// Move is trivial, just memcpy the bytes across.
|
||||
memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
|
||||
} else {
|
||||
// Non-trivial move, so dispatch to a type-erased implementation.
|
||||
getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
|
||||
RHS.getInlineStorage());
|
||||
}
|
||||
|
||||
// Clear the old callback and inline flag to get back to as-if-null.
|
||||
RHS.CallbackAndInlineFlag = {};
|
||||
|
||||
#ifndef NDEBUG
|
||||
// In debug builds, we also scribble across the rest of the storage.
|
||||
memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
UniqueFunctionBase &operator=(UniqueFunctionBase &&RHS) noexcept {
|
||||
if (this == &RHS)
|
||||
return *this;
|
||||
|
||||
// Because we don't try to provide any exception safety guarantees we can
|
||||
// implement move assignment very simply by first destroying the current
|
||||
// object and then move-constructing over top of it.
|
||||
this->~UniqueFunctionBase();
|
||||
new (this) UniqueFunctionBase(std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
UniqueFunctionBase() = default;
|
||||
|
||||
public:
|
||||
explicit operator bool() const {
|
||||
return (bool)CallbackAndInlineFlag.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... P>
|
||||
template <typename CallableT, typename CalledAsT, typename Enable>
|
||||
typename UniqueFunctionBase<R, P...>::NonTrivialCallbacks UniqueFunctionBase<
|
||||
R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
|
||||
&CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
|
||||
|
||||
template <typename R, typename... P>
|
||||
template <typename CallableT, typename CalledAsT>
|
||||
typename UniqueFunctionBase<R, P...>::TrivialCallback
|
||||
UniqueFunctionBase<R, P...>::CallbacksHolder<
|
||||
CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
|
||||
&CallImpl<CalledAsT>};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename R, typename... P>
|
||||
class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
|
||||
using Base = detail::UniqueFunctionBase<R, P...>;
|
||||
|
||||
public:
|
||||
unique_function() = default;
|
||||
unique_function(std::nullptr_t) {}
|
||||
unique_function(unique_function &&) = default;
|
||||
unique_function(const unique_function &) = delete;
|
||||
unique_function &operator=(unique_function &&) = default;
|
||||
unique_function &operator=(const unique_function &) = delete;
|
||||
|
||||
template <typename CallableT>
|
||||
unique_function(
|
||||
CallableT Callable,
|
||||
detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
|
||||
detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
|
||||
: Base(std::forward<CallableT>(Callable),
|
||||
typename Base::template CalledAs<CallableT>{}) {}
|
||||
|
||||
R operator()(P... Params) {
|
||||
return this->getCallPtr()(this->getCalleePtr(), Params...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... P>
|
||||
class unique_function<R(P...) const>
|
||||
: public detail::UniqueFunctionBase<R, P...> {
|
||||
using Base = detail::UniqueFunctionBase<R, P...>;
|
||||
|
||||
public:
|
||||
unique_function() = default;
|
||||
unique_function(std::nullptr_t) {}
|
||||
unique_function(unique_function &&) = default;
|
||||
unique_function(const unique_function &) = delete;
|
||||
unique_function &operator=(unique_function &&) = default;
|
||||
unique_function &operator=(const unique_function &) = delete;
|
||||
|
||||
template <typename CallableT>
|
||||
unique_function(
|
||||
CallableT Callable,
|
||||
detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
|
||||
detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
|
||||
: Base(std::forward<CallableT>(Callable),
|
||||
typename Base::template CalledAs<const CallableT>{}) {}
|
||||
|
||||
R operator()(P... Params) const {
|
||||
return this->getCallPtr()(this->getCalleePtr(), Params...);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_FUNCTIONEXTRAS_H
|
||||
690
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
vendored
Normal file
690
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
vendored
Normal file
@@ -0,0 +1,690 @@
|
||||
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the newly proposed standard C++ interfaces for hashing
|
||||
// arbitrary data and building hash functions for user-defined types. This
|
||||
// interface was originally proposed in N3333[1] and is currently under review
|
||||
// for inclusion in a future TR and/or standard.
|
||||
//
|
||||
// The primary interfaces provide are comprised of one type and three functions:
|
||||
//
|
||||
// -- 'hash_code' class is an opaque type representing the hash code for some
|
||||
// data. It is the intended product of hashing, and can be used to implement
|
||||
// hash tables, checksumming, and other common uses of hashes. It is not an
|
||||
// integer type (although it can be converted to one) because it is risky
|
||||
// to assume much about the internals of a hash_code. In particular, each
|
||||
// execution of the program has a high probability of producing a different
|
||||
// hash_code for a given input. Thus their values are not stable to save or
|
||||
// persist, and should only be used during the execution for the
|
||||
// construction of hashing datastructures.
|
||||
//
|
||||
// -- 'hash_value' is a function designed to be overloaded for each
|
||||
// user-defined type which wishes to be used within a hashing context. It
|
||||
// should be overloaded within the user-defined type's namespace and found
|
||||
// via ADL. Overloads for primitive types are provided by this library.
|
||||
//
|
||||
// -- 'hash_combine' and 'hash_combine_range' are functions designed to aid
|
||||
// programmers in easily and intuitively combining a set of data into
|
||||
// a single hash_code for their object. They should only logically be used
|
||||
// within the implementation of a 'hash_value' routine or similar context.
|
||||
//
|
||||
// Note that 'hash_combine_range' contains very special logic for hashing
|
||||
// a contiguous array of integers or pointers. This logic is *extremely* fast,
|
||||
// on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were
|
||||
// benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys
|
||||
// under 32-bytes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_HASHING_H
|
||||
#define WPIUTIL_WPI_HASHING_H
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26495)
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// An opaque object representing a hash code.
|
||||
///
|
||||
/// This object represents the result of hashing some entity. It is intended to
|
||||
/// be used to implement hashtables or other hashing-based data structures.
|
||||
/// While it wraps and exposes a numeric value, this value should not be
|
||||
/// trusted to be stable or predictable across processes or executions.
|
||||
///
|
||||
/// In order to obtain the hash_code for an object 'x':
|
||||
/// \code
|
||||
/// using wpi::hash_value;
|
||||
/// wpi::hash_code code = hash_value(x);
|
||||
/// \endcode
|
||||
class hash_code {
|
||||
size_t value;
|
||||
|
||||
public:
|
||||
/// Default construct a hash_code.
|
||||
/// Note that this leaves the value uninitialized.
|
||||
hash_code() = default;
|
||||
|
||||
/// Form a hash code directly from a numerical value.
|
||||
hash_code(size_t value) : value(value) {}
|
||||
|
||||
/// Convert the hash code to its numerical value for use.
|
||||
/*explicit*/ operator size_t() const { return value; }
|
||||
|
||||
friend bool operator==(const hash_code &lhs, const hash_code &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
friend bool operator!=(const hash_code &lhs, const hash_code &rhs) {
|
||||
return lhs.value != rhs.value;
|
||||
}
|
||||
|
||||
/// Allow a hash_code to be directly run through hash_value.
|
||||
friend size_t hash_value(const hash_code &code) { return code.value; }
|
||||
};
|
||||
|
||||
/// Compute a hash_code for any integer value.
|
||||
///
|
||||
/// Note that this function is intended to compute the same hash_code for
|
||||
/// a particular value without regard to the pre-promotion type. This is in
|
||||
/// contrast to hash_combine which may produce different hash_codes for
|
||||
/// differing argument types even if they would implicit promote to a common
|
||||
/// type without changing the value.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value);
|
||||
|
||||
/// Compute a hash_code for a pointer's address.
|
||||
///
|
||||
/// N.B.: This hashes the *address*. Not the value and not the type.
|
||||
template <typename T> hash_code hash_value(const T *ptr);
|
||||
|
||||
/// Compute a hash_code for a pair of objects.
|
||||
template <typename T, typename U>
|
||||
hash_code hash_value(const std::pair<T, U> &arg);
|
||||
|
||||
/// Compute a hash_code for a tuple.
|
||||
template <typename... Ts>
|
||||
hash_code hash_value(const std::tuple<Ts...> &arg);
|
||||
|
||||
/// Compute a hash_code for a standard string.
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg);
|
||||
|
||||
|
||||
/// Override the execution seed with a fixed value.
|
||||
///
|
||||
/// This hashing library uses a per-execution seed designed to change on each
|
||||
/// run with high probability in order to ensure that the hash codes are not
|
||||
/// attackable and to ensure that output which is intended to be stable does
|
||||
/// not rely on the particulars of the hash codes produced.
|
||||
///
|
||||
/// That said, there are use cases where it is important to be able to
|
||||
/// reproduce *exactly* a specific behavior. To that end, we provide a function
|
||||
/// which will forcibly set the seed to a fixed value. This must be done at the
|
||||
/// start of the program, before any hashes are computed. Also, it cannot be
|
||||
/// undone. This makes it thread-hostile and very hard to use outside of
|
||||
/// immediately on start of a simple program designed for reproducible
|
||||
/// behavior.
|
||||
void set_fixed_execution_hash_seed(uint64_t fixed_value);
|
||||
|
||||
|
||||
// All of the implementation details of actually computing the various hash
|
||||
// code values are held within this namespace. These routines are included in
|
||||
// the header file mainly to allow inlining and constant propagation.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
inline uint64_t fetch64(const char *p) {
|
||||
uint64_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
if (sys::IsBigEndianHost)
|
||||
sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint32_t fetch32(const char *p) {
|
||||
uint32_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
if (sys::IsBigEndianHost)
|
||||
sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Some primes between 2^63 and 2^64 for various uses.
|
||||
static constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
|
||||
static constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
|
||||
static constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
|
||||
static constexpr uint64_t k3 = 0xc949d7c7509e6557ULL;
|
||||
|
||||
/// Bitwise right rotate.
|
||||
/// Normally this will compile to a single instruction, especially if the
|
||||
/// shift is a manifest constant.
|
||||
inline uint64_t rotate(uint64_t val, size_t shift) {
|
||||
// Avoid shifting by 64: doing so yields an undefined result.
|
||||
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
|
||||
}
|
||||
|
||||
inline uint64_t shift_mix(uint64_t val) {
|
||||
return val ^ (val >> 47);
|
||||
}
|
||||
|
||||
inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (low ^ high) * kMul;
|
||||
a ^= (a >> 47);
|
||||
uint64_t b = (high ^ a) * kMul;
|
||||
b ^= (b >> 47);
|
||||
b *= kMul;
|
||||
return b;
|
||||
}
|
||||
|
||||
inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint8_t a = s[0];
|
||||
uint8_t b = s[len >> 1];
|
||||
uint8_t c = s[len - 1];
|
||||
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
|
||||
uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
|
||||
return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
|
||||
}
|
||||
|
||||
inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch32(s);
|
||||
return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4));
|
||||
}
|
||||
|
||||
inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch64(s);
|
||||
uint64_t b = fetch64(s + len - 8);
|
||||
return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b;
|
||||
}
|
||||
|
||||
inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch64(s) * k1;
|
||||
uint64_t b = fetch64(s + 8);
|
||||
uint64_t c = fetch64(s + len - 8) * k2;
|
||||
uint64_t d = fetch64(s + len - 16) * k0;
|
||||
return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d,
|
||||
a + rotate(b ^ k3, 20) - c + len + seed);
|
||||
}
|
||||
|
||||
inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t z = fetch64(s + 24);
|
||||
uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
|
||||
uint64_t b = rotate(a + z, 52);
|
||||
uint64_t c = rotate(a, 37);
|
||||
a += fetch64(s + 8);
|
||||
c += rotate(a, 7);
|
||||
a += fetch64(s + 16);
|
||||
uint64_t vf = a + z;
|
||||
uint64_t vs = b + rotate(a, 31) + c;
|
||||
a = fetch64(s + 16) + fetch64(s + len - 32);
|
||||
z = fetch64(s + len - 8);
|
||||
b = rotate(a + z, 52);
|
||||
c = rotate(a, 37);
|
||||
a += fetch64(s + len - 24);
|
||||
c += rotate(a, 7);
|
||||
a += fetch64(s + len - 16);
|
||||
uint64_t wf = a + z;
|
||||
uint64_t ws = b + rotate(a, 31) + c;
|
||||
uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
|
||||
return shift_mix((seed ^ (r * k0)) + vs) * k2;
|
||||
}
|
||||
|
||||
inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
|
||||
if (length >= 4 && length <= 8)
|
||||
return hash_4to8_bytes(s, length, seed);
|
||||
if (length > 8 && length <= 16)
|
||||
return hash_9to16_bytes(s, length, seed);
|
||||
if (length > 16 && length <= 32)
|
||||
return hash_17to32_bytes(s, length, seed);
|
||||
if (length > 32)
|
||||
return hash_33to64_bytes(s, length, seed);
|
||||
if (length != 0)
|
||||
return hash_1to3_bytes(s, length, seed);
|
||||
|
||||
return k2 ^ seed;
|
||||
}
|
||||
|
||||
/// The intermediate state used during hashing.
|
||||
/// Currently, the algorithm for computing hash codes is based on CityHash and
|
||||
/// keeps 56 bytes of arbitrary state.
|
||||
struct hash_state {
|
||||
uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0;
|
||||
|
||||
/// Create a new hash_state structure and initialize it based on the
|
||||
/// seed and the first 64-byte chunk.
|
||||
/// This effectively performs the initial mix.
|
||||
static hash_state create(const char *s, uint64_t seed) {
|
||||
hash_state state = {
|
||||
0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
|
||||
seed * k1, shift_mix(seed), 0 };
|
||||
state.h6 = hash_16_bytes(state.h4, state.h5);
|
||||
state.mix(s);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Mix 32-bytes from the input sequence into the 16-bytes of 'a'
|
||||
/// and 'b', including whatever is already in 'a' and 'b'.
|
||||
static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
|
||||
a += fetch64(s);
|
||||
uint64_t c = fetch64(s + 24);
|
||||
b = rotate(b + a + c, 21);
|
||||
uint64_t d = a;
|
||||
a += fetch64(s + 8) + fetch64(s + 16);
|
||||
b += rotate(a, 44) + d;
|
||||
a += c;
|
||||
}
|
||||
|
||||
/// Mix in a 64-byte buffer of data.
|
||||
/// We mix all 64 bytes even when the chunk length is smaller, but we
|
||||
/// record the actual length.
|
||||
void mix(const char *s) {
|
||||
h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
|
||||
h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1;
|
||||
h0 ^= h6;
|
||||
h1 += h3 + fetch64(s + 40);
|
||||
h2 = rotate(h2 + h5, 33) * k1;
|
||||
h3 = h4 * k1;
|
||||
h4 = h0 + h5;
|
||||
mix_32_bytes(s, h3, h4);
|
||||
h5 = h2 + h6;
|
||||
h6 = h1 + fetch64(s + 16);
|
||||
mix_32_bytes(s + 32, h5, h6);
|
||||
std::swap(h2, h0);
|
||||
}
|
||||
|
||||
/// Compute the final 64-bit hash code value based on the current
|
||||
/// state and the length of bytes hashed.
|
||||
uint64_t finalize(size_t length) {
|
||||
return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2,
|
||||
hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// A global, fixed seed-override variable.
|
||||
///
|
||||
/// This variable can be set using the \see wpi::set_fixed_execution_seed
|
||||
/// function. See that function for details. Do not, under any circumstances,
|
||||
/// set or read this variable.
|
||||
extern uint64_t fixed_seed_override;
|
||||
|
||||
inline uint64_t get_execution_seed() {
|
||||
// FIXME: This needs to be a per-execution seed. This is just a placeholder
|
||||
// implementation. Switching to a per-execution seed is likely to flush out
|
||||
// instability bugs and so will happen as its own commit.
|
||||
//
|
||||
// However, if there is a fixed seed override set the first time this is
|
||||
// called, return that instead of the per-execution seed.
|
||||
const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
|
||||
static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime;
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
||||
/// Trait to indicate whether a type's bits can be hashed directly.
|
||||
///
|
||||
/// A type trait which is true if we want to combine values for hashing by
|
||||
/// reading the underlying data. It is false if values of this type must
|
||||
/// first be passed to hash_value, and the resulting hash_codes combined.
|
||||
//
|
||||
// FIXME: We want to replace is_integral_or_enum and is_pointer here with
|
||||
// a predicate which asserts that comparing the underlying storage of two
|
||||
// values of the type for equality is equivalent to comparing the two values
|
||||
// for equality. For all the platforms we care about, this holds for integers
|
||||
// and pointers, but there are platforms where it doesn't and we would like to
|
||||
// support user-defined types which happen to satisfy this property.
|
||||
template <typename T> struct is_hashable_data
|
||||
: std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
||||
std::is_pointer<T>::value) &&
|
||||
64 % sizeof(T) == 0)> {};
|
||||
|
||||
// Special case std::pair to detect when both types are viable and when there
|
||||
// is no alignment-derived padding in the pair. This is a bit of a lie because
|
||||
// std::pair isn't truly POD, but it's close enough in all reasonable
|
||||
// implementations for our use case of hashing the underlying data.
|
||||
template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
||||
: std::integral_constant<bool, (is_hashable_data<T>::value &&
|
||||
is_hashable_data<U>::value &&
|
||||
(sizeof(T) + sizeof(U)) ==
|
||||
sizeof(std::pair<T, U>))> {};
|
||||
|
||||
/// Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when the type itself can be used.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_hashable_data<T>::value, T>
|
||||
get_hashable_data(const T &value) {
|
||||
return value;
|
||||
}
|
||||
/// Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when we must first call hash_value and use the
|
||||
/// result as our data.
|
||||
template <typename T>
|
||||
std::enable_if_t<!is_hashable_data<T>::value, size_t>
|
||||
get_hashable_data(const T &value) {
|
||||
using ::wpi::hash_value;
|
||||
return hash_value(value);
|
||||
}
|
||||
|
||||
/// Helper to store data from a value into a buffer and advance the
|
||||
/// pointer into that buffer.
|
||||
///
|
||||
/// This routine first checks whether there is enough space in the provided
|
||||
/// buffer, and if not immediately returns false. If there is space, it
|
||||
/// copies the underlying bytes of value into the buffer, advances the
|
||||
/// buffer_ptr past the copied bytes, and returns true.
|
||||
template <typename T>
|
||||
bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
|
||||
size_t offset = 0) {
|
||||
size_t store_size = sizeof(value) - offset;
|
||||
if (buffer_ptr + store_size > buffer_end)
|
||||
return false;
|
||||
const char *value_data = reinterpret_cast<const char *>(&value);
|
||||
memcpy(buffer_ptr, value_data + offset, store_size);
|
||||
buffer_ptr += store_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Implement the combining of integral values into a hash_code.
|
||||
///
|
||||
/// This overload is selected when the value type of the iterator is
|
||||
/// integral. Rather than computing a hash_code for each object and then
|
||||
/// combining them, this (as an optimization) directly combines the integers.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
const uint64_t seed = get_execution_seed();
|
||||
char buffer[64], *buffer_ptr = buffer;
|
||||
char *const buffer_end = std::end(buffer);
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
if (first == last)
|
||||
return hash_short(buffer, buffer_ptr - buffer, seed);
|
||||
assert(buffer_ptr == buffer_end);
|
||||
|
||||
hash_state state = state.create(buffer, seed);
|
||||
size_t length = 64;
|
||||
while (first != last) {
|
||||
// Fill up the buffer. We don't clear it, which re-mixes the last round
|
||||
// when only a partial 64-byte chunk is left.
|
||||
buffer_ptr = buffer;
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
|
||||
// Rotate the buffer if we did a partial fill in order to simulate doing
|
||||
// a mix of the last 64-bytes. That is how the algorithm works when we
|
||||
// have a contiguous byte sequence, and we want to emulate that here.
|
||||
std::rotate(buffer, buffer_ptr, buffer_end);
|
||||
|
||||
// Mix this chunk into the current state.
|
||||
state.mix(buffer);
|
||||
length += buffer_ptr - buffer;
|
||||
};
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
/// Implement the combining of integral values into a hash_code.
|
||||
///
|
||||
/// This overload is selected when the value type of the iterator is integral
|
||||
/// and when the input iterator is actually a pointer. Rather than computing
|
||||
/// a hash_code for each object and then combining them, this (as an
|
||||
/// optimization) directly combines the integers. Also, because the integers
|
||||
/// are stored in contiguous memory, this routine avoids copying each value
|
||||
/// and directly reads from the underlying memory.
|
||||
template <typename ValueT>
|
||||
std::enable_if_t<is_hashable_data<ValueT>::value, hash_code>
|
||||
hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||
const uint64_t seed = get_execution_seed();
|
||||
const char *s_begin = reinterpret_cast<const char *>(first);
|
||||
const char *s_end = reinterpret_cast<const char *>(last);
|
||||
const size_t length = std::distance(s_begin, s_end);
|
||||
if (length <= 64)
|
||||
return hash_short(s_begin, length, seed);
|
||||
|
||||
const char *s_aligned_end = s_begin + (length & ~63);
|
||||
hash_state state = state.create(s_begin, seed);
|
||||
s_begin += 64;
|
||||
while (s_begin != s_aligned_end) {
|
||||
state.mix(s_begin);
|
||||
s_begin += 64;
|
||||
}
|
||||
if (length & 63)
|
||||
state.mix(s_end - 64);
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
|
||||
/// Compute a hash_code for a sequence of values.
|
||||
///
|
||||
/// This hashes a sequence of values. It produces the same hash_code as
|
||||
/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences
|
||||
/// and is significantly faster given pointers and types which can be hashed as
|
||||
/// a sequence of bytes.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
|
||||
return ::wpi::hashing::detail::hash_combine_range_impl(first, last);
|
||||
}
|
||||
|
||||
|
||||
// Implementation details for hash_combine.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// Helper class to manage the recursive combining of hash_combine
|
||||
/// arguments.
|
||||
///
|
||||
/// This class exists to manage the state and various calls involved in the
|
||||
/// recursive combining of arguments used in hash_combine. It is particularly
|
||||
/// useful at minimizing the code in the recursive calls to ease the pain
|
||||
/// caused by a lack of variadic functions.
|
||||
struct hash_combine_recursive_helper {
|
||||
char buffer[64] = {};
|
||||
hash_state state;
|
||||
const uint64_t seed;
|
||||
|
||||
public:
|
||||
/// Construct a recursive hash combining helper.
|
||||
///
|
||||
/// This sets up the state for a recursive hash combine, including getting
|
||||
/// the seed and buffer setup.
|
||||
hash_combine_recursive_helper()
|
||||
: seed(get_execution_seed()) {}
|
||||
|
||||
/// Combine one chunk of data into the current in-flight hash.
|
||||
///
|
||||
/// This merges one chunk of data into the hash. First it tries to buffer
|
||||
/// the data. If the buffer is full, it hashes the buffer into its
|
||||
/// hash_state, empties it, and then merges the new chunk in. This also
|
||||
/// handles cases where the data straddles the end of the buffer.
|
||||
template <typename T>
|
||||
char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
|
||||
if (!store_and_advance(buffer_ptr, buffer_end, data)) {
|
||||
// Check for skew which prevents the buffer from being packed, and do
|
||||
// a partial store into the buffer to fill it. This is only a concern
|
||||
// with the variadic combine because that formation can have varying
|
||||
// argument types.
|
||||
size_t partial_store_size = buffer_end - buffer_ptr;
|
||||
memcpy(buffer_ptr, &data, partial_store_size);
|
||||
|
||||
// If the store fails, our buffer is full and ready to hash. We have to
|
||||
// either initialize the hash state (on the first full buffer) or mix
|
||||
// this buffer into the existing hash state. Length tracks the *hashed*
|
||||
// length, not the buffered length.
|
||||
if (length == 0) {
|
||||
state = state.create(buffer, seed);
|
||||
length = 64;
|
||||
} else {
|
||||
// Mix this chunk into the current state and bump length up by 64.
|
||||
state.mix(buffer);
|
||||
length += 64;
|
||||
}
|
||||
// Reset the buffer_ptr to the head of the buffer for the next chunk of
|
||||
// data.
|
||||
buffer_ptr = buffer;
|
||||
|
||||
// Try again to store into the buffer -- this cannot fail as we only
|
||||
// store types smaller than the buffer.
|
||||
if (!store_and_advance(buffer_ptr, buffer_end, data,
|
||||
partial_store_size))
|
||||
wpi_unreachable("buffer smaller than stored type");
|
||||
}
|
||||
return buffer_ptr;
|
||||
}
|
||||
|
||||
/// Recursive, variadic combining method.
|
||||
///
|
||||
/// This function recurses through each argument, combining that argument
|
||||
/// into a single hash.
|
||||
template <typename T, typename ...Ts>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T &arg, const Ts &...args) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
|
||||
|
||||
// Recurse to the next argument.
|
||||
return combine(length, buffer_ptr, buffer_end, args...);
|
||||
}
|
||||
|
||||
/// Base case for recursive, variadic combining.
|
||||
///
|
||||
/// The base case when combining arguments recursively is reached when all
|
||||
/// arguments have been handled. It flushes the remaining buffer and
|
||||
/// constructs a hash_code.
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
|
||||
// Check whether the entire set of values fit in the buffer. If so, we'll
|
||||
// use the optimized short hashing routine and skip state entirely.
|
||||
if (length == 0)
|
||||
return hash_short(buffer, buffer_ptr - buffer, seed);
|
||||
|
||||
// Mix the final buffer, rotating it if we did a partial fill in order to
|
||||
// simulate doing a mix of the last 64-bytes. That is how the algorithm
|
||||
// works when we have a contiguous byte sequence, and we want to emulate
|
||||
// that here.
|
||||
std::rotate(buffer, buffer_ptr, buffer_end);
|
||||
|
||||
// Mix this chunk into the current state.
|
||||
state.mix(buffer);
|
||||
length += buffer_ptr - buffer;
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
/// Combine values into a single hash_code.
|
||||
///
|
||||
/// This routine accepts a varying number of arguments of any type. It will
|
||||
/// attempt to combine them into a single hash_code. For user-defined types it
|
||||
/// attempts to call a \see hash_value overload (via ADL) for the type. For
|
||||
/// integer and pointer types it directly combines their data into the
|
||||
/// resulting hash_code.
|
||||
///
|
||||
/// The result is suitable for returning from a user's hash_value
|
||||
/// *implementation* for their user-defined type. Consumers of a type should
|
||||
/// *not* call this routine, they should instead call 'hash_value'.
|
||||
template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
|
||||
// Recursively hash each argument using a helper class.
|
||||
::wpi::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
|
||||
}
|
||||
|
||||
// Implementation details for implementations of hash_value overloads provided
|
||||
// here.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// Helper to hash the value of a single integer.
|
||||
///
|
||||
/// Overloads for smaller integer types are not provided to ensure consistent
|
||||
/// behavior in the presence of integral promotions. Essentially,
|
||||
/// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
|
||||
inline hash_code hash_integer_value(uint64_t value) {
|
||||
// Similar to hash_4to8_bytes but using a seed instead of length.
|
||||
const uint64_t seed = get_execution_seed();
|
||||
const char *s = reinterpret_cast<const char *>(&value);
|
||||
const uint64_t a = fetch32(s);
|
||||
return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value) {
|
||||
return ::wpi::hashing::detail::hash_integer_value(
|
||||
static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T> hash_code hash_value(const T *ptr) {
|
||||
return ::wpi::hashing::detail::hash_integer_value(
|
||||
reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T, typename U>
|
||||
hash_code hash_value(const std::pair<T, U> &arg) {
|
||||
return hash_combine(arg.first, arg.second);
|
||||
}
|
||||
|
||||
// Implementation details for the hash_value overload for std::tuple<...>(...).
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
template <typename... Ts, std::size_t... Indices>
|
||||
hash_code hash_value_tuple_helper(const std::tuple<Ts...> &arg,
|
||||
std::index_sequence<Indices...>) {
|
||||
return hash_combine(std::get<Indices>(arg)...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
template <typename... Ts>
|
||||
hash_code hash_value(const std::tuple<Ts...> &arg) {
|
||||
// TODO: Use std::apply when LLVM starts using C++17.
|
||||
return ::wpi::hashing::detail::hash_value_tuple_helper(
|
||||
arg, typename std::index_sequence_for<Ts...>());
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg) {
|
||||
return hash_combine_range(arg.begin(), arg.end());
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
125
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ManagedStatic.h
vendored
Normal file
125
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ManagedStatic.h
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
//===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ManagedStatic class and the wpi_shutdown() function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MANAGEDSTATIC_H
|
||||
#define WPIUTIL_WPI_MANAGEDSTATIC_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// object_creator - Helper method for ManagedStatic.
|
||||
template <class C> struct object_creator {
|
||||
static void *call() { return new C(); }
|
||||
};
|
||||
|
||||
/// object_deleter - Helper method for ManagedStatic.
|
||||
///
|
||||
template <typename T> struct object_deleter {
|
||||
static void call(void *Ptr) { delete (T *)Ptr; }
|
||||
};
|
||||
template <typename T, size_t N> struct object_deleter<T[N]> {
|
||||
static void call(void *Ptr) { delete[](T *)Ptr; }
|
||||
};
|
||||
|
||||
// ManagedStatic must be initialized to zero, and it must *not* have a dynamic
|
||||
// initializer because managed statics are often created while running other
|
||||
// dynamic initializers. In standard C++11, the best way to accomplish this is
|
||||
// with a constexpr default constructor. However, different versions of the
|
||||
// Visual C++ compiler have had bugs where, even though the constructor may be
|
||||
// constexpr, a dynamic initializer may be emitted depending on optimization
|
||||
// settings. For the affected versions of MSVC, use the old linker
|
||||
// initialization pattern of not providing a constructor and leaving the fields
|
||||
// uninitialized. See http://llvm.org/PR41367 for details.
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1925) || defined(__clang__)
|
||||
#define LLVM_USE_CONSTEXPR_CTOR
|
||||
#endif
|
||||
|
||||
/// ManagedStaticBase - Common base class for ManagedStatic instances.
|
||||
class ManagedStaticBase {
|
||||
protected:
|
||||
#ifdef LLVM_USE_CONSTEXPR_CTOR
|
||||
mutable std::atomic<void *> Ptr{};
|
||||
mutable void (*DeleterFn)(void *) = nullptr;
|
||||
mutable const ManagedStaticBase *Next = nullptr;
|
||||
#else
|
||||
// This should only be used as a static variable, which guarantees that this
|
||||
// will be zero initialized.
|
||||
mutable std::atomic<void *> Ptr;
|
||||
mutable void (*DeleterFn)(void *);
|
||||
mutable const ManagedStaticBase *Next;
|
||||
#endif
|
||||
|
||||
void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
|
||||
|
||||
public:
|
||||
#ifdef LLVM_USE_CONSTEXPR_CTOR
|
||||
constexpr ManagedStaticBase() = default;
|
||||
#endif
|
||||
|
||||
/// isConstructed - Return true if this object has not been created yet.
|
||||
bool isConstructed() const { return Ptr != nullptr; }
|
||||
|
||||
void destroy() const;
|
||||
};
|
||||
|
||||
/// ManagedStatic - This transparently changes the behavior of global statics to
|
||||
/// be lazily constructed on demand (good for reducing startup times of dynamic
|
||||
/// libraries that link in LLVM components) and for making destruction be
|
||||
/// explicit through the wpi_shutdown() function call.
|
||||
///
|
||||
template <class C, class Creator = object_creator<C>,
|
||||
class Deleter = object_deleter<C>>
|
||||
class ManagedStatic : public ManagedStaticBase {
|
||||
public:
|
||||
// Accessors.
|
||||
C &operator*() {
|
||||
void *Tmp = Ptr.load(std::memory_order_acquire);
|
||||
if (!Tmp)
|
||||
RegisterManagedStatic(Creator::call, Deleter::call);
|
||||
|
||||
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
C *operator->() { return &**this; }
|
||||
|
||||
const C &operator*() const {
|
||||
void *Tmp = Ptr.load(std::memory_order_acquire);
|
||||
if (!Tmp)
|
||||
RegisterManagedStatic(Creator::call, Deleter::call);
|
||||
|
||||
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
const C *operator->() const { return &**this; }
|
||||
|
||||
// Extract the instance, leaving the ManagedStatic uninitialized. The
|
||||
// user is then responsible for the lifetime of the returned instance.
|
||||
C *claim() {
|
||||
return static_cast<C *>(Ptr.exchange(nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
|
||||
void wpi_shutdown();
|
||||
|
||||
/// wpi_shutdown_obj - This is a simple helper class that calls
|
||||
/// wpi_shutdown() when it is destroyed.
|
||||
struct wpi_shutdown_obj {
|
||||
wpi_shutdown_obj() = default;
|
||||
~wpi_shutdown_obj() { wpi_shutdown(); }
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_MANAGEDSTATIC_H
|
||||
239
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
vendored
Normal file
239
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a map that provides insertion order iteration. The
|
||||
// interface is purposefully minimal. The key is assumed to be cheap to copy
|
||||
// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in
|
||||
// a std::vector.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MAPVECTOR_H
|
||||
#define WPIUTIL_WPI_MAPVECTOR_H
|
||||
|
||||
#include "wpi/DenseMap.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// This class implements a map that also provides access to all stored values
|
||||
/// in a deterministic order. The values are kept in a std::vector and the
|
||||
/// mapping is done with DenseMap from Keys to indexes in that vector.
|
||||
template<typename KeyT, typename ValueT,
|
||||
typename MapType = DenseMap<KeyT, unsigned>,
|
||||
typename VectorType = std::vector<std::pair<KeyT, ValueT>>>
|
||||
class MapVector {
|
||||
MapType Map;
|
||||
VectorType Vector;
|
||||
|
||||
static_assert(
|
||||
std::is_integral<typename MapType::mapped_type>::value,
|
||||
"The mapped_type of the specified Map must be an integral type");
|
||||
|
||||
public:
|
||||
using value_type = typename VectorType::value_type;
|
||||
using size_type = typename VectorType::size_type;
|
||||
|
||||
using iterator = typename VectorType::iterator;
|
||||
using const_iterator = typename VectorType::const_iterator;
|
||||
using reverse_iterator = typename VectorType::reverse_iterator;
|
||||
using const_reverse_iterator = typename VectorType::const_reverse_iterator;
|
||||
|
||||
/// Clear the MapVector and return the underlying vector.
|
||||
VectorType takeVector() {
|
||||
Map.clear();
|
||||
return std::move(Vector);
|
||||
}
|
||||
|
||||
size_type size() const { return Vector.size(); }
|
||||
|
||||
/// Grow the MapVector so that it can contain at least \p NumEntries items
|
||||
/// before resizing again.
|
||||
void reserve(size_type NumEntries) {
|
||||
Map.reserve(NumEntries);
|
||||
Vector.reserve(NumEntries);
|
||||
}
|
||||
|
||||
iterator begin() { return Vector.begin(); }
|
||||
const_iterator begin() const { return Vector.begin(); }
|
||||
iterator end() { return Vector.end(); }
|
||||
const_iterator end() const { return Vector.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Vector.rbegin(); }
|
||||
const_reverse_iterator rbegin() const { return Vector.rbegin(); }
|
||||
reverse_iterator rend() { return Vector.rend(); }
|
||||
const_reverse_iterator rend() const { return Vector.rend(); }
|
||||
|
||||
bool empty() const {
|
||||
return Vector.empty();
|
||||
}
|
||||
|
||||
std::pair<KeyT, ValueT> &front() { return Vector.front(); }
|
||||
const std::pair<KeyT, ValueT> &front() const { return Vector.front(); }
|
||||
std::pair<KeyT, ValueT> &back() { return Vector.back(); }
|
||||
const std::pair<KeyT, ValueT> &back() const { return Vector.back(); }
|
||||
|
||||
void clear() {
|
||||
Map.clear();
|
||||
Vector.clear();
|
||||
}
|
||||
|
||||
void swap(MapVector &RHS) {
|
||||
std::swap(Map, RHS.Map);
|
||||
std::swap(Vector, RHS.Vector);
|
||||
}
|
||||
|
||||
ValueT &operator[](const KeyT &Key) {
|
||||
std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(Key, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
auto &I = Result.first->second;
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::make_pair(Key, ValueT()));
|
||||
I = Vector.size() - 1;
|
||||
}
|
||||
return Vector[I].second;
|
||||
}
|
||||
|
||||
// Returns a copy of the value. Only allowed if ValueT is copyable.
|
||||
ValueT lookup(const KeyT &Key) const {
|
||||
static_assert(std::is_copy_constructible<ValueT>::value,
|
||||
"Cannot call lookup() if ValueT is not copyable.");
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? ValueT() : Vector[Pos->second].second;
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
|
||||
std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
auto &I = Result.first->second;
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::make_pair(KV.first, KV.second));
|
||||
I = Vector.size() - 1;
|
||||
return std::make_pair(std::prev(end()), true);
|
||||
}
|
||||
return std::make_pair(begin() + I, false);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
|
||||
// Copy KV.first into the map, then move it into the vector.
|
||||
std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
auto &I = Result.first->second;
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::move(KV));
|
||||
I = Vector.size() - 1;
|
||||
return std::make_pair(std::prev(end()), true);
|
||||
}
|
||||
return std::make_pair(begin() + I, false);
|
||||
}
|
||||
|
||||
size_type count(const KeyT &Key) const {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? 0 : 1;
|
||||
}
|
||||
|
||||
iterator find(const KeyT &Key) {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? Vector.end() :
|
||||
(Vector.begin() + Pos->second);
|
||||
}
|
||||
|
||||
const_iterator find(const KeyT &Key) const {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? Vector.end() :
|
||||
(Vector.begin() + Pos->second);
|
||||
}
|
||||
|
||||
/// Remove the last element from the vector.
|
||||
void pop_back() {
|
||||
typename MapType::iterator Pos = Map.find(Vector.back().first);
|
||||
Map.erase(Pos);
|
||||
Vector.pop_back();
|
||||
}
|
||||
|
||||
/// Remove the element given by Iterator.
|
||||
///
|
||||
/// Returns an iterator to the element following the one which was removed,
|
||||
/// which may be end().
|
||||
///
|
||||
/// \note This is a deceivingly expensive operation (linear time). It's
|
||||
/// usually better to use \a remove_if() if possible.
|
||||
typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
|
||||
Map.erase(Iterator->first);
|
||||
auto Next = Vector.erase(Iterator);
|
||||
if (Next == Vector.end())
|
||||
return Next;
|
||||
|
||||
// Update indices in the map.
|
||||
size_t Index = Next - Vector.begin();
|
||||
for (auto &I : Map) {
|
||||
assert(I.second != Index && "Index was already erased!");
|
||||
if (I.second > Index)
|
||||
--I.second;
|
||||
}
|
||||
return Next;
|
||||
}
|
||||
|
||||
/// Remove all elements with the key value Key.
|
||||
///
|
||||
/// Returns the number of elements removed.
|
||||
size_type erase(const KeyT &Key) {
|
||||
auto Iterator = find(Key);
|
||||
if (Iterator == end())
|
||||
return 0;
|
||||
erase(Iterator);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Remove the elements that match the predicate.
|
||||
///
|
||||
/// Erase all elements that match \c Pred in a single pass. Takes linear
|
||||
/// time.
|
||||
template <class Predicate> void remove_if(Predicate Pred);
|
||||
};
|
||||
|
||||
template <typename KeyT, typename ValueT, typename MapType, typename VectorType>
|
||||
template <class Function>
|
||||
void MapVector<KeyT, ValueT, MapType, VectorType>::remove_if(Function Pred) {
|
||||
auto O = Vector.begin();
|
||||
for (auto I = O, E = Vector.end(); I != E; ++I) {
|
||||
if (Pred(*I)) {
|
||||
// Erase from the map.
|
||||
Map.erase(I->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (I != O) {
|
||||
// Move the value and update the index in the map.
|
||||
*O = std::move(*I);
|
||||
Map[O->first] = O - Vector.begin();
|
||||
}
|
||||
++O;
|
||||
}
|
||||
// Erase trailing entries in the vector.
|
||||
Vector.erase(O, Vector.end());
|
||||
}
|
||||
|
||||
/// A MapVector that performs no allocations if smaller than a certain
|
||||
/// size.
|
||||
template <typename KeyT, typename ValueT, unsigned N>
|
||||
struct SmallMapVector
|
||||
: MapVector<KeyT, ValueT, SmallDenseMap<KeyT, unsigned, N>,
|
||||
SmallVector<std::pair<KeyT, ValueT>, N>> {
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_MAPVECTOR_H
|
||||
955
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
vendored
Normal file
955
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
vendored
Normal file
@@ -0,0 +1,955 @@
|
||||
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful for math stuff.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MATHEXTRAS_H
|
||||
#define WPIUTIL_WPI_MATHEXTRAS_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Declare these intrinsics manually rather including intrin.h. It's very
|
||||
// expensive, and MathExtras.h is popular.
|
||||
// #include <intrin.h>
|
||||
extern "C" {
|
||||
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
|
||||
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
|
||||
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// The behavior an operation has on an input of 0.
|
||||
enum ZeroBehavior {
|
||||
/// The returned value is undefined.
|
||||
ZB_Undefined,
|
||||
/// The returned value is numeric_limits<T>::max()
|
||||
ZB_Max,
|
||||
/// The returned value is numeric_limits<T>::digits
|
||||
ZB_Width
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
|
||||
static unsigned count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
if (Val & 0x1)
|
||||
return 0;
|
||||
|
||||
// Bisection method.
|
||||
unsigned ZeroBits = 0;
|
||||
T Shift = std::numeric_limits<T>::digits >> 1;
|
||||
T Mask = (std::numeric_limits<T>::max)() >> Shift;
|
||||
while (Shift) {
|
||||
if ((Val & Mask) == 0) {
|
||||
Val >>= Shift;
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
Shift >>= 1;
|
||||
Mask >>= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
template <typename T> struct TrailingZerosCounter<T, 4> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
|
||||
return __builtin_ctz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct TrailingZerosCounter<T, 8> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
|
||||
return __builtin_ctzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward64(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the least significant bit to the most
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return wpi::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
|
||||
static unsigned count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
|
||||
// Bisection method.
|
||||
unsigned ZeroBits = 0;
|
||||
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
|
||||
T Tmp = Val >> Shift;
|
||||
if (Tmp)
|
||||
Val = Tmp;
|
||||
else
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
template <typename T> struct LeadingZerosCounter<T, 4> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
|
||||
return __builtin_clz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse(&Index, Val);
|
||||
return Index ^ 31;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct LeadingZerosCounter<T, 8> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
|
||||
return __builtin_clzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse64(&Index, Val);
|
||||
return Index ^ 63;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the most significant bit to the least
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return wpi::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
/// Get the index of the first set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
|
||||
return countTrailingZeros(Val, ZB_Undefined);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingOnes(unsigned N) {
|
||||
static_assert(std::is_unsigned<T>::value, "Invalid type!");
|
||||
const unsigned Bits = CHAR_BIT * sizeof(T);
|
||||
assert(N <= Bits && "Invalid bit index");
|
||||
return N == 0 ? 0 : (T(-1) >> (Bits - N));
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingOnes(unsigned N) {
|
||||
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingZeros(unsigned N) {
|
||||
return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingZeros(unsigned N) {
|
||||
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Get the index of the last set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
|
||||
// Use ^ instead of - because both gcc and llvm can remove the associated ^
|
||||
// in the __builtin_clz intrinsic on x86.
|
||||
return countLeadingZeros(Val, ZB_Undefined) ^
|
||||
(std::numeric_limits<T>::digits - 1);
|
||||
}
|
||||
|
||||
/// Macro compressed bit reversal table for 256 bits.
|
||||
///
|
||||
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
|
||||
static const unsigned char BitReverseTable256[256] = {
|
||||
#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
|
||||
#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
|
||||
#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
|
||||
R6(0), R6(2), R6(1), R6(3)
|
||||
#undef R2
|
||||
#undef R4
|
||||
#undef R6
|
||||
};
|
||||
|
||||
/// Reverse the bits in \p Val.
|
||||
template <typename T>
|
||||
T reverseBits(T Val) {
|
||||
unsigned char in[sizeof(Val)];
|
||||
unsigned char out[sizeof(Val)];
|
||||
std::memcpy(in, &Val, sizeof(Val));
|
||||
for (unsigned i = 0; i < sizeof(Val); ++i)
|
||||
out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
|
||||
std::memcpy(&Val, out, sizeof(Val));
|
||||
return Val;
|
||||
}
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse8)
|
||||
template<>
|
||||
inline uint8_t reverseBits<uint8_t>(uint8_t Val) {
|
||||
return __builtin_bitreverse8(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse16)
|
||||
template<>
|
||||
inline uint16_t reverseBits<uint16_t>(uint16_t Val) {
|
||||
return __builtin_bitreverse16(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse32)
|
||||
template<>
|
||||
inline uint32_t reverseBits<uint32_t>(uint32_t Val) {
|
||||
return __builtin_bitreverse32(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse64)
|
||||
template<>
|
||||
inline uint64_t reverseBits<uint64_t>(uint64_t Val) {
|
||||
return __builtin_bitreverse64(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE: The following support functions use the _32/_64 extensions instead of
|
||||
// type overloading so that signed and unsigned integers can be used without
|
||||
// ambiguity.
|
||||
|
||||
/// Return the high 32 bits of a 64 bit value.
|
||||
constexpr inline uint32_t Hi_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value >> 32);
|
||||
}
|
||||
|
||||
/// Return the low 32 bits of a 64 bit value.
|
||||
constexpr inline uint32_t Lo_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value);
|
||||
}
|
||||
|
||||
/// Make a 64-bit integer from a high / low pair of 32-bit integers.
|
||||
constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
|
||||
return ((uint64_t)High << 32) | (uint64_t)Low;
|
||||
}
|
||||
|
||||
/// Checks if an integer fits into the given bit width.
|
||||
template <unsigned N> constexpr inline bool isInt(int64_t x) {
|
||||
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
|
||||
}
|
||||
// Template specializations to get better code for common cases.
|
||||
template <> constexpr inline bool isInt<8>(int64_t x) {
|
||||
return static_cast<int8_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isInt<16>(int64_t x) {
|
||||
return static_cast<int16_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isInt<32>(int64_t x) {
|
||||
return static_cast<int32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a signed integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedInt(int64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
|
||||
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
|
||||
return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given bit width.
|
||||
///
|
||||
/// This is written as two functions rather than as simply
|
||||
///
|
||||
/// return N >= 64 || X < (UINT64_C(1) << N);
|
||||
///
|
||||
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
|
||||
/// left too many places.
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<(N < 64), bool> isUInt(uint64_t X) {
|
||||
static_assert(N > 0, "isUInt<0> doesn't make sense");
|
||||
return X < (UINT64_C(1) << (N));
|
||||
}
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Template specializations to get better code for common cases.
|
||||
template <> constexpr inline bool isUInt<8>(uint64_t x) {
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isUInt<16>(uint64_t x) {
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isUInt<32>(uint64_t x) {
|
||||
return static_cast<uint32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a unsigned integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedUInt(uint64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
|
||||
static_assert(N + S <= 64,
|
||||
"isShiftedUInt<N, S> with N + S > 64 is too wide.");
|
||||
// Per the two static_asserts above, S must be strictly less than 64. So
|
||||
// 1 << S is not undefined behavior.
|
||||
return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
|
||||
}
|
||||
|
||||
/// Gets the maximum value for a N-bit unsigned integer.
|
||||
inline uint64_t maxUIntN(uint64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
// uint64_t(1) << 64 is undefined behavior, so we can't do
|
||||
// (uint64_t(1) << N) - 1
|
||||
// without checking first that N != 64. But this works and doesn't have a
|
||||
// branch.
|
||||
return UINT64_MAX >> (64 - N);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
#endif
|
||||
|
||||
/// Gets the minimum value for a N-bit signed integer.
|
||||
inline int64_t minIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/// Gets the maximum value for a N-bit signed integer.
|
||||
inline int64_t maxIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
// This relies on two's complement wraparound when N == 64, so we convert to
|
||||
// int64_t only at the very end to avoid UB.
|
||||
return (UINT64_C(1) << (N - 1)) - 1;
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given (dynamic) bit width.
|
||||
inline bool isUIntN(unsigned N, uint64_t x) {
|
||||
return N >= 64 || x <= maxUIntN(N);
|
||||
}
|
||||
|
||||
/// Checks if an signed integer fits into the given (dynamic) bit width.
|
||||
inline bool isIntN(unsigned N, int64_t x) {
|
||||
return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
|
||||
}
|
||||
|
||||
/// Return true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (32 bit version).
|
||||
/// Ex. isMask_32(0x0000FFFFU) == true.
|
||||
constexpr inline bool isMask_32(uint32_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// Return true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (64 bit version).
|
||||
constexpr inline bool isMask_64(uint64_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
|
||||
constexpr inline bool isShiftedMask_32(uint32_t Value) {
|
||||
return Value && isMask_32((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (64 bit version.)
|
||||
constexpr inline bool isShiftedMask_64(uint64_t Value) {
|
||||
return Value && isMask_64((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0.
|
||||
/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
|
||||
constexpr inline bool isPowerOf2_32(uint32_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0 (64 bit edition.)
|
||||
constexpr inline bool isPowerOf2_64(uint64_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// Count the number of ones from the most significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countLeadingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
/// Count the number of ones from the least significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countTrailingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct PopulationCounter {
|
||||
static unsigned count(T Value) {
|
||||
// Generic version, forward to 32 bits.
|
||||
static_assert(SizeOfT <= 4, "Not implemented!");
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_popcount(Value);
|
||||
#else
|
||||
uint32_t v = Value;
|
||||
v = v - ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct PopulationCounter<T, 8> {
|
||||
static unsigned count(T Value) {
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_popcountll(Value);
|
||||
#else
|
||||
uint64_t v = Value;
|
||||
v = v - ((v >> 1) & 0x5555555555555555ULL);
|
||||
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
|
||||
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Count the number of set bits in a value.
|
||||
/// Ex. countPopulation(0xF000F000) = 8
|
||||
/// Returns 0 if the word is zero.
|
||||
template <typename T>
|
||||
inline unsigned countPopulation(T Value) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
|
||||
}
|
||||
|
||||
/// Compile time Log2.
|
||||
/// Valid only for positive powers of two.
|
||||
template <size_t kValue> constexpr inline size_t CTLog2() {
|
||||
static_assert(kValue > 0 && wpi::isPowerOf2_64(kValue),
|
||||
"Value is not a valid power of 2");
|
||||
return 1 + CTLog2<kValue / 2>();
|
||||
}
|
||||
|
||||
template <> constexpr inline size_t CTLog2<1>() { return 0; }
|
||||
|
||||
/// Return the log base 2 of the specified value.
|
||||
inline double Log2(double Value) {
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
|
||||
return __builtin_log(Value) / __builtin_log(2.0);
|
||||
#else
|
||||
return std::log2(Value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (32 bit edition.)
|
||||
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
|
||||
inline unsigned Log2_32(uint32_t Value) {
|
||||
return static_cast<unsigned>(31 - countLeadingZeros(Value));
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64(uint64_t Value) {
|
||||
return static_cast<unsigned>(63 - countLeadingZeros(Value));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
|
||||
/// (32 bit edition).
|
||||
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
|
||||
inline unsigned Log2_32_Ceil(uint32_t Value) {
|
||||
return static_cast<unsigned>(32 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64_Ceil(uint64_t Value) {
|
||||
return static_cast<unsigned>(64 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the greatest common divisor of the values using Euclid's algorithm.
|
||||
template <typename T>
|
||||
inline T greatestCommonDivisor(T A, T B) {
|
||||
while (B) {
|
||||
T Tmp = B;
|
||||
B = A % B;
|
||||
A = Tmp;
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
return greatestCommonDivisor<uint64_t>(A, B);
|
||||
}
|
||||
|
||||
/// This function takes a 64-bit integer and returns the bit equivalent double.
|
||||
inline double BitsToDouble(uint64_t Bits) {
|
||||
double D;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&D, &Bits, sizeof(Bits));
|
||||
return D;
|
||||
}
|
||||
|
||||
/// This function takes a 32-bit integer and returns the bit equivalent float.
|
||||
inline float BitsToFloat(uint32_t Bits) {
|
||||
float F;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&F, &Bits, sizeof(Bits));
|
||||
return F;
|
||||
}
|
||||
|
||||
/// This function takes a double and returns the bit equivalent 64-bit integer.
|
||||
/// Note that copying doubles around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint64_t DoubleToBits(double Double) {
|
||||
uint64_t Bits;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Double, sizeof(Double));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// This function takes a float and returns the bit equivalent 32-bit integer.
|
||||
/// Note that copying floats around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint32_t FloatToBits(float Float) {
|
||||
uint32_t Bits;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Float, sizeof(Float));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// A and B are either alignments or offsets. Return the minimum alignment that
|
||||
/// may be assumed after adding the two together.
|
||||
constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
|
||||
// The largest power of 2 that divides both A and B.
|
||||
//
|
||||
// Replace "-Value" by "1+~Value" in the following commented code to avoid
|
||||
// MSVC warning C4146
|
||||
// return (A | B) & -(A | B);
|
||||
return (A | B) & (1 + ~(A | B));
|
||||
}
|
||||
|
||||
/// Returns the next power of two (in 64-bits) that is strictly greater than A.
|
||||
/// Returns zero on overflow.
|
||||
inline uint64_t NextPowerOf2(uint64_t A) {
|
||||
A |= (A >> 1);
|
||||
A |= (A >> 2);
|
||||
A |= (A >> 4);
|
||||
A |= (A >> 8);
|
||||
A |= (A >> 16);
|
||||
A |= (A >> 32);
|
||||
return A + 1;
|
||||
}
|
||||
|
||||
/// Returns the power of two which is less than or equal to the given value.
|
||||
/// Essentially, it is a floor operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
if (!A) return 0;
|
||||
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
|
||||
}
|
||||
|
||||
/// Returns the power of two which is greater than or equal to the given value.
|
||||
/// Essentially, it is a ceil operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Ceil(uint64_t A) {
|
||||
if (!A)
|
||||
return 0;
|
||||
return NextPowerOf2(A - 1);
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
|
||||
///
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal
|
||||
/// integer that is greater than or equal to \p Value and equal to
|
||||
/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
|
||||
/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
|
||||
///
|
||||
/// Examples:
|
||||
/// \code
|
||||
/// alignTo(5, 8) = 8
|
||||
/// alignTo(17, 8) = 24
|
||||
/// alignTo(~0LL, 8) = 0
|
||||
/// alignTo(321, 255) = 510
|
||||
///
|
||||
/// alignTo(5, 8, 7) = 7
|
||||
/// alignTo(17, 8, 1) = 17
|
||||
/// alignTo(~0LL, 8, 3) = 3
|
||||
/// alignTo(321, 255, 42) = 552
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value + Align - 1 - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
|
||||
template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
|
||||
static_assert(Align != 0u, "Align must be non-zero");
|
||||
return (Value + Align - 1) / Align * Align;
|
||||
}
|
||||
|
||||
/// Returns the integer ceil(Numerator / Denominator).
|
||||
inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
|
||||
return alignTo(Numerator, Denominator) / Denominator;
|
||||
}
|
||||
|
||||
/// Returns the integer nearest(Numerator / Denominator).
|
||||
inline uint64_t divideNearest(uint64_t Numerator, uint64_t Denominator) {
|
||||
return (Numerator + (Denominator / 2)) / Denominator;
|
||||
}
|
||||
|
||||
/// Returns the largest uint64_t less than or equal to \p Value and is
|
||||
/// \p Skew mod \p Align. \p Align must be non-zero
|
||||
inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B <= 32.
|
||||
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 32, "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B <= 32.
|
||||
inline int32_t SignExtend32(uint32_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 32 && "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B <= 64.
|
||||
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 64, "Bit width out of range.");
|
||||
return int64_t(x << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B <= 64.
|
||||
inline int64_t SignExtend64(uint64_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 64 && "Bit width out of range.");
|
||||
return int64_t(X << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
|
||||
/// value of the result.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
|
||||
return X > Y ? (X - Y) : (Y - X);
|
||||
}
|
||||
|
||||
/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
// Hacker's Delight, p. 29
|
||||
T Z = X + Y;
|
||||
Overflowed = (Z < X || Z < Y);
|
||||
if (Overflowed)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
else
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
// Hacker's Delight, p. 30 has a different algorithm, but we don't use that
|
||||
// because it fails for uint16_t (where multiplication can have undefined
|
||||
// behavior due to promotion to int), and requires a division in addition
|
||||
// to the multiplication.
|
||||
|
||||
Overflowed = false;
|
||||
|
||||
// Log2(Z) would be either Log2Z or Log2Z + 1.
|
||||
// Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
|
||||
// will necessarily be less than Log2Max as desired.
|
||||
int Log2Z = Log2_64(X) + Log2_64(Y);
|
||||
const T Max = (std::numeric_limits<T>::max)();
|
||||
int Log2Max = Log2_64(Max);
|
||||
if (Log2Z < Log2Max) {
|
||||
return X * Y;
|
||||
}
|
||||
if (Log2Z > Log2Max) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
|
||||
// We're going to use the top bit, and maybe overflow one
|
||||
// bit past it. Multiply all but the bottom bit then add
|
||||
// that on at the end.
|
||||
T Z = (X >> 1) * Y;
|
||||
if (Z & ~(Max >> 1)) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
Z <<= 1;
|
||||
if (X & 1)
|
||||
return SaturatingAdd(Z, Y, ResultOverflowed);
|
||||
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
|
||||
/// the product. Clamp the result to the maximum representable value of T on
|
||||
/// overflow. ResultOverflowed indicates if the result is larger than the
|
||||
/// maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
T Product = SaturatingMultiply(X, Y, &Overflowed);
|
||||
if (Overflowed)
|
||||
return Product;
|
||||
|
||||
return SaturatingAdd(A, Product, &Overflowed);
|
||||
}
|
||||
|
||||
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
|
||||
extern const float huge_valf;
|
||||
|
||||
|
||||
/// Add two signed integers, computing the two's complement truncated result,
|
||||
/// returning true if overflow occured.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
|
||||
#if __has_builtin(__builtin_add_overflow)
|
||||
return __builtin_add_overflow(X, Y, &Result);
|
||||
#else
|
||||
// Perform the unsigned addition.
|
||||
using U = std::make_unsigned_t<T>;
|
||||
const U UX = static_cast<U>(X);
|
||||
const U UY = static_cast<U>(Y);
|
||||
const U UResult = UX + UY;
|
||||
|
||||
// Convert to signed.
|
||||
Result = static_cast<T>(UResult);
|
||||
|
||||
// Adding two positive numbers should result in a positive number.
|
||||
if (X > 0 && Y > 0)
|
||||
return Result <= 0;
|
||||
// Adding two negatives should result in a negative number.
|
||||
if (X < 0 && Y < 0)
|
||||
return Result >= 0;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Subtract two signed integers, computing the two's complement truncated
|
||||
/// result, returning true if an overflow ocurred.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
|
||||
#if __has_builtin(__builtin_sub_overflow)
|
||||
return __builtin_sub_overflow(X, Y, &Result);
|
||||
#else
|
||||
// Perform the unsigned addition.
|
||||
using U = std::make_unsigned_t<T>;
|
||||
const U UX = static_cast<U>(X);
|
||||
const U UY = static_cast<U>(Y);
|
||||
const U UResult = UX - UY;
|
||||
|
||||
// Convert to signed.
|
||||
Result = static_cast<T>(UResult);
|
||||
|
||||
// Subtracting a positive number from a negative results in a negative number.
|
||||
if (X <= 0 && Y > 0)
|
||||
return Result >= 0;
|
||||
// Subtracting a negative number from a positive results in a positive number.
|
||||
if (X >= 0 && Y < 0)
|
||||
return Result <= 0;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Multiply two signed integers, computing the two's complement truncated
|
||||
/// result, returning true if an overflow ocurred.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
|
||||
// Perform the unsigned multiplication on absolute values.
|
||||
using U = std::make_unsigned_t<T>;
|
||||
const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
|
||||
const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
|
||||
const U UResult = UX * UY;
|
||||
|
||||
// Convert to signed.
|
||||
const bool IsNegative = (X < 0) ^ (Y < 0);
|
||||
Result = IsNegative ? (0 - UResult) : UResult;
|
||||
|
||||
// If any of the args was 0, result is 0 and no overflow occurs.
|
||||
if (UX == 0 || UY == 0)
|
||||
return false;
|
||||
|
||||
// UX and UY are in [1, 2^n], where n is the number of digits.
|
||||
// Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
|
||||
// positive) divided by an argument compares to the other.
|
||||
if (IsNegative)
|
||||
return UX > (static_cast<U>((std::numeric_limits<T>::max)()) + U(1)) / UY;
|
||||
else
|
||||
return UX > (static_cast<U>((std::numeric_limits<T>::max)())) / UY;
|
||||
}
|
||||
|
||||
// Typesafe implementation of the signum function.
|
||||
// Returns -1 if negative, 1 if positive, 0 if 0.
|
||||
template <typename T>
|
||||
constexpr int sgn(T val) {
|
||||
return (T(0) < val) - (val < T(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly interpolates between two values.
|
||||
*
|
||||
* @param startValue The start value.
|
||||
* @param endValue The end value.
|
||||
* @param t The fraction for interpolation.
|
||||
*
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr T Lerp(const T& startValue, const T& endValue, double t) {
|
||||
return startValue + (endValue - startValue) * t;
|
||||
}
|
||||
} // End wpi namespace
|
||||
|
||||
#endif
|
||||
100
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h
vendored
Normal file
100
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This file defines counterparts of C library allocation functions defined in
|
||||
/// the namespace 'std'. The new allocation functions crash on allocation
|
||||
/// failure instead of returning null pointer.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MEMALLOC_H
|
||||
#define WPIUTIL_WPI_MEMALLOC_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
// Warning on NONNULL, report is not known to abort
|
||||
#pragma warning(disable : 6387)
|
||||
#pragma warning(disable : 28196)
|
||||
#pragma warning(disable : 28183)
|
||||
#endif
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
|
||||
void *Result = std::malloc(Sz);
|
||||
if (Result == nullptr) {
|
||||
// It is implementation-defined whether allocation occurs if the space
|
||||
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
|
||||
// non-zero, if the space requested was zero.
|
||||
if (Sz == 0)
|
||||
return safe_malloc(1);
|
||||
report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
|
||||
size_t Sz) {
|
||||
void *Result = std::calloc(Count, Sz);
|
||||
if (Result == nullptr) {
|
||||
// It is implementation-defined whether allocation occurs if the space
|
||||
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
|
||||
// non-zero, if the space requested was zero.
|
||||
if (Count == 0 || Sz == 0)
|
||||
return safe_malloc(1);
|
||||
report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
|
||||
void *Result = std::realloc(Ptr, Sz);
|
||||
if (Result == nullptr) {
|
||||
// It is implementation-defined whether allocation occurs if the space
|
||||
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
|
||||
// non-zero, if the space requested was zero.
|
||||
if (Sz == 0)
|
||||
return safe_malloc(1);
|
||||
report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Allocate a buffer of memory with the given size and alignment.
|
||||
///
|
||||
/// When the compiler supports aligned operator new, this will use it to to
|
||||
/// handle even over-aligned allocations.
|
||||
///
|
||||
/// However, this doesn't make any attempt to leverage the fancier techniques
|
||||
/// like posix_memalign due to portability. It is mostly intended to allow
|
||||
/// compatibility with platforms that, after aligned allocation was added, use
|
||||
/// reduced default alignment.
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
|
||||
allocate_buffer(size_t Size, size_t Alignment);
|
||||
|
||||
/// Deallocate a buffer of memory with the given size and alignment.
|
||||
///
|
||||
/// If supported, this will used the sized delete operator. Also if supported,
|
||||
/// this will pass the alignment to the delete operator.
|
||||
///
|
||||
/// The pointer must have been allocated with the corresponding new operator,
|
||||
/// most likely using the above helper.
|
||||
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
240
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h
vendored
Normal file
240
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
// 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.
|
||||
|
||||
//===--- MemoryBuffer.h - Memory Buffer Interface ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the MemoryBuffer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
#include "wpi/span.h"
|
||||
|
||||
// Duplicated from fs.h to avoid a dependency
|
||||
namespace fs {
|
||||
#if defined(_WIN32)
|
||||
// A Win32 HANDLE is a typedef of void*
|
||||
using file_t = void*;
|
||||
#else
|
||||
using file_t = int;
|
||||
#endif
|
||||
} // namespace fs
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class MemoryBufferRef;
|
||||
|
||||
/// This interface provides simple read-only access to a block of memory, and
|
||||
/// provides simple methods for reading files and standard input into a memory
|
||||
/// buffer.
|
||||
class MemoryBuffer {
|
||||
const uint8_t* m_bufferStart; // Start of the buffer.
|
||||
const uint8_t* m_bufferEnd; // End of the buffer.
|
||||
|
||||
protected:
|
||||
MemoryBuffer() = default;
|
||||
|
||||
void Init(const uint8_t* bufStart, const uint8_t* bufEnd);
|
||||
|
||||
public:
|
||||
MemoryBuffer(const MemoryBuffer&) = delete;
|
||||
MemoryBuffer& operator=(const MemoryBuffer&) = delete;
|
||||
virtual ~MemoryBuffer();
|
||||
|
||||
const uint8_t* begin() const { return m_bufferStart; }
|
||||
const uint8_t* end() const { return m_bufferEnd; }
|
||||
size_t size() const { return m_bufferEnd - m_bufferStart; }
|
||||
|
||||
span<const uint8_t> GetBuffer() const { return {begin(), end()}; }
|
||||
|
||||
/// Return an identifier for this buffer, typically the filename it was read
|
||||
/// from.
|
||||
virtual std::string_view GetBufferIdentifier() const {
|
||||
return "Unknown buffer";
|
||||
}
|
||||
|
||||
/// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
|
||||
/// if successful, otherwise returning null. If FileSize is specified, this
|
||||
/// means that the client knows that the file exists and that it has the
|
||||
/// specified size.
|
||||
static std::unique_ptr<MemoryBuffer> GetFile(std::string_view filename,
|
||||
std::error_code& ec,
|
||||
int64_t fileSize = -1);
|
||||
|
||||
/// Read all of the specified file into a MemoryBuffer as a stream
|
||||
/// (i.e. until EOF reached). This is useful for special files that
|
||||
/// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux).
|
||||
static std::unique_ptr<MemoryBuffer> GetFileAsStream(
|
||||
std::string_view filename, std::error_code& ec);
|
||||
|
||||
/// Given an already-open file descriptor, map some slice of it into a
|
||||
/// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize.
|
||||
static std::unique_ptr<MemoryBuffer> GetOpenFileSlice(
|
||||
fs::file_t f, std::string_view filename, std::error_code& ec,
|
||||
uint64_t mapSize, int64_t offset);
|
||||
|
||||
/// Given an already-open file descriptor, read the file and return a
|
||||
/// MemoryBuffer.
|
||||
static std::unique_ptr<MemoryBuffer> GetOpenFile(fs::file_t f,
|
||||
std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t fileSize);
|
||||
|
||||
/// Open the specified memory range as a MemoryBuffer.
|
||||
static std::unique_ptr<MemoryBuffer> GetMemBuffer(
|
||||
span<const uint8_t> inputData, std::string_view bufferName = "");
|
||||
|
||||
static std::unique_ptr<MemoryBuffer> GetMemBuffer(MemoryBufferRef ref);
|
||||
|
||||
/// Open the specified memory range as a MemoryBuffer, copying the contents
|
||||
/// and taking ownership of it.
|
||||
static std::unique_ptr<MemoryBuffer> GetMemBufferCopy(
|
||||
span<const uint8_t> inputData, std::string_view bufferName = "");
|
||||
|
||||
/// Map a subrange of the specified file as a MemoryBuffer.
|
||||
static std::unique_ptr<MemoryBuffer> GetFileSlice(std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t mapSize,
|
||||
uint64_t offset);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Provided for performance analysis.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// The kind of memory backing used to support the MemoryBuffer.
|
||||
enum BufferKind { MemoryBuffer_Malloc, MemoryBuffer_MMap };
|
||||
|
||||
/// Return information on the memory mechanism used to support the
|
||||
/// MemoryBuffer.
|
||||
virtual BufferKind GetBufferKind() const = 0;
|
||||
|
||||
MemoryBufferRef GetMemBufferRef() const;
|
||||
};
|
||||
|
||||
/// This class is an extension of MemoryBuffer, which allows copy-on-write
|
||||
/// access to the underlying contents. It only supports creation methods that
|
||||
/// are guaranteed to produce a writable buffer. For example, mapping a file
|
||||
/// read-only is not supported.
|
||||
class WritableMemoryBuffer : public MemoryBuffer {
|
||||
protected:
|
||||
WritableMemoryBuffer() = default;
|
||||
|
||||
public:
|
||||
using MemoryBuffer::begin;
|
||||
using MemoryBuffer::end;
|
||||
using MemoryBuffer::GetBuffer;
|
||||
using MemoryBuffer::size;
|
||||
|
||||
// const_cast is well-defined here, because the underlying buffer is
|
||||
// guaranteed to have been initialized with a mutable buffer.
|
||||
uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
|
||||
uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
|
||||
span<uint8_t> GetBuffer() { return {begin(), end()}; }
|
||||
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
|
||||
|
||||
/// Map a subrange of the specified file as a WritableMemoryBuffer.
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetFileSlice(
|
||||
std::string_view filename, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset);
|
||||
|
||||
/// Allocate a new MemoryBuffer of the specified size that is not initialized.
|
||||
/// Note that the caller should initialize the memory allocated by this
|
||||
/// method. The memory is owned by the MemoryBuffer object.
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetNewUninitMemBuffer(
|
||||
size_t size, std::string_view bufferName = "");
|
||||
|
||||
/// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
|
||||
/// that the caller need not initialize the memory allocated by this method.
|
||||
/// The memory is owned by the MemoryBuffer object.
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetNewMemBuffer(
|
||||
size_t size, std::string_view bufferName = "");
|
||||
|
||||
private:
|
||||
// Hide these base class factory function so one can't write
|
||||
// WritableMemoryBuffer::getXXX()
|
||||
// and be surprised that they got a read-only Buffer.
|
||||
using MemoryBuffer::GetFileAsStream;
|
||||
using MemoryBuffer::GetMemBuffer;
|
||||
using MemoryBuffer::GetMemBufferCopy;
|
||||
using MemoryBuffer::GetOpenFile;
|
||||
using MemoryBuffer::GetOpenFileSlice;
|
||||
};
|
||||
|
||||
/// This class is an extension of MemoryBuffer, which allows write access to
|
||||
/// the underlying contents and committing those changes to the original source.
|
||||
/// It only supports creation methods that are guaranteed to produce a writable
|
||||
/// buffer. For example, mapping a file read-only is not supported.
|
||||
class WriteThroughMemoryBuffer : public MemoryBuffer {
|
||||
protected:
|
||||
WriteThroughMemoryBuffer() = default;
|
||||
|
||||
public:
|
||||
using MemoryBuffer::begin;
|
||||
using MemoryBuffer::end;
|
||||
using MemoryBuffer::GetBuffer;
|
||||
using MemoryBuffer::size;
|
||||
|
||||
// const_cast is well-defined here, because the underlying buffer is
|
||||
// guaranteed to have been initialized with a mutable buffer.
|
||||
uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
|
||||
uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
|
||||
span<uint8_t> GetBuffer() { return {begin(), end()}; }
|
||||
|
||||
static std::unique_ptr<WriteThroughMemoryBuffer> GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
|
||||
|
||||
/// Map a subrange of the specified file as a ReadWriteMemoryBuffer.
|
||||
static std::unique_ptr<WriteThroughMemoryBuffer> GetFileSlice(
|
||||
std::string_view filename, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset);
|
||||
|
||||
private:
|
||||
// Hide these base class factory function so one can't write
|
||||
// WritableMemoryBuffer::getXXX()
|
||||
// and be surprised that they got a read-only Buffer.
|
||||
using MemoryBuffer::GetFileAsStream;
|
||||
using MemoryBuffer::GetMemBuffer;
|
||||
using MemoryBuffer::GetMemBufferCopy;
|
||||
using MemoryBuffer::GetOpenFile;
|
||||
using MemoryBuffer::GetOpenFileSlice;
|
||||
};
|
||||
|
||||
class MemoryBufferRef {
|
||||
span<const uint8_t> m_buffer;
|
||||
std::string_view m_id;
|
||||
|
||||
public:
|
||||
MemoryBufferRef() = default;
|
||||
MemoryBufferRef(MemoryBuffer& buffer) // NOLINT
|
||||
: m_buffer(buffer.GetBuffer()), m_id(buffer.GetBufferIdentifier()) {}
|
||||
MemoryBufferRef(span<const uint8_t> buffer, std::string_view id)
|
||||
: m_buffer(buffer), m_id(id) {}
|
||||
|
||||
span<const uint8_t> GetBuffer() const { return m_buffer; }
|
||||
|
||||
std::string_view GetBufferIdentifier() const { return m_id; }
|
||||
|
||||
const uint8_t* begin() const { return m_buffer.begin(); }
|
||||
const uint8_t* end() const { return m_buffer.end(); }
|
||||
size_t size() const { return m_buffer.size(); }
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
232
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
vendored
Normal file
232
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerIntPair class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
#define WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T> struct DenseMapInfo;
|
||||
template <typename PointerT, unsigned IntBits, typename PtrTraits>
|
||||
struct PointerIntPairInfo;
|
||||
|
||||
/// PointerIntPair - This class implements a pair of a pointer and small
|
||||
/// integer. It is designed to represent this in the space required by one
|
||||
/// pointer by bitmangling the integer into the low part of the pointer. This
|
||||
/// can only be done for small integers: typically up to 3 bits, but it depends
|
||||
/// on the number of bits available according to PointerLikeTypeTraits for the
|
||||
/// type.
|
||||
///
|
||||
/// Note that PointerIntPair always puts the IntVal part in the highest bits
|
||||
/// possible. For example, PointerIntPair<void*, 1, bool> will put the bit for
|
||||
/// the bool into bit #2, not bit #0, which allows the low two bits to be used
|
||||
/// for something else. For example, this allows:
|
||||
/// PointerIntPair<PointerIntPair<void*, 1, bool>, 1, bool>
|
||||
/// ... and the two bools will land in different bits.
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType = unsigned,
|
||||
typename PtrTraits = PointerLikeTypeTraits<PointerTy>,
|
||||
typename Info = PointerIntPairInfo<PointerTy, IntBits, PtrTraits>>
|
||||
class PointerIntPair {
|
||||
// Used by MSVC visualizer and generally helpful for debugging/visualizing.
|
||||
using InfoTy = Info;
|
||||
intptr_t Value = 0;
|
||||
|
||||
public:
|
||||
constexpr PointerIntPair() = default;
|
||||
|
||||
PointerIntPair(PointerTy PtrVal, IntType IntVal) {
|
||||
setPointerAndInt(PtrVal, IntVal);
|
||||
}
|
||||
|
||||
explicit PointerIntPair(PointerTy PtrVal) { initWithPointer(PtrVal); }
|
||||
|
||||
PointerTy getPointer() const { return Info::getPointer(Value); }
|
||||
|
||||
IntType getInt() const { return (IntType)Info::getInt(Value); }
|
||||
|
||||
void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updatePointer(Value, PtrVal);
|
||||
}
|
||||
|
||||
void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updatePointer(0, PtrVal);
|
||||
}
|
||||
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
|
||||
static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
PointerTy const *getAddrOfPointer() const {
|
||||
return const_cast<PointerIntPair *>(this)->getAddrOfPointer();
|
||||
}
|
||||
|
||||
PointerTy *getAddrOfPointer() {
|
||||
assert(Value == reinterpret_cast<intptr_t>(getPointer()) &&
|
||||
"Can only return the address if IntBits is cleared and "
|
||||
"PtrTraits doesn't change the pointer");
|
||||
return reinterpret_cast<PointerTy *>(&Value);
|
||||
}
|
||||
|
||||
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
|
||||
|
||||
void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
|
||||
Value = reinterpret_cast<intptr_t>(Val);
|
||||
}
|
||||
|
||||
static PointerIntPair getFromOpaqueValue(void *V) {
|
||||
PointerIntPair P;
|
||||
P.setFromOpaqueValue(V);
|
||||
return P;
|
||||
}
|
||||
|
||||
// Allow PointerIntPairs to be created from const void * if and only if the
|
||||
// pointer type could be created from a const void *.
|
||||
static PointerIntPair getFromOpaqueValue(const void *V) {
|
||||
(void)PtrTraits::getFromVoidPointer(V);
|
||||
return getFromOpaqueValue(const_cast<void *>(V));
|
||||
}
|
||||
|
||||
bool operator==(const PointerIntPair &RHS) const {
|
||||
return Value == RHS.Value;
|
||||
}
|
||||
|
||||
bool operator!=(const PointerIntPair &RHS) const {
|
||||
return Value != RHS.Value;
|
||||
}
|
||||
|
||||
bool operator<(const PointerIntPair &RHS) const { return Value < RHS.Value; }
|
||||
bool operator>(const PointerIntPair &RHS) const { return Value > RHS.Value; }
|
||||
|
||||
bool operator<=(const PointerIntPair &RHS) const {
|
||||
return Value <= RHS.Value;
|
||||
}
|
||||
|
||||
bool operator>=(const PointerIntPair &RHS) const {
|
||||
return Value >= RHS.Value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename PointerT, unsigned IntBits, typename PtrTraits>
|
||||
struct PointerIntPairInfo {
|
||||
static_assert(PtrTraits::NumLowBitsAvailable <
|
||||
std::numeric_limits<uintptr_t>::digits,
|
||||
"cannot use a pointer type that has all bits free");
|
||||
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
|
||||
"PointerIntPair with integer size too large for pointer");
|
||||
enum MaskAndShiftConstants : uintptr_t {
|
||||
/// PointerBitMask - The bits that come from the pointer.
|
||||
PointerBitMask =
|
||||
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
|
||||
|
||||
/// IntShift - The number of low bits that we reserve for other uses, and
|
||||
/// keep zero.
|
||||
IntShift = (uintptr_t)PtrTraits::NumLowBitsAvailable - IntBits,
|
||||
|
||||
/// IntMask - This is the unshifted mask for valid bits of the int type.
|
||||
IntMask = (uintptr_t)(((intptr_t)1 << IntBits) - 1),
|
||||
|
||||
// ShiftedIntMask - This is the bits for the integer shifted in place.
|
||||
ShiftedIntMask = (uintptr_t)(IntMask << IntShift)
|
||||
};
|
||||
|
||||
static PointerT getPointer(intptr_t Value) {
|
||||
return PtrTraits::getFromVoidPointer(
|
||||
reinterpret_cast<void *>(Value & PointerBitMask));
|
||||
}
|
||||
|
||||
static intptr_t getInt(intptr_t Value) {
|
||||
return (Value >> IntShift) & IntMask;
|
||||
}
|
||||
|
||||
static intptr_t updatePointer(intptr_t OrigValue, PointerT Ptr) {
|
||||
intptr_t PtrWord =
|
||||
reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr));
|
||||
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||
"Pointer is not sufficiently aligned");
|
||||
// Preserve all low bits, just update the pointer.
|
||||
return PtrWord | (OrigValue & ~PointerBitMask);
|
||||
}
|
||||
|
||||
static intptr_t updateInt(intptr_t OrigValue, intptr_t Int) {
|
||||
intptr_t IntWord = static_cast<intptr_t>(Int);
|
||||
assert((IntWord & ~IntMask) == 0 && "Integer too large for field");
|
||||
|
||||
// Preserve all bits other than the ones we are updating.
|
||||
return (OrigValue & ~ShiftedIntMask) | IntWord << IntShift;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide specialization of DenseMapInfo for PointerIntPair.
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType>
|
||||
struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> {
|
||||
using Ty = PointerIntPair<PointerTy, IntBits, IntType>;
|
||||
|
||||
static Ty getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable;
|
||||
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||
}
|
||||
|
||||
static Ty getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
||||
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(Ty V) {
|
||||
uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue());
|
||||
return unsigned(IV) ^ unsigned(IV >> 9);
|
||||
}
|
||||
|
||||
static bool isEqual(const Ty &LHS, const Ty &RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Teach SmallPtrSet that PointerIntPair is "basically a pointer".
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType,
|
||||
typename PtrTraits>
|
||||
struct PointerLikeTypeTraits<
|
||||
PointerIntPair<PointerTy, IntBits, IntType, PtrTraits>> {
|
||||
static inline void *
|
||||
getAsVoidPointer(const PointerIntPair<PointerTy, IntBits, IntType> &P) {
|
||||
return P.getOpaqueValue();
|
||||
}
|
||||
|
||||
static inline PointerIntPair<PointerTy, IntBits, IntType>
|
||||
getFromVoidPointer(void *P) {
|
||||
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
static inline PointerIntPair<PointerTy, IntBits, IntType>
|
||||
getFromVoidPointer(const void *P) {
|
||||
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
PtrTraits::NumLowBitsAvailable - IntBits;
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
vendored
Normal file
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerLikeTypeTraits class. This allows data
|
||||
// structures to reason about pointers and other things that are pointer sized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
|
||||
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// A traits type that is used to handle pointer types and things that are just
|
||||
/// wrappers for pointers as a uniform entity.
|
||||
template <typename T> struct PointerLikeTypeTraits;
|
||||
|
||||
namespace detail {
|
||||
/// A tiny meta function to compute the log2 of a compile time constant.
|
||||
template <size_t N>
|
||||
struct ConstantLog2
|
||||
: std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
|
||||
template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
|
||||
|
||||
// Provide a trait to check if T is pointer-like.
|
||||
template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
// sizeof(T) is valid only for a complete T.
|
||||
template <typename T>
|
||||
struct HasPointerLikeTypeTraits<
|
||||
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename T> struct IsPointerLike {
|
||||
static const bool value = HasPointerLikeTypeTraits<T>::value;
|
||||
};
|
||||
|
||||
template <typename T> struct IsPointerLike<T *> {
|
||||
static const bool value = true;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// Provide PointerLikeTypeTraits for non-cvr pointers.
|
||||
template <typename T> struct PointerLikeTypeTraits<T *> {
|
||||
static inline void *getAsVoidPointer(T *P) { return P; }
|
||||
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
|
||||
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
detail::ConstantLog2<alignof(T)>::value;
|
||||
};
|
||||
|
||||
template <> struct PointerLikeTypeTraits<void *> {
|
||||
static inline void *getAsVoidPointer(void *P) { return P; }
|
||||
static inline void *getFromVoidPointer(void *P) { return P; }
|
||||
|
||||
/// Note, we assume here that void* is related to raw malloc'ed memory and
|
||||
/// that malloc returns objects at least 4-byte aligned. However, this may be
|
||||
/// wrong, or pointers may be from something other than malloc. In this case,
|
||||
/// you should specify a real typed pointer or avoid this template.
|
||||
///
|
||||
/// All clients should use assertions to do a run-time check to ensure that
|
||||
/// this is actually true.
|
||||
static constexpr int NumLowBitsAvailable = 2;
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const things.
|
||||
template <typename T> struct PointerLikeTypeTraits<const T> {
|
||||
typedef PointerLikeTypeTraits<T> NonConst;
|
||||
|
||||
static inline const void *getAsVoidPointer(const T P) {
|
||||
return NonConst::getAsVoidPointer(P);
|
||||
}
|
||||
static inline const T getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void *>(P));
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const pointers.
|
||||
template <typename T> struct PointerLikeTypeTraits<const T *> {
|
||||
typedef PointerLikeTypeTraits<T *> NonConst;
|
||||
|
||||
static inline const void *getAsVoidPointer(const T *P) {
|
||||
return NonConst::getAsVoidPointer(const_cast<T *>(P));
|
||||
}
|
||||
static inline const T *getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void *>(P));
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for uintptr_t.
|
||||
template <> struct PointerLikeTypeTraits<uintptr_t> {
|
||||
static inline void *getAsVoidPointer(uintptr_t P) {
|
||||
return reinterpret_cast<void *>(P);
|
||||
}
|
||||
static inline uintptr_t getFromVoidPointer(void *P) {
|
||||
return reinterpret_cast<uintptr_t>(P);
|
||||
}
|
||||
// No bits are available!
|
||||
static constexpr int NumLowBitsAvailable = 0;
|
||||
};
|
||||
|
||||
/// Provide suitable custom traits struct for function pointers.
|
||||
///
|
||||
/// Function pointers can't be directly given these traits as functions can't
|
||||
/// have their alignment computed with `alignof` and we need different casting.
|
||||
///
|
||||
/// To rely on higher alignment for a specialized use, you can provide a
|
||||
/// customized form of this template explicitly with higher alignment, and
|
||||
/// potentially use alignment attributes on functions to satisfy that.
|
||||
template <int Alignment, typename FunctionPointerT>
|
||||
struct FunctionPointerLikeTypeTraits {
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
detail::ConstantLog2<Alignment>::value;
|
||||
static inline void *getAsVoidPointer(FunctionPointerT P) {
|
||||
assert((reinterpret_cast<uintptr_t>(P) &
|
||||
~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
|
||||
"Alignment not satisfied for an actual function pointer!");
|
||||
return reinterpret_cast<void *>(P);
|
||||
}
|
||||
static inline FunctionPointerT getFromVoidPointer(void *P) {
|
||||
return reinterpret_cast<FunctionPointerT>(P);
|
||||
}
|
||||
};
|
||||
|
||||
/// Provide a default specialization for function pointers that assumes 4-byte
|
||||
/// alignment.
|
||||
///
|
||||
/// We assume here that functions used with this are always at least 4-byte
|
||||
/// aligned. This means that, for example, thumb functions won't work or systems
|
||||
/// with weird unaligned function pointers won't work. But all practical systems
|
||||
/// we support satisfy this requirement.
|
||||
template <typename ReturnT, typename... ParamTs>
|
||||
struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)>
|
||||
: FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
292
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
vendored
Normal file
292
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerUnion class, which is a discriminated union of
|
||||
// pointer types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_POINTERUNION_H
|
||||
#define WPIUTIL_WPI_POINTERUNION_H
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/PointerIntPair.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T> struct PointerUnionTypeSelectorReturn {
|
||||
using Return = T;
|
||||
};
|
||||
|
||||
/// Get a type based on whether two types are the same or not.
|
||||
///
|
||||
/// For:
|
||||
///
|
||||
/// \code
|
||||
/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
|
||||
/// \endcode
|
||||
///
|
||||
/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
|
||||
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
|
||||
struct PointerUnionTypeSelector {
|
||||
using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
|
||||
};
|
||||
|
||||
template <typename T, typename RET_EQ, typename RET_NE>
|
||||
struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
|
||||
using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
|
||||
};
|
||||
|
||||
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
|
||||
struct PointerUnionTypeSelectorReturn<
|
||||
PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
|
||||
using Return =
|
||||
typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
|
||||
};
|
||||
|
||||
namespace pointer_union_detail {
|
||||
/// Determine the number of bits required to store integers with values < n.
|
||||
/// This is ceil(log2(n)).
|
||||
constexpr int bitsRequired(unsigned n) {
|
||||
return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
|
||||
}
|
||||
|
||||
template <typename... Ts> constexpr int lowBitsAvailable() {
|
||||
return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
|
||||
}
|
||||
|
||||
/// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
|
||||
/// is the index of T in Us, or sizeof...(Us) if T does not appear in the
|
||||
/// list.
|
||||
template <typename T, typename ...Us> struct TypeIndex;
|
||||
template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> {
|
||||
static constexpr int Index = 0;
|
||||
};
|
||||
template <typename T, typename U, typename... Us>
|
||||
struct TypeIndex<T, U, Us...> {
|
||||
static constexpr int Index = 1 + TypeIndex<T, Us...>::Index;
|
||||
};
|
||||
template <typename T> struct TypeIndex<T> {
|
||||
static constexpr int Index = 0;
|
||||
};
|
||||
|
||||
/// Find the first type in a list of types.
|
||||
template <typename T, typename...> struct GetFirstType {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
|
||||
/// for the template arguments.
|
||||
template <typename ...PTs> class PointerUnionUIntTraits {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(void *P) { return P; }
|
||||
static inline void *getFromVoidPointer(void *P) { return P; }
|
||||
static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
|
||||
};
|
||||
|
||||
template <typename Derived, typename ValTy, int I, typename ...Types>
|
||||
class PointerUnionMembers;
|
||||
|
||||
template <typename Derived, typename ValTy, int I>
|
||||
class PointerUnionMembers<Derived, ValTy, I> {
|
||||
protected:
|
||||
ValTy Val;
|
||||
PointerUnionMembers() = default;
|
||||
PointerUnionMembers(ValTy Val) : Val(Val) {}
|
||||
|
||||
friend struct PointerLikeTypeTraits<Derived>;
|
||||
};
|
||||
|
||||
template <typename Derived, typename ValTy, int I, typename Type,
|
||||
typename ...Types>
|
||||
class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
|
||||
: public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
|
||||
using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
|
||||
public:
|
||||
using Base::Base;
|
||||
PointerUnionMembers() = default;
|
||||
PointerUnionMembers(Type V)
|
||||
: Base(ValTy(const_cast<void *>(
|
||||
PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
|
||||
I)) {}
|
||||
|
||||
using Base::operator=;
|
||||
Derived &operator=(Type V) {
|
||||
this->Val = ValTy(
|
||||
const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
|
||||
I);
|
||||
return static_cast<Derived &>(*this);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// A discriminated union of two or more pointer types, with the discriminator
|
||||
/// in the low bit of the pointer.
|
||||
///
|
||||
/// This implementation is extremely efficient in space due to leveraging the
|
||||
/// low bits of the pointer, while exposing a natural and type-safe API.
|
||||
///
|
||||
/// Common use patterns would be something like this:
|
||||
/// PointerUnion<int*, float*> P;
|
||||
/// P = (int*)0;
|
||||
/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
|
||||
/// X = P.get<int*>(); // ok.
|
||||
/// Y = P.get<float*>(); // runtime assertion failure.
|
||||
/// Z = P.get<double*>(); // compile time failure.
|
||||
/// P = (float*)0;
|
||||
/// Y = P.get<float*>(); // ok.
|
||||
/// X = P.get<int*>(); // runtime assertion failure.
|
||||
template <typename... PTs>
|
||||
class PointerUnion
|
||||
: public pointer_union_detail::PointerUnionMembers<
|
||||
PointerUnion<PTs...>,
|
||||
PointerIntPair<
|
||||
void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
|
||||
pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
|
||||
0, PTs...> {
|
||||
// The first type is special because we want to directly cast a pointer to a
|
||||
// default-initialized union to a pointer to the first type. But we don't
|
||||
// want PointerUnion to be a 'template <typename First, typename ...Rest>'
|
||||
// because it's much more convenient to have a name for the whole pack. So
|
||||
// split off the first type here.
|
||||
using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
|
||||
using Base = typename PointerUnion::PointerUnionMembers;
|
||||
|
||||
public:
|
||||
PointerUnion() = default;
|
||||
|
||||
PointerUnion(std::nullptr_t) : PointerUnion() {}
|
||||
using Base::Base;
|
||||
|
||||
/// Test if the pointer held in the union is null, regardless of
|
||||
/// which type it is.
|
||||
bool isNull() const { return !this->Val.getPointer(); }
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
/// Test if the Union currently holds the type matching T.
|
||||
template <typename T> bool is() const {
|
||||
constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index;
|
||||
static_assert(Index < sizeof...(PTs),
|
||||
"PointerUnion::is<T> given type not in the union");
|
||||
return this->Val.getInt() == Index;
|
||||
}
|
||||
|
||||
/// Returns the value of the specified pointer type.
|
||||
///
|
||||
/// If the specified pointer type is incorrect, assert.
|
||||
template <typename T> T get() const {
|
||||
assert(is<T>() && "Invalid accessor called");
|
||||
return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
|
||||
}
|
||||
|
||||
/// Returns the current pointer if it is of the specified pointer type,
|
||||
/// otherwise returns null.
|
||||
template <typename T> T dyn_cast() const {
|
||||
if (is<T>())
|
||||
return get<T>();
|
||||
return T();
|
||||
}
|
||||
|
||||
/// If the union is set to the first pointer type get an address pointing to
|
||||
/// it.
|
||||
First const *getAddrOfPtr1() const {
|
||||
return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
|
||||
}
|
||||
|
||||
/// If the union is set to the first pointer type get an address pointing to
|
||||
/// it.
|
||||
First *getAddrOfPtr1() {
|
||||
assert(is<First>() && "Val is not the first pointer");
|
||||
assert(
|
||||
PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
|
||||
this->Val.getPointer() &&
|
||||
"Can't get the address because PointerLikeTypeTraits changes the ptr");
|
||||
return const_cast<First *>(
|
||||
reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
|
||||
}
|
||||
|
||||
/// Assignment from nullptr which just clears the union.
|
||||
const PointerUnion &operator=(std::nullptr_t) {
|
||||
this->Val.initWithPointer(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assignment from elements of the union.
|
||||
using Base::operator=;
|
||||
|
||||
void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
|
||||
static inline PointerUnion getFromOpaqueValue(void *VP) {
|
||||
PointerUnion V;
|
||||
V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
|
||||
return V;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ...PTs>
|
||||
bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template <typename ...PTs>
|
||||
bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template <typename ...PTs>
|
||||
bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
|
||||
// # low bits available = min(PT1bits,PT2bits)-1.
|
||||
template <typename ...PTs>
|
||||
struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
|
||||
static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
|
||||
return P.getOpaqueValue();
|
||||
}
|
||||
|
||||
static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
|
||||
return PointerUnion<PTs...>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
// The number of bits available are the min of the pointer types minus the
|
||||
// bits needed for the discriminator.
|
||||
static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
|
||||
PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
// Teach DenseMap how to use PointerUnions as keys.
|
||||
template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
|
||||
using Union = PointerUnion<PTs...>;
|
||||
using FirstInfo =
|
||||
DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
|
||||
|
||||
static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
|
||||
|
||||
static inline Union getTombstoneKey() {
|
||||
return Union(FirstInfo::getTombstoneKey());
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const Union &UnionVal) {
|
||||
intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
|
||||
return DenseMapInfo<intptr_t>::getHashValue(key);
|
||||
}
|
||||
|
||||
static bool isEqual(const Union &LHS, const Union &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_POINTERUNION_H
|
||||
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
vendored
Normal file
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef WPIUTIL_WPI_REVERSEITERATION_H
|
||||
#define WPIUTIL_WPI_REVERSEITERATION_H
|
||||
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template<class T = void *>
|
||||
bool shouldReverseIterate() {
|
||||
#if LLVM_ENABLE_REVERSE_ITERATION
|
||||
return detail::IsPointerLike<T>::value;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
82
wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
vendored
Normal file
82
wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
//===- STLForwardCompat.h - Library features from future STLs ------C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains library features backported from future STL versions.
|
||||
//
|
||||
// These should be replaced with their STL counterparts as the C++ version LLVM
|
||||
// is compiled with is updated.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
#define WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++17
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct negation // NOLINT(readability-identifier-naming)
|
||||
: std::integral_constant<bool, !bool(T::value)> {};
|
||||
|
||||
template <typename...>
|
||||
struct conjunction // NOLINT(readability-identifier-naming)
|
||||
: std::true_type {};
|
||||
template <typename B1> struct conjunction<B1> : B1 {};
|
||||
template <typename B1, typename... Bn>
|
||||
struct conjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
|
||||
|
||||
template <typename...>
|
||||
struct disjunction // NOLINT(readability-identifier-naming)
|
||||
: std::false_type {};
|
||||
template <typename B1> struct disjunction<B1> : B1 {};
|
||||
template <typename B1, typename... Bn>
|
||||
struct disjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type {};
|
||||
|
||||
struct in_place_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_t() = default;
|
||||
};
|
||||
/// \warning This must not be odr-used, as it cannot be made \c inline in C++14.
|
||||
constexpr in_place_t in_place; // NOLINT(readability-identifier-naming)
|
||||
|
||||
template <typename T>
|
||||
struct in_place_type_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_type_t() = default;
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
struct in_place_index_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_index_t() = default;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++20
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct remove_cvref // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
using type = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t // NOLINT(readability-identifier-naming)
|
||||
= typename wpi::remove_cvref<T>::type;
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
517
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
vendored
Normal file
517
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallPtrSet class. See the doxygen comment for
|
||||
// SmallPtrSetImplBase for more details on the algorithm used.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SMALLPTRSET_H
|
||||
#define WPIUTIL_WPI_SMALLPTRSET_H
|
||||
|
||||
#include "wpi/EpochTracker.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ReverseIteration.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||
/// for small and one for large sets.
|
||||
///
|
||||
/// Small sets use an array of pointers allocated in the SmallPtrSet object,
|
||||
/// which is treated as a simple array of pointers. When a pointer is added to
|
||||
/// the set, the array is scanned to see if the element already exists, if not
|
||||
/// the element is 'pushed back' onto the array. If we run out of space in the
|
||||
/// array, we grow into the 'large set' case. SmallSet should be used when the
|
||||
/// sets are often small. In this case, no memory allocation is used, and only
|
||||
/// light-weight and cache-efficient scanning is used.
|
||||
///
|
||||
/// Large sets use a classic exponentially-probed hash table. Empty buckets are
|
||||
/// represented with an illegal pointer value (-1) to allow null pointers to be
|
||||
/// inserted. Tombstones are represented with another illegal pointer value
|
||||
/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
|
||||
/// more. When this happens, the table is doubled in size.
|
||||
///
|
||||
class SmallPtrSetImplBase : public DebugEpochBase {
|
||||
friend class SmallPtrSetIteratorImpl;
|
||||
|
||||
protected:
|
||||
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
||||
const void **SmallArray;
|
||||
/// CurArray - This is the current set of buckets. If equal to SmallArray,
|
||||
/// then the set is in 'small mode'.
|
||||
const void **CurArray;
|
||||
/// CurArraySize - The allocated size of CurArray, always a power of two.
|
||||
unsigned CurArraySize;
|
||||
|
||||
/// Number of elements in CurArray that contain a value or are a tombstone.
|
||||
/// If small, all these elements are at the beginning of CurArray and the rest
|
||||
/// is uninitialized.
|
||||
unsigned NumNonEmpty;
|
||||
/// Number of tombstones in CurArray.
|
||||
unsigned NumTombstones;
|
||||
|
||||
// Helpers to copy and move construct a SmallPtrSet.
|
||||
SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that);
|
||||
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallArray(SmallStorage), CurArray(SmallStorage),
|
||||
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
|
||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||
"Initial size must be a power of two!");
|
||||
}
|
||||
|
||||
~SmallPtrSetImplBase() {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
}
|
||||
|
||||
public:
|
||||
using size_type = unsigned;
|
||||
|
||||
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
|
||||
|
||||
LLVM_NODISCARD bool empty() const { return size() == 0; }
|
||||
size_type size() const { return NumNonEmpty - NumTombstones; }
|
||||
|
||||
void clear() {
|
||||
incrementEpoch();
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
// shrink the array.
|
||||
if (!isSmall()) {
|
||||
if (size() * 4 < CurArraySize && CurArraySize > 32)
|
||||
return shrink_and_clear();
|
||||
// Fill the array with empty markers.
|
||||
memset(CurArray, -1, CurArraySize * sizeof(void *));
|
||||
}
|
||||
|
||||
NumNonEmpty = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
|
||||
|
||||
static void *getEmptyMarker() {
|
||||
// Note that -1 is chosen to make clear() efficiently implementable with
|
||||
// memset and because it's not a valid pointer value.
|
||||
return reinterpret_cast<void*>(-1);
|
||||
}
|
||||
|
||||
const void **EndPointer() const {
|
||||
return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
|
||||
}
|
||||
|
||||
/// insert_imp - This returns true if the pointer was new to the set, false if
|
||||
/// it was already in the set. This is hidden from the client so that the
|
||||
/// derived class can check that the right type of pointer is passed in.
|
||||
std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
|
||||
if (isSmall()) {
|
||||
// Check to see if it is already in the set.
|
||||
const void **LastTombstone = nullptr;
|
||||
for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
|
||||
APtr != E; ++APtr) {
|
||||
const void *Value = *APtr;
|
||||
if (Value == Ptr)
|
||||
return std::make_pair(APtr, false);
|
||||
if (Value == getTombstoneMarker())
|
||||
LastTombstone = APtr;
|
||||
}
|
||||
|
||||
// Did we find any tombstone marker?
|
||||
if (LastTombstone != nullptr) {
|
||||
*LastTombstone = Ptr;
|
||||
--NumTombstones;
|
||||
incrementEpoch();
|
||||
return std::make_pair(LastTombstone, true);
|
||||
}
|
||||
|
||||
// Nope, there isn't. If we stay small, just 'pushback' now.
|
||||
if (NumNonEmpty < CurArraySize) {
|
||||
SmallArray[NumNonEmpty++] = Ptr;
|
||||
incrementEpoch();
|
||||
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
|
||||
}
|
||||
// Otherwise, hit the big set case, which will call grow.
|
||||
}
|
||||
return insert_imp_big(Ptr);
|
||||
}
|
||||
|
||||
/// erase_imp - If the set contains the specified pointer, remove it and
|
||||
/// return true, otherwise return false. This is hidden from the client so
|
||||
/// that the derived class can check that the right type of pointer is passed
|
||||
/// in.
|
||||
bool erase_imp(const void * Ptr) {
|
||||
const void *const *P = find_imp(Ptr);
|
||||
if (P == EndPointer())
|
||||
return false;
|
||||
|
||||
const void **Loc = const_cast<const void **>(P);
|
||||
assert(*Loc == Ptr && "broken find!");
|
||||
*Loc = getTombstoneMarker();
|
||||
NumTombstones++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the raw pointer needed to construct an iterator. If element not
|
||||
/// found, this will be EndPointer. Otherwise, it will be a pointer to the
|
||||
/// slot which stores Ptr;
|
||||
const void *const * find_imp(const void * Ptr) const {
|
||||
if (isSmall()) {
|
||||
// Linear search for the item.
|
||||
for (const void *const *APtr = SmallArray,
|
||||
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
|
||||
if (*APtr == Ptr)
|
||||
return APtr;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
// Big set case.
|
||||
auto *Bucket = FindBucketFor(Ptr);
|
||||
if (*Bucket == Ptr)
|
||||
return Bucket;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isSmall() const { return CurArray == SmallArray; }
|
||||
|
||||
std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
|
||||
|
||||
const void * const *FindBucketFor(const void *Ptr) const;
|
||||
void shrink_and_clear();
|
||||
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
void Grow(unsigned NewSize);
|
||||
|
||||
protected:
|
||||
/// swap - Swaps the elements of two sets.
|
||||
/// Note: This method assumes that both sets have the same small size.
|
||||
void swap(SmallPtrSetImplBase &RHS);
|
||||
|
||||
void CopyFrom(const SmallPtrSetImplBase &RHS);
|
||||
void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
|
||||
private:
|
||||
/// Code shared by MoveFrom() and move constructor.
|
||||
void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
/// Code shared by CopyFrom() and copy constructor.
|
||||
void CopyHelper(const SmallPtrSetImplBase &RHS);
|
||||
};
|
||||
|
||||
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||
/// instances of SmallPtrSetIterator.
|
||||
class SmallPtrSetIteratorImpl {
|
||||
protected:
|
||||
const void *const *Bucket;
|
||||
const void *const *End;
|
||||
|
||||
public:
|
||||
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
|
||||
: Bucket(BP), End(E) {
|
||||
if (shouldReverseIterate()) {
|
||||
RetreatIfNotValid();
|
||||
return;
|
||||
}
|
||||
AdvanceIfNotValid();
|
||||
}
|
||||
|
||||
bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
return Bucket == RHS.Bucket;
|
||||
}
|
||||
bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
return Bucket != RHS.Bucket;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
|
||||
/// that is. This is guaranteed to stop because the end() bucket is marked
|
||||
/// valid.
|
||||
void AdvanceIfNotValid() {
|
||||
assert(Bucket <= End);
|
||||
while (Bucket != End &&
|
||||
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||
++Bucket;
|
||||
}
|
||||
void RetreatIfNotValid() {
|
||||
assert(Bucket >= End);
|
||||
while (Bucket != End &&
|
||||
(Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
|
||||
--Bucket;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
||||
template <typename PtrTy>
|
||||
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
|
||||
DebugEpochBase::HandleBase {
|
||||
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
|
||||
|
||||
public:
|
||||
using value_type = PtrTy;
|
||||
using reference = PtrTy;
|
||||
using pointer = PtrTy;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
|
||||
const DebugEpochBase &Epoch)
|
||||
: SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
|
||||
|
||||
// Most methods are provided by the base class.
|
||||
|
||||
const PtrTy operator*() const {
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
if (shouldReverseIterate()) {
|
||||
assert(Bucket > End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
|
||||
}
|
||||
assert(Bucket < End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
|
||||
}
|
||||
|
||||
inline SmallPtrSetIterator& operator++() { // Preincrement
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
if (shouldReverseIterate()) {
|
||||
--Bucket;
|
||||
RetreatIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
++Bucket;
|
||||
AdvanceIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSetIterator operator++(int) { // Postincrement
|
||||
SmallPtrSetIterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
|
||||
/// power of two (which means N itself if N is already a power of two).
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo;
|
||||
|
||||
/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a
|
||||
/// helper template used to implement RoundUpToPowerOfTwo.
|
||||
template<unsigned N, bool isPowerTwo>
|
||||
struct RoundUpToPowerOfTwoH {
|
||||
enum { Val = N };
|
||||
};
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwoH<N, false> {
|
||||
enum {
|
||||
// We could just use NextVal = N+1, but this converges faster. N|(N-1) sets
|
||||
// the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
|
||||
Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
|
||||
};
|
||||
};
|
||||
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo {
|
||||
enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
|
||||
};
|
||||
|
||||
/// A templated base class for \c SmallPtrSet which provides the
|
||||
/// typesafe interface that is common across all small sizes.
|
||||
///
|
||||
/// This is particularly useful for passing around between interface boundaries
|
||||
/// to avoid encoding a particular small size in the interface boundary.
|
||||
template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
|
||||
using PtrTraits = PointerLikeTypeTraits<PtrType>;
|
||||
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
|
||||
|
||||
protected:
|
||||
// Forward constructors to the base.
|
||||
using SmallPtrSetImplBase::SmallPtrSetImplBase;
|
||||
|
||||
public:
|
||||
using iterator = SmallPtrSetIterator<PtrType>;
|
||||
using const_iterator = SmallPtrSetIterator<PtrType>;
|
||||
using key_type = ConstPtrType;
|
||||
using value_type = PtrType;
|
||||
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
|
||||
|
||||
/// Inserts Ptr if and only if there is no element in the container equal to
|
||||
/// Ptr. The bool component of the returned pair is true if and only if the
|
||||
/// insertion takes place, and the iterator component of the pair points to
|
||||
/// the element equal to Ptr.
|
||||
std::pair<iterator, bool> insert(PtrType Ptr) {
|
||||
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return std::make_pair(makeIterator(p.first), p.second);
|
||||
}
|
||||
|
||||
/// Insert the given pointer with an iterator hint that is ignored. This is
|
||||
/// identical to calling insert(Ptr), but allows SmallPtrSet to be used by
|
||||
/// std::insert_iterator and std::inserter().
|
||||
iterator insert(iterator, PtrType Ptr) {
|
||||
return insert(Ptr).first;
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
/// true, otherwise return false.
|
||||
bool erase(PtrType Ptr) {
|
||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
}
|
||||
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||
size_type count(ConstPtrType Ptr) const {
|
||||
return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
|
||||
}
|
||||
iterator find(ConstPtrType Ptr) const {
|
||||
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
|
||||
}
|
||||
bool contains(ConstPtrType Ptr) const {
|
||||
return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<PtrType> IL) {
|
||||
insert(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
if (shouldReverseIterate())
|
||||
return makeIterator(EndPointer() - 1);
|
||||
return makeIterator(CurArray);
|
||||
}
|
||||
iterator end() const { return makeIterator(EndPointer()); }
|
||||
|
||||
private:
|
||||
/// Create an iterator that dereferences to same place as the given pointer.
|
||||
iterator makeIterator(const void *const *P) const {
|
||||
if (shouldReverseIterate())
|
||||
return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
|
||||
return iterator(P, EndPointer(), *this);
|
||||
}
|
||||
};
|
||||
|
||||
/// Equality comparison for SmallPtrSet.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each value from LHS is also in
|
||||
/// RHS, and that no additional values are in RHS.
|
||||
template <typename PtrType>
|
||||
bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
|
||||
const SmallPtrSetImpl<PtrType> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (const auto *KV : LHS)
|
||||
if (!RHS.count(KV))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inequality comparison for SmallPtrSet.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS).
|
||||
template <typename PtrType>
|
||||
bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
|
||||
const SmallPtrSetImpl<PtrType> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||
/// power of two if it is not already a power of two. See the comments above
|
||||
/// SmallPtrSetImplBase for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(SmallSize <= 32, "SmallSize should be small");
|
||||
|
||||
using BaseT = SmallPtrSetImpl<PtrType>;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
||||
const void *SmallStorage[SmallSizePowTwo];
|
||||
|
||||
public:
|
||||
SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
|
||||
SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
|
||||
SmallPtrSet(SmallPtrSet &&that)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
|
||||
|
||||
template<typename It>
|
||||
SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
SmallPtrSet(std::initializer_list<PtrType> IL)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
if (&RHS != this)
|
||||
this->CopyFrom(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
|
||||
if (&RHS != this)
|
||||
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(std::initializer_list<PtrType> IL) {
|
||||
this->clear();
|
||||
this->insert(IL.begin(), IL.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap - Swaps the elements of two sets.
|
||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
SmallPtrSetImplBase::swap(RHS);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
|
||||
/// Implement std::swap in terms of SmallPtrSet swap.
|
||||
template<class T, unsigned N>
|
||||
inline void swap(wpi::SmallPtrSet<T, N> &LHS, wpi::SmallPtrSet<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
|
||||
} // end namespace std
|
||||
|
||||
#endif // WPIUTIL_WPI_SMALLPTRSET_H
|
||||
285
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
vendored
Normal file
285
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallSet class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SMALLSET_H
|
||||
#define WPIUTIL_WPI_SMALLSET_H
|
||||
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallSetIterator - This class implements a const_iterator for SmallSet by
|
||||
/// delegating to the underlying SmallVector or Set iterators.
|
||||
template <typename T, unsigned N, typename C>
|
||||
class SmallSetIterator
|
||||
: public iterator_facade_base<SmallSetIterator<T, N, C>,
|
||||
std::forward_iterator_tag, T> {
|
||||
private:
|
||||
using SetIterTy = typename std::set<T, C>::const_iterator;
|
||||
using VecIterTy = typename SmallVector<T, N>::const_iterator;
|
||||
using SelfTy = SmallSetIterator<T, N, C>;
|
||||
|
||||
/// Iterators to the parts of the SmallSet containing the data. They are set
|
||||
/// depending on isSmall.
|
||||
union {
|
||||
SetIterTy SetIter;
|
||||
VecIterTy VecIter;
|
||||
};
|
||||
|
||||
bool isSmall;
|
||||
|
||||
public:
|
||||
SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), isSmall(false) {}
|
||||
|
||||
SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), isSmall(true) {}
|
||||
|
||||
// Spell out destructor, copy/move constructor and assignment operators for
|
||||
// MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
|
||||
~SmallSetIterator() {
|
||||
if (isSmall)
|
||||
VecIter.~VecIterTy();
|
||||
else
|
||||
SetIter.~SetIterTy();
|
||||
}
|
||||
|
||||
SmallSetIterator(const SmallSetIterator &Other) : isSmall(Other.isSmall) {
|
||||
if (isSmall)
|
||||
VecIter = Other.VecIter;
|
||||
else
|
||||
// Use placement new, to make sure SetIter is properly constructed, even
|
||||
// if it is not trivially copy-able (e.g. in MSVC).
|
||||
new (&SetIter) SetIterTy(Other.SetIter);
|
||||
}
|
||||
|
||||
SmallSetIterator(SmallSetIterator &&Other) : isSmall(Other.isSmall) {
|
||||
if (isSmall)
|
||||
VecIter = std::move(Other.VecIter);
|
||||
else
|
||||
// Use placement new, to make sure SetIter is properly constructed, even
|
||||
// if it is not trivially copy-able (e.g. in MSVC).
|
||||
new (&SetIter) SetIterTy(std::move(Other.SetIter));
|
||||
}
|
||||
|
||||
SmallSetIterator& operator=(const SmallSetIterator& Other) {
|
||||
// Call destructor for SetIter, so it gets properly destroyed if it is
|
||||
// not trivially destructible in case we are setting VecIter.
|
||||
if (!isSmall)
|
||||
SetIter.~SetIterTy();
|
||||
|
||||
isSmall = Other.isSmall;
|
||||
if (isSmall)
|
||||
VecIter = Other.VecIter;
|
||||
else
|
||||
new (&SetIter) SetIterTy(Other.SetIter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallSetIterator& operator=(SmallSetIterator&& Other) {
|
||||
// Call destructor for SetIter, so it gets properly destroyed if it is
|
||||
// not trivially destructible in case we are setting VecIter.
|
||||
if (!isSmall)
|
||||
SetIter.~SetIterTy();
|
||||
|
||||
isSmall = Other.isSmall;
|
||||
if (isSmall)
|
||||
VecIter = std::move(Other.VecIter);
|
||||
else
|
||||
new (&SetIter) SetIterTy(std::move(Other.SetIter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const SmallSetIterator &RHS) const {
|
||||
if (isSmall != RHS.isSmall)
|
||||
return false;
|
||||
if (isSmall)
|
||||
return VecIter == RHS.VecIter;
|
||||
return SetIter == RHS.SetIter;
|
||||
}
|
||||
|
||||
SmallSetIterator &operator++() { // Preincrement
|
||||
if (isSmall)
|
||||
VecIter++;
|
||||
else
|
||||
SetIter++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T &operator*() const { return isSmall ? *VecIter : *SetIter; }
|
||||
};
|
||||
|
||||
/// SmallSet - This maintains a set of unique values, optimizing for the case
|
||||
/// when the set is small (less than N). In this case, the set can be
|
||||
/// maintained with no mallocs. If the set gets large, we expand to using an
|
||||
/// std::set to maintain reasonable lookup times.
|
||||
template <typename T, unsigned N, typename C = std::less<T>>
|
||||
class SmallSet {
|
||||
/// Use a SmallVector to hold the elements here (even though it will never
|
||||
/// reach its 'large' stage) to avoid calling the default ctors of elements
|
||||
/// we will never use.
|
||||
SmallVector<T, N> Vector;
|
||||
std::set<T, C> Set;
|
||||
|
||||
using VIterator = typename SmallVector<T, N>::const_iterator;
|
||||
using mutable_iterator = typename SmallVector<T, N>::iterator;
|
||||
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(N <= 32, "N should be small");
|
||||
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using const_iterator = SmallSetIterator<T, N, C>;
|
||||
|
||||
SmallSet() = default;
|
||||
|
||||
LLVM_NODISCARD bool empty() const {
|
||||
return Vector.empty() && Set.empty();
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return isSmall() ? Vector.size() : Set.size();
|
||||
}
|
||||
|
||||
/// count - Return 1 if the element is in the set, 0 otherwise.
|
||||
size_type count(const T &V) const {
|
||||
if (isSmall()) {
|
||||
// Since the collection is small, just do a linear search.
|
||||
return vfind(V) == Vector.end() ? 0 : 1;
|
||||
} else {
|
||||
return Set.count(V);
|
||||
}
|
||||
}
|
||||
|
||||
/// insert - Insert an element into the set if it isn't already there.
|
||||
/// Returns true if the element is inserted (it was not in the set before).
|
||||
/// The first value of the returned pair is unused and provided for
|
||||
/// partial compatibility with the standard library self-associative container
|
||||
/// concept.
|
||||
// FIXME: Add iterators that abstract over the small and large form, and then
|
||||
// return those here.
|
||||
std::pair<std::nullopt_t, bool> insert(const T &V) {
|
||||
if (!isSmall())
|
||||
return std::make_pair(std::nullopt, Set.insert(V).second);
|
||||
|
||||
VIterator I = vfind(V);
|
||||
if (I != Vector.end()) // Don't reinsert if it already exists.
|
||||
return std::make_pair(std::nullopt, false);
|
||||
if (Vector.size() < N) {
|
||||
Vector.push_back(V);
|
||||
return std::make_pair(std::nullopt, true);
|
||||
}
|
||||
|
||||
// Otherwise, grow from vector to set.
|
||||
while (!Vector.empty()) {
|
||||
Set.insert(Vector.back());
|
||||
Vector.pop_back();
|
||||
}
|
||||
Set.insert(V);
|
||||
return std::make_pair(std::nullopt, true);
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
bool erase(const T &V) {
|
||||
if (!isSmall())
|
||||
return Set.erase(V);
|
||||
for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V) {
|
||||
Vector.erase(I);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Vector.clear();
|
||||
Set.clear();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (isSmall())
|
||||
return {Vector.begin()};
|
||||
return {Set.begin()};
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (isSmall())
|
||||
return {Vector.end()};
|
||||
return {Set.end()};
|
||||
}
|
||||
|
||||
/// Check if the SmallSet contains the given element.
|
||||
bool contains(const T &V) const {
|
||||
if (isSmall())
|
||||
return vfind(V) != Vector.end();
|
||||
return Set.find(V) != Set.end();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isSmall() const { return Set.empty(); }
|
||||
|
||||
VIterator vfind(const T &V) const {
|
||||
for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V)
|
||||
return I;
|
||||
return Vector.end();
|
||||
}
|
||||
};
|
||||
|
||||
/// If this set is of pointer values, transparently switch over to using
|
||||
/// SmallPtrSet for performance.
|
||||
template <typename PointeeType, unsigned N>
|
||||
class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
|
||||
|
||||
/// Equality comparison for SmallSet.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each element is also a member
|
||||
/// of RHS, and that RHS contains no additional values.
|
||||
/// Equivalent to N calls to RHS.count.
|
||||
/// For small-set mode amortized complexity is O(N^2)
|
||||
/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
|
||||
/// every hash collides).
|
||||
template <typename T, unsigned LN, unsigned RN, typename C>
|
||||
bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
// All elements in LHS must also be in RHS
|
||||
return std::all_of(LHS.begin(), LHS.end(), [&RHS](const T &E) { return RHS.count(E); });
|
||||
}
|
||||
|
||||
/// Inequality comparison for SmallSet.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
|
||||
template <typename T, unsigned LN, unsigned RN, typename C>
|
||||
bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_SMALLSET_H
|
||||
215
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
vendored
Normal file
215
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallString class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SMALLSTRING_H
|
||||
#define WPIUTIL_WPI_SMALLSTRING_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallString - A SmallString is just a SmallVector with methods and accessors
|
||||
/// that make it work better as a string (e.g. operator+ etc).
|
||||
template<unsigned InternalLen>
|
||||
class SmallString : public SmallVector<char, InternalLen> {
|
||||
public:
|
||||
/// Default ctor - Initialize to empty.
|
||||
SmallString() = default;
|
||||
|
||||
/// Initialize from a std::string_view.
|
||||
SmallString(std::string_view S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
|
||||
|
||||
/// Initialize by concatenating a list of std::string_views.
|
||||
SmallString(std::initializer_list<std::string_view> Refs)
|
||||
: SmallVector<char, InternalLen>() {
|
||||
this->append(Refs);
|
||||
}
|
||||
|
||||
/// Initialize with a range.
|
||||
template<typename ItTy>
|
||||
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
|
||||
|
||||
/// @}
|
||||
/// @name String Assignment
|
||||
/// @{
|
||||
|
||||
using SmallVector<char, InternalLen>::assign;
|
||||
|
||||
/// Assign from a std::string_view.
|
||||
void assign(std::string_view RHS) {
|
||||
SmallVectorImpl<char>::assign(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Assign from a list of std::string_views.
|
||||
void assign(std::initializer_list<std::string_view> Refs) {
|
||||
this->clear();
|
||||
append(Refs);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Concatenation
|
||||
/// @{
|
||||
|
||||
using SmallVector<char, InternalLen>::append;
|
||||
|
||||
/// Append from a std::string_view.
|
||||
void append(std::string_view RHS) {
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Append from a list of std::string_views.
|
||||
void append(std::initializer_list<std::string_view> Refs) {
|
||||
size_t SizeNeeded = this->size();
|
||||
for (std::string_view Ref : Refs)
|
||||
SizeNeeded += Ref.size();
|
||||
this->reserve(SizeNeeded);
|
||||
auto CurEnd = this->end();
|
||||
for (std::string_view Ref : Refs) {
|
||||
this->uninitialized_copy(Ref.begin(), Ref.end(), CurEnd);
|
||||
CurEnd += Ref.size();
|
||||
}
|
||||
this->set_size(SizeNeeded);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Comparison
|
||||
/// @{
|
||||
|
||||
/// Compare two strings; the result is -1, 0, or 1 if this string is
|
||||
/// lexicographically less than, equal to, or greater than the \p RHS.
|
||||
int compare(std::string_view RHS) const {
|
||||
return str().compare(RHS);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Searching
|
||||
/// @{
|
||||
|
||||
/// find - Search for the first character \p C in the string.
|
||||
///
|
||||
/// \return - The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
return str().find(C, From);
|
||||
}
|
||||
|
||||
/// Search for the first string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t find(std::string_view Str, size_t From = 0) const {
|
||||
return str().find(Str, From);
|
||||
}
|
||||
|
||||
/// Search for the last character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t rfind(char C, size_t From = std::string_view::npos) const {
|
||||
return str().rfind(C, From);
|
||||
}
|
||||
|
||||
/// Search for the last string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t rfind(std::string_view Str) const {
|
||||
return str().rfind(Str);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is \p C, or npos if not
|
||||
/// found. Same as find.
|
||||
size_t find_first_of(char C, size_t From = 0) const {
|
||||
return str().find_first_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is in \p Chars, or npos if
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_of(std::string_view Chars, size_t From = 0) const {
|
||||
return str().find_first_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is not \p C or npos if not
|
||||
/// found.
|
||||
size_t find_first_not_of(char C, size_t From = 0) const {
|
||||
return str().find_first_not_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is not in the string
|
||||
/// \p Chars, or npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_not_of(std::string_view Chars, size_t From = 0) const {
|
||||
return str().find_first_not_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
size_t find_last_of(char C, size_t From = std::string_view::npos) const {
|
||||
return str().find_last_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is in \p C, or npos if not
|
||||
/// found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_last_of(
|
||||
std::string_view Chars, size_t From = std::string_view::npos) const {
|
||||
return str().find_last_of(Chars, From);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// Extra methods.
|
||||
|
||||
/// Explicit conversion to std::string_view.
|
||||
std::string_view str() const { return std::string_view(this->begin(), this->size()); }
|
||||
|
||||
// TODO: Make this const, if it's safe...
|
||||
const char* c_str() {
|
||||
this->push_back(0);
|
||||
this->pop_back();
|
||||
return this->data();
|
||||
}
|
||||
|
||||
/// Implicit conversion to std::string_view.
|
||||
operator std::string_view() const { return str(); }
|
||||
|
||||
/// Explicit conversion to std::string.
|
||||
std::string string() const { return {this->begin(), this->size()}; }
|
||||
|
||||
/// Implicit conversion to std::string.
|
||||
operator std::string() const { return string(); }
|
||||
|
||||
// Extra operators.
|
||||
SmallString &operator=(std::string_view RHS) {
|
||||
this->assign(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallString &operator+=(std::string_view RHS) {
|
||||
this->append(RHS.begin(), RHS.end());
|
||||
return *this;
|
||||
}
|
||||
SmallString &operator+=(char C) {
|
||||
this->push_back(C);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_SMALLSTRING_H
|
||||
1276
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
vendored
Normal file
1276
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h
vendored
Normal file
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
|
||||
//===- SmallVectorMemoryBuffer.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares a wrapper class to hold the memory into which an
|
||||
// object will be generated.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/MemoryBuffer.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallVector-backed MemoryBuffer instance.
|
||||
///
|
||||
/// This class enables efficient construction of MemoryBuffers from SmallVector
|
||||
/// instances.
|
||||
class SmallVectorMemoryBuffer : public MemoryBuffer {
|
||||
public:
|
||||
/// Construct an SmallVectorMemoryBuffer from the given SmallVector
|
||||
/// r-value.
|
||||
SmallVectorMemoryBuffer(SmallVectorImpl<uint8_t>&& sv) // NOLINT
|
||||
: m_sv(std::move(sv)), m_bufferName("<in-memory object>") {
|
||||
Init(this->m_sv.begin(), this->m_sv.end());
|
||||
}
|
||||
|
||||
/// Construct a named SmallVectorMemoryBuffer from the given
|
||||
/// SmallVector r-value and StringRef.
|
||||
SmallVectorMemoryBuffer(SmallVectorImpl<uint8_t>&& sv, std::string_view name)
|
||||
: m_sv(std::move(sv)), m_bufferName(name) {
|
||||
Init(this->m_sv.begin(), this->m_sv.end());
|
||||
}
|
||||
|
||||
// Key function.
|
||||
~SmallVectorMemoryBuffer() override;
|
||||
|
||||
std::string_view GetBufferIdentifier() const override { return m_bufferName; }
|
||||
|
||||
BufferKind GetBufferKind() const override { return MemoryBuffer_Malloc; }
|
||||
|
||||
private:
|
||||
SmallVector<uint8_t, 0> m_sv;
|
||||
std::string m_bufferName;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
712
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
vendored
Normal file
712
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
vendored
Normal file
@@ -0,0 +1,712 @@
|
||||
// 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.
|
||||
|
||||
//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful when dealing with strings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
/// hexdigit - Return the hexadecimal character for the
|
||||
/// given number \p X (which should be less than 16).
|
||||
constexpr char hexdigit(unsigned X, bool LowerCase = false) noexcept {
|
||||
const char HexChar = LowerCase ? 'a' : 'A';
|
||||
return X < 10 ? '0' + X : HexChar + X - 10;
|
||||
}
|
||||
|
||||
/// Interpret the given character \p C as a hexadecimal digit and return its
|
||||
/// value.
|
||||
///
|
||||
/// If \p C is not a valid hex digit, -1U is returned.
|
||||
constexpr unsigned hexDigitValue(char C) noexcept {
|
||||
if (C >= '0' && C <= '9') {
|
||||
return C - '0';
|
||||
}
|
||||
if (C >= 'a' && C <= 'f') {
|
||||
return C - 'a' + 10U;
|
||||
}
|
||||
if (C >= 'A' && C <= 'F') {
|
||||
return C - 'A' + 10U;
|
||||
}
|
||||
return (std::numeric_limits<unsigned>::max)();
|
||||
}
|
||||
|
||||
/// Checks if character \p C is one of the 10 decimal digits.
|
||||
constexpr bool isDigit(char C) noexcept {
|
||||
return C >= '0' && C <= '9';
|
||||
}
|
||||
|
||||
/// Checks if character \p C is a hexadecimal numeric character.
|
||||
constexpr bool isHexDigit(char C) noexcept {
|
||||
return hexDigitValue(C) != (std::numeric_limits<unsigned>::max)();
|
||||
}
|
||||
|
||||
/// Checks if character \p C is a valid letter as classified by "C" locale.
|
||||
constexpr bool isAlpha(char C) noexcept {
|
||||
return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z');
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is either a decimal digit or an uppercase or
|
||||
/// lowercase letter as classified by "C" locale.
|
||||
constexpr bool isAlnum(char C) noexcept {
|
||||
return isAlpha(C) || isDigit(C);
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is valid ASCII (high bit is zero).
|
||||
constexpr bool isASCII(char C) noexcept {
|
||||
return static_cast<unsigned char>(C) <= 127;
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is printable.
|
||||
///
|
||||
/// Locale-independent version of the C standard library isprint whose results
|
||||
/// may differ on different platforms.
|
||||
constexpr bool isPrint(char C) noexcept {
|
||||
unsigned char UC = static_cast<unsigned char>(C);
|
||||
return (0x20 <= UC) && (UC <= 0x7E);
|
||||
}
|
||||
|
||||
/// Returns the corresponding lowercase character if \p x is uppercase.
|
||||
constexpr char toLower(char x) noexcept {
|
||||
if (x >= 'A' && x <= 'Z') {
|
||||
return x - 'A' + 'a';
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/// Returns the corresponding uppercase character if \p x is lowercase.
|
||||
constexpr char toUpper(char x) noexcept {
|
||||
if (x >= 'a' && x <= 'z') {
|
||||
return x - 'a' + 'A';
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline std::string utohexstr(unsigned long long val, // NOLINT(runtime/int)
|
||||
bool lowerCase = false) {
|
||||
char buf[17];
|
||||
char* bufptr = std::end(buf);
|
||||
|
||||
if (val == 0) {
|
||||
*--bufptr = '0';
|
||||
}
|
||||
|
||||
while (val) {
|
||||
unsigned char mod = static_cast<unsigned char>(val) & 15;
|
||||
*--bufptr = hexdigit(mod, lowerCase);
|
||||
val >>= 4;
|
||||
}
|
||||
|
||||
return std::string(bufptr, std::end(buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* equals - Check for string equality, this is more efficient than
|
||||
* compare() when the relative ordering of inequal strings isn't needed.
|
||||
*/
|
||||
constexpr bool equals(std::string_view lhs, std::string_view rhs) noexcept {
|
||||
auto length = lhs.size();
|
||||
return length == rhs.size() && std::string_view::traits_type::compare(
|
||||
lhs.data(), rhs.data(), length) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare_lower - Compare two strings, ignoring case.
|
||||
*/
|
||||
int compare_lower(std::string_view lhs, std::string_view rhs) noexcept;
|
||||
|
||||
/**
|
||||
* equals_lower - Check for string equality, ignoring case.
|
||||
*/
|
||||
constexpr bool equals_lower(std::string_view lhs,
|
||||
std::string_view rhs) noexcept {
|
||||
return lhs.size() == rhs.size() && compare_lower(lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first character @p ch in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the first occurrence of @p ch, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type find_lower(
|
||||
std::string_view str, char ch,
|
||||
std::string_view::size_type from = 0) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the first string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the first occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type find_lower(
|
||||
std::string_view str, std::string_view other,
|
||||
std::string_view::size_type from = 0) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the first string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the first occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
inline std::string_view::size_type find_lower(
|
||||
std::string_view str, const char* other,
|
||||
std::string_view::size_type from = 0) noexcept {
|
||||
return find_lower(str, std::string_view{other}, from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the last character @p ch in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the last occurrence of @p ch, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type rfind_lower(
|
||||
std::string_view str, char ch,
|
||||
std::string_view::size_type from = std::string_view::npos) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the last string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the last occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type rfind_lower(std::string_view str,
|
||||
std::string_view other) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the last string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the last occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
inline std::string_view::size_type rfind_lower(std::string_view str,
|
||||
const char* other) noexcept {
|
||||
return rfind_lower(str, std::string_view{other});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the substring of @p str from [start, start + n).
|
||||
*
|
||||
* @param start The index of the starting character in the substring; if
|
||||
* the index is npos or greater than the length of the string then the
|
||||
* empty substring will be returned.
|
||||
*
|
||||
* @param n The number of characters to included in the substring. If n
|
||||
* exceeds the number of characters remaining in the string, the string
|
||||
* suffix (starting with @p start) will be returned.
|
||||
*/
|
||||
constexpr std::string_view substr(
|
||||
std::string_view str, std::string_view::size_type start,
|
||||
std::string_view::size_type n = std::string_view::npos) noexcept {
|
||||
auto length = str.size();
|
||||
start = (std::min)(start, length);
|
||||
return {str.data() + start, (std::min)(n, length - start)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix.
|
||||
*/
|
||||
constexpr bool starts_with(std::string_view str,
|
||||
std::string_view prefix) noexcept {
|
||||
return substr(str, 0, prefix.size()) == prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix.
|
||||
*/
|
||||
constexpr bool starts_with(std::string_view str, char prefix) noexcept {
|
||||
return !str.empty() && std::string_view::traits_type::eq(str.front(), prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix.
|
||||
*/
|
||||
constexpr bool starts_with(std::string_view str, const char* prefix) noexcept {
|
||||
return starts_with(str, std::string_view(prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix, ignoring case.
|
||||
*/
|
||||
bool starts_with_lower(std::string_view str, std::string_view prefix) noexcept;
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix, ignoring case.
|
||||
*/
|
||||
constexpr bool starts_with_lower(std::string_view str, char prefix) noexcept {
|
||||
return !str.empty() && toLower(str.front()) == toLower(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix, ignoring case.
|
||||
*/
|
||||
inline bool starts_with_lower(std::string_view str,
|
||||
const char* prefix) noexcept {
|
||||
return starts_with_lower(str, std::string_view(prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix.
|
||||
*/
|
||||
constexpr bool ends_with(std::string_view str,
|
||||
std::string_view suffix) noexcept {
|
||||
return str.size() >= suffix.size() &&
|
||||
str.compare(str.size() - suffix.size(), std::string_view::npos,
|
||||
suffix) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix.
|
||||
*/
|
||||
constexpr bool ends_with(std::string_view str, char suffix) noexcept {
|
||||
return !str.empty() && std::string_view::traits_type::eq(str.back(), suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix.
|
||||
*/
|
||||
constexpr bool ends_with(std::string_view str, const char* suffix) noexcept {
|
||||
return ends_with(str, std::string_view(suffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix, ignoring case.
|
||||
*/
|
||||
bool ends_with_lower(std::string_view str, std::string_view suffix) noexcept;
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix, ignoring case.
|
||||
*/
|
||||
constexpr bool ends_with_lower(std::string_view str, char suffix) noexcept {
|
||||
return !str.empty() && toLower(str.back()) == toLower(suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix, ignoring case.
|
||||
*/
|
||||
inline bool ends_with_lower(std::string_view str, const char* suffix) noexcept {
|
||||
return ends_with_lower(str, std::string_view(suffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other.
|
||||
*/
|
||||
constexpr bool contains(std::string_view str, std::string_view other) noexcept {
|
||||
return str.find(other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other.
|
||||
*/
|
||||
constexpr bool contains(std::string_view str, char ch) noexcept {
|
||||
return str.find(ch) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other.
|
||||
*/
|
||||
constexpr bool contains(std::string_view str, const char* other) noexcept {
|
||||
return str.find(other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other, ignoring case.
|
||||
*/
|
||||
inline bool contains_lower(std::string_view str,
|
||||
std::string_view other) noexcept {
|
||||
return find_lower(str, other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other, ignoring case.
|
||||
*/
|
||||
inline bool contains_lower(std::string_view str, char ch) noexcept {
|
||||
return find_lower(str, ch) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other, ignoring case.
|
||||
*/
|
||||
inline bool contains_lower(std::string_view str, const char* other) noexcept {
|
||||
return find_lower(str, other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string_view equal to @p str but with the first @p n elements
|
||||
* dropped.
|
||||
*/
|
||||
constexpr std::string_view drop_front(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
str.remove_prefix(n);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string_view equal to @p str but with the last @p n elements dropped.
|
||||
*/
|
||||
constexpr std::string_view drop_back(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
str.remove_suffix(n);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view equal to @p str but with only the first @p n
|
||||
* elements remaining. If @p n is greater than the length of the
|
||||
* string, the entire string is returned.
|
||||
*/
|
||||
constexpr std::string_view take_front(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
auto length = str.size();
|
||||
if (n >= length) {
|
||||
return str;
|
||||
}
|
||||
return drop_back(str, length - n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view equal to @p str but with only the last @p n
|
||||
* elements remaining. If @p n is greater than the length of the
|
||||
* string, the entire string is returned.
|
||||
*/
|
||||
constexpr std::string_view take_back(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
auto length = str.size();
|
||||
if (n >= length) {
|
||||
return str;
|
||||
}
|
||||
return drop_front(str, length - n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the substring of @p str from [start, end).
|
||||
*
|
||||
* @param start The index of the starting character in the substring; if
|
||||
* the index is npos or greater than the length of the string then the
|
||||
* empty substring will be returned.
|
||||
*
|
||||
* @param end The index following the last character to include in the
|
||||
* substring. If this is npos or exceeds the number of characters
|
||||
* remaining in the string, the string suffix (starting with @p start)
|
||||
* will be returned. If this is less than @p start, an empty string will
|
||||
* be returned.
|
||||
*/
|
||||
constexpr std::string_view slice(std::string_view str,
|
||||
std::string_view::size_type start,
|
||||
std::string_view::size_type end) noexcept {
|
||||
auto length = str.size();
|
||||
start = (std::min)(start, length);
|
||||
end = (std::min)((std::max)(start, end), length);
|
||||
return {str.data() + start, end - start};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the first occurrence of a separator
|
||||
* character.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* maximal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The character to split on.
|
||||
* @returns The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> split(
|
||||
std::string_view str, char separator) noexcept {
|
||||
auto idx = str.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx), slice(str, idx + 1, std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the first occurrence of a separator
|
||||
* string.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* maximal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The string to split on.
|
||||
* @return The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> split(
|
||||
std::string_view str, std::string_view separator) noexcept {
|
||||
auto idx = str.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx),
|
||||
slice(str, idx + separator.size(), std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the last occurrence of a separator
|
||||
* character.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* minimal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The string to split on.
|
||||
* @return The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> rsplit(
|
||||
std::string_view str, char separator) noexcept {
|
||||
auto idx = str.rfind(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx), slice(str, idx + 1, std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the last occurrence of a separator
|
||||
* string.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* minimal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The string to split on.
|
||||
* @return The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> rsplit(
|
||||
std::string_view str, std::string_view separator) noexcept {
|
||||
auto idx = str.rfind(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx),
|
||||
slice(str, idx + separator.size(), std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into substrings around the occurrences of a separator string.
|
||||
*
|
||||
* Each substring is stored in @p arr. If @p maxSplit is >= 0, at most
|
||||
* @p maxSplit splits are done and consequently <= @p maxSplit + 1
|
||||
* elements are added to arr.
|
||||
* If @p keepEmpty is false, empty strings are not added to @p arr. They
|
||||
* still count when considering @p maxSplit
|
||||
* An useful invariant is that
|
||||
* separator.join(arr) == str if maxSplit == -1 and keepEmpty == true
|
||||
*
|
||||
* @param arr Where to put the substrings.
|
||||
* @param separator The string to split on.
|
||||
* @param maxSplit The maximum number of times the string is split.
|
||||
* @param keepEmpty True if empty substring should be added.
|
||||
*/
|
||||
void split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
std::string_view separator, int maxSplit = -1,
|
||||
bool keepEmpty = true) noexcept;
|
||||
|
||||
/**
|
||||
* Splits @p str into substrings around the occurrences of a separator
|
||||
* character.
|
||||
*
|
||||
* Each substring is stored in @p arr. If @p maxSplit is >= 0, at most
|
||||
* @p maxSplit splits are done and consequently <= @p maxSplit + 1
|
||||
* elements are added to arr.
|
||||
* If @p keepEmpty is false, empty strings are not added to @p arr. They
|
||||
* still count when considering @p maxSplit
|
||||
* An useful invariant is that
|
||||
* separator.join(arr) == str if maxSplit == -1 and keepEmpty == true
|
||||
*
|
||||
* @param arr Where to put the substrings.
|
||||
* @param separator The character to split on.
|
||||
* @param maxSplit The maximum number of times the string is split.
|
||||
* @param keepEmpty True if empty substring should be added.
|
||||
*/
|
||||
void split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
char separator, int maxSplit = -1, bool keepEmpty = true) noexcept;
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive @p ch characters starting from the
|
||||
* the left removed.
|
||||
*/
|
||||
constexpr std::string_view ltrim(std::string_view str, char ch) noexcept {
|
||||
return drop_front(str, (std::min)(str.size(), str.find_first_not_of(ch)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive characters in @p chars starting from
|
||||
* the left removed.
|
||||
*/
|
||||
constexpr std::string_view ltrim(
|
||||
std::string_view str, std::string_view chars = " \t\n\v\f\r") noexcept {
|
||||
return drop_front(str, (std::min)(str.size(), str.find_first_not_of(chars)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive @p Char characters starting from the
|
||||
* right removed.
|
||||
*/
|
||||
constexpr std::string_view rtrim(std::string_view str, char ch) noexcept {
|
||||
return drop_back(
|
||||
str, str.size() - (std::min)(str.size(), str.find_last_not_of(ch) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive characters in @p chars starting from
|
||||
* the right removed.
|
||||
*/
|
||||
constexpr std::string_view rtrim(
|
||||
std::string_view str, std::string_view chars = " \t\n\v\f\r") noexcept {
|
||||
return drop_back(
|
||||
str,
|
||||
str.size() - (std::min)(str.size(), str.find_last_not_of(chars) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive @p ch characters starting from the
|
||||
* left and right removed.
|
||||
*/
|
||||
constexpr std::string_view trim(std::string_view str, char ch) noexcept {
|
||||
return rtrim(ltrim(str, ch), ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive characters in @p chars starting from
|
||||
* the left and right removed.
|
||||
*/
|
||||
constexpr std::string_view trim(
|
||||
std::string_view str, std::string_view chars = " \t\n\v\f\r") noexcept {
|
||||
return rtrim(ltrim(str, chars), chars);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
bool GetAsUnsignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
unsigned long long& result) noexcept; // NOLINT(runtime/int)
|
||||
bool GetAsSignedInteger(std::string_view str, unsigned radix,
|
||||
long long& result) noexcept; // NOLINT(runtime/int)
|
||||
|
||||
bool ConsumeUnsignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
unsigned long long& result) noexcept; // NOLINT(runtime/int)
|
||||
bool ConsumeSignedInteger(std::string_view& str, unsigned radix,
|
||||
long long& result) noexcept; // NOLINT(runtime/int)
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Parses the string @p str as an integer of the specified radix. If
|
||||
* @p radix is specified as zero, this does radix autosensing using
|
||||
* extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
*
|
||||
* If the string is invalid or if only a subset of the string is valid,
|
||||
* this returns nullopt to signify the error. The string is considered
|
||||
* erroneous if empty or if it overflows T.
|
||||
*/
|
||||
template <typename T,
|
||||
std::enable_if_t<std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> parse_integer(std::string_view str,
|
||||
unsigned radix) noexcept {
|
||||
long long val; // NOLINT(runtime/int)
|
||||
if (detail::GetAsSignedInteger(str, radix, val) ||
|
||||
static_cast<T>(val) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> parse_integer(std::string_view str,
|
||||
unsigned radix) noexcept {
|
||||
using Int = unsigned long long; // NOLINT(runtime/int)
|
||||
Int val;
|
||||
// The additional cast to unsigned long long is required to avoid the
|
||||
// Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type
|
||||
// 'unsigned __int64' when instantiating getAsInteger with T = bool.
|
||||
if (detail::GetAsUnsignedInteger(str, radix, val) ||
|
||||
static_cast<Int>(static_cast<T>(val)) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string @p str as an integer of the specified radix. If
|
||||
* @p radix is specified as zero, this does radix autosensing using
|
||||
* extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
*
|
||||
* If the string does not begin with a number of the specified radix,
|
||||
* this returns nullopt to signify the error. The string is considered
|
||||
* erroneous if empty or if it overflows T.
|
||||
* The portion of the string representing the discovered numeric value
|
||||
* is removed from the beginning of the string.
|
||||
*/
|
||||
template <typename T,
|
||||
std::enable_if_t<std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> consume_integer(std::string_view* str,
|
||||
unsigned radix) noexcept {
|
||||
using Int = long long; // NOLINT(runtime/int)
|
||||
Int val;
|
||||
if (detail::ConsumeSignedInteger(*str, radix, val) ||
|
||||
static_cast<Int>(static_cast<T>(val)) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> consume_integer(std::string_view* str,
|
||||
unsigned radix) noexcept {
|
||||
using Int = unsigned long long; // NOLINT(runtime/int)
|
||||
Int val;
|
||||
if (detail::ConsumeUnsignedInteger(*str, radix, val) ||
|
||||
static_cast<Int>(static_cast<T>(val)) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string @p str as a floating point value.
|
||||
*
|
||||
* If the string is invalid or if only a subset of the string is valid,
|
||||
* this returns nullopt to signify the error. The string is considered
|
||||
* erroneous if empty or if it overflows T.
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<T> parse_float(std::string_view str) noexcept;
|
||||
|
||||
template <>
|
||||
std::optional<float> parse_float<float>(std::string_view str) noexcept;
|
||||
template <>
|
||||
std::optional<double> parse_float<double>(std::string_view str) noexcept;
|
||||
template <>
|
||||
std::optional<long double> parse_float<long double>(
|
||||
std::string_view str) noexcept;
|
||||
|
||||
} // namespace wpi
|
||||
584
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
vendored
Normal file
584
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
vendored
Normal file
@@ -0,0 +1,584 @@
|
||||
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the StringMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGMAP_H
|
||||
#define WPIUTIL_WPI_STRINGMAP_H
|
||||
|
||||
#include "wpi/StringMapEntry.h"
|
||||
#include "wpi/AllocatorBase.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename ValueTy> class StringMapConstIterator;
|
||||
template <typename ValueTy> class StringMapIterator;
|
||||
template <typename ValueTy> class StringMapKeyIterator;
|
||||
|
||||
/// StringMapImpl - This is the base class of StringMap that is shared among
|
||||
/// all of its instantiations.
|
||||
class StringMapImpl {
|
||||
protected:
|
||||
// Array of NumBuckets pointers to entries, null pointers are holes.
|
||||
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
|
||||
// by an array of the actual hash values as unsigned integers.
|
||||
StringMapEntryBase **TheTable = nullptr;
|
||||
unsigned NumBuckets = 0;
|
||||
unsigned NumItems = 0;
|
||||
unsigned NumTombstones = 0;
|
||||
unsigned ItemSize;
|
||||
|
||||
protected:
|
||||
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
|
||||
StringMapImpl(StringMapImpl &&RHS) noexcept
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
ItemSize(RHS.ItemSize) {
|
||||
RHS.TheTable = nullptr;
|
||||
RHS.NumBuckets = 0;
|
||||
RHS.NumItems = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
StringMapImpl(unsigned InitSize, unsigned ItemSize);
|
||||
unsigned RehashTable(unsigned BucketNo = 0);
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned LookupBucketFor(std::string_view Key);
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int FindKey(std::string_view Key) const;
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void RemoveKey(StringMapEntryBase *V);
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *RemoveKey(std::string_view Key);
|
||||
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
void init(unsigned Size);
|
||||
|
||||
public:
|
||||
static constexpr uintptr_t TombstoneIntVal =
|
||||
static_cast<uintptr_t>(-1)
|
||||
<< PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
|
||||
|
||||
static StringMapEntryBase *getTombstoneVal() {
|
||||
return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal);
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const { return NumBuckets; }
|
||||
unsigned getNumItems() const { return NumItems; }
|
||||
|
||||
bool empty() const { return NumItems == 0; }
|
||||
unsigned size() const { return NumItems; }
|
||||
|
||||
void swap(StringMapImpl &Other) {
|
||||
std::swap(TheTable, Other.TheTable);
|
||||
std::swap(NumBuckets, Other.NumBuckets);
|
||||
std::swap(NumItems, Other.NumItems);
|
||||
std::swap(NumTombstones, Other.NumTombstones);
|
||||
}
|
||||
};
|
||||
|
||||
/// StringMap - This is an unconventional map that is specialized for handling
|
||||
/// keys that are "strings", which are basically ranges of bytes. This does some
|
||||
/// funky memory allocation and hashing things to make it extremely efficient,
|
||||
/// storing the string data *after* the value in the map.
|
||||
template <typename ValueTy, typename AllocatorTy = MallocAllocator>
|
||||
class StringMap : public StringMapImpl {
|
||||
AllocatorTy Allocator;
|
||||
|
||||
public:
|
||||
using MapEntryTy = StringMapEntry<ValueTy>;
|
||||
|
||||
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(unsigned InitialSize)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(AllocatorTy A)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {
|
||||
}
|
||||
|
||||
StringMap(unsigned InitialSize, AllocatorTy A)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(A) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
for (const auto &P : List) {
|
||||
insert(P);
|
||||
}
|
||||
}
|
||||
|
||||
StringMap(StringMap &&RHS)
|
||||
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
||||
|
||||
StringMap(const StringMap &RHS)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(RHS.Allocator) {
|
||||
if (RHS.empty())
|
||||
return;
|
||||
|
||||
// Allocate TheTable of the same size as RHS's TheTable, and set the
|
||||
// sentinel appropriately (and NumBuckets).
|
||||
init(RHS.NumBuckets);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
|
||||
*RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
|
||||
|
||||
NumItems = RHS.NumItems;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = RHS.TheTable[I];
|
||||
if (!Bucket || Bucket == getTombstoneVal()) {
|
||||
TheTable[I] = Bucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
TheTable[I] = MapEntryTy::Create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
|
||||
static_cast<MapEntryTy *>(Bucket)->getValue());
|
||||
HashTable[I] = RHSHashTable[I];
|
||||
}
|
||||
|
||||
// Note that here we've copied everything from the RHS into this object,
|
||||
// tombstones included. We could, instead, have re-probed for each key to
|
||||
// instantiate this new object without any tombstone buckets. The
|
||||
// assumption here is that items are rarely deleted from most StringMaps,
|
||||
// and so tombstones are rare, so the cost of re-probing for all inputs is
|
||||
// not worthwhile.
|
||||
}
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
std::swap(Allocator, RHS.Allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~StringMap() {
|
||||
// Delete all the elements in the map, but don't reset the elements
|
||||
// to default values. This is a copy of clear(), but avoids unnecessary
|
||||
// work not required in the destructor.
|
||||
if (!empty()) {
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(TheTable);
|
||||
}
|
||||
|
||||
AllocatorTy &getAllocator() { return Allocator; }
|
||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||
|
||||
using key_type = const char *;
|
||||
using mapped_type = ValueTy;
|
||||
using value_type = StringMapEntry<ValueTy>;
|
||||
using size_type = size_t;
|
||||
|
||||
using const_iterator = StringMapConstIterator<ValueTy>;
|
||||
using iterator = StringMapIterator<ValueTy>;
|
||||
|
||||
iterator begin() { return iterator(TheTable, NumBuckets == 0); }
|
||||
iterator end() { return iterator(TheTable + NumBuckets, true); }
|
||||
const_iterator begin() const {
|
||||
return const_iterator(TheTable, NumBuckets == 0);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator(TheTable + NumBuckets, true);
|
||||
}
|
||||
|
||||
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
||||
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
iterator find(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
const_iterator find(std::string_view Key) const {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return const_iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueTy lookup(std::string_view Key) const {
|
||||
const_iterator it = find(Key);
|
||||
if (it != end())
|
||||
return it->second;
|
||||
return ValueTy();
|
||||
}
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(std::string_view Key) const { return find(Key) == end() ? 0 : 1; }
|
||||
|
||||
template <typename InputTy>
|
||||
size_type count(const StringMapEntry<InputTy> &MapEntry) const {
|
||||
return count(MapEntry.getKey());
|
||||
}
|
||||
|
||||
/// equal - check whether both of the containers are equal.
|
||||
bool operator==(const StringMap &RHS) const {
|
||||
if (size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (const auto &KeyValue : *this) {
|
||||
auto FindInRHS = RHS.find(KeyValue.getKey());
|
||||
|
||||
if (FindInRHS == RHS.end())
|
||||
return false;
|
||||
|
||||
if (!(KeyValue.getValue() == FindInRHS->getValue()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const StringMap &RHS) const { return !(*this == RHS); }
|
||||
|
||||
/// insert - Insert the specified key/value pair into the map. If the key
|
||||
/// already exists in the map, return false and ignore the request, otherwise
|
||||
/// insert it and return true.
|
||||
bool insert(MapEntryTy *KeyValue) {
|
||||
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return false; // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = KeyValue;
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
RehashTable();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// insert - Inserts the specified key/value pair into the map if the key
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
std::pair<iterator, bool> insert(std::pair<std::string_view, ValueTy> KV) {
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
/// Inserts an element or assigns to the current element if the key already
|
||||
/// exists. The return type is the same as try_emplace.
|
||||
template <typename V>
|
||||
std::pair<iterator, bool> insert_or_assign(std::string_view Key, V &&Val) {
|
||||
auto Ret = try_emplace(Key, std::forward<V>(Val));
|
||||
if (!Ret.second)
|
||||
Ret.first->second = std::forward<V>(Val);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key into the map if the key isn't
|
||||
/// already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&... Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false),
|
||||
false); // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
BucketNo = RehashTable(BucketNo);
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false), true);
|
||||
}
|
||||
|
||||
// clear - Empties out the StringMap
|
||||
void clear() {
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
// Zap all values, resetting the keys back to non-present (not tombstone),
|
||||
// which is safe because we're removing all elements.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *&Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
|
||||
}
|
||||
Bucket = nullptr;
|
||||
}
|
||||
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
/// remove - Remove the specified key/value pair from the map, but do not
|
||||
/// erase it. This aborts if the key is not in the map.
|
||||
void remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); }
|
||||
|
||||
void erase(iterator I) {
|
||||
MapEntryTy &V = *I;
|
||||
remove(&V);
|
||||
V.Destroy(Allocator);
|
||||
}
|
||||
|
||||
bool erase(std::string_view Key) {
|
||||
iterator I = find(Key);
|
||||
if (I == end())
|
||||
return false;
|
||||
erase(I);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DerivedTy, typename ValueTy>
|
||||
class StringMapIterBase
|
||||
: public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
|
||||
ValueTy> {
|
||||
protected:
|
||||
StringMapEntryBase **Ptr = nullptr;
|
||||
|
||||
public:
|
||||
StringMapIterBase() = default;
|
||||
|
||||
explicit StringMapIterBase(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
if (!NoAdvance)
|
||||
AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
DerivedTy &operator=(const DerivedTy &Other) {
|
||||
Ptr = Other.Ptr;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
|
||||
return LHS.Ptr == RHS.Ptr;
|
||||
}
|
||||
|
||||
DerivedTy &operator++() { // Preincrement
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
DerivedTy operator++(int) { // Post-increment
|
||||
DerivedTy Tmp(Ptr);
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
DerivedTy &operator--() { // Predecrement
|
||||
--Ptr;
|
||||
ReversePastEmptyBuckets();
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
DerivedTy operator--(int) { // Post-decrement
|
||||
DerivedTy Tmp(Ptr);
|
||||
--*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
++Ptr;
|
||||
}
|
||||
void ReversePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
--Ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapConstIterator
|
||||
: public StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>> {
|
||||
using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapConstIterator() = default;
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
const StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
|
||||
StringMapEntry<ValueTy>> {
|
||||
using base =
|
||||
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapIterator() = default;
|
||||
explicit StringMapIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
|
||||
operator StringMapConstIterator<ValueTy>() const {
|
||||
return StringMapConstIterator<ValueTy>(this->Ptr, true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapKeyIterator
|
||||
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, std::string_view> {
|
||||
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, std::string_view>;
|
||||
|
||||
public:
|
||||
StringMapKeyIterator() = default;
|
||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||
: base(std::move(Iter)) {}
|
||||
|
||||
std::string_view &operator*() {
|
||||
Key = this->wrapped()->getKey();
|
||||
return Key;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view Key;
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
bool operator==(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
// same instance?
|
||||
if (&lhs == &rhs) return true;
|
||||
|
||||
// first check that sizes are identical
|
||||
if (lhs.size() != rhs.size()) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<StringMapConstIterator<ValueTy>, 16> lhs_items;
|
||||
lhs_items.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_items.push_back(i);
|
||||
std::sort(lhs_items.begin(), lhs_items.end(),
|
||||
[](const StringMapConstIterator<ValueTy>& a,
|
||||
const StringMapConstIterator<ValueTy>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
SmallVector<StringMapConstIterator<ValueTy>, 16> rhs_items;
|
||||
rhs_items.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_items.push_back(i);
|
||||
std::sort(rhs_items.begin(), rhs_items.end(),
|
||||
[](const StringMapConstIterator<ValueTy>& a,
|
||||
const StringMapConstIterator<ValueTy>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
// compare vector keys and values
|
||||
for (auto a = lhs_items.begin(), b = rhs_items.begin(),
|
||||
aend = lhs_items.end(), bend = rhs_items.end();
|
||||
a != aend && b != bend; ++a, ++b) {
|
||||
if ((*a)->first() != (*b)->first() || (*a)->second != (*b)->second)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator!=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
bool operator<(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
// same instance?
|
||||
if (&lhs == &rhs) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<std::string_view, 16> lhs_keys;
|
||||
lhs_keys.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_keys.push_back(i->getKey());
|
||||
std::sort(lhs_keys.begin(), lhs_keys.end());
|
||||
|
||||
SmallVector<std::string_view, 16> rhs_keys;
|
||||
rhs_keys.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_keys.push_back(i->getKey());
|
||||
std::sort(rhs_keys.begin(), rhs_keys.end());
|
||||
|
||||
// use std::vector comparison
|
||||
return lhs_keys < rhs_keys;
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator<=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator>(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator>=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAP_H
|
||||
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
vendored
Normal file
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
//===- StringMapEntry.h - String Hash table map interface -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the StringMapEntry class - it is intended to be a low
|
||||
// dependency implementation detail of StringMap that is more suitable for
|
||||
// inclusion in public headers than StringMap.h itself is.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
#define WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||
class StringMapEntryBase {
|
||||
size_t keyLength;
|
||||
|
||||
public:
|
||||
explicit StringMapEntryBase(size_t keyLength) : keyLength(keyLength) {}
|
||||
|
||||
size_t getKeyLength() const { return keyLength; }
|
||||
|
||||
protected:
|
||||
/// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
|
||||
/// could be reused elsewhere, maybe even taking an wpi::function_ref to
|
||||
/// type-erase the allocator and put it in a source file.
|
||||
template <typename AllocatorTy>
|
||||
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
std::string_view Key, AllocatorTy &Allocator);
|
||||
};
|
||||
|
||||
// Define out-of-line to dissuade inlining.
|
||||
template <typename AllocatorTy>
|
||||
void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
std::string_view Key,
|
||||
AllocatorTy &Allocator) {
|
||||
size_t KeyLength = Key.size();
|
||||
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
// terminator.
|
||||
size_t AllocSize = EntrySize + KeyLength + 1;
|
||||
void *Allocation = Allocator.Allocate(AllocSize, EntryAlign);
|
||||
assert(Allocation && "Unhandled out-of-memory");
|
||||
|
||||
// Copy the string information.
|
||||
char *Buffer = reinterpret_cast<char *>(Allocation) + EntrySize;
|
||||
if (KeyLength > 0)
|
||||
::memcpy(Buffer, Key.data(), KeyLength);
|
||||
Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
|
||||
return Allocation;
|
||||
}
|
||||
|
||||
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
|
||||
///
|
||||
/// Factored out into a separate base class to make it easier to specialize.
|
||||
/// This is primarily intended to support StringSet, which doesn't need a value
|
||||
/// stored at all.
|
||||
template <typename ValueTy>
|
||||
class StringMapEntryStorage : public StringMapEntryBase {
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
explicit StringMapEntryStorage(size_t keyLength)
|
||||
: StringMapEntryBase(keyLength), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntryStorage(size_t keyLength, InitTy &&... initVals)
|
||||
: StringMapEntryBase(keyLength),
|
||||
second(std::forward<InitTy>(initVals)...) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &e) = delete;
|
||||
|
||||
const ValueTy &getValue() const { return second; }
|
||||
ValueTy &getValue() { return second; }
|
||||
|
||||
void setValue(const ValueTy &V) { second = V; }
|
||||
};
|
||||
|
||||
template <> class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
|
||||
public:
|
||||
explicit StringMapEntryStorage(size_t keyLength, std::nullopt_t = std::nullopt)
|
||||
: StringMapEntryBase(keyLength) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
|
||||
|
||||
std::nullopt_t getValue() const { return std::nullopt; }
|
||||
};
|
||||
|
||||
/// StringMapEntry - This is used to represent one value that is inserted into
|
||||
/// a StringMap. It contains the Value itself and the key: the string length
|
||||
/// and data.
|
||||
template <typename ValueTy>
|
||||
class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
|
||||
public:
|
||||
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
|
||||
|
||||
std::string_view getKey() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// getKeyData - Return the start of the string data that is the key for this
|
||||
/// value. The string data is always stored immediately after the
|
||||
/// StringMapEntry object.
|
||||
const char *getKeyData() const {
|
||||
return reinterpret_cast<const char *>(this + 1);
|
||||
}
|
||||
|
||||
std::string_view first() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename AllocatorTy, typename... InitTy>
|
||||
static StringMapEntry *Create(std::string_view key, AllocatorTy &allocator,
|
||||
InitTy &&... initVals) {
|
||||
return new (StringMapEntryBase::allocateWithKey(
|
||||
sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
|
||||
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
|
||||
}
|
||||
|
||||
/// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
|
||||
/// into a StringMapEntry, return the StringMapEntry itself.
|
||||
static StringMapEntry &GetStringMapEntryFromKeyData(const char *keyData) {
|
||||
char *ptr = const_cast<char *>(keyData) - sizeof(StringMapEntry<ValueTy>);
|
||||
return *reinterpret_cast<StringMapEntry *>(ptr);
|
||||
}
|
||||
|
||||
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
|
||||
/// specified allocator.
|
||||
template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) {
|
||||
// Free memory referenced by the item.
|
||||
size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
|
||||
this->~StringMapEntry();
|
||||
allocator.Deallocate(static_cast<void *>(this), AllocSize,
|
||||
alignof(StringMapEntry));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
165
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
vendored
Normal file
165
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares generic and optimized functions to swap the byte order of
|
||||
// an integral type.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
|
||||
#define WPIUTIL_WPI_SWAPBYTEORDER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
|
||||
defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
|
||||
#include <endian.h>
|
||||
#elif defined(_AIX)
|
||||
#include <sys/machine.h>
|
||||
#elif defined(__sun)
|
||||
/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
|
||||
#include <sys/types.h>
|
||||
#define BIG_ENDIAN 4321
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#if defined(_BIG_ENDIAN)
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
#elif defined(__MVS__)
|
||||
#define BIG_ENDIAN 4321
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
#if !defined(BYTE_ORDER) && !defined(_WIN32)
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// ByteSwap_16 - This function returns a byte-swapped representation of
|
||||
/// the 16-bit argument.
|
||||
inline uint16_t ByteSwap_16(uint16_t value) {
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
// The DLL version of the runtime lacks these functions (bug!?), but in a
|
||||
// release build they're replaced with BSWAP instructions anyway.
|
||||
return _byteswap_ushort(value);
|
||||
#else
|
||||
uint16_t Hi = value << 8;
|
||||
uint16_t Lo = value >> 8;
|
||||
return Hi | Lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// This function returns a byte-swapped representation of the 32-bit argument.
|
||||
inline uint32_t ByteSwap_32(uint32_t value) {
|
||||
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
|
||||
return __builtin_bswap32(value);
|
||||
#elif defined(_MSC_VER) && !defined(_DEBUG)
|
||||
return _byteswap_ulong(value);
|
||||
#else
|
||||
uint32_t Byte0 = value & 0x000000FF;
|
||||
uint32_t Byte1 = value & 0x0000FF00;
|
||||
uint32_t Byte2 = value & 0x00FF0000;
|
||||
uint32_t Byte3 = value & 0xFF000000;
|
||||
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// This function returns a byte-swapped representation of the 64-bit argument.
|
||||
inline uint64_t ByteSwap_64(uint64_t value) {
|
||||
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
|
||||
return __builtin_bswap64(value);
|
||||
#elif defined(_MSC_VER) && !defined(_DEBUG)
|
||||
return _byteswap_uint64(value);
|
||||
#else
|
||||
uint64_t Hi = ByteSwap_32(uint32_t(value));
|
||||
uint32_t Lo = ByteSwap_32(uint32_t(value >> 32));
|
||||
return (Hi << 32) | Lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace sys {
|
||||
|
||||
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
|
||||
constexpr bool IsBigEndianHost = true;
|
||||
#else
|
||||
constexpr bool IsBigEndianHost = false;
|
||||
#endif
|
||||
|
||||
static const bool IsLittleEndianHost = !IsBigEndianHost;
|
||||
|
||||
inline unsigned char getSwappedBytes(unsigned char C) { return C; }
|
||||
inline signed char getSwappedBytes(signed char C) { return C; }
|
||||
inline char getSwappedBytes(char C) { return C; }
|
||||
|
||||
inline unsigned short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); }
|
||||
inline signed short getSwappedBytes( signed short C) { return ByteSwap_16(C); }
|
||||
|
||||
inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
|
||||
inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); }
|
||||
|
||||
inline unsigned long getSwappedBytes(unsigned long C) {
|
||||
// Handle LLP64 and LP64 platforms.
|
||||
return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
|
||||
: ByteSwap_64((uint64_t)C);
|
||||
}
|
||||
inline signed long getSwappedBytes(signed long C) {
|
||||
// Handle LLP64 and LP64 platforms.
|
||||
return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
|
||||
: ByteSwap_64((uint64_t)C);
|
||||
}
|
||||
|
||||
inline unsigned long long getSwappedBytes(unsigned long long C) {
|
||||
return ByteSwap_64(C);
|
||||
}
|
||||
inline signed long long getSwappedBytes(signed long long C) {
|
||||
return ByteSwap_64(C);
|
||||
}
|
||||
|
||||
inline float getSwappedBytes(float C) {
|
||||
union {
|
||||
uint32_t i;
|
||||
float f;
|
||||
} in, out;
|
||||
in.f = C;
|
||||
out.i = ByteSwap_32(in.i);
|
||||
return out.f;
|
||||
}
|
||||
|
||||
inline double getSwappedBytes(double C) {
|
||||
union {
|
||||
uint64_t i;
|
||||
double d;
|
||||
} in, out;
|
||||
in.d = C;
|
||||
out.i = ByteSwap_64(in.i);
|
||||
return out.d;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
|
||||
return static_cast<T>(
|
||||
getSwappedBytes(static_cast<std::underlying_type_t<T>>(C)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void swapByteOrder(T &Value) {
|
||||
Value = getSwappedBytes(Value);
|
||||
}
|
||||
|
||||
} // end namespace sys
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
164
wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
vendored
Normal file
164
wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Defines the llvm::VersionTuple class, which represents a version in
|
||||
/// the form major[.minor[.subminor]].
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
#define WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace wpi {
|
||||
class raw_ostream;
|
||||
|
||||
/// Represents a version number in the form major[.minor[.subminor[.build]]].
|
||||
class VersionTuple {
|
||||
unsigned Major : 32;
|
||||
|
||||
unsigned Minor : 31;
|
||||
unsigned HasMinor : 1;
|
||||
|
||||
unsigned Subminor : 31;
|
||||
unsigned HasSubminor : 1;
|
||||
|
||||
unsigned Build : 31;
|
||||
unsigned HasBuild : 1;
|
||||
|
||||
public:
|
||||
VersionTuple()
|
||||
: Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
|
||||
Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major)
|
||||
: Major(Major), Minor(0), HasMinor(false), Subminor(0),
|
||||
HasSubminor(false), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
|
||||
HasSubminor(false), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
|
||||
HasSubminor(true), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
|
||||
unsigned Build)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
|
||||
HasSubminor(true), Build(Build), HasBuild(true) {}
|
||||
|
||||
/// Determine whether this version information is empty
|
||||
/// (e.g., all version components are zero).
|
||||
bool empty() const {
|
||||
return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
|
||||
}
|
||||
|
||||
/// Retrieve the major version number.
|
||||
unsigned getMajor() const { return Major; }
|
||||
|
||||
/// Retrieve the minor version number, if provided.
|
||||
std::optional<unsigned> getMinor() const {
|
||||
if (!HasMinor)
|
||||
return std::nullopt;
|
||||
return Minor;
|
||||
}
|
||||
|
||||
/// Retrieve the subminor version number, if provided.
|
||||
std::optional<unsigned> getSubminor() const {
|
||||
if (!HasSubminor)
|
||||
return std::nullopt;
|
||||
return Subminor;
|
||||
}
|
||||
|
||||
/// Retrieve the build version number, if provided.
|
||||
std::optional<unsigned> getBuild() const {
|
||||
if (!HasBuild)
|
||||
return std::nullopt;
|
||||
return Build;
|
||||
}
|
||||
|
||||
/// Return a version tuple that contains only the first 3 version components.
|
||||
VersionTuple withoutBuild() const {
|
||||
if (HasBuild)
|
||||
return VersionTuple(Major, Minor, Subminor);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return a version tuple that contains only components that are non-zero.
|
||||
VersionTuple normalize() const {
|
||||
VersionTuple Result = *this;
|
||||
if (Result.Build == 0) {
|
||||
Result.HasBuild = false;
|
||||
if (Result.Subminor == 0) {
|
||||
Result.HasSubminor = false;
|
||||
if (Result.Minor == 0)
|
||||
Result.HasMinor = false;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Determine if two version numbers are equivalent. If not
|
||||
/// provided, minor and subminor version numbers are considered to be zero.
|
||||
friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return X.Major == Y.Major && X.Minor == Y.Minor &&
|
||||
X.Subminor == Y.Subminor && X.Build == Y.Build;
|
||||
}
|
||||
|
||||
/// Determine if two version numbers are not equivalent.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
|
||||
/// Determine whether one version number precedes another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
|
||||
std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
|
||||
}
|
||||
|
||||
/// Determine whether one version number follows another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return Y < X;
|
||||
}
|
||||
|
||||
/// Determine whether one version number precedes or is
|
||||
/// equivalent to another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(Y < X);
|
||||
}
|
||||
|
||||
/// Determine whether one version number follows or is
|
||||
/// equivalent to another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(X < Y);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
#endif // WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
vendored
Normal file
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_WINDOWSERROR_H
|
||||
#define WPIUTIL_WPI_WINDOWSERROR_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace wpi {
|
||||
std::error_code mapWindowsError(unsigned EV);
|
||||
}
|
||||
|
||||
#endif
|
||||
66
wpiutil/src/main/native/thirdparty/llvm/include/wpi/function_ref.h
vendored
Normal file
66
wpiutil/src/main/native/thirdparty/llvm/include/wpi/function_ref.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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.
|
||||
|
||||
//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_FUNCTION_REF_H_
|
||||
#define WPIUTIL_WPI_FUNCTION_REF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
///
|
||||
/// This class does not own the callable, so it is not in general safe to store
|
||||
/// a function_ref.
|
||||
template <typename Fn>
|
||||
class function_ref;
|
||||
|
||||
template <typename Ret, typename... Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(intptr_t callable, Params... params) = nullptr;
|
||||
intptr_t callable;
|
||||
|
||||
template <typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Params... params) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(std::forward<Params>(
|
||||
params)...);
|
||||
}
|
||||
|
||||
public:
|
||||
function_ref() = default;
|
||||
/*implicit*/ function_ref(std::nullptr_t) {} // NOLINT
|
||||
|
||||
template <typename Callable>
|
||||
/*implicit*/ function_ref( // NOLINT
|
||||
Callable&& callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type* = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
|
||||
Ret operator()(Params... params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
explicit operator bool() const { return callback; }
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_FUNCTION_REF_H_
|
||||
355
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
vendored
Normal file
355
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ITERATOR_H
|
||||
#define WPIUTIL_WPI_ITERATOR_H
|
||||
|
||||
#include "wpi/iterator_range.h"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// CRTP base class which implements the entire standard iterator facade
|
||||
/// in terms of a minimal subset of the interface.
|
||||
///
|
||||
/// Use this when it is reasonable to implement most of the iterator
|
||||
/// functionality in terms of a core subset. If you need special behavior or
|
||||
/// there are performance implications for this, you may want to override the
|
||||
/// relevant members instead.
|
||||
///
|
||||
/// Note, one abstraction that this does *not* provide is implementing
|
||||
/// subtraction in terms of addition by negating the difference. Negation isn't
|
||||
/// always information preserving, and I can see very reasonable iterator
|
||||
/// designs where this doesn't work well. It doesn't really force much added
|
||||
/// boilerplate anyways.
|
||||
///
|
||||
/// Another abstraction that this doesn't provide is implementing increment in
|
||||
/// terms of addition of one. These aren't equivalent for all iterator
|
||||
/// categories, and respecting that adds a lot of complexity for little gain.
|
||||
///
|
||||
/// Classes wishing to use `iterator_facade_base` should implement the following
|
||||
/// methods:
|
||||
///
|
||||
/// Forward Iterators:
|
||||
/// (All of the following methods)
|
||||
/// - DerivedT &operator=(const DerivedT &R);
|
||||
/// - bool operator==(const DerivedT &R) const;
|
||||
/// - const T &operator*() const;
|
||||
/// - T &operator*();
|
||||
/// - DerivedT &operator++();
|
||||
///
|
||||
/// Bidirectional Iterators:
|
||||
/// (All methods of forward iterators, plus the following)
|
||||
/// - DerivedT &operator--();
|
||||
///
|
||||
/// Random-access Iterators:
|
||||
/// (All methods of bidirectional iterators excluding the following)
|
||||
/// - DerivedT &operator++();
|
||||
/// - DerivedT &operator--();
|
||||
/// (and plus the following)
|
||||
/// - bool operator<(const DerivedT &RHS) const;
|
||||
/// - DifferenceTypeT operator-(const DerivedT &R) const;
|
||||
/// - DerivedT &operator+=(DifferenceTypeT N);
|
||||
/// - DerivedT &operator-=(DifferenceTypeT N);
|
||||
///
|
||||
template <typename DerivedT, typename IteratorCategoryT, typename T,
|
||||
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
|
||||
typename ReferenceT = T &>
|
||||
class iterator_facade_base {
|
||||
public:
|
||||
using iterator_category = IteratorCategoryT;
|
||||
using value_type = T;
|
||||
using difference_type = DifferenceTypeT;
|
||||
using pointer = PointerT;
|
||||
using reference = ReferenceT;
|
||||
|
||||
protected:
|
||||
enum {
|
||||
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
|
||||
IteratorCategoryT>::value,
|
||||
IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
|
||||
IteratorCategoryT>::value,
|
||||
};
|
||||
|
||||
/// A proxy object for computing a reference via indirecting a copy of an
|
||||
/// iterator. This is used in APIs which need to produce a reference via
|
||||
/// indirection but for which the iterator object might be a temporary. The
|
||||
/// proxy preserves the iterator internally and exposes the indirected
|
||||
/// reference via a conversion operator.
|
||||
class ReferenceProxy {
|
||||
friend iterator_facade_base;
|
||||
|
||||
DerivedT I;
|
||||
|
||||
ReferenceProxy(DerivedT I) : I(std::move(I)) {}
|
||||
|
||||
public:
|
||||
operator ReferenceT() const { return *I; }
|
||||
};
|
||||
|
||||
public:
|
||||
DerivedT operator+(DifferenceTypeT n) const {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp += n;
|
||||
return tmp;
|
||||
}
|
||||
friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
return i + n;
|
||||
}
|
||||
DerivedT operator-(DifferenceTypeT n) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp -= n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
DerivedT &operator++() {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
return static_cast<DerivedT *>(this)->operator+=(1);
|
||||
}
|
||||
DerivedT operator++(int) {
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
++*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
return static_cast<DerivedT *>(this)->operator-=(1);
|
||||
}
|
||||
DerivedT operator--(int) {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
--*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#ifndef __cpp_impl_three_way_comparison
|
||||
bool operator!=(const DerivedT &RHS) const {
|
||||
return !(static_cast<const DerivedT &>(*this) == RHS);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator>(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !(static_cast<const DerivedT &>(*this) < RHS) &&
|
||||
!(static_cast<const DerivedT &>(*this) == RHS);
|
||||
}
|
||||
bool operator<=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !(static_cast<const DerivedT &>(*this) > RHS);
|
||||
}
|
||||
bool operator>=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !(static_cast<const DerivedT &>(*this) < RHS);
|
||||
}
|
||||
|
||||
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
|
||||
PointerT operator->() const {
|
||||
return &static_cast<const DerivedT *>(this)->operator*();
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) const {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
};
|
||||
|
||||
/// CRTP base class for adapting an iterator to a different type.
|
||||
///
|
||||
/// This class can be used through CRTP to adapt one iterator into another.
|
||||
/// Typically this is done through providing in the derived class a custom \c
|
||||
/// operator* implementation. Other methods can be overridden as well.
|
||||
template <
|
||||
typename DerivedT, typename WrappedIteratorT,
|
||||
typename IteratorCategoryT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
|
||||
typename DifferenceTypeT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::difference_type,
|
||||
typename PointerT = std::conditional_t<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::pointer, T *>,
|
||||
typename ReferenceT = std::conditional_t<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::reference, T &>>
|
||||
class iterator_adaptor_base
|
||||
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
|
||||
DifferenceTypeT, PointerT, ReferenceT> {
|
||||
using BaseT = typename iterator_adaptor_base::iterator_facade_base;
|
||||
|
||||
protected:
|
||||
WrappedIteratorT I;
|
||||
|
||||
iterator_adaptor_base() = default;
|
||||
|
||||
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
|
||||
static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
}
|
||||
|
||||
const WrappedIteratorT &wrapped() const { return I; }
|
||||
|
||||
public:
|
||||
using difference_type = DifferenceTypeT;
|
||||
|
||||
DerivedT &operator+=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '+=' operator is only defined for random access iterators.");
|
||||
I += n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
DerivedT &operator-=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-=' operator is only defined for random access iterators.");
|
||||
I -= n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator-;
|
||||
difference_type operator-(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
return I - RHS.I;
|
||||
}
|
||||
|
||||
// We have to explicitly provide ++ and -- rather than letting the facade
|
||||
// forward to += because WrappedIteratorT might not support +=.
|
||||
using BaseT::operator++;
|
||||
DerivedT &operator++() {
|
||||
++I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator--;
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
BaseT::IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
--I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator_adaptor_base &LHS,
|
||||
const iterator_adaptor_base &RHS) {
|
||||
return LHS.I == RHS.I;
|
||||
}
|
||||
friend bool operator<(const iterator_adaptor_base &LHS,
|
||||
const iterator_adaptor_base &RHS) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return LHS.I < RHS.I;
|
||||
}
|
||||
|
||||
ReferenceT operator*() const { return *I; }
|
||||
};
|
||||
|
||||
/// An iterator type that allows iterating over the pointees via some
|
||||
/// other iterator.
|
||||
///
|
||||
/// The typical usage of this is to expose a type that iterates over Ts, but
|
||||
/// which is implemented with some iterator over T*s:
|
||||
///
|
||||
/// \code
|
||||
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
|
||||
/// \endcode
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = std::remove_reference_t<decltype(
|
||||
**std::declval<WrappedIteratorT>())>>
|
||||
struct pointee_iterator
|
||||
: iterator_adaptor_base<
|
||||
pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
pointee_iterator() = default;
|
||||
template <typename U>
|
||||
pointee_iterator(U &&u)
|
||||
: pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
|
||||
|
||||
T &operator*() const { return **this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointee_iterator<WrappedIteratorT>>
|
||||
make_pointee_range(RangeT &&Range) {
|
||||
using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
|
||||
return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = decltype(&*std::declval<WrappedIteratorT>())>
|
||||
class pointer_iterator
|
||||
: public iterator_adaptor_base<
|
||||
pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
mutable T Ptr;
|
||||
|
||||
public:
|
||||
pointer_iterator() = default;
|
||||
|
||||
explicit pointer_iterator(WrappedIteratorT u)
|
||||
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
|
||||
|
||||
T &operator*() { return Ptr = &*this->I; }
|
||||
const T &operator*() const { return Ptr = &*this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointer_iterator<WrappedIteratorT>>
|
||||
make_pointer_range(RangeT &&Range) {
|
||||
using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
|
||||
return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
template <typename WrappedIteratorT,
|
||||
typename T1 = std::remove_reference_t<decltype(
|
||||
**std::declval<WrappedIteratorT>())>,
|
||||
typename T2 = std::add_pointer_t<T1>>
|
||||
using raw_pointer_iterator =
|
||||
pointer_iterator<pointee_iterator<WrappedIteratorT, T1>, T2>;
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ITERATOR_H
|
||||
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
vendored
Normal file
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This provides a very simple, boring adaptor for a begin and end iterator
|
||||
/// into a range type. This should be used to build range views that work well
|
||||
/// with range based for loops and range based constructors.
|
||||
///
|
||||
/// Note that code here follows more standards-based coding conventions as it
|
||||
/// is mirroring proposed interfaces for standardization.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
|
||||
#define WPIUTIL_WPI_ITERATOR_RANGE_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// A range adaptor for a pair of iterators.
|
||||
///
|
||||
/// This just wraps two iterators into a range-compatible interface. Nothing
|
||||
/// fancy at all.
|
||||
template <typename IteratorT>
|
||||
class iterator_range {
|
||||
IteratorT begin_iterator, end_iterator;
|
||||
|
||||
public:
|
||||
//TODO: Add SFINAE to test that the Container's iterators match the range's
|
||||
// iterators.
|
||||
template <typename Container>
|
||||
iterator_range(Container &&c)
|
||||
//TODO: Consider ADL/non-member begin/end calls.
|
||||
: begin_iterator(c.begin()), end_iterator(c.end()) {}
|
||||
iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
|
||||
: begin_iterator(std::move(begin_iterator)),
|
||||
end_iterator(std::move(end_iterator)) {}
|
||||
|
||||
IteratorT begin() const { return begin_iterator; }
|
||||
IteratorT end() const { return end_iterator; }
|
||||
bool empty() const { return begin_iterator == end_iterator; }
|
||||
};
|
||||
|
||||
/// Convenience function for iterating over sub-ranges.
|
||||
///
|
||||
/// This provides a bit of syntactic sugar to make using sub-ranges
|
||||
/// in for loops a bit easier. Analogous to std::make_pair().
|
||||
template <class T> iterator_range<T> make_range(T x, T y) {
|
||||
return iterator_range<T>(std::move(x), std::move(y));
|
||||
}
|
||||
|
||||
template <typename T> iterator_range<T> make_range(std::pair<T, T> p) {
|
||||
return iterator_range<T>(std::move(p.first), std::move(p.second));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
41
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
vendored
Normal file
41
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the raw_os_ostream class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_RAW_OS_OSTREAM_H
|
||||
#define WPIUTIL_WPI_RAW_OS_OSTREAM_H
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// raw_os_ostream - A raw_ostream that writes to an std::ostream. This is a
|
||||
/// simple adaptor class. It does not check for output errors; clients should
|
||||
/// use the underlying stream to detect errors.
|
||||
class raw_os_ostream : public raw_ostream {
|
||||
std::ostream &OS;
|
||||
|
||||
/// write_impl - See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
/// current_pos - Return the current position within the stream, not
|
||||
/// counting the bytes currently in the buffer.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
raw_os_ostream(std::ostream &O) : OS(O) {}
|
||||
~raw_os_ostream() override;
|
||||
};
|
||||
|
||||
} // end wpi namespace
|
||||
|
||||
#endif
|
||||
754
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
vendored
Normal file
754
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
vendored
Normal file
@@ -0,0 +1,754 @@
|
||||
//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the raw_ostream class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
#define WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/span.h"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#if __cplusplus > 201402L
|
||||
#include <string_view>
|
||||
#endif
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace fs {
|
||||
enum FileAccess : unsigned;
|
||||
enum OpenFlags : unsigned;
|
||||
enum CreationDisposition : unsigned;
|
||||
class FileLocker;
|
||||
} // end namespace fs
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// This class implements an extremely fast bulk output stream that can *only*
|
||||
/// output to a stream. It does not support seeking, reopening, rewinding, line
|
||||
/// buffered disciplines etc. It is a simple buffer that outputs
|
||||
/// a chunk at a time.
|
||||
class raw_ostream {
|
||||
public:
|
||||
// Class kinds to support LLVM-style RTTI.
|
||||
enum class OStreamKind {
|
||||
OK_OStream,
|
||||
OK_FDStream,
|
||||
};
|
||||
|
||||
private:
|
||||
OStreamKind Kind;
|
||||
|
||||
/// The buffer is handled in such a way that the buffer is
|
||||
/// uninitialized, unbuffered, or out of space when OutBufCur >=
|
||||
/// OutBufEnd. Thus a single comparison suffices to determine if we
|
||||
/// need to take the slow path to write a single character.
|
||||
///
|
||||
/// The buffer is in one of three states:
|
||||
/// 1. Unbuffered (BufferMode == Unbuffered)
|
||||
/// 1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0).
|
||||
/// 2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 &&
|
||||
/// OutBufEnd - OutBufStart >= 1).
|
||||
///
|
||||
/// If buffered, then the raw_ostream owns the buffer if (BufferMode ==
|
||||
/// InternalBuffer); otherwise the buffer has been set via SetBuffer and is
|
||||
/// managed by the subclass.
|
||||
///
|
||||
/// If a subclass installs an external buffer using SetBuffer then it can wait
|
||||
/// for a \see write_impl() call to handle the data which has been put into
|
||||
/// this buffer.
|
||||
char *OutBufStart, *OutBufEnd, *OutBufCur;
|
||||
|
||||
/// Optional stream this stream is tied to. If this stream is written to, the
|
||||
/// tied-to stream will be flushed first.
|
||||
raw_ostream *TiedStream = nullptr;
|
||||
|
||||
enum class BufferKind {
|
||||
Unbuffered = 0,
|
||||
InternalBuffer,
|
||||
ExternalBuffer
|
||||
} BufferMode;
|
||||
|
||||
public:
|
||||
// color order matches ANSI escape sequence, don't change
|
||||
enum class Colors {
|
||||
BLACK = 0,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
BLUE,
|
||||
MAGENTA,
|
||||
CYAN,
|
||||
WHITE,
|
||||
SAVEDCOLOR,
|
||||
RESET,
|
||||
};
|
||||
|
||||
static constexpr Colors BLACK = Colors::BLACK;
|
||||
static constexpr Colors RED = Colors::RED;
|
||||
static constexpr Colors GREEN = Colors::GREEN;
|
||||
static constexpr Colors YELLOW = Colors::YELLOW;
|
||||
static constexpr Colors BLUE = Colors::BLUE;
|
||||
static constexpr Colors MAGENTA = Colors::MAGENTA;
|
||||
static constexpr Colors CYAN = Colors::CYAN;
|
||||
static constexpr Colors WHITE = Colors::WHITE;
|
||||
static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR;
|
||||
static constexpr Colors RESET = Colors::RESET;
|
||||
|
||||
explicit raw_ostream(bool unbuffered = false,
|
||||
OStreamKind K = OStreamKind::OK_OStream)
|
||||
: Kind(K), BufferMode(unbuffered ? BufferKind::Unbuffered
|
||||
: BufferKind::InternalBuffer) {
|
||||
// Start out ready to flush.
|
||||
OutBufStart = OutBufEnd = OutBufCur = nullptr;
|
||||
}
|
||||
|
||||
raw_ostream(const raw_ostream &) = delete;
|
||||
void operator=(const raw_ostream &) = delete;
|
||||
|
||||
virtual ~raw_ostream();
|
||||
|
||||
/// tell - Return the current offset with the file.
|
||||
uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
|
||||
|
||||
OStreamKind get_kind() const { return Kind; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Configuration Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// If possible, pre-allocate \p ExtraSize bytes for stream data.
|
||||
/// i.e. it extends internal buffers to keep additional ExtraSize bytes.
|
||||
/// So that the stream could keep at least tell() + ExtraSize bytes
|
||||
/// without re-allocations. reserveExtraSpace() does not change
|
||||
/// the size/data of the stream.
|
||||
virtual void reserveExtraSpace(uint64_t ExtraSize) {}
|
||||
|
||||
/// Set the stream to be buffered, with an automatically determined buffer
|
||||
/// size.
|
||||
void SetBuffered();
|
||||
|
||||
/// Set the stream to be buffered, using the specified buffer size.
|
||||
void SetBufferSize(size_t Size) {
|
||||
flush();
|
||||
SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer);
|
||||
}
|
||||
|
||||
size_t GetBufferSize() const {
|
||||
// If we're supposed to be buffered but haven't actually gotten around
|
||||
// to allocating the buffer yet, return the value that would be used.
|
||||
if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
|
||||
return preferred_buffer_size();
|
||||
|
||||
// Otherwise just return the size of the allocated buffer.
|
||||
return OutBufEnd - OutBufStart;
|
||||
}
|
||||
|
||||
/// Set the stream to be unbuffered. When unbuffered, the stream will flush
|
||||
/// after every write. This routine will also flush the buffer immediately
|
||||
/// when the stream is being set to unbuffered.
|
||||
void SetUnbuffered() {
|
||||
flush();
|
||||
SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
|
||||
}
|
||||
|
||||
size_t GetNumBytesInBuffer() const {
|
||||
return OutBufCur - OutBufStart;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Data Output Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void flush() {
|
||||
if (OutBufCur != OutBufStart)
|
||||
flush_nonempty();
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(unsigned char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(signed char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(span<const uint8_t> Arr) {
|
||||
// Inline fast path, particularly for arrays with a known length.
|
||||
size_t Size = Arr.size();
|
||||
|
||||
// Make sure we can use the fast path.
|
||||
if (Size > (size_t)(OutBufEnd - OutBufCur))
|
||||
return write(Arr.data(), Size);
|
||||
|
||||
if (Size) {
|
||||
memcpy(OutBufCur, Arr.data(), Size);
|
||||
OutBufCur += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(std::string_view Str) {
|
||||
// Inline fast path, particularly for strings with a known length.
|
||||
size_t Size = Str.size();
|
||||
|
||||
// Make sure we can use the fast path.
|
||||
if (Size > (size_t)(OutBufEnd - OutBufCur))
|
||||
return write(Str.data(), Size);
|
||||
|
||||
if (Size) {
|
||||
memcpy(OutBufCur, Str.data(), Size);
|
||||
OutBufCur += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const char *Str) {
|
||||
// Inline fast path, particularly for constant strings where a sufficiently
|
||||
// smart compiler will simplify strlen.
|
||||
|
||||
return this->operator<<(std::string_view(Str));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const std::string &Str) {
|
||||
// Avoid the fast path, it would only increase code size for a marginal win.
|
||||
return write(Str.data(), Str.length());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const SmallVectorImpl<char> &Str) {
|
||||
return write(Str.data(), Str.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const std::vector<uint8_t> &Arr) {
|
||||
// Avoid the fast path, it would only increase code size for a marginal win.
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const SmallVectorImpl<uint8_t> &Arr) {
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
|
||||
/// satisfy wpi::isPrint into an escape sequence.
|
||||
raw_ostream &write_escaped(std::string_view Str, bool UseHexEscapes = false);
|
||||
|
||||
raw_ostream &write(unsigned char C);
|
||||
raw_ostream &write(const char *Ptr, size_t Size);
|
||||
raw_ostream &write(const uint8_t *Ptr, size_t Size) {
|
||||
return write(reinterpret_cast<const char *>(Ptr), Size);
|
||||
}
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
/// write_zeros - Insert 'NumZeros' nulls.
|
||||
raw_ostream &write_zeros(unsigned NumZeros);
|
||||
|
||||
/// Changes the foreground color of text that will be output from this point
|
||||
/// forward.
|
||||
/// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
|
||||
/// change only the bold attribute, and keep colors untouched
|
||||
/// @param Bold bold/brighter text, default false
|
||||
/// @param BG if true change the background, default: change foreground
|
||||
/// @returns itself so it can be used within << invocations
|
||||
virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
|
||||
bool BG = false) {
|
||||
(void)Color;
|
||||
(void)Bold;
|
||||
(void)BG;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Resets the colors to terminal defaults. Call this when you are done
|
||||
/// outputting colored text, or before program exit.
|
||||
virtual raw_ostream &resetColor() { return *this; }
|
||||
|
||||
/// Reverses the foreground and background colors.
|
||||
virtual raw_ostream &reverseColor() { return *this; }
|
||||
|
||||
/// This function determines if this stream is connected to a "tty" or
|
||||
/// "console" window. That is, the output would be displayed to the user
|
||||
/// rather than being put on a pipe or stored in a file.
|
||||
virtual bool is_displayed() const { return false; }
|
||||
|
||||
/// This function determines if this stream is displayed and supports colors.
|
||||
/// The result is unaffected by calls to enable_color().
|
||||
virtual bool has_colors() const { return is_displayed(); }
|
||||
|
||||
// Enable or disable colors. Once enable_colors(false) is called,
|
||||
// changeColor() has no effect until enable_colors(true) is called.
|
||||
virtual void enable_colors(bool /*enable*/) {}
|
||||
|
||||
/// Tie this stream to the specified stream. Replaces any existing tied-to
|
||||
/// stream. Specifying a nullptr unties the stream.
|
||||
void tie(raw_ostream *TieTo) { TiedStream = TieTo; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Subclass Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
private:
|
||||
/// The is the piece of the class that is implemented by subclasses. This
|
||||
/// writes the \p Size bytes starting at
|
||||
/// \p Ptr to the underlying stream.
|
||||
///
|
||||
/// This function is guaranteed to only be called at a point at which it is
|
||||
/// safe for the subclass to install a new buffer via SetBuffer.
|
||||
///
|
||||
/// \param Ptr The start of the data to be written. For buffered streams this
|
||||
/// is guaranteed to be the start of the buffer.
|
||||
///
|
||||
/// \param Size The number of bytes to be written.
|
||||
///
|
||||
/// \invariant { Size > 0 }
|
||||
virtual void write_impl(const char *Ptr, size_t Size) = 0;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
virtual uint64_t current_pos() const = 0;
|
||||
|
||||
protected:
|
||||
/// Use the provided buffer as the raw_ostream buffer. This is intended for
|
||||
/// use only by subclasses which can arrange for the output to go directly
|
||||
/// into the desired output buffer, instead of being copied on each flush.
|
||||
void SetBuffer(char *BufferStart, size_t Size) {
|
||||
SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
|
||||
}
|
||||
|
||||
/// Return an efficient buffer size for the underlying output mechanism.
|
||||
virtual size_t preferred_buffer_size() const;
|
||||
|
||||
/// Return the beginning of the current stream buffer, or 0 if the stream is
|
||||
/// unbuffered.
|
||||
const char *getBufferStart() const { return OutBufStart; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Private Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
private:
|
||||
/// Install the given buffer and mode.
|
||||
void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode);
|
||||
|
||||
/// Flush the current buffer, which is known to be non-empty. This outputs the
|
||||
/// currently buffered data and resets the buffer to empty.
|
||||
void flush_nonempty();
|
||||
|
||||
/// Copy data into the buffer. Size must not be greater than the number of
|
||||
/// unused bytes in the buffer.
|
||||
void copy_to_buffer(const char *Ptr, size_t Size);
|
||||
|
||||
/// Flush the tied-to stream (if present) and then write the required data.
|
||||
void flush_tied_then_write(const char *Ptr, size_t Size);
|
||||
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// Call the appropriate insertion operator, given an rvalue reference to a
|
||||
/// raw_ostream object and return a stream of the same type as the argument.
|
||||
template <typename OStream, typename T>
|
||||
std::enable_if_t<!std::is_reference<OStream>::value &&
|
||||
std::is_base_of<raw_ostream, OStream>::value,
|
||||
OStream &&>
|
||||
operator<<(OStream &&OS, const T &Value) {
|
||||
OS << Value;
|
||||
return std::move(OS);
|
||||
}
|
||||
|
||||
/// An abstract base class for streams implementations that also support a
|
||||
/// pwrite operation. This is useful for code that can mostly stream out data,
|
||||
/// but needs to patch in a header that needs to know the output size.
|
||||
class raw_pwrite_stream : public raw_ostream {
|
||||
virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
explicit raw_pwrite_stream(bool Unbuffered = false,
|
||||
OStreamKind K = OStreamKind::OK_OStream)
|
||||
: raw_ostream(Unbuffered, K) {}
|
||||
void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
|
||||
#ifndef NDEBUG
|
||||
uint64_t Pos = tell();
|
||||
// /dev/null always reports a pos of 0, so we cannot perform this check
|
||||
// in that case.
|
||||
if (Pos)
|
||||
assert(Size + Offset <= Pos && "We don't support extending the stream");
|
||||
#endif
|
||||
pwrite_impl(Ptr, Size, Offset);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Output Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream that writes to a file descriptor.
|
||||
///
|
||||
class raw_fd_ostream : public raw_pwrite_stream {
|
||||
int FD;
|
||||
bool ShouldClose;
|
||||
bool SupportsSeeking = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
/// True if this fd refers to a Windows console device. Mintty and other
|
||||
/// terminal emulators are TTYs, but they are not consoles.
|
||||
bool IsWindowsConsole = false;
|
||||
#endif
|
||||
|
||||
std::error_code EC;
|
||||
|
||||
uint64_t pos = 0;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override { return pos; }
|
||||
|
||||
/// Determine an efficient buffer size.
|
||||
size_t preferred_buffer_size() const override;
|
||||
|
||||
void anchor() override;
|
||||
|
||||
protected:
|
||||
/// Set the flag indicating that an output error has been encountered.
|
||||
void error_detected(std::error_code EC) { this->EC = EC; }
|
||||
|
||||
/// Return the file descriptor.
|
||||
int get_fd() const { return FD; }
|
||||
|
||||
// Update the file position by increasing \p Delta.
|
||||
void inc_pos(uint64_t Delta) { pos += Delta; }
|
||||
|
||||
public:
|
||||
/// Open the specified file for writing. If an error occurs, information
|
||||
/// about the error is put into EC, and the stream should be immediately
|
||||
/// destroyed;
|
||||
/// \p Flags allows optional flags to control how the file will be opened.
|
||||
///
|
||||
/// As a special case, if Filename is "-", then the stream will use
|
||||
/// STDOUT_FILENO instead of opening a file. This will not close the stdout
|
||||
/// descriptor.
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags);
|
||||
|
||||
/// FD is the file descriptor that this writes to. If ShouldClose is true,
|
||||
/// this closes the file when the stream is destroyed. If FD is for stdout or
|
||||
/// stderr, it will not be closed.
|
||||
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered = false,
|
||||
OStreamKind K = OStreamKind::OK_OStream);
|
||||
|
||||
~raw_fd_ostream() override;
|
||||
|
||||
/// Manually flush the stream and close the file. Note that this does not call
|
||||
/// fsync.
|
||||
void close();
|
||||
|
||||
bool supportsSeeking() const { return SupportsSeeking; }
|
||||
|
||||
/// Flushes the stream and repositions the underlying file descriptor position
|
||||
/// to the offset specified from the beginning of the file.
|
||||
uint64_t seek(uint64_t off);
|
||||
|
||||
std::error_code error() const { return EC; }
|
||||
|
||||
/// Return the value of the flag in this raw_fd_ostream indicating whether an
|
||||
/// output error has been encountered.
|
||||
/// This doesn't implicitly flush any pending output. Also, it doesn't
|
||||
/// guarantee to detect all errors unless the stream has been closed.
|
||||
bool has_error() const { return bool(EC); }
|
||||
|
||||
/// Set the flag read by has_error() to false. If the error flag is set at the
|
||||
/// time when this raw_ostream's destructor is called, report_fatal_error is
|
||||
/// called to report the error. Use clear_error() after handling the error to
|
||||
/// avoid this behavior.
|
||||
///
|
||||
/// "Errors should never pass silently.
|
||||
/// Unless explicitly silenced."
|
||||
/// - from The Zen of Python, by Tim Peters
|
||||
///
|
||||
void clear_error() { EC = std::error_code(); }
|
||||
};
|
||||
|
||||
/// This returns a reference to a raw_fd_ostream for standard output. Use it
|
||||
/// like: outs() << "foo" << "bar";
|
||||
raw_fd_ostream &outs();
|
||||
|
||||
/// This returns a reference to a raw_ostream for standard error.
|
||||
/// Use it like: errs() << "foo" << "bar";
|
||||
/// By default, the stream is tied to stdout to ensure stdout is flushed before
|
||||
/// stderr is written, to ensure the error messages are written in their
|
||||
/// expected place.
|
||||
raw_fd_ostream &errs();
|
||||
|
||||
/// This returns a reference to a raw_ostream which simply discards output.
|
||||
raw_ostream &nulls();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream of a file for reading/writing/seeking.
|
||||
///
|
||||
class raw_fd_stream : public raw_fd_ostream {
|
||||
public:
|
||||
/// Open the specified file for reading/writing/seeking. If an error occurs,
|
||||
/// information about the error is put into EC, and the stream should be
|
||||
/// immediately destroyed.
|
||||
raw_fd_stream(std::string_view Filename, std::error_code &EC);
|
||||
|
||||
/// Check if \p OS is a pointer of type raw_fd_stream*.
|
||||
static bool classof(const raw_ostream *OS);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Output Stream Adaptors
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream that writes to an std::string. This is a simple adaptor
|
||||
/// class. This class does not encounter output errors.
|
||||
class raw_string_ostream : public raw_ostream {
|
||||
std::string &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override { return OS.size(); }
|
||||
|
||||
public:
|
||||
explicit raw_string_ostream(std::string &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_string_ostream() override;
|
||||
|
||||
/// Flushes the stream contents to the target string and returns the string's
|
||||
/// reference.
|
||||
std::string& str() {
|
||||
flush();
|
||||
return OS;
|
||||
}
|
||||
|
||||
void reserveExtraSpace(uint64_t ExtraSize) override {
|
||||
OS.reserve(tell() + ExtraSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_svector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the SmallString. Thus the SmallString is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_svector_ostream : public raw_pwrite_stream {
|
||||
SmallVectorImpl<char> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_svector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a std::string_view for the vector contents.
|
||||
std::string_view str() const { return std::string_view(OS.data(), OS.size()); }
|
||||
|
||||
void reserveExtraSpace(uint64_t ExtraSize) override {
|
||||
OS.reserve(tell() + ExtraSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to a vector. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_vector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the vector. Thus the vector is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_vector_ostream : public raw_pwrite_stream {
|
||||
std::vector<char> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_vector_ostream(std::vector<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_vector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a std::string_view for the vector contents.
|
||||
std::string_view str() { return std::string_view(OS.data(), OS.size()); }
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_svector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the SmallString. Thus the SmallString is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_usvector_ostream : public raw_pwrite_stream {
|
||||
SmallVectorImpl<uint8_t> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_usvector_ostream(SmallVectorImpl<uint8_t> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_usvector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return an span for the vector contents.
|
||||
span<uint8_t> array() { return {OS.data(), OS.size()}; }
|
||||
span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to a vector. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_vector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the vector. Thus the vector is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_uvector_ostream : public raw_pwrite_stream {
|
||||
std::vector<uint8_t> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_uvector_ostream(std::vector<uint8_t> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_uvector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a span for the vector contents.
|
||||
span<uint8_t> array() { return {OS.data(), OS.size()}; }
|
||||
span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
|
||||
};
|
||||
|
||||
|
||||
/// A raw_ostream that discards all output.
|
||||
class raw_null_ostream : public raw_pwrite_stream {
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t size) override;
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
explicit raw_null_ostream() = default;
|
||||
~raw_null_ostream() override;
|
||||
};
|
||||
|
||||
class buffer_ostream : public raw_svector_ostream {
|
||||
raw_ostream &OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
virtual void anchor() override;
|
||||
|
||||
public:
|
||||
buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
|
||||
~buffer_ostream() override { OS << str(); }
|
||||
};
|
||||
|
||||
class buffer_unique_ostream : public raw_svector_ostream {
|
||||
std::unique_ptr<raw_ostream> OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
virtual void anchor() override;
|
||||
|
||||
public:
|
||||
buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
|
||||
: raw_svector_ostream(Buffer), OS(std::move(OS)) {}
|
||||
~buffer_unique_ostream() override { *OS << str(); }
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
104
wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
vendored
Normal file
104
wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides useful additions to the standard type_traits library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
#define WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
|
||||
/// Metafunction that determines whether the given type is either an
|
||||
/// integral type or an enumeration type, including enum classes.
|
||||
///
|
||||
/// Note that this accepts potentially more integral types than is_integral
|
||||
/// because it is based on being implicitly convertible to an integral type.
|
||||
/// Also note that enum classes aren't implicitly convertible to integral types,
|
||||
/// the value may therefore need to be explicitly converted before being used.
|
||||
template <typename T> class is_integral_or_enum {
|
||||
using UnderlyingT = std::remove_reference_t<T>;
|
||||
|
||||
public:
|
||||
static const bool value =
|
||||
!std::is_class<UnderlyingT>::value && // Filter conversion operators.
|
||||
!std::is_pointer<UnderlyingT>::value &&
|
||||
!std::is_floating_point<UnderlyingT>::value &&
|
||||
(std::is_enum<UnderlyingT>::value ||
|
||||
std::is_convertible<UnderlyingT, unsigned long long>::value);
|
||||
};
|
||||
|
||||
/// If T is a pointer, just return it. If it is not, return T&.
|
||||
template<typename T, typename Enable = void>
|
||||
struct add_lvalue_reference_if_not_pointer { using type = T &; };
|
||||
|
||||
template <typename T>
|
||||
struct add_lvalue_reference_if_not_pointer<
|
||||
T, std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// If T is a pointer to X, return a pointer to const X. If it is not,
|
||||
/// return const T.
|
||||
template<typename T, typename Enable = void>
|
||||
struct add_const_past_pointer { using type = const T; };
|
||||
|
||||
template <typename T>
|
||||
struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
using type = const std::remove_pointer_t<T> *;
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct const_pointer_or_const_ref {
|
||||
using type = const T &;
|
||||
};
|
||||
template <typename T>
|
||||
struct const_pointer_or_const_ref<T,
|
||||
std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
using type = typename add_const_past_pointer<T>::type;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// Internal utility to detect trivial copy construction.
|
||||
template<typename T> union copy_construction_triviality_helper {
|
||||
T t;
|
||||
copy_construction_triviality_helper() = default;
|
||||
copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
|
||||
~copy_construction_triviality_helper() = default;
|
||||
};
|
||||
/// Internal utility to detect trivial move construction.
|
||||
template<typename T> union move_construction_triviality_helper {
|
||||
T t;
|
||||
move_construction_triviality_helper() = default;
|
||||
move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
|
||||
~move_construction_triviality_helper() = default;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
union trivial_helper {
|
||||
T t;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template <typename T>
|
||||
using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;
|
||||
|
||||
template <typename T>
|
||||
using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
|
||||
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
8207
wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
vendored
Normal file
8207
wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7251
wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
vendored
Normal file
7251
wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
832
wpiutil/src/main/native/thirdparty/sigslot/include/wpi/Signal.h
vendored
Normal file
832
wpiutil/src/main/native/thirdparty/sigslot/include/wpi/Signal.h
vendored
Normal file
@@ -0,0 +1,832 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
||||
Sigslot, a signal-slot library
|
||||
|
||||
https://github.com/palacaze/sigslot
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Pierre-Antoine Lacaze
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
namespace sig {
|
||||
|
||||
namespace trait {
|
||||
|
||||
/// represent a list of types
|
||||
template <typename...> struct typelist {};
|
||||
|
||||
/**
|
||||
* Pointers that can be converted to a weak pointer concept for tracking
|
||||
* purpose must implement the to_weak() function in order to make use of
|
||||
* ADL to convert that type and make it usable
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
std::weak_ptr<T> to_weak(std::weak_ptr<T> w) {
|
||||
return w;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::weak_ptr<T> to_weak(std::shared_ptr<T> s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// tools
|
||||
namespace detail {
|
||||
|
||||
template <class...>
|
||||
struct voider { using type = void; };
|
||||
|
||||
// void_t from c++17
|
||||
template <class...T>
|
||||
using void_t = typename detail::voider<T...>::type;
|
||||
|
||||
|
||||
template <typename, typename, typename = void, typename = void>
|
||||
struct is_callable : std::false_type {};
|
||||
|
||||
template <typename F, typename P, typename... T>
|
||||
struct is_callable<F, P, typelist<T...>,
|
||||
void_t<decltype(((*std::declval<P>()).*std::declval<F>())(std::declval<T>()...))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename F, typename... T>
|
||||
struct is_callable<F, typelist<T...>,
|
||||
void_t<decltype(std::declval<F>()(std::declval<T>()...))>>
|
||||
: std::true_type {};
|
||||
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_weak_ptr : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_weak_ptr<T, void_t<decltype(std::declval<T>().expired()),
|
||||
decltype(std::declval<T>().lock()),
|
||||
decltype(std::declval<T>().reset())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_weak_ptr_compatible : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_weak_ptr_compatible<T, void_t<decltype(to_weak(std::declval<T>()))>>
|
||||
: is_weak_ptr<decltype(to_weak(std::declval<T>()))> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// determine if a pointer is convertible into a "weak" pointer
|
||||
template <typename P>
|
||||
constexpr bool is_weak_ptr_compatible_v = detail::is_weak_ptr_compatible<std::decay_t<P>>::value;
|
||||
|
||||
/// determine if a type T (Callable or Pmf) is callable with supplied arguments in L
|
||||
template <typename L, typename... T>
|
||||
constexpr bool is_callable_v = detail::is_callable<T..., L>::value;
|
||||
|
||||
} // namespace trait
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* SlotState holds slot type independent state, to be used to interact with
|
||||
* slots indirectly through connection and ScopedConnection objects.
|
||||
*/
|
||||
class SlotState {
|
||||
public:
|
||||
constexpr SlotState() noexcept
|
||||
: m_connected(true),
|
||||
m_blocked(false) {}
|
||||
|
||||
virtual ~SlotState() = default;
|
||||
|
||||
bool connected() const noexcept { return m_connected; }
|
||||
bool disconnect() noexcept { return m_connected.exchange(false); }
|
||||
|
||||
bool blocked() const noexcept { return m_blocked.load(); }
|
||||
void block() noexcept { m_blocked.store(true); }
|
||||
void unblock() noexcept { m_blocked.store(false); }
|
||||
|
||||
private:
|
||||
std::atomic<bool> m_connected;
|
||||
std::atomic<bool> m_blocked;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* ConnectionBlocker is a RAII object that blocks a connection until destruction
|
||||
*/
|
||||
class ConnectionBlocker {
|
||||
public:
|
||||
ConnectionBlocker() = default;
|
||||
~ConnectionBlocker() noexcept { release(); }
|
||||
|
||||
ConnectionBlocker(const ConnectionBlocker &) = delete;
|
||||
ConnectionBlocker & operator=(const ConnectionBlocker &) = delete;
|
||||
|
||||
ConnectionBlocker(ConnectionBlocker && o) noexcept
|
||||
: m_state{std::move(o.m_state)}
|
||||
{}
|
||||
|
||||
ConnectionBlocker & operator=(ConnectionBlocker && o) noexcept {
|
||||
release();
|
||||
m_state.swap(o.m_state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Connection;
|
||||
ConnectionBlocker(std::weak_ptr<detail::SlotState> s) noexcept
|
||||
: m_state{std::move(s)}
|
||||
{
|
||||
auto d = m_state.lock();
|
||||
if (d) d->block();
|
||||
}
|
||||
|
||||
void release() noexcept {
|
||||
auto d = m_state.lock();
|
||||
if (d) d->unblock();
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<detail::SlotState> m_state;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Connection object allows interaction with an ongoing slot connection
|
||||
*
|
||||
* It allows common actions such as connection blocking and disconnection.
|
||||
* Note that Connection is not a RAII object, one does not need to hold one
|
||||
* such object to keep the signal-slot connection alive.
|
||||
*/
|
||||
class Connection {
|
||||
public:
|
||||
Connection() = default;
|
||||
virtual ~Connection() = default;
|
||||
|
||||
Connection(const Connection &) noexcept = default;
|
||||
Connection & operator=(const Connection &) noexcept = default;
|
||||
Connection(Connection &&) noexcept = default;
|
||||
Connection & operator=(Connection &&) noexcept = default;
|
||||
|
||||
bool valid() const noexcept {
|
||||
return !m_state.expired();
|
||||
}
|
||||
|
||||
bool connected() const noexcept {
|
||||
const auto d = m_state.lock();
|
||||
return d && d->connected();
|
||||
}
|
||||
|
||||
bool disconnect() noexcept {
|
||||
auto d = m_state.lock();
|
||||
return d && d->disconnect();
|
||||
}
|
||||
|
||||
bool blocked() const noexcept {
|
||||
const auto d = m_state.lock();
|
||||
return d && d->blocked();
|
||||
}
|
||||
|
||||
void block() noexcept {
|
||||
auto d = m_state.lock();
|
||||
if(d)
|
||||
d->block();
|
||||
}
|
||||
|
||||
void unblock() noexcept {
|
||||
auto d = m_state.lock();
|
||||
if(d)
|
||||
d->unblock();
|
||||
}
|
||||
|
||||
ConnectionBlocker blocker() const noexcept {
|
||||
return ConnectionBlocker{m_state};
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename, typename...> friend class SignalBase;
|
||||
Connection(std::weak_ptr<detail::SlotState> s) noexcept
|
||||
: m_state{std::move(s)}
|
||||
{}
|
||||
|
||||
protected:
|
||||
std::weak_ptr<detail::SlotState> m_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* ScopedConnection is a RAII version of Connection
|
||||
* It disconnects the slot from the signal upon destruction.
|
||||
*/
|
||||
class ScopedConnection : public Connection {
|
||||
public:
|
||||
ScopedConnection() = default;
|
||||
~ScopedConnection() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
ScopedConnection(const Connection &c) noexcept : Connection(c) {}
|
||||
ScopedConnection(Connection &&c) noexcept : Connection(std::move(c)) {}
|
||||
|
||||
ScopedConnection(const ScopedConnection &) noexcept = delete;
|
||||
ScopedConnection & operator=(const ScopedConnection &) noexcept = delete;
|
||||
|
||||
ScopedConnection(ScopedConnection && o) noexcept
|
||||
: Connection{std::move(o.m_state)}
|
||||
{}
|
||||
|
||||
ScopedConnection & operator=(ScopedConnection && o) noexcept {
|
||||
disconnect();
|
||||
m_state.swap(o.m_state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename...> friend class SignalBase;
|
||||
ScopedConnection(std::weak_ptr<detail::SlotState> s) noexcept
|
||||
: Connection{std::move(s)}
|
||||
{}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename...>
|
||||
class SlotBase;
|
||||
|
||||
template <typename... T>
|
||||
using SlotPtr = std::shared_ptr<SlotBase<T...>>;
|
||||
|
||||
/* A base class for slot objects. This base type only depends on slot argument
|
||||
* types, it will be used as an element in an intrusive singly-linked list of
|
||||
* slots, hence the public next member.
|
||||
*/
|
||||
template <typename... Args>
|
||||
class SlotBase : public SlotState {
|
||||
public:
|
||||
using base_types = trait::typelist<Args...>;
|
||||
|
||||
virtual ~SlotBase() noexcept = default;
|
||||
|
||||
// method effectively responsible for calling the "slot" function with
|
||||
// supplied arguments whenever emission happens.
|
||||
virtual void call_slot(Args...) = 0;
|
||||
|
||||
template <typename... U>
|
||||
void operator()(U && ...u) {
|
||||
if (SlotState::connected() && !SlotState::blocked())
|
||||
call_slot(std::forward<U>(u)...);
|
||||
}
|
||||
|
||||
SlotPtr<Args...> next;
|
||||
};
|
||||
|
||||
template <typename, typename...> class Slot {};
|
||||
|
||||
/*
|
||||
* A slot object holds state information, and a callable to to be called
|
||||
* whenever the function call operator of its SlotBase base class is called.
|
||||
*/
|
||||
template <typename Func, typename... Args>
|
||||
class Slot<Func, trait::typelist<Args...>> : public SlotBase<Args...> {
|
||||
public:
|
||||
template <typename F>
|
||||
constexpr Slot(F && f) : func{std::forward<F>(f)} {}
|
||||
|
||||
virtual void call_slot(Args ...args) override {
|
||||
func(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::decay_t<Func> func;
|
||||
};
|
||||
|
||||
/*
|
||||
* Variation of slot that prepends a Connection object to the callable
|
||||
*/
|
||||
template <typename Func, typename... Args>
|
||||
class Slot<Func, trait::typelist<Connection&, Args...>> : public SlotBase<Args...> {
|
||||
public:
|
||||
template <typename F>
|
||||
constexpr Slot(F && f) : func{std::forward<F>(f)} {}
|
||||
|
||||
virtual void call_slot(Args ...args) override {
|
||||
func(conn, args...);
|
||||
}
|
||||
|
||||
Connection conn;
|
||||
|
||||
private:
|
||||
std::decay_t<Func> func;
|
||||
};
|
||||
|
||||
/*
|
||||
* A slot object holds state information, an object and a pointer over member
|
||||
* function to be called whenever the function call operator of its SlotBase
|
||||
* base class is called.
|
||||
*/
|
||||
template <typename Pmf, typename Ptr, typename... Args>
|
||||
class Slot<Pmf, Ptr, trait::typelist<Args...>> : public SlotBase<Args...> {
|
||||
public:
|
||||
template <typename F, typename P>
|
||||
constexpr Slot(F && f, P && p)
|
||||
: pmf{std::forward<F>(f)},
|
||||
ptr{std::forward<P>(p)} {}
|
||||
|
||||
virtual void call_slot(Args ...args) override {
|
||||
((*ptr).*pmf)(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::decay_t<Pmf> pmf;
|
||||
std::decay_t<Ptr> ptr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Variation of slot that prepends a Connection object to the callable
|
||||
*/
|
||||
template <typename Pmf, typename Ptr, typename... Args>
|
||||
class Slot<Pmf, Ptr, trait::typelist<Connection&, Args...>> : public SlotBase<Args...> {
|
||||
public:
|
||||
template <typename F, typename P>
|
||||
constexpr Slot(F && f, P && p)
|
||||
: pmf{std::forward<F>(f)},
|
||||
ptr{std::forward<P>(p)} {}
|
||||
|
||||
virtual void call_slot(Args ...args) override {
|
||||
((*ptr).*pmf)(conn, args...);
|
||||
}
|
||||
|
||||
Connection conn;
|
||||
|
||||
private:
|
||||
std::decay_t<Pmf> pmf;
|
||||
std::decay_t<Ptr> ptr;
|
||||
};
|
||||
|
||||
template <typename, typename, typename...> class SlotTracked {};
|
||||
|
||||
/*
|
||||
* An implementation of a slot that tracks the life of a supplied object
|
||||
* through a weak pointer in order to automatically disconnect the slot
|
||||
* on said object destruction.
|
||||
*/
|
||||
template <typename Func, typename WeakPtr, typename... Args>
|
||||
class SlotTracked<Func, WeakPtr, trait::typelist<Args...>> : public SlotBase<Args...> {
|
||||
public:
|
||||
template <typename F, typename P>
|
||||
constexpr SlotTracked(F && f, P && p)
|
||||
: func{std::forward<F>(f)},
|
||||
ptr{std::forward<P>(p)}
|
||||
{}
|
||||
|
||||
virtual void call_slot(Args ...args) override {
|
||||
if (! SlotState::connected())
|
||||
return;
|
||||
if (ptr.expired())
|
||||
SlotState::disconnect();
|
||||
else
|
||||
func(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::decay_t<Func> func;
|
||||
std::decay_t<WeakPtr> ptr;
|
||||
};
|
||||
|
||||
template <typename, typename, typename...> class SlotPmfTracked {};
|
||||
|
||||
/*
|
||||
* An implementation of a slot as a pointer over member function, that tracks
|
||||
* the life of a supplied object through a weak pointer in order to automatically
|
||||
* disconnect the slot on said object destruction.
|
||||
*/
|
||||
template <typename Pmf, typename WeakPtr, typename... Args>
|
||||
class SlotPmfTracked<Pmf, WeakPtr, trait::typelist<Args...>> : public SlotBase<Args...> {
|
||||
public:
|
||||
template <typename F, typename P>
|
||||
constexpr SlotPmfTracked(F && f, P && p)
|
||||
: pmf{std::forward<F>(f)},
|
||||
ptr{std::forward<P>(p)}
|
||||
{}
|
||||
|
||||
virtual void call_slot(Args ...args) override {
|
||||
if (! SlotState::connected())
|
||||
return;
|
||||
auto sp = ptr.lock();
|
||||
if (!sp)
|
||||
SlotState::disconnect();
|
||||
else
|
||||
((*sp).*pmf)(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::decay_t<Pmf> pmf;
|
||||
std::decay_t<WeakPtr> ptr;
|
||||
};
|
||||
|
||||
|
||||
// noop mutex for thread-unsafe use
|
||||
struct NullMutex {
|
||||
NullMutex() = default;
|
||||
NullMutex(const NullMutex &) = delete;
|
||||
NullMutex operator=(const NullMutex &) = delete;
|
||||
NullMutex(NullMutex &&) = delete;
|
||||
NullMutex operator=(NullMutex &&) = delete;
|
||||
|
||||
bool try_lock() { return true; }
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/**
|
||||
* SignalBase is an implementation of the observer pattern, through the use
|
||||
* of an emitting object and slots that are connected to the signal and called
|
||||
* with supplied arguments when a signal is emitted.
|
||||
*
|
||||
* wpi::SignalBase is the general implementation, whose locking policy must be
|
||||
* set in order to decide thread safety guarantees. wpi::Signal and wpi::Signal_st
|
||||
* are partial specializations for multi-threaded and single-threaded use.
|
||||
*
|
||||
* It does not allow slots to return a value.
|
||||
*
|
||||
* @tparam Lockable a lock type to decide the lock policy
|
||||
* @tparam T... the argument types of the emitting and slots functions.
|
||||
*/
|
||||
template <typename Lockable, typename... T>
|
||||
class SignalBase {
|
||||
using lock_type = std::unique_lock<Lockable>;
|
||||
using SlotPtr = detail::SlotPtr<T...>;
|
||||
|
||||
struct CallSlots {
|
||||
SlotPtr m_slots;
|
||||
SignalBase& m_base;
|
||||
|
||||
CallSlots(SignalBase& base) : m_base(base) {}
|
||||
|
||||
template <typename... A>
|
||||
void operator()(A && ... a) {
|
||||
SlotPtr *prev = nullptr;
|
||||
SlotPtr *curr = m_slots ? &m_slots : nullptr;
|
||||
|
||||
while (curr) {
|
||||
// call non blocked, non connected slots
|
||||
if ((*curr)->connected()) {
|
||||
if (!m_base.m_block && !(*curr)->blocked())
|
||||
(*curr)->operator()(a...);
|
||||
prev = curr;
|
||||
curr = (*curr)->next ? &((*curr)->next) : nullptr;
|
||||
}
|
||||
// remove slots marked as disconnected
|
||||
else {
|
||||
if (prev) {
|
||||
(*prev)->next = (*curr)->next;
|
||||
curr = (*prev)->next ? &((*prev)->next) : nullptr;
|
||||
}
|
||||
else
|
||||
curr = (*curr)->next ? &((*curr)->next) : nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using arg_list = trait::typelist<T...>;
|
||||
using ext_arg_list = trait::typelist<Connection&, T...>;
|
||||
|
||||
SignalBase() noexcept : m_block(false) {}
|
||||
~SignalBase() {
|
||||
disconnect_all();
|
||||
}
|
||||
|
||||
SignalBase(const SignalBase&) = delete;
|
||||
SignalBase & operator=(const SignalBase&) = delete;
|
||||
|
||||
SignalBase(SignalBase && o)
|
||||
: m_block{o.m_block.load()}
|
||||
{
|
||||
lock_type lock(o.m_mutex);
|
||||
std::swap(m_func, o.m_func);
|
||||
}
|
||||
|
||||
SignalBase & operator=(SignalBase && o) {
|
||||
std::scoped_lock lock(m_mutex, o.m_mutex);
|
||||
|
||||
std::swap(m_func, o.m_func);
|
||||
m_block.store(o.m_block.exchange(m_block.load()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a signal
|
||||
*
|
||||
* Effect: All non blocked and connected slot functions will be called
|
||||
* with supplied arguments.
|
||||
* Safety: With proper locking (see wpi::Signal), emission can happen from
|
||||
* multiple threads simultaneously. The guarantees only apply to the
|
||||
* signal object, it does not cover thread safety of potentially
|
||||
* shared state used in slot functions.
|
||||
*
|
||||
* @param a arguments to emit
|
||||
*/
|
||||
template <typename... A>
|
||||
void operator()(A && ... a) const {
|
||||
lock_type lock(m_mutex);
|
||||
if (!m_block && m_func) m_func(std::forward<A>(a)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a callable of compatible arguments
|
||||
*
|
||||
* Effect: Creates and stores a new slot responsible for executing the
|
||||
* supplied callable for every subsequent signal emission.
|
||||
* Safety: Thread-safety depends on locking policy.
|
||||
*
|
||||
* @param c a callable
|
||||
*/
|
||||
template <typename Callable>
|
||||
void connect(Callable && c) {
|
||||
if (!m_func) {
|
||||
m_func = std::forward<Callable>(c);
|
||||
} else {
|
||||
using slot_t = detail::Slot<Callable, arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Callable>(c));
|
||||
add_slot(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a callable of compatible arguments, returning a Connection
|
||||
*
|
||||
* Effect: Creates and stores a new slot responsible for executing the
|
||||
* supplied callable for every subsequent signal emission.
|
||||
* Safety: Thread-safety depends on locking policy.
|
||||
*
|
||||
* @param c a callable
|
||||
* @return a Connection object that can be used to interact with the slot
|
||||
*/
|
||||
template <typename Callable>
|
||||
std::enable_if_t<trait::is_callable_v<arg_list, Callable>, Connection>
|
||||
connect_connection(Callable && c) {
|
||||
using slot_t = detail::Slot<Callable, arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Callable>(c));
|
||||
add_slot(s);
|
||||
return Connection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a callable with an additional Connection argument
|
||||
*
|
||||
* The callable's first argument must be of type Connection. This overload
|
||||
* the callable to manage it's own connection through this argument.
|
||||
*
|
||||
* @param c a callable
|
||||
* @return a Connection object that can be used to interact with the slot
|
||||
*/
|
||||
template <typename Callable>
|
||||
std::enable_if_t<trait::is_callable_v<ext_arg_list, Callable>, Connection>
|
||||
connect_extended(Callable && c) {
|
||||
using slot_t = detail::Slot<Callable, ext_arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Callable>(c));
|
||||
s->conn = Connection(s);
|
||||
add_slot(s);
|
||||
return Connection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload of connect for pointers over member functions
|
||||
*
|
||||
* @param pmf a pointer over member function
|
||||
* @param ptr an object pointer
|
||||
* @return a Connection object that can be used to interact with the slot
|
||||
*/
|
||||
template <typename Pmf, typename Ptr>
|
||||
std::enable_if_t<trait::is_callable_v<arg_list, Pmf, Ptr> &&
|
||||
!trait::is_weak_ptr_compatible_v<Ptr>, Connection>
|
||||
connect(Pmf && pmf, Ptr && ptr) {
|
||||
using slot_t = detail::Slot<Pmf, Ptr, arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr));
|
||||
add_slot(s);
|
||||
return Connection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload of connect for pointer over member functions and
|
||||
*
|
||||
* @param pmf a pointer over member function
|
||||
* @param ptr an object pointer
|
||||
* @return a Connection object that can be used to interact with the slot
|
||||
*/
|
||||
template <typename Pmf, typename Ptr>
|
||||
std::enable_if_t<trait::is_callable_v<ext_arg_list, Pmf, Ptr> &&
|
||||
!trait::is_weak_ptr_compatible_v<Ptr>, Connection>
|
||||
connect_extended(Pmf && pmf, Ptr && ptr) {
|
||||
using slot_t = detail::Slot<Pmf, Ptr, ext_arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr));
|
||||
s->conn = Connection(s);
|
||||
add_slot(s);
|
||||
return Connection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload of connect for lifetime object tracking and automatic disconnection
|
||||
*
|
||||
* Ptr must be convertible to an object following a loose form of weak pointer
|
||||
* concept, by implementing the ADL-detected conversion function to_weak().
|
||||
*
|
||||
* This overload covers the case of a pointer over member function and a
|
||||
* trackable pointer of that class.
|
||||
*
|
||||
* Note: only weak references are stored, a slot does not extend the lifetime
|
||||
* of a suppied object.
|
||||
*
|
||||
* @param pmf a pointer over member function
|
||||
* @param ptr a trackable object pointer
|
||||
* @return a Connection object that can be used to interact with the slot
|
||||
*/
|
||||
template <typename Pmf, typename Ptr>
|
||||
std::enable_if_t<!trait::is_callable_v<arg_list, Pmf> &&
|
||||
trait::is_weak_ptr_compatible_v<Ptr>, Connection>
|
||||
connect(Pmf && pmf, Ptr && ptr) {
|
||||
using trait::to_weak;
|
||||
auto w = to_weak(std::forward<Ptr>(ptr));
|
||||
using slot_t = detail::SlotPmfTracked<Pmf, decltype(w), arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Pmf>(pmf), w);
|
||||
add_slot(s);
|
||||
return Connection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload of connect for lifetime object tracking and automatic disconnection
|
||||
*
|
||||
* Trackable must be convertible to an object following a loose form of weak
|
||||
* pointer concept, by implementing the ADL-detected conversion function to_weak().
|
||||
*
|
||||
* This overload covers the case of a standalone callable and unrelated trackable
|
||||
* object.
|
||||
*
|
||||
* Note: only weak references are stored, a slot does not extend the lifetime
|
||||
* of a suppied object.
|
||||
*
|
||||
* @param c a callable
|
||||
* @param ptr a trackable object pointer
|
||||
* @return a Connection object that can be used to interact with the slot
|
||||
*/
|
||||
template <typename Callable, typename Trackable>
|
||||
std::enable_if_t<trait::is_callable_v<arg_list, Callable> &&
|
||||
trait::is_weak_ptr_compatible_v<Trackable>, Connection>
|
||||
connect(Callable && c, Trackable && ptr) {
|
||||
using trait::to_weak;
|
||||
auto w = to_weak(std::forward<Trackable>(ptr));
|
||||
using slot_t = detail::SlotTracked<Callable, decltype(w), arg_list>;
|
||||
auto s = std::make_shared<slot_t>(std::forward<Callable>(c), w);
|
||||
add_slot(s);
|
||||
return Connection(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection whose duration is tied to the return object
|
||||
* Use the same semantics as connect
|
||||
*/
|
||||
template <typename... CallArgs>
|
||||
ScopedConnection connect_scoped(CallArgs && ...args) {
|
||||
return connect_connection(std::forward<CallArgs>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects all the slots
|
||||
* Safety: Thread safety depends on locking policy
|
||||
*/
|
||||
void disconnect_all() {
|
||||
lock_type lock(m_mutex);
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks signal emission
|
||||
* Safety: thread safe
|
||||
*/
|
||||
void block() noexcept {
|
||||
m_block.store(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks signal emission
|
||||
* Safety: thread safe
|
||||
*/
|
||||
void unblock() noexcept {
|
||||
m_block.store(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests blocking state of signal emission
|
||||
*/
|
||||
bool blocked() const noexcept {
|
||||
return m_block.load();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename S>
|
||||
void add_slot(S &s) {
|
||||
lock_type lock(m_mutex);
|
||||
if (!m_func) {
|
||||
// nothing stored
|
||||
m_func = CallSlots(*this);
|
||||
auto slots = m_func.template target<CallSlots>();
|
||||
s->next = slots->m_slots;
|
||||
slots->m_slots = s;
|
||||
} else if (auto call_slots = m_func.template target<CallSlots>()) {
|
||||
// already CallSlots
|
||||
s->next = call_slots->m_slots;
|
||||
call_slots->m_slots = s;
|
||||
} else {
|
||||
// was normal std::function, need to move it into a call slot
|
||||
using slot_t = detail::Slot<std::function<void(T...)>, arg_list>;
|
||||
auto s2 = std::make_shared<slot_t>(
|
||||
std::forward<std::function<void(T...)>>(m_func));
|
||||
m_func = CallSlots(*this);
|
||||
auto slots = m_func.template target<CallSlots>();
|
||||
s2->next = slots->m_slots;
|
||||
s->next = s2;
|
||||
slots->m_slots = s;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_func = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(T...)> m_func;
|
||||
mutable Lockable m_mutex;
|
||||
std::atomic<bool> m_block;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization of SignalBase to be used in single threaded contexts.
|
||||
* Slot connection, disconnection and signal emission are not thread-safe.
|
||||
* This is significantly smaller than the thread-safe variant.
|
||||
*/
|
||||
template <typename... T>
|
||||
using Signal = SignalBase<detail::NullMutex, T...>;
|
||||
|
||||
/**
|
||||
* Specialization of SignalBase to be used in multi-threaded contexts.
|
||||
* Slot connection, disconnection and signal emission are thread-safe.
|
||||
*
|
||||
* Beware of accidentally using recursive signal emission or cycles between
|
||||
* two or more signals in your code. Locking std::mutex more than once is
|
||||
* undefined behavior, even if it "seems to work somehow". Use signal_r
|
||||
* instead for that use case.
|
||||
*/
|
||||
template <typename... T>
|
||||
using Signal_mt = SignalBase<mutex, T...>;
|
||||
|
||||
/**
|
||||
* Specialization of SignalBase to be used in multi-threaded contexts, allowing
|
||||
* for recursive signal emission and emission cycles.
|
||||
* Slot connection, disconnection and signal emission are thread-safe.
|
||||
*/
|
||||
template <typename... T>
|
||||
using Signal_r = SignalBase<recursive_mutex, T...>;
|
||||
|
||||
} // namespace sig
|
||||
} // namespace wpi
|
||||
415
wpiutil/src/main/native/thirdparty/tcb_span/include/wpi/span.h
vendored
Normal file
415
wpiutil/src/main/native/thirdparty/tcb_span/include/wpi/span.h
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
|
||||
/*
|
||||
This is an implementation of C++20's std::span
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf
|
||||
*/
|
||||
|
||||
// Copyright Tristan Brindle 2018.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file ../../LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef WPIUTIL_WPI_SPAN_HPP_INCLUDED
|
||||
#define WPIUTIL_WPI_SPAN_HPP_INCLUDED
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#if __cplusplus >= 202002L && __has_include(<span>)
|
||||
#include <span>
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
inline constexpr std::size_t dynamic_extent = SIZE_MAX;
|
||||
|
||||
template <typename ElementType, std::size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename E, std::size_t S>
|
||||
struct span_storage {
|
||||
constexpr span_storage() noexcept = default;
|
||||
|
||||
constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept
|
||||
: ptr(p_ptr)
|
||||
{}
|
||||
|
||||
E* ptr = nullptr;
|
||||
static constexpr std::size_t size = S;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
struct span_storage<E, dynamic_extent> {
|
||||
constexpr span_storage() noexcept = default;
|
||||
|
||||
constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept
|
||||
: ptr(p_ptr), size(p_size)
|
||||
{}
|
||||
|
||||
E* ptr = nullptr;
|
||||
std::size_t size = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using uncvref_t =
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
template <typename>
|
||||
struct is_span : std::false_type {};
|
||||
|
||||
template <typename T, std::size_t S>
|
||||
struct is_span<span<T, S>> : std::true_type {};
|
||||
|
||||
template <typename>
|
||||
struct is_std_array : std::false_type {};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct is_std_array<std::array<T, N>> : std::true_type {};
|
||||
|
||||
template <typename, typename = void>
|
||||
struct has_size_and_data : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_size_and_data<T, std::void_t<decltype(std::size(std::declval<T>())),
|
||||
decltype(std::data(std::declval<T>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename C, typename U = uncvref_t<C>>
|
||||
struct is_container {
|
||||
static constexpr bool value =
|
||||
!is_span<U>::value && !is_std_array<U>::value &&
|
||||
!std::is_array<U>::value && has_size_and_data<C>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_pointer_t = typename std::remove_pointer<T>::type;
|
||||
|
||||
template <typename, typename, typename = void>
|
||||
struct is_container_element_type_compatible : std::false_type {};
|
||||
|
||||
template <typename T, typename E>
|
||||
struct is_container_element_type_compatible<
|
||||
T, E,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_cv<decltype(
|
||||
std::data(std::declval<T>()))>::type,
|
||||
void>::value>::type>
|
||||
: std::is_convertible<
|
||||
remove_pointer_t<decltype(std::data(std::declval<T>()))> (*)[],
|
||||
E (*)[]> {};
|
||||
|
||||
template <typename, typename = size_t>
|
||||
struct is_complete : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename ElementType, std::size_t Extent>
|
||||
class span {
|
||||
static_assert(std::is_object<ElementType>::value,
|
||||
"A span's ElementType must be an object type (not a "
|
||||
"reference type or void)");
|
||||
static_assert(detail::is_complete<ElementType>::value,
|
||||
"A span's ElementType must be a complete type (not a forward "
|
||||
"declaration)");
|
||||
static_assert(!std::is_abstract<ElementType>::value,
|
||||
"A span's ElementType cannot be an abstract class type");
|
||||
|
||||
using storage_type = detail::span_storage<ElementType, Extent>;
|
||||
|
||||
public:
|
||||
// constants and types
|
||||
using element_type = ElementType;
|
||||
using value_type = typename std::remove_cv<ElementType>::type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = element_type*;
|
||||
using const_pointer = const element_type*;
|
||||
using reference = element_type&;
|
||||
using const_reference = const element_type&;
|
||||
using iterator = pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
static constexpr size_type extent = Extent;
|
||||
|
||||
// [span.cons], span constructors, copy, assignment, and destructor
|
||||
template <
|
||||
std::size_t E = Extent,
|
||||
typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
|
||||
constexpr span() noexcept
|
||||
{}
|
||||
|
||||
constexpr span(pointer ptr, size_type count)
|
||||
: storage_(ptr, count)
|
||||
{
|
||||
assert(extent == dynamic_extent || count == extent);
|
||||
}
|
||||
|
||||
constexpr span(pointer first_elem, pointer last_elem)
|
||||
: storage_(first_elem, last_elem - first_elem)
|
||||
{
|
||||
assert(extent == dynamic_extent ||
|
||||
last_elem - first_elem ==
|
||||
static_cast<std::ptrdiff_t>(extent));
|
||||
}
|
||||
|
||||
template <std::size_t N, std::size_t E = Extent,
|
||||
typename std::enable_if<
|
||||
(E == dynamic_extent || N == E) &&
|
||||
detail::is_container_element_type_compatible<
|
||||
element_type (&)[N], ElementType>::value,
|
||||
int>::type = 0>
|
||||
constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
|
||||
{}
|
||||
|
||||
template <std::size_t N, std::size_t E = Extent,
|
||||
typename std::enable_if<
|
||||
(E == dynamic_extent || N == E) &&
|
||||
detail::is_container_element_type_compatible<
|
||||
std::array<value_type, N>&, ElementType>::value,
|
||||
int>::type = 0>
|
||||
constexpr span(std::array<value_type, N>& arr) noexcept
|
||||
: storage_(arr.data(), N)
|
||||
{}
|
||||
|
||||
template <std::size_t N, std::size_t E = Extent,
|
||||
typename std::enable_if<
|
||||
(E == dynamic_extent || N == E) &&
|
||||
detail::is_container_element_type_compatible<
|
||||
const std::array<value_type, N>&, ElementType>::value,
|
||||
int>::type = 0>
|
||||
constexpr span(const std::array<value_type, N>& arr) noexcept
|
||||
: storage_(arr.data(), N)
|
||||
{}
|
||||
|
||||
template <
|
||||
typename Container, std::size_t E = Extent,
|
||||
typename std::enable_if<
|
||||
E == dynamic_extent && detail::is_container<Container>::value &&
|
||||
detail::is_container_element_type_compatible<
|
||||
Container&, ElementType>::value,
|
||||
int>::type = 0>
|
||||
constexpr span(Container& cont)
|
||||
: storage_(std::data(cont), std::size(cont))
|
||||
{}
|
||||
|
||||
template <
|
||||
typename Container, std::size_t E = Extent,
|
||||
typename std::enable_if<
|
||||
E == dynamic_extent && detail::is_container<Container>::value &&
|
||||
detail::is_container_element_type_compatible<
|
||||
const Container&, ElementType>::value,
|
||||
int>::type = 0>
|
||||
constexpr span(const Container& cont)
|
||||
: storage_(std::data(cont), std::size(cont))
|
||||
{}
|
||||
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
|
||||
template <typename OtherElementType, std::size_t OtherExtent,
|
||||
typename std::enable_if<
|
||||
(Extent == OtherExtent || Extent == dynamic_extent) &&
|
||||
std::is_convertible<OtherElementType (*)[],
|
||||
ElementType (*)[]>::value,
|
||||
int>::type = 0>
|
||||
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
|
||||
: storage_(other.data(), other.size())
|
||||
{}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
constexpr span(std::span<ElementType> other) noexcept
|
||||
: storage_(other.data(), other.size())
|
||||
{}
|
||||
#endif
|
||||
|
||||
~span() noexcept = default;
|
||||
|
||||
constexpr span&
|
||||
operator=(const span& other) noexcept = default;
|
||||
|
||||
// [span.sub], span subviews
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const
|
||||
{
|
||||
assert(Count <= size());
|
||||
return {data(), Count};
|
||||
}
|
||||
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> last() const
|
||||
{
|
||||
assert(Count <= size());
|
||||
return {data() + (size() - Count), Count};
|
||||
}
|
||||
|
||||
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
using subspan_return_t =
|
||||
span<ElementType, Count != dynamic_extent
|
||||
? Count
|
||||
: (Extent != dynamic_extent ? Extent - Offset
|
||||
: dynamic_extent)>;
|
||||
|
||||
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
constexpr subspan_return_t<Offset, Count> subspan() const
|
||||
{
|
||||
assert(Offset <= size() &&
|
||||
(Count == dynamic_extent || Offset + Count <= size()));
|
||||
return {data() + Offset,
|
||||
Count != dynamic_extent ? Count : size() - Offset};
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
first(size_type count) const
|
||||
{
|
||||
assert(count <= size());
|
||||
return {data(), count};
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
last(size_type count) const
|
||||
{
|
||||
assert(count <= size());
|
||||
return {data() + (size() - count), count};
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
subspan(size_type offset, size_type count = dynamic_extent) const
|
||||
{
|
||||
assert(offset <= size() &&
|
||||
(count == dynamic_extent || offset + count <= size()));
|
||||
return {data() + offset,
|
||||
count == dynamic_extent ? size() - offset : count};
|
||||
}
|
||||
|
||||
// [span.obs], span observers
|
||||
constexpr size_type size() const noexcept { return storage_.size; }
|
||||
|
||||
constexpr size_type size_bytes() const noexcept
|
||||
{
|
||||
return size() * sizeof(element_type);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
// [span.elem], span element access
|
||||
constexpr reference operator[](size_type idx) const
|
||||
{
|
||||
assert(idx < size());
|
||||
return *(data() + idx);
|
||||
}
|
||||
|
||||
constexpr reference front() const
|
||||
{
|
||||
assert(!empty());
|
||||
return *data();
|
||||
}
|
||||
|
||||
constexpr reference back() const
|
||||
{
|
||||
assert(!empty());
|
||||
return *(data() + (size() - 1));
|
||||
}
|
||||
|
||||
constexpr pointer data() const noexcept { return storage_.ptr; }
|
||||
|
||||
// [span.iterators], span iterator support
|
||||
constexpr iterator begin() const noexcept { return data(); }
|
||||
|
||||
constexpr iterator end() const noexcept { return data() + size(); }
|
||||
|
||||
constexpr reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rend() const noexcept
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
constexpr operator auto() const {
|
||||
return std::span < ElementType,
|
||||
(Extent == dynamic_extent)
|
||||
? std::dynamic_extent
|
||||
: Extent > (storage_.ptr, storage_.size);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
storage_type storage_{};
|
||||
};
|
||||
|
||||
/* Deduction Guides */
|
||||
template <class T, size_t N>
|
||||
span(T (&)[N])->span<T, N>;
|
||||
|
||||
template <class T, size_t N>
|
||||
span(std::array<T, N>&)->span<T, N>;
|
||||
|
||||
template <class T, size_t N>
|
||||
span(const std::array<T, N>&)->span<const T, N>;
|
||||
|
||||
template <class Container>
|
||||
span(Container&)->span<typename Container::value_type>;
|
||||
|
||||
template <class Container>
|
||||
span(const Container&)->span<const typename Container::value_type>;
|
||||
|
||||
template <typename ElementType, std::size_t Extent>
|
||||
span<const std::byte, ((Extent == dynamic_extent) ? dynamic_extent
|
||||
: sizeof(ElementType) * Extent)>
|
||||
as_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <
|
||||
class ElementType, size_t Extent,
|
||||
typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
|
||||
span<std::byte, ((Extent == dynamic_extent) ? dynamic_extent
|
||||
: sizeof(ElementType) * Extent)>
|
||||
as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <std::size_t N, typename E, std::size_t S>
|
||||
constexpr auto get(span<E, S> s) -> decltype(s[N])
|
||||
{
|
||||
return s[N];
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename ElementType, size_t Extent>
|
||||
class tuple_size<wpi::span<ElementType, Extent>>
|
||||
: public integral_constant<size_t, Extent> {};
|
||||
|
||||
template <typename ElementType>
|
||||
class tuple_size<wpi::span<
|
||||
ElementType, wpi::dynamic_extent>>; // not defined
|
||||
|
||||
template <size_t I, typename ElementType, size_t Extent>
|
||||
class tuple_element<I, wpi::span<ElementType, Extent>> {
|
||||
public:
|
||||
static_assert(Extent != wpi::dynamic_extent &&
|
||||
I < Extent,
|
||||
"");
|
||||
using type = ElementType;
|
||||
};
|
||||
|
||||
} // end namespace std
|
||||
|
||||
#endif // WPIUTIL_WPI_SPAN_HPP_INCLUDED
|
||||
Reference in New Issue
Block a user