[seiscomp, scanloc] Install, add .gitignore
This commit is contained in:
234
include/fmt/args.h
Normal file
234
include/fmt/args.h
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<
|
||||
std::is_convertible<T, std::basic_string<char_type>>::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_
|
||||
2069
include/fmt/chrono.h
Normal file
2069
include/fmt/chrono.h
Normal file
File diff suppressed because it is too large
Load Diff
651
include/fmt/color.h
Normal file
651
include/fmt/color.h
Normal file
@@ -0,0 +1,651 @@
|
||||
// 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"
|
||||
|
||||
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() noexcept : is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||
}
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) 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) 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()) 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_CONSTEXPR bool has_foreground() const noexcept {
|
||||
return set_foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_background() const noexcept {
|
||||
return set_background_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_emphasis() const noexcept {
|
||||
return static_cast<uint8_t>(ems) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
|
||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||
return foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
|
||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||
return background_color;
|
||||
}
|
||||
FMT_CONSTEXPR emphasis get_emphasis() const 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) 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;
|
||||
}
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept;
|
||||
|
||||
friend FMT_CONSTEXPR text_style bg(detail::color_type background) 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) noexcept {
|
||||
return text_style(true, foreground);
|
||||
}
|
||||
|
||||
/** Creates a text style from the background color. */
|
||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
|
||||
return text_style(false, background);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) 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) 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) 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 noexcept { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
|
||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const 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) 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) 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) 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) noexcept {
|
||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
|
||||
int result = std::fputs(chars, stream);
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
|
||||
int result = std::fputws(chars, stream);
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
template <typename Char> inline void reset_color(FILE* stream) {
|
||||
fputs("\x1b[0m", stream);
|
||||
}
|
||||
|
||||
template <> inline void reset_color<wchar_t>(FILE* stream) {
|
||||
fputs(L"\x1b[0m", stream);
|
||||
}
|
||||
|
||||
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
buffer.append(reset_color.begin(), reset_color.end());
|
||||
}
|
||||
|
||||
template <typename T> struct styled_arg {
|
||||
const T& value;
|
||||
text_style style;
|
||||
};
|
||||
|
||||
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, detail::to_string_view(format), args);
|
||||
if (detail::is_utf8()) {
|
||||
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
|
||||
} else {
|
||||
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_format_args<buffer_context<char_t<S>>>(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, detail::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, detail::to_string_view(format_str),
|
||||
fmt::make_format_args<buffer_context<Char>>(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, detail::to_string_view(format_str),
|
||||
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
const auto& ts = arg.style;
|
||||
const auto& value = arg.value;
|
||||
auto out = ctx.out();
|
||||
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||
out = std::copy(emphasis.begin(), emphasis.end(), out);
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
auto foreground =
|
||||
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||
out = std::copy(foreground.begin(), foreground.end(), out);
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
auto background =
|
||||
detail::make_background_color<Char>(ts.get_background());
|
||||
out = std::copy(background.begin(), background.end(), out);
|
||||
}
|
||||
out = formatter<T, Char>::format(value, ctx);
|
||||
if (has_style) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
out = std::copy(reset_color.begin(), reset_color.end(), out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns an argument that will be formatted using ANSI escape sequences,
|
||||
to be used in a formatting function.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print("Elapsed time: {0:.2f} seconds",
|
||||
fmt::styled(1.23, fmt::fg(fmt::color::green) |
|
||||
fmt::bg(fmt::color::blue)));
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COLOR_H_
|
||||
611
include/fmt/compile.h
Normal file
611
include/fmt/compile.h
Normal file
@@ -0,0 +1,611 @@
|
||||
// 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 {
|
||||
|
||||
template <typename Char, typename InputIt>
|
||||
FMT_CONSTEXPR 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;
|
||||
FMT_UNCHECKED_ITERATOR(truncating_iterator_base);
|
||||
|
||||
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_ARGS
|
||||
template <typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct udl_compiled_string : compiled_string {
|
||||
using char_type = Char;
|
||||
explicit 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 = compile_parse_context<Char>(str, max_value<int>(), nullptr, {},
|
||||
next_arg_id);
|
||||
auto f = formatter<T, Char>();
|
||||
auto end = f.parse(ctx);
|
||||
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
|
||||
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 != ':') {
|
||||
FMT_THROW(format_error("expected ':'"));
|
||||
} else {
|
||||
constexpr auto result = parse_specs<typename field_type<T>::type>(
|
||||
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
|
||||
if constexpr (result.end >= str.size() || str[result.end] != '}') {
|
||||
FMT_THROW(format_error("expected '}'"));
|
||||
return 0;
|
||||
} else {
|
||||
return parse_tail<Args, result.end + 1, 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 fmt::format(
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return fmt::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 fmt::format_to(
|
||||
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return fmt::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 = fmt::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)>
|
||||
FMT_CONSTEXPR20 size_t formatted_size(const S& format_str,
|
||||
const Args&... args) {
|
||||
return fmt::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;
|
||||
fmt::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_ARGS
|
||||
inline namespace literals {
|
||||
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
|
||||
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||
Str>();
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COMPILE_H_
|
||||
3323
include/fmt/core.h
Normal file
3323
include/fmt/core.h
Normal file
File diff suppressed because it is too large
Load Diff
1723
include/fmt/format-inl.h
Normal file
1723
include/fmt/format-inl.h
Normal file
File diff suppressed because it is too large
Load Diff
4217
include/fmt/format.h
Normal file
4217
include/fmt/format.h
Normal file
File diff suppressed because it is too large
Load Diff
478
include/fmt/os.h
Normal file
478
include/fmt/os.h
Normal file
@@ -0,0 +1,478 @@
|
||||
// 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 <cstddef>
|
||||
#include <cstdio>
|
||||
#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() 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) 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) noexcept;
|
||||
#else
|
||||
inline const std::error_category& system_category() 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() noexcept : file_(nullptr) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~buffered_file() noexcept;
|
||||
|
||||
public:
|
||||
buffered_file(buffered_file&& other) 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 noexcept { return file_; }
|
||||
|
||||
FMT_API int descriptor() 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 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 FMT_API 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() noexcept : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a file object representing this file.
|
||||
file(cstring_view path, int oflag);
|
||||
|
||||
public:
|
||||
file(const file&) = delete;
|
||||
void operator=(const file&) = delete;
|
||||
|
||||
file(file&& other) 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.
|
||||
~file() noexcept;
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const noexcept { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
long long size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
size_t read(void* buffer, size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
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.
|
||||
static file dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd, std::error_code& ec) noexcept;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
static void pipe(file& read_end, file& write_end);
|
||||
|
||||
// Creates a buffered_file object associated with this file and detaches
|
||||
// this file object from the file.
|
||||
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 | file::TRUNC`` 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
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OS_H_
|
||||
237
include/fmt/ostream.h
Normal file
237
include/fmt/ostream.h
Normal file
@@ -0,0 +1,237 @@
|
||||
// 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 <fstream>
|
||||
#include <ostream>
|
||||
#if defined(_WIN32) && defined(__GLIBCXX__)
|
||||
# include <ext/stdio_filebuf.h>
|
||||
# include <ext/stdio_sync_filebuf.h>
|
||||
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
|
||||
# include <__std_stream>
|
||||
#endif
|
||||
|
||||
#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_convertible<T, fmt::basic_string_view<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 {};
|
||||
|
||||
// Generate a unique explicit instantion in every translation unit using a tag
|
||||
// type in an anonymous namespace.
|
||||
namespace {
|
||||
struct file_access_tag {};
|
||||
} // namespace
|
||||
template <class Tag, class BufType, FILE* BufType::*FileMemberPtr>
|
||||
class file_access {
|
||||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
|
||||
};
|
||||
|
||||
#if FMT_MSC_VERSION
|
||||
template class file_access<file_access_tag, std::filebuf,
|
||||
&std::filebuf::_Myfile>;
|
||||
auto get_file(std::filebuf&) -> FILE*;
|
||||
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
|
||||
template class file_access<file_access_tag, std::__stdoutbuf<char>,
|
||||
&std::__stdoutbuf<char>::__file_>;
|
||||
auto get_file(std::__stdoutbuf<char>&) -> FILE*;
|
||||
#endif
|
||||
|
||||
inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
|
||||
#if FMT_MSC_VERSION
|
||||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
|
||||
if (FILE* f = get_file(*buf)) return write_console(f, data);
|
||||
#elif defined(_WIN32) && defined(__GLIBCXX__)
|
||||
auto* rdbuf = os.rdbuf();
|
||||
FILE* c_file;
|
||||
if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
|
||||
c_file = fbuf->file();
|
||||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
|
||||
c_file = fbuf->file();
|
||||
else
|
||||
return false;
|
||||
if (c_file) return write_console(c_file, data);
|
||||
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
|
||||
if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf()))
|
||||
if (FILE* f = get_file(*buf)) return write_console(f, data);
|
||||
#else
|
||||
ignore_unused(os, data);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
inline bool write_ostream_unicode(std::wostream&,
|
||||
fmt::basic_string_view<wchar_t>) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
template <typename T> struct streamed_view { const T& value; };
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename Char>
|
||||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||
void set_debug_format() = delete;
|
||||
|
||||
template <typename T, typename OutputIt>
|
||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
||||
-> 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);
|
||||
}
|
||||
};
|
||||
|
||||
using ostream_formatter = basic_ostream_formatter<char>;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::streamed_view<T>, Char>
|
||||
: basic_ostream_formatter<Char> {
|
||||
template <typename OutputIt>
|
||||
auto format(detail::streamed_view<T> view,
|
||||
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
|
||||
return basic_ostream_formatter<Char>::format(view.value, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a view that formats `value` via an ostream ``operator<<``.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print("Current thread id: {}\n",
|
||||
fmt::streamed(std::this_thread::get_id()));
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
auto streamed(const T& value) -> detail::streamed_view<T> {
|
||||
return {value};
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// 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>>
|
||||
: basic_ostream_formatter<Char> {
|
||||
using basic_ostream_formatter<Char>::format;
|
||||
};
|
||||
|
||||
inline void vprint_directly(std::ostream& os, string_view format_str,
|
||||
format_args args) {
|
||||
auto buffer = memory_buffer();
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_MODULE_EXPORT template <typename Char>
|
||||
void vprint(std::basic_ostream<Char>& os,
|
||||
basic_string_view<type_identity_t<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);
|
||||
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
|
||||
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... T>
|
||||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
const auto& vargs = fmt::make_format_args(args...);
|
||||
if (detail::is_utf8())
|
||||
vprint(os, fmt, vargs);
|
||||
else
|
||||
detail::vprint_directly(os, fmt, vargs);
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT
|
||||
template <typename... Args>
|
||||
void print(std::wostream& os,
|
||||
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
|
||||
Args&&... args) {
|
||||
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OSTREAM_H_
|
||||
640
include/fmt/printf.h
Normal file
640
include/fmt/printf.h
Normal file
@@ -0,0 +1,640 @@
|
||||
// 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 "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, detail::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(detail::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, detail::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, detail::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, detail::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(
|
||||
detail::to_string_view(fmt),
|
||||
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_PRINTF_H_
|
||||
722
include/fmt/ranges.h
Normal file
722
include/fmt/ranges.h
Normal file
@@ -0,0 +1,722 @@
|
||||
// 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 constexpr 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 constexpr const bool value = false;
|
||||
#else
|
||||
static constexpr 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 constexpr const bool value = false;
|
||||
#else
|
||||
static constexpr 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_VERSION || FMT_MSC_VERSION > 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 constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 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 <typename T>
|
||||
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||
|
||||
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||
class is_tuple_formattable_ {
|
||||
public:
|
||||
static constexpr const bool value = false;
|
||||
};
|
||||
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||
template <std::size_t... I>
|
||||
static std::true_type check2(index_sequence<I...>,
|
||||
integer_sequence<bool, (I == I)...>);
|
||||
static std::false_type check2(...);
|
||||
template <std::size_t... I>
|
||||
static decltype(check2(
|
||||
index_sequence<I...>{},
|
||||
integer_sequence<
|
||||
bool, (is_formattable<typename std::tuple_element<I, T>::type,
|
||||
C>::value)...>{})) check(index_sequence<I...>);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
template <class Tuple, class F, size_t... Is>
|
||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) 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));
|
||||
}
|
||||
|
||||
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
|
||||
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||
template <typename R> struct range_reference_type_impl {
|
||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||
#else
|
||||
template <typename Range>
|
||||
using range_reference_type =
|
||||
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||
#endif
|
||||
|
||||
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||
// reference type, with cv-ref stripped.
|
||||
template <typename Range>
|
||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||
|
||||
template <typename Range>
|
||||
using uncvref_first_type =
|
||||
remove_cvref_t<decltype(std::declval<range_reference_type<Range>>().first)>;
|
||||
|
||||
template <typename Range>
|
||||
using uncvref_second_type = remove_cvref_t<
|
||||
decltype(std::declval<range_reference_type<Range>>().second)>;
|
||||
|
||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||
*out++ = ',';
|
||||
*out++ = ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
||||
return write_escaped_string(out, str);
|
||||
}
|
||||
|
||||
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) {
|
||||
return write_escaped_char(out, v);
|
||||
}
|
||||
|
||||
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 constexpr const bool value =
|
||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_tuple_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_tuple_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
template <typename TupleT, typename Char>
|
||||
struct formatter<TupleT, Char,
|
||||
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
|
||||
fmt::is_tuple_formattable<TupleT, Char>::value>> {
|
||||
private:
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '('>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ')'>{};
|
||||
|
||||
// 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::copy_str<Char>(separator, out);
|
||||
out = detail::write_range_entry<Char>(out, v);
|
||||
++i;
|
||||
}
|
||||
int i;
|
||||
typename FormatContext::iterator& out;
|
||||
basic_string_view<Char> separator;
|
||||
};
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR formatter() {}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
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) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::copy_str<Char>(opening_bracket_, out);
|
||||
detail::for_each(values, format_each<FormatContext>{0, out, separator_});
|
||||
out = detail::copy_str<Char>(closing_bracket_, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr const bool value =
|
||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||
!std::is_convertible<T, detail::std_string_view<Char>>::value;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename Context> struct range_mapper {
|
||||
using mapper = arg_mapper<Context>;
|
||||
|
||||
template <typename T,
|
||||
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||
static auto map(T&& value) -> T&& {
|
||||
return static_cast<T&&>(value);
|
||||
}
|
||||
template <typename T,
|
||||
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||
static auto map(T&& value)
|
||||
-> decltype(mapper().map(static_cast<T&&>(value))) {
|
||||
return mapper().map(static_cast<T&&>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Element>
|
||||
using range_formatter_type = conditional_t<
|
||||
is_formattable<Element, Char>::value,
|
||||
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||
std::declval<Element>()))>,
|
||||
Char>,
|
||||
fallback_formatter<Element, Char>>;
|
||||
|
||||
template <typename R>
|
||||
using maybe_const_range =
|
||||
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||
|
||||
// Workaround a bug in MSVC 2015 and earlier.
|
||||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||
template <typename R, typename Char>
|
||||
struct is_formattable_delayed
|
||||
: disjunction<
|
||||
is_formattable<uncvref_type<maybe_const_range<R>>, Char>,
|
||||
has_fallback_formatter<uncvref_type<maybe_const_range<R>>, Char>> {};
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_formatter;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct range_formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<
|
||||
std::is_same<T, remove_cvref_t<T>>,
|
||||
disjunction<is_formattable<T, Char>,
|
||||
detail::has_fallback_formatter<T, Char>>>::value>> {
|
||||
private:
|
||||
detail::range_formatter_type<Char, T> underlying_;
|
||||
bool custom_specs_ = false;
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '['>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ']'>{};
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, int)
|
||||
-> decltype(u.set_debug_format()) {
|
||||
u.set_debug_format();
|
||||
}
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||
|
||||
FMT_CONSTEXPR void maybe_set_debug_format() {
|
||||
maybe_set_debug_format(underlying_, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR range_formatter() {}
|
||||
|
||||
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
|
||||
return underlying_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it == end || *it == '}') {
|
||||
maybe_set_debug_format();
|
||||
return it;
|
||||
}
|
||||
|
||||
if (*it == 'n') {
|
||||
set_brackets({}, {});
|
||||
++it;
|
||||
}
|
||||
|
||||
if (*it == '}') {
|
||||
maybe_set_debug_format();
|
||||
return it;
|
||||
}
|
||||
|
||||
if (*it != ':')
|
||||
FMT_THROW(format_error("no other top-level range formatters supported"));
|
||||
|
||||
custom_specs_ = true;
|
||||
++it;
|
||||
ctx.advance_to(it);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename R, class FormatContext>
|
||||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
detail::range_mapper<buffer_context<Char>> mapper;
|
||||
auto out = ctx.out();
|
||||
out = detail::copy_str<Char>(opening_bracket_, out);
|
||||
int i = 0;
|
||||
auto it = detail::range_begin(range);
|
||||
auto end = detail::range_end(range);
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) out = detail::copy_str<Char>(separator_, out);
|
||||
;
|
||||
ctx.advance_to(out);
|
||||
out = underlying_.format(mapper.map(*it), ctx);
|
||||
++i;
|
||||
}
|
||||
out = detail::copy_str<Char>(closing_bracket_, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||
|
||||
namespace detail {
|
||||
template <typename T> struct range_format_kind_ {
|
||||
static constexpr auto value = std::is_same<range_reference_type<T>, T>::value
|
||||
? range_format::disabled
|
||||
: is_map<T>::value ? range_format::map
|
||||
: is_set<T>::value ? range_format::set
|
||||
: range_format::sequence;
|
||||
};
|
||||
|
||||
template <range_format K, typename R, typename Char, typename Enable = void>
|
||||
struct range_default_formatter;
|
||||
|
||||
template <range_format K>
|
||||
using range_format_constant = std::integral_constant<range_format, K>;
|
||||
|
||||
template <range_format K, typename R, typename Char>
|
||||
struct range_default_formatter<
|
||||
K, R, Char,
|
||||
enable_if_t<(K == range_format::sequence || K == range_format::map ||
|
||||
K == range_format::set)>> {
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
|
||||
|
||||
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
|
||||
|
||||
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
|
||||
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||
detail::string_literal<Char, '}'>{});
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
|
||||
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||
detail::string_literal<Char, '}'>{});
|
||||
underlying_.underlying().set_brackets({}, {});
|
||||
underlying_.underlying().set_separator(
|
||||
detail::string_literal<Char, ':', ' '>{});
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return underlying_.format(range, ctx);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_format_kind
|
||||
: conditional_t<
|
||||
is_range<T, Char>::value, detail::range_format_kind_<T>,
|
||||
std::integral_constant<range_format, range_format::disabled>> {};
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
|
||||
range_format::disabled>
|
||||
// Workaround a bug in MSVC 2015 and earlier.
|
||||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||
,
|
||||
detail::is_formattable_delayed<R, Char>
|
||||
#endif
|
||||
>::value>>
|
||||
: detail::range_default_formatter<range_format_kind<R, Char>::value, R,
|
||||
Char> {
|
||||
};
|
||||
|
||||
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_
|
||||
171
include/fmt/std.h
Normal file
171
include/fmt/std.h
Normal file
@@ -0,0 +1,171 @@
|
||||
// Formatting library for C++ - formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_STD_H_
|
||||
#define FMT_STD_H_
|
||||
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "ostream.h"
|
||||
|
||||
#if FMT_HAS_INCLUDE(<version>)
|
||||
# include <version>
|
||||
#endif
|
||||
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
|
||||
#if FMT_CPLUSPLUS >= 201703L
|
||||
# if FMT_HAS_INCLUDE(<filesystem>)
|
||||
# include <filesystem>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<variant>)
|
||||
# include <variant>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_filesystem
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char>
|
||||
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
const std::filesystem::path& p) {
|
||||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||
}
|
||||
# ifdef _WIN32
|
||||
template <>
|
||||
inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
|
||||
const std::filesystem::path& p) {
|
||||
auto s = p.u8string();
|
||||
write_escaped_string<char>(
|
||||
std::back_inserter(quoted),
|
||||
string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
|
||||
}
|
||||
# endif
|
||||
template <>
|
||||
inline void write_escaped_path<std::filesystem::path::value_type>(
|
||||
basic_memory_buffer<std::filesystem::path::value_type>& quoted,
|
||||
const std::filesystem::path& p) {
|
||||
write_escaped_string<std::filesystem::path::value_type>(
|
||||
std::back_inserter(quoted), p.native());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::filesystem::path, Char>
|
||||
: formatter<basic_string_view<Char>> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
|
||||
typename FormatContext::iterator {
|
||||
basic_memory_buffer<Char> quoted;
|
||||
detail::write_escaped_path(quoted, p);
|
||||
return formatter<basic_string_view<Char>>::format(
|
||||
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <typename Char>
|
||||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#ifdef __cpp_lib_variant
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <typename Char> struct formatter<std::monostate, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::monostate&, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::write<Char>(out, "monostate");
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using variant_index_sequence =
|
||||
std::make_index_sequence<std::variant_size<T>::value>;
|
||||
|
||||
// variant_size and variant_alternative check.
|
||||
template <typename T, typename U = void>
|
||||
struct is_variant_like_ : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>>
|
||||
: std::true_type {};
|
||||
|
||||
// formattable element check
|
||||
template <typename T, typename C> class is_variant_formattable_ {
|
||||
template <std::size_t... I>
|
||||
static std::conjunction<
|
||||
is_formattable<std::variant_alternative_t<I, T>, C>...>
|
||||
check(std::index_sequence<I...>);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(variant_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
template <typename Char, typename OutputIt, typename T>
|
||||
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||
if constexpr (is_string<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
else if constexpr (std::is_same_v<T, Char>)
|
||||
return write_escaped_char(out, v);
|
||||
else
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_variant_like {
|
||||
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_variant_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_variant_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
template <typename Variant, typename Char>
|
||||
struct formatter<
|
||||
Variant, Char,
|
||||
std::enable_if_t<std::conjunction_v<
|
||||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Variant& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
out = detail::write<Char>(out, "variant(");
|
||||
std::visit(
|
||||
[&](const auto& v) {
|
||||
out = detail::write_variant_alternative<Char>(out, v);
|
||||
},
|
||||
value);
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#endif // FMT_STD_H_
|
||||
229
include/fmt/xchar.h
Normal file
229
include/fmt/xchar.h
Normal file
@@ -0,0 +1,229 @@
|
||||
// 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 "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;
|
||||
inline auto runtime(wstring_view s) -> wstring_view { return s; }
|
||||
#else
|
||||
template <typename... Args>
|
||||
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||
inline auto runtime(wstring_view s) -> basic_runtime<wchar_t> { return {{s}}; }
|
||||
#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 {
|
||||
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
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);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
|
||||
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
// 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 &&
|
||||
!std::is_same<Char, wchar_t>::value)>
|
||||
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
||||
return vformat(detail::to_string_view(format_str),
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
}
|
||||
|
||||
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, detail::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, detail::to_string_view(format_str),
|
||||
fmt::make_format_args<buffer_context<Char>>(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, detail::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 {
|
||||
return vformat_to(out, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
}
|
||||
|
||||
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, detail::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 {
|
||||
return vformat_to(out, loc, to_string_view(format_str),
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
}
|
||||
|
||||
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> {
|
||||
return vformat_to_n(out, n, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
}
|
||||
|
||||
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;
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
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');
|
||||
if (std::fputws(buffer.data(), f) == -1)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
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_
|
||||
18
include/libbson-1.0/bson.h
Normal file
18
include/libbson-1.0/bson.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2018-present MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Including bson.h is superseded. Use bson/bson.h instead. */
|
||||
#include "bson/bson.h"
|
||||
295
include/libbson-1.0/bson/bcon.h
Normal file
295
include/libbson-1.0/bson/bcon.h
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* @file bcon.h
|
||||
* @brief BCON (BSON C Object Notation) Declarations
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
/* Copyright 2009-2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef BCON_H_
|
||||
#define BCON_H_
|
||||
|
||||
#include "bson/bson.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BCON_STACK_MAX 100
|
||||
|
||||
#define BCON_ENSURE_DECLARE(fun, type) \
|
||||
static BSON_INLINE type bcon_ensure_##fun (type _t) \
|
||||
{ \
|
||||
return _t; \
|
||||
}
|
||||
|
||||
#define BCON_ENSURE(fun, val) bcon_ensure_##fun (val)
|
||||
|
||||
#define BCON_ENSURE_STORAGE(fun, val) bcon_ensure_##fun (&(val))
|
||||
|
||||
BCON_ENSURE_DECLARE (const_char_ptr, const char *)
|
||||
BCON_ENSURE_DECLARE (const_char_ptr_ptr, const char **)
|
||||
BCON_ENSURE_DECLARE (double, double)
|
||||
BCON_ENSURE_DECLARE (double_ptr, double *)
|
||||
BCON_ENSURE_DECLARE (const_bson_ptr, const bson_t *)
|
||||
BCON_ENSURE_DECLARE (bson_ptr, bson_t *)
|
||||
BCON_ENSURE_DECLARE (subtype, bson_subtype_t)
|
||||
BCON_ENSURE_DECLARE (subtype_ptr, bson_subtype_t *)
|
||||
BCON_ENSURE_DECLARE (const_uint8_ptr, const uint8_t *)
|
||||
BCON_ENSURE_DECLARE (const_uint8_ptr_ptr, const uint8_t **)
|
||||
BCON_ENSURE_DECLARE (uint32, uint32_t)
|
||||
BCON_ENSURE_DECLARE (uint32_ptr, uint32_t *)
|
||||
BCON_ENSURE_DECLARE (const_oid_ptr, const bson_oid_t *)
|
||||
BCON_ENSURE_DECLARE (const_oid_ptr_ptr, const bson_oid_t **)
|
||||
BCON_ENSURE_DECLARE (int32, int32_t)
|
||||
BCON_ENSURE_DECLARE (int32_ptr, int32_t *)
|
||||
BCON_ENSURE_DECLARE (int64, int64_t)
|
||||
BCON_ENSURE_DECLARE (int64_ptr, int64_t *)
|
||||
BCON_ENSURE_DECLARE (const_decimal128_ptr, const bson_decimal128_t *)
|
||||
BCON_ENSURE_DECLARE (bool, bool)
|
||||
BCON_ENSURE_DECLARE (bool_ptr, bool *)
|
||||
BCON_ENSURE_DECLARE (bson_type, bson_type_t)
|
||||
BCON_ENSURE_DECLARE (bson_iter_ptr, bson_iter_t *)
|
||||
BCON_ENSURE_DECLARE (const_bson_iter_ptr, const bson_iter_t *)
|
||||
|
||||
#define BCON_UTF8(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE (const_char_ptr, (_val))
|
||||
#define BCON_DOUBLE(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE (double, (_val))
|
||||
#define BCON_DOCUMENT(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE (const_bson_ptr, (_val))
|
||||
#define BCON_ARRAY(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE (const_bson_ptr, (_val))
|
||||
#define BCON_BIN(_subtype, _binary, _length) \
|
||||
BCON_MAGIC, BCON_TYPE_BIN, BCON_ENSURE (subtype, (_subtype)), \
|
||||
BCON_ENSURE (const_uint8_ptr, (_binary)), \
|
||||
BCON_ENSURE (uint32, (_length))
|
||||
#define BCON_UNDEFINED BCON_MAGIC, BCON_TYPE_UNDEFINED
|
||||
#define BCON_OID(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_OID, BCON_ENSURE (const_oid_ptr, (_val))
|
||||
#define BCON_BOOL(_val) BCON_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE (bool, (_val))
|
||||
#define BCON_DATE_TIME(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE (int64, (_val))
|
||||
#define BCON_NULL BCON_MAGIC, BCON_TYPE_NULL
|
||||
#define BCON_REGEX(_regex, _flags) \
|
||||
BCON_MAGIC, BCON_TYPE_REGEX, BCON_ENSURE (const_char_ptr, (_regex)), \
|
||||
BCON_ENSURE (const_char_ptr, (_flags))
|
||||
#define BCON_DBPOINTER(_collection, _oid) \
|
||||
BCON_MAGIC, BCON_TYPE_DBPOINTER, \
|
||||
BCON_ENSURE (const_char_ptr, (_collection)), \
|
||||
BCON_ENSURE (const_oid_ptr, (_oid))
|
||||
#define BCON_CODE(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_CODE, BCON_ENSURE (const_char_ptr, (_val))
|
||||
#define BCON_SYMBOL(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE (const_char_ptr, (_val))
|
||||
#define BCON_CODEWSCOPE(_js, _scope) \
|
||||
BCON_MAGIC, BCON_TYPE_CODEWSCOPE, BCON_ENSURE (const_char_ptr, (_js)), \
|
||||
BCON_ENSURE (const_bson_ptr, (_scope))
|
||||
#define BCON_INT32(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_INT32, BCON_ENSURE (int32, (_val))
|
||||
#define BCON_TIMESTAMP(_timestamp, _increment) \
|
||||
BCON_MAGIC, BCON_TYPE_TIMESTAMP, BCON_ENSURE (int32, (_timestamp)), \
|
||||
BCON_ENSURE (int32, (_increment))
|
||||
#define BCON_INT64(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_INT64, BCON_ENSURE (int64, (_val))
|
||||
#define BCON_DECIMAL128(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DECIMAL128, BCON_ENSURE (const_decimal128_ptr, (_val))
|
||||
#define BCON_MAXKEY BCON_MAGIC, BCON_TYPE_MAXKEY
|
||||
#define BCON_MINKEY BCON_MAGIC, BCON_TYPE_MINKEY
|
||||
#define BCON(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_BCON, BCON_ENSURE (const_bson_ptr, (_val))
|
||||
#define BCON_ITER(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_ITER, BCON_ENSURE (const_bson_iter_ptr, (_val))
|
||||
|
||||
#define BCONE_UTF8(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val))
|
||||
#define BCONE_DOUBLE(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE_STORAGE (double_ptr, (_val))
|
||||
#define BCONE_DOCUMENT(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE_STORAGE (bson_ptr, (_val))
|
||||
#define BCONE_ARRAY(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE_STORAGE (bson_ptr, (_val))
|
||||
#define BCONE_BIN(subtype, binary, length) \
|
||||
BCONE_MAGIC, BCON_TYPE_BIN, BCON_ENSURE_STORAGE (subtype_ptr, (subtype)), \
|
||||
BCON_ENSURE_STORAGE (const_uint8_ptr_ptr, (binary)), \
|
||||
BCON_ENSURE_STORAGE (uint32_ptr, (length))
|
||||
#define BCONE_UNDEFINED BCONE_MAGIC, BCON_TYPE_UNDEFINED
|
||||
#define BCONE_OID(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_OID, BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_val))
|
||||
#define BCONE_BOOL(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE_STORAGE (bool_ptr, (_val))
|
||||
#define BCONE_DATE_TIME(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE_STORAGE (int64_ptr, (_val))
|
||||
#define BCONE_NULL BCONE_MAGIC, BCON_TYPE_NULL
|
||||
#define BCONE_REGEX(_regex, _flags) \
|
||||
BCONE_MAGIC, BCON_TYPE_REGEX, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_regex)), \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_flags))
|
||||
#define BCONE_DBPOINTER(_collection, _oid) \
|
||||
BCONE_MAGIC, BCON_TYPE_DBPOINTER, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_collection)), \
|
||||
BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_oid))
|
||||
#define BCONE_CODE(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_CODE, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val))
|
||||
#define BCONE_SYMBOL(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_SYMBOL, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val))
|
||||
#define BCONE_CODEWSCOPE(_js, _scope) \
|
||||
BCONE_MAGIC, BCON_TYPE_CODEWSCOPE, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_js)), \
|
||||
BCON_ENSURE_STORAGE (bson_ptr, (_scope))
|
||||
#define BCONE_INT32(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_INT32, BCON_ENSURE_STORAGE (int32_ptr, (_val))
|
||||
#define BCONE_TIMESTAMP(_timestamp, _increment) \
|
||||
BCONE_MAGIC, BCON_TYPE_TIMESTAMP, \
|
||||
BCON_ENSURE_STORAGE (int32_ptr, (_timestamp)), \
|
||||
BCON_ENSURE_STORAGE (int32_ptr, (_increment))
|
||||
#define BCONE_INT64(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_INT64, BCON_ENSURE_STORAGE (int64_ptr, (_val))
|
||||
#define BCONE_DECIMAL128(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_DECIMAL128, \
|
||||
BCON_ENSURE_STORAGE (const_decimal128_ptr, (_val))
|
||||
#define BCONE_MAXKEY BCONE_MAGIC, BCON_TYPE_MAXKEY
|
||||
#define BCONE_MINKEY BCONE_MAGIC, BCON_TYPE_MINKEY
|
||||
#define BCONE_SKIP(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_SKIP, BCON_ENSURE (bson_type, (_val))
|
||||
#define BCONE_ITER(_val) \
|
||||
BCONE_MAGIC, BCON_TYPE_ITER, BCON_ENSURE_STORAGE (bson_iter_ptr, (_val))
|
||||
|
||||
#define BCON_MAGIC bson_bcon_magic ()
|
||||
#define BCONE_MAGIC bson_bcone_magic ()
|
||||
|
||||
typedef enum {
|
||||
BCON_TYPE_UTF8,
|
||||
BCON_TYPE_DOUBLE,
|
||||
BCON_TYPE_DOCUMENT,
|
||||
BCON_TYPE_ARRAY,
|
||||
BCON_TYPE_BIN,
|
||||
BCON_TYPE_UNDEFINED,
|
||||
BCON_TYPE_OID,
|
||||
BCON_TYPE_BOOL,
|
||||
BCON_TYPE_DATE_TIME,
|
||||
BCON_TYPE_NULL,
|
||||
BCON_TYPE_REGEX,
|
||||
BCON_TYPE_DBPOINTER,
|
||||
BCON_TYPE_CODE,
|
||||
BCON_TYPE_SYMBOL,
|
||||
BCON_TYPE_CODEWSCOPE,
|
||||
BCON_TYPE_INT32,
|
||||
BCON_TYPE_TIMESTAMP,
|
||||
BCON_TYPE_INT64,
|
||||
BCON_TYPE_DECIMAL128,
|
||||
BCON_TYPE_MAXKEY,
|
||||
BCON_TYPE_MINKEY,
|
||||
BCON_TYPE_BCON,
|
||||
BCON_TYPE_ARRAY_START,
|
||||
BCON_TYPE_ARRAY_END,
|
||||
BCON_TYPE_DOC_START,
|
||||
BCON_TYPE_DOC_END,
|
||||
BCON_TYPE_END,
|
||||
BCON_TYPE_RAW,
|
||||
BCON_TYPE_SKIP,
|
||||
BCON_TYPE_ITER,
|
||||
BCON_TYPE_ERROR,
|
||||
} bcon_type_t;
|
||||
|
||||
typedef struct bcon_append_ctx_frame {
|
||||
int i;
|
||||
bool is_array;
|
||||
bson_t bson;
|
||||
} bcon_append_ctx_frame_t;
|
||||
|
||||
typedef struct bcon_extract_ctx_frame {
|
||||
int i;
|
||||
bool is_array;
|
||||
bson_iter_t iter;
|
||||
} bcon_extract_ctx_frame_t;
|
||||
|
||||
typedef struct _bcon_append_ctx_t {
|
||||
bcon_append_ctx_frame_t stack[BCON_STACK_MAX];
|
||||
int n;
|
||||
} bcon_append_ctx_t;
|
||||
|
||||
typedef struct _bcon_extract_ctx_t {
|
||||
bcon_extract_ctx_frame_t stack[BCON_STACK_MAX];
|
||||
int n;
|
||||
} bcon_extract_ctx_t;
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bcon_append (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED;
|
||||
BSON_EXPORT (void)
|
||||
bcon_append_ctx (bson_t *bson,
|
||||
bcon_append_ctx_t *ctx,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
BSON_EXPORT (void)
|
||||
bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *va);
|
||||
BSON_EXPORT (void)
|
||||
bcon_append_ctx_init (bcon_append_ctx_t *ctx);
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bcon_extract_ctx_init (bcon_extract_ctx_t *ctx);
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bcon_extract_ctx (bson_t *bson,
|
||||
bcon_extract_ctx_t *ctx,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap);
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bcon_extract (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bcon_extract_va (bson_t *bson,
|
||||
bcon_extract_ctx_t *ctx,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
BSON_EXPORT (bson_t *)
|
||||
bcon_new (void *unused, ...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
/**
|
||||
* The bcon_..() functions are all declared with __attribute__((sentinel)).
|
||||
*
|
||||
* From GCC manual for "sentinel": "A valid NULL in this context is defined as
|
||||
* zero with any pointer type. If your system defines the NULL macro with an
|
||||
* integer type then you need to add an explicit cast."
|
||||
* Case in point: GCC on Solaris (at least)
|
||||
*/
|
||||
#define BCON_APPEND(_bson, ...) \
|
||||
bcon_append ((_bson), __VA_ARGS__, (void *) NULL)
|
||||
#define BCON_APPEND_CTX(_bson, _ctx, ...) \
|
||||
bcon_append_ctx ((_bson), (_ctx), __VA_ARGS__, (void *) NULL)
|
||||
|
||||
#define BCON_EXTRACT(_bson, ...) \
|
||||
bcon_extract ((_bson), __VA_ARGS__, (void *) NULL)
|
||||
|
||||
#define BCON_EXTRACT_CTX(_bson, _ctx, ...) \
|
||||
bcon_extract ((_bson), (_ctx), __VA_ARGS__, (void *) NULL)
|
||||
|
||||
#define BCON_NEW(...) bcon_new (NULL, __VA_ARGS__, (void *) NULL)
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_bcon_magic (void) BSON_GNUC_PURE;
|
||||
BSON_EXPORT (const char *)
|
||||
bson_bcone_magic (void) BSON_GNUC_PURE;
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif
|
||||
105
include/libbson-1.0/bson/bson-atomic.h
Normal file
105
include/libbson-1.0/bson/bson-atomic.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2013-2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_ATOMIC_H
|
||||
#define BSON_ATOMIC_H
|
||||
|
||||
|
||||
#include "bson/bson-config.h"
|
||||
#include "bson/bson-compat.h"
|
||||
#include "bson/bson-macros.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#if defined(__sun) && defined(__SVR4)
|
||||
/* Solaris */
|
||||
#include <atomic.h>
|
||||
#define bson_atomic_int_add(p, v) \
|
||||
atomic_add_32_nv ((volatile uint32_t *) p, (v))
|
||||
#define bson_atomic_int64_add(p, v) \
|
||||
atomic_add_64_nv ((volatile uint64_t *) p, (v))
|
||||
#elif defined(_WIN32)
|
||||
/* MSVC/MinGW */
|
||||
#define bson_atomic_int_add(p, v) \
|
||||
(InterlockedExchangeAdd ((volatile LONG *) (p), (LONG) (v)) + (LONG) (v))
|
||||
#define bson_atomic_int64_add(p, v) \
|
||||
(InterlockedExchangeAdd64 ((volatile LONGLONG *) (p), (LONGLONG) (v)) + \
|
||||
(LONGLONG) (v))
|
||||
#else
|
||||
#ifdef BSON_HAVE_ATOMIC_32_ADD_AND_FETCH
|
||||
#define bson_atomic_int_add(p, v) __sync_add_and_fetch ((p), (v))
|
||||
#else
|
||||
#define __BSON_NEED_ATOMIC_32
|
||||
#endif
|
||||
#ifdef BSON_HAVE_ATOMIC_64_ADD_AND_FETCH
|
||||
#if BSON_GNUC_IS_VERSION(4, 1)
|
||||
/*
|
||||
* GCC 4.1 on i386 can generate buggy 64-bit atomic increment.
|
||||
* So we will work around with a fallback.
|
||||
*
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40693
|
||||
*/
|
||||
#define __BSON_NEED_ATOMIC_64
|
||||
#else
|
||||
#define bson_atomic_int64_add(p, v) \
|
||||
__sync_add_and_fetch ((volatile int64_t *) (p), (int64_t) (v))
|
||||
#endif
|
||||
#else
|
||||
#define __BSON_NEED_ATOMIC_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __BSON_NEED_ATOMIC_32
|
||||
BSON_EXPORT (int32_t)
|
||||
bson_atomic_int_add (volatile int32_t *p, int32_t n);
|
||||
#endif
|
||||
#ifdef __BSON_NEED_ATOMIC_64
|
||||
BSON_EXPORT (int64_t)
|
||||
bson_atomic_int64_add (volatile int64_t *p, int64_t n);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define bson_memory_barrier() MemoryBarrier ()
|
||||
#elif defined(__GNUC__)
|
||||
#if BSON_GNUC_CHECK_VERSION(4, 1)
|
||||
#define bson_memory_barrier() __sync_synchronize ()
|
||||
#else
|
||||
#warning "GCC Pre-4.1 discovered, using inline assembly for memory barrier."
|
||||
#define bson_memory_barrier() __asm__ volatile("" ::: "memory")
|
||||
#endif
|
||||
#elif defined(__SUNPRO_C)
|
||||
#include <mbarrier.h>
|
||||
#define bson_memory_barrier() __machine_rw_barrier ()
|
||||
#elif defined(__xlC__)
|
||||
#define bson_memory_barrier() __sync ()
|
||||
#else
|
||||
#define __BSON_NEED_BARRIER 1
|
||||
#warning "Unknown compiler, using lock for compiler barrier."
|
||||
BSON_EXPORT (void)
|
||||
bson_memory_barrier (void);
|
||||
#endif
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ATOMIC_H */
|
||||
41
include/libbson-1.0/bson/bson-clock.h
Normal file
41
include/libbson-1.0/bson/bson-clock.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_CLOCK_H
|
||||
#define BSON_CLOCK_H
|
||||
|
||||
|
||||
#include "bson/bson-compat.h"
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
BSON_EXPORT (int64_t)
|
||||
bson_get_monotonic_time (void);
|
||||
BSON_EXPORT (int)
|
||||
bson_gettimeofday (struct timeval *tv);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_CLOCK_H */
|
||||
177
include/libbson-1.0/bson/bson-compat.h
Normal file
177
include/libbson-1.0/bson/bson-compat.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_COMPAT_H
|
||||
#define BSON_COMPAT_H
|
||||
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#if defined(__USE_MINGW_ANSI_STDIO)
|
||||
#if __USE_MINGW_ANSI_STDIO < 1
|
||||
#error "__USE_MINGW_ANSI_STDIO > 0 is required for correct PRI* macros"
|
||||
#endif
|
||||
#else
|
||||
#define __USE_MINGW_ANSI_STDIO 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "bson/bson-config.h"
|
||||
#include "bson/bson-macros.h"
|
||||
|
||||
|
||||
#ifdef BSON_OS_WIN32
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BSON_OS_UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1800)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#ifndef __cplusplus
|
||||
/* benign redefinition of type */
|
||||
#pragma warning(disable : 4142)
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
#define _SSIZE_T_DEFINED
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
#ifndef _SIZE_T_DEFINED
|
||||
#define _SIZE_T_DEFINED
|
||||
typedef SIZE_T size_t;
|
||||
#endif
|
||||
#pragma warning(default : 4142)
|
||||
#else
|
||||
/*
|
||||
* MSVC++ does not include ssize_t, just size_t.
|
||||
* So we need to synthesize that as well.
|
||||
*/
|
||||
#pragma warning(disable : 4142)
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
#define _SSIZE_T_DEFINED
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
#pragma warning(default : 4142)
|
||||
#endif
|
||||
#ifndef PRIi32
|
||||
#define PRIi32 "d"
|
||||
#endif
|
||||
#ifndef PRId32
|
||||
#define PRId32 "d"
|
||||
#endif
|
||||
#ifndef PRIu32
|
||||
#define PRIu32 "u"
|
||||
#endif
|
||||
#ifndef PRIi64
|
||||
#define PRIi64 "I64i"
|
||||
#endif
|
||||
#ifndef PRId64
|
||||
#define PRId64 "I64i"
|
||||
#endif
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "I64u"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT)
|
||||
#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT
|
||||
typedef RTL_RUN_ONCE INIT_ONCE;
|
||||
#endif
|
||||
|
||||
#ifdef BSON_HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#elif !defined(__bool_true_false_are_defined)
|
||||
#ifndef __cplusplus
|
||||
typedef signed char bool;
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
|
||||
#define bson_sync_synchronize() __sync_synchronize ()
|
||||
#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || \
|
||||
defined(__i686__) || defined(__x86_64__)
|
||||
#define bson_sync_synchronize() asm volatile("mfence" ::: "memory")
|
||||
#else
|
||||
#define bson_sync_synchronize() asm volatile("sync" ::: "memory")
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#define bson_sync_synchronize() MemoryBarrier ()
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(va_copy) && defined(__va_copy)
|
||||
#define va_copy(dst, src) __va_copy (dst, src)
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(va_copy)
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
#endif
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_COMPAT_H */
|
||||
151
include/libbson-1.0/bson/bson-config.h
Normal file
151
include/libbson-1.0/bson/bson-config.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2018-present MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION)
|
||||
#error "Only <bson/bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef BSON_CONFIG_H
|
||||
#define BSON_CONFIG_H
|
||||
|
||||
/*
|
||||
* Define to 1234 for Little Endian, 4321 for Big Endian.
|
||||
*/
|
||||
#define BSON_BYTE_ORDER 1234
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have stdbool.h
|
||||
*/
|
||||
#define BSON_HAVE_STDBOOL_H 1
|
||||
#if BSON_HAVE_STDBOOL_H != 1
|
||||
# undef BSON_HAVE_STDBOOL_H
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 for POSIX-like systems, 2 for Windows.
|
||||
*/
|
||||
#define BSON_OS 1
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if we have access to GCC 32-bit atomic builtins.
|
||||
* While this requires GCC 4.1+ in most cases, it is also architecture
|
||||
* dependent. For example, some PPC or ARM systems may not have it even
|
||||
* if it is a recent GCC version.
|
||||
*/
|
||||
#define BSON_HAVE_ATOMIC_32_ADD_AND_FETCH 1
|
||||
#if BSON_HAVE_ATOMIC_32_ADD_AND_FETCH != 1
|
||||
# undef BSON_HAVE_ATOMIC_32_ADD_AND_FETCH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Similarly, define to 1 if we have access to GCC 64-bit atomic builtins.
|
||||
*/
|
||||
#define BSON_HAVE_ATOMIC_64_ADD_AND_FETCH 1
|
||||
#if BSON_HAVE_ATOMIC_64_ADD_AND_FETCH != 1
|
||||
# undef BSON_HAVE_ATOMIC_64_ADD_AND_FETCH
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have clock_gettime() available.
|
||||
*/
|
||||
#define BSON_HAVE_CLOCK_GETTIME 1
|
||||
#if BSON_HAVE_CLOCK_GETTIME != 1
|
||||
# undef BSON_HAVE_CLOCK_GETTIME
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have strings.h available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_STRINGS_H 1
|
||||
#if BSON_HAVE_STRINGS_H != 1
|
||||
# undef BSON_HAVE_STRINGS_H
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have strnlen available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_STRNLEN 1
|
||||
#if BSON_HAVE_STRNLEN != 1
|
||||
# undef BSON_HAVE_STRNLEN
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have snprintf available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_SNPRINTF 1
|
||||
#if BSON_HAVE_SNPRINTF != 1
|
||||
# undef BSON_HAVE_SNPRINTF
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have gmtime_r available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_GMTIME_R 1
|
||||
#if BSON_HAVE_GMTIME_R != 1
|
||||
# undef BSON_HAVE_GMTIME_R
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have reallocf available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_REALLOCF 0
|
||||
#if BSON_HAVE_REALLOCF != 1
|
||||
# undef BSON_HAVE_REALLOCF
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have struct timespec available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_TIMESPEC 1
|
||||
#if BSON_HAVE_TIMESPEC != 1
|
||||
# undef BSON_HAVE_TIMESPEC
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you want extra aligned types in libbson
|
||||
*/
|
||||
#define BSON_EXTRA_ALIGN 0
|
||||
#if BSON_EXTRA_ALIGN != 1
|
||||
# undef BSON_EXTRA_ALIGN
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have SYS_gettid syscall
|
||||
*/
|
||||
#define BSON_HAVE_SYSCALL_TID 1
|
||||
#if BSON_HAVE_SYSCALL_TID != 1
|
||||
# undef BSON_HAVE_SYSCALL_TID
|
||||
#endif
|
||||
|
||||
#define BSON_HAVE_RAND_R 1
|
||||
#if BSON_HAVE_RAND_R != 1
|
||||
# undef BSON_HAVE_RAND_R
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* BSON_CONFIG_H */
|
||||
42
include/libbson-1.0/bson/bson-context.h
Normal file
42
include/libbson-1.0/bson/bson-context.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_CONTEXT_H
|
||||
#define BSON_CONTEXT_H
|
||||
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
BSON_EXPORT (bson_context_t *)
|
||||
bson_context_new (bson_context_flags_t flags);
|
||||
BSON_EXPORT (void)
|
||||
bson_context_destroy (bson_context_t *context);
|
||||
BSON_EXPORT (bson_context_t *)
|
||||
bson_context_get_default (void);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_CONTEXT_H */
|
||||
64
include/libbson-1.0/bson/bson-decimal128.h
Normal file
64
include/libbson-1.0/bson/bson-decimal128.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2015 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_DECIMAL128_H
|
||||
#define BSON_DECIMAL128_H
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-config.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
/**
|
||||
* BSON_DECIMAL128_STRING:
|
||||
*
|
||||
* The length of a decimal128 string (with null terminator).
|
||||
*
|
||||
* 1 for the sign
|
||||
* 35 for digits and radix
|
||||
* 2 for exponent indicator and sign
|
||||
* 4 for exponent digits
|
||||
*/
|
||||
#define BSON_DECIMAL128_STRING 43
|
||||
#define BSON_DECIMAL128_INF "Infinity"
|
||||
#define BSON_DECIMAL128_NAN "NaN"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_decimal128_to_string (const bson_decimal128_t *dec, char *str);
|
||||
|
||||
|
||||
/* Note: @string must be ASCII characters only! */
|
||||
BSON_EXPORT (bool)
|
||||
bson_decimal128_from_string (const char *string, bson_decimal128_t *dec);
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_decimal128_from_string_w_len (const char *string,
|
||||
int len,
|
||||
bson_decimal128_t *dec);
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_DECIMAL128_H */
|
||||
227
include/libbson-1.0/bson/bson-endian.h
Normal file
227
include/libbson-1.0/bson/bson-endian.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_ENDIAN_H
|
||||
#define BSON_ENDIAN_H
|
||||
|
||||
|
||||
#if defined(__sun)
|
||||
#include <sys/byteorder.h>
|
||||
#endif
|
||||
|
||||
#include "bson/bson-config.h"
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-compat.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_BIG_ENDIAN 4321
|
||||
#define BSON_LITTLE_ENDIAN 1234
|
||||
|
||||
|
||||
#if defined(__sun)
|
||||
#define BSON_UINT16_SWAP_LE_BE(v) BSWAP_16 ((uint16_t) v)
|
||||
#define BSON_UINT32_SWAP_LE_BE(v) BSWAP_32 ((uint32_t) v)
|
||||
#define BSON_UINT64_SWAP_LE_BE(v) BSWAP_64 ((uint64_t) v)
|
||||
#elif defined(__clang__) && defined(__clang_major__) && \
|
||||
defined(__clang_minor__) && (__clang_major__ >= 3) && \
|
||||
(__clang_minor__ >= 1)
|
||||
#if __has_builtin(__builtin_bswap16)
|
||||
#define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 (v)
|
||||
#endif
|
||||
#if __has_builtin(__builtin_bswap32)
|
||||
#define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 (v)
|
||||
#endif
|
||||
#if __has_builtin(__builtin_bswap64)
|
||||
#define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 (v)
|
||||
#endif
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3)
|
||||
#define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t) v)
|
||||
#define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t) v)
|
||||
#endif
|
||||
#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8)
|
||||
#define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t) v)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_UINT16_SWAP_LE_BE
|
||||
#define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow ((uint16_t) v)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_UINT32_SWAP_LE_BE
|
||||
#define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow ((uint32_t) v)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_UINT64_SWAP_LE_BE
|
||||
#define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow ((uint64_t) v)
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN
|
||||
#define BSON_UINT16_FROM_LE(v) ((uint16_t) v)
|
||||
#define BSON_UINT16_TO_LE(v) ((uint16_t) v)
|
||||
#define BSON_UINT16_FROM_BE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
#define BSON_UINT16_TO_BE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
#define BSON_UINT32_FROM_LE(v) ((uint32_t) v)
|
||||
#define BSON_UINT32_TO_LE(v) ((uint32_t) v)
|
||||
#define BSON_UINT32_FROM_BE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
#define BSON_UINT32_TO_BE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
#define BSON_UINT64_FROM_LE(v) ((uint64_t) v)
|
||||
#define BSON_UINT64_TO_LE(v) ((uint64_t) v)
|
||||
#define BSON_UINT64_FROM_BE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
#define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
#define BSON_DOUBLE_FROM_LE(v) ((double) v)
|
||||
#define BSON_DOUBLE_TO_LE(v) ((double) v)
|
||||
#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN
|
||||
#define BSON_UINT16_FROM_LE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
#define BSON_UINT16_TO_LE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
#define BSON_UINT16_FROM_BE(v) ((uint16_t) v)
|
||||
#define BSON_UINT16_TO_BE(v) ((uint16_t) v)
|
||||
#define BSON_UINT32_FROM_LE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
#define BSON_UINT32_TO_LE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
#define BSON_UINT32_FROM_BE(v) ((uint32_t) v)
|
||||
#define BSON_UINT32_TO_BE(v) ((uint32_t) v)
|
||||
#define BSON_UINT64_FROM_LE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
#define BSON_UINT64_TO_LE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
#define BSON_UINT64_FROM_BE(v) ((uint64_t) v)
|
||||
#define BSON_UINT64_TO_BE(v) ((uint64_t) v)
|
||||
#define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow (v))
|
||||
#define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow (v))
|
||||
#else
|
||||
#error "The endianness of target architecture is unknown."
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_uint16_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for 16-bit integers.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE uint16_t
|
||||
__bson_uint16_swap_slow (uint16_t v) /* IN */
|
||||
{
|
||||
return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_uint32_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for 32-bit integers.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE uint32_t
|
||||
__bson_uint32_swap_slow (uint32_t v) /* IN */
|
||||
{
|
||||
return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) |
|
||||
((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_uint64_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for 64-bit integers.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE uint64_t
|
||||
__bson_uint64_swap_slow (uint64_t v) /* IN */
|
||||
{
|
||||
return ((v & 0x00000000000000FFULL) << 56) |
|
||||
((v & 0x000000000000FF00ULL) << 40) |
|
||||
((v & 0x0000000000FF0000ULL) << 24) |
|
||||
((v & 0x00000000FF000000ULL) << 8) |
|
||||
((v & 0x000000FF00000000ULL) >> 8) |
|
||||
((v & 0x0000FF0000000000ULL) >> 24) |
|
||||
((v & 0x00FF000000000000ULL) >> 40) |
|
||||
((v & 0xFF00000000000000ULL) >> 56);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_double_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for double floating point.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
BSON_STATIC_ASSERT2 (sizeof_uint64_t, sizeof (double) == sizeof (uint64_t));
|
||||
|
||||
static BSON_INLINE double
|
||||
__bson_double_swap_slow (double v) /* IN */
|
||||
{
|
||||
uint64_t uv;
|
||||
|
||||
memcpy (&uv, &v, sizeof (v));
|
||||
uv = BSON_UINT64_SWAP_LE_BE (uv);
|
||||
memcpy (&v, &uv, sizeof (v));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ENDIAN_H */
|
||||
50
include/libbson-1.0/bson/bson-error.h
Normal file
50
include/libbson-1.0/bson/bson-error.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_ERROR_H
|
||||
#define BSON_ERROR_H
|
||||
|
||||
|
||||
#include "bson/bson-compat.h"
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_ERROR_JSON 1
|
||||
#define BSON_ERROR_READER 2
|
||||
#define BSON_ERROR_INVALID 3
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_set_error (bson_error_t *error,
|
||||
uint32_t domain,
|
||||
uint32_t code,
|
||||
const char *format,
|
||||
...) BSON_GNUC_PRINTF (4, 5);
|
||||
BSON_EXPORT (char *)
|
||||
bson_strerror_r (int err_code, char *buf, size_t buflen);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ERROR_H */
|
||||
547
include/libbson-1.0/bson/bson-iter.h
Normal file
547
include/libbson-1.0/bson/bson-iter.h
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_ITER_H
|
||||
#define BSON_ITER_H
|
||||
|
||||
|
||||
#include "bson/bson.h"
|
||||
#include "bson/bson-endian.h"
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_ITER_HOLDS_DOUBLE(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DOUBLE)
|
||||
|
||||
#define BSON_ITER_HOLDS_UTF8(iter) (bson_iter_type ((iter)) == BSON_TYPE_UTF8)
|
||||
|
||||
#define BSON_ITER_HOLDS_DOCUMENT(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DOCUMENT)
|
||||
|
||||
#define BSON_ITER_HOLDS_ARRAY(iter) (bson_iter_type ((iter)) == BSON_TYPE_ARRAY)
|
||||
|
||||
#define BSON_ITER_HOLDS_BINARY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_BINARY)
|
||||
|
||||
#define BSON_ITER_HOLDS_UNDEFINED(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED)
|
||||
|
||||
#define BSON_ITER_HOLDS_OID(iter) (bson_iter_type ((iter)) == BSON_TYPE_OID)
|
||||
|
||||
#define BSON_ITER_HOLDS_BOOL(iter) (bson_iter_type ((iter)) == BSON_TYPE_BOOL)
|
||||
|
||||
#define BSON_ITER_HOLDS_DATE_TIME(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DATE_TIME)
|
||||
|
||||
#define BSON_ITER_HOLDS_NULL(iter) (bson_iter_type ((iter)) == BSON_TYPE_NULL)
|
||||
|
||||
#define BSON_ITER_HOLDS_REGEX(iter) (bson_iter_type ((iter)) == BSON_TYPE_REGEX)
|
||||
|
||||
#define BSON_ITER_HOLDS_DBPOINTER(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DBPOINTER)
|
||||
|
||||
#define BSON_ITER_HOLDS_CODE(iter) (bson_iter_type ((iter)) == BSON_TYPE_CODE)
|
||||
|
||||
#define BSON_ITER_HOLDS_SYMBOL(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_SYMBOL)
|
||||
|
||||
#define BSON_ITER_HOLDS_CODEWSCOPE(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_CODEWSCOPE)
|
||||
|
||||
#define BSON_ITER_HOLDS_INT32(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT32)
|
||||
|
||||
#define BSON_ITER_HOLDS_TIMESTAMP(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_TIMESTAMP)
|
||||
|
||||
#define BSON_ITER_HOLDS_INT64(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT64)
|
||||
|
||||
#define BSON_ITER_HOLDS_DECIMAL128(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DECIMAL128)
|
||||
|
||||
#define BSON_ITER_HOLDS_MAXKEY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_MAXKEY)
|
||||
|
||||
#define BSON_ITER_HOLDS_MINKEY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_MINKEY)
|
||||
|
||||
#define BSON_ITER_HOLDS_INT(iter) \
|
||||
(BSON_ITER_HOLDS_INT32 (iter) || BSON_ITER_HOLDS_INT64 (iter))
|
||||
|
||||
#define BSON_ITER_HOLDS_NUMBER(iter) \
|
||||
(BSON_ITER_HOLDS_INT (iter) || BSON_ITER_HOLDS_DOUBLE (iter))
|
||||
|
||||
#define BSON_ITER_IS_KEY(iter, key) \
|
||||
(0 == strcmp ((key), bson_iter_key ((iter))))
|
||||
|
||||
|
||||
BSON_EXPORT (const bson_value_t *)
|
||||
bson_iter_value (bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_utf8_len_unsafe:
|
||||
* @iter: a bson_iter_t.
|
||||
*
|
||||
* Returns the length of a string currently pointed to by @iter. This performs
|
||||
* no validation so the is responsible for knowing the BSON is valid. Calling
|
||||
* bson_validate() is one way to do this ahead of time.
|
||||
*/
|
||||
static BSON_INLINE uint32_t
|
||||
bson_iter_utf8_len_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
val = BSON_UINT32_FROM_LE (val);
|
||||
return BSON_MAX (0, val - 1);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_array (const bson_iter_t *iter,
|
||||
uint32_t *array_len,
|
||||
const uint8_t **array);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_binary (const bson_iter_t *iter,
|
||||
bson_subtype_t *subtype,
|
||||
uint32_t *binary_len,
|
||||
const uint8_t **binary);
|
||||
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_iter_code (const bson_iter_t *iter, uint32_t *length);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_code_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
* @length: A location for the length of the resulting string.
|
||||
*
|
||||
* Like bson_iter_code() but performs no integrity checks.
|
||||
*
|
||||
* Returns: A string that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const char *
|
||||
bson_iter_code_unsafe (const bson_iter_t *iter, uint32_t *length)
|
||||
{
|
||||
*length = bson_iter_utf8_len_unsafe (iter);
|
||||
return (const char *) (iter->raw + iter->d2);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_iter_codewscope (const bson_iter_t *iter,
|
||||
uint32_t *length,
|
||||
uint32_t *scope_len,
|
||||
const uint8_t **scope);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_dbpointer (const bson_iter_t *iter,
|
||||
uint32_t *collection_len,
|
||||
const char **collection,
|
||||
const bson_oid_t **oid);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_document (const bson_iter_t *iter,
|
||||
uint32_t *document_len,
|
||||
const uint8_t **document);
|
||||
|
||||
|
||||
BSON_EXPORT (double)
|
||||
bson_iter_double (const bson_iter_t *iter);
|
||||
|
||||
BSON_EXPORT (double)
|
||||
bson_iter_as_double (const bson_iter_t *iter);
|
||||
|
||||
/**
|
||||
* bson_iter_double_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_double() but does not perform an integrity checking.
|
||||
*
|
||||
* Returns: A double.
|
||||
*/
|
||||
static BSON_INLINE double
|
||||
bson_iter_double_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
double val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
return BSON_DOUBLE_FROM_LE (val);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_init (bson_iter_t *iter, const bson_t *bson);
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_init_from_data (bson_iter_t *iter,
|
||||
const uint8_t *data,
|
||||
size_t length);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_init_find (bson_iter_t *iter, const bson_t *bson, const char *key);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_init_find_w_len (bson_iter_t *iter,
|
||||
const bson_t *bson,
|
||||
const char *key,
|
||||
int keylen);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_init_find_case (bson_iter_t *iter,
|
||||
const bson_t *bson,
|
||||
const char *key);
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_init_from_data_at_offset (bson_iter_t *iter,
|
||||
const uint8_t *data,
|
||||
size_t length,
|
||||
uint32_t offset,
|
||||
uint32_t keylen);
|
||||
|
||||
BSON_EXPORT (int32_t)
|
||||
bson_iter_int32 (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_int32_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_int32() but with no integrity checking.
|
||||
*
|
||||
* Returns: A 32-bit signed integer.
|
||||
*/
|
||||
static BSON_INLINE int32_t
|
||||
bson_iter_int32_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
return BSON_UINT32_FROM_LE (val);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (int64_t)
|
||||
bson_iter_int64 (const bson_iter_t *iter);
|
||||
|
||||
|
||||
BSON_EXPORT (int64_t)
|
||||
bson_iter_as_int64 (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_int64_unsafe:
|
||||
* @iter: a bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_int64() but without integrity checking.
|
||||
*
|
||||
* Returns: A 64-bit signed integer.
|
||||
*/
|
||||
static BSON_INLINE int64_t
|
||||
bson_iter_int64_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
int64_t val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
return BSON_UINT64_FROM_LE (val);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_find (bson_iter_t *iter, const char *key);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_find_w_len (bson_iter_t *iter, const char *key, int keylen);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_find_case (bson_iter_t *iter, const char *key);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_find_descendant (bson_iter_t *iter,
|
||||
const char *dotkey,
|
||||
bson_iter_t *descendant);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_next (bson_iter_t *iter);
|
||||
|
||||
|
||||
BSON_EXPORT (const bson_oid_t *)
|
||||
bson_iter_oid (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_oid_unsafe:
|
||||
* @iter: A #bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_oid() but performs no integrity checks.
|
||||
*
|
||||
* Returns: A #bson_oid_t that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const bson_oid_t *
|
||||
bson_iter_oid_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (const bson_oid_t *) (iter->raw + iter->d1);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_decimal128 (const bson_iter_t *iter, bson_decimal128_t *dec);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_decimal128_unsafe:
|
||||
* @iter: A #bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_decimal128() but performs no integrity checks.
|
||||
*
|
||||
* Returns: A #bson_decimal128_t.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_iter_decimal128_unsafe (const bson_iter_t *iter, bson_decimal128_t *dec)
|
||||
{
|
||||
uint64_t low_le;
|
||||
uint64_t high_le;
|
||||
|
||||
memcpy (&low_le, iter->raw + iter->d1, sizeof (low_le));
|
||||
memcpy (&high_le, iter->raw + iter->d1 + 8, sizeof (high_le));
|
||||
|
||||
dec->low = BSON_UINT64_FROM_LE (low_le);
|
||||
dec->high = BSON_UINT64_FROM_LE (high_le);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_iter_key (const bson_iter_t *iter);
|
||||
|
||||
BSON_EXPORT (uint32_t)
|
||||
bson_iter_key_len (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_key_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_key() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A string that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const char *
|
||||
bson_iter_key_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (const char *) (iter->raw + iter->key);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_iter_utf8 (const bson_iter_t *iter, uint32_t *length);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_utf8_unsafe:
|
||||
*
|
||||
* Similar to bson_iter_utf8() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A string that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const char *
|
||||
bson_iter_utf8_unsafe (const bson_iter_t *iter, size_t *length)
|
||||
{
|
||||
*length = bson_iter_utf8_len_unsafe (iter);
|
||||
return (const char *) (iter->raw + iter->d2);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (char *)
|
||||
bson_iter_dup_utf8 (const bson_iter_t *iter, uint32_t *length);
|
||||
|
||||
|
||||
BSON_EXPORT (int64_t)
|
||||
bson_iter_date_time (const bson_iter_t *iter);
|
||||
|
||||
|
||||
BSON_EXPORT (time_t)
|
||||
bson_iter_time_t (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_time_t_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_time_t() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A time_t containing the number of seconds since UNIX epoch
|
||||
* in UTC.
|
||||
*/
|
||||
static BSON_INLINE time_t
|
||||
bson_iter_time_t_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (time_t) (bson_iter_int64_unsafe (iter) / 1000UL);
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_timeval (const bson_iter_t *iter, struct timeval *tv);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_timeval_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
* @tv: A struct timeval.
|
||||
*
|
||||
* Similar to bson_iter_timeval() but performs no integrity checking.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_iter_timeval_unsafe (const bson_iter_t *iter, struct timeval *tv)
|
||||
{
|
||||
int64_t value = bson_iter_int64_unsafe (iter);
|
||||
#ifdef BSON_OS_WIN32
|
||||
tv->tv_sec = (long) (value / 1000);
|
||||
#else
|
||||
tv->tv_sec = (suseconds_t) (value / 1000);
|
||||
#endif
|
||||
tv->tv_usec = (value % 1000) * 1000;
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_timestamp (const bson_iter_t *iter,
|
||||
uint32_t *timestamp,
|
||||
uint32_t *increment);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_bool (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_bool_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_bool() but performs no integrity checking.
|
||||
*
|
||||
* Returns: true or false.
|
||||
*/
|
||||
static BSON_INLINE bool
|
||||
bson_iter_bool_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
char val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, 1);
|
||||
return !!val;
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_as_bool (const bson_iter_t *iter);
|
||||
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_iter_regex (const bson_iter_t *iter, const char **options);
|
||||
|
||||
|
||||
BSON_EXPORT (const char *)
|
||||
bson_iter_symbol (const bson_iter_t *iter, uint32_t *length);
|
||||
|
||||
|
||||
BSON_EXPORT (bson_type_t)
|
||||
bson_iter_type (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_type_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_type() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A bson_type_t.
|
||||
*/
|
||||
static BSON_INLINE bson_type_t
|
||||
bson_iter_type_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (bson_type_t) (iter->raw + iter->type)[0];
|
||||
}
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_recurse (const bson_iter_t *iter, bson_iter_t *child);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_int32 (bson_iter_t *iter, int32_t value);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_int64 (bson_iter_t *iter, int64_t value);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_double (bson_iter_t *iter, double value);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_decimal128 (bson_iter_t *iter, bson_decimal128_t *value);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_bool (bson_iter_t *iter, bool value);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_oid (bson_iter_t *iter, const bson_oid_t *value);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_timestamp (bson_iter_t *iter,
|
||||
uint32_t timestamp,
|
||||
uint32_t increment);
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_iter_overwrite_date_time (bson_iter_t *iter, int64_t value);
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_iter_visit_all (bson_iter_t *iter,
|
||||
const bson_visitor_t *visitor,
|
||||
void *data);
|
||||
|
||||
BSON_EXPORT (uint32_t)
|
||||
bson_iter_offset (bson_iter_t *iter);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ITER_H */
|
||||
73
include/libbson-1.0/bson/bson-json.h
Normal file
73
include/libbson-1.0/bson/bson-json.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_JSON_H
|
||||
#define BSON_JSON_H
|
||||
|
||||
|
||||
#include "bson/bson.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct _bson_json_reader_t bson_json_reader_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
BSON_JSON_ERROR_READ_CORRUPT_JS = 1,
|
||||
BSON_JSON_ERROR_READ_INVALID_PARAM,
|
||||
BSON_JSON_ERROR_READ_CB_FAILURE,
|
||||
} bson_json_error_code_t;
|
||||
|
||||
|
||||
typedef ssize_t (*bson_json_reader_cb) (void *handle,
|
||||
uint8_t *buf,
|
||||
size_t count);
|
||||
typedef void (*bson_json_destroy_cb) (void *handle);
|
||||
|
||||
|
||||
BSON_EXPORT (bson_json_reader_t *)
|
||||
bson_json_reader_new (void *data,
|
||||
bson_json_reader_cb cb,
|
||||
bson_json_destroy_cb dcb,
|
||||
bool allow_multiple,
|
||||
size_t buf_size);
|
||||
BSON_EXPORT (bson_json_reader_t *)
|
||||
bson_json_reader_new_from_fd (int fd, bool close_on_destroy);
|
||||
BSON_EXPORT (bson_json_reader_t *)
|
||||
bson_json_reader_new_from_file (const char *filename, bson_error_t *error);
|
||||
BSON_EXPORT (void)
|
||||
bson_json_reader_destroy (bson_json_reader_t *reader);
|
||||
BSON_EXPORT (int)
|
||||
bson_json_reader_read (bson_json_reader_t *reader,
|
||||
bson_t *bson,
|
||||
bson_error_t *error);
|
||||
BSON_EXPORT (bson_json_reader_t *)
|
||||
bson_json_data_reader_new (bool allow_multiple, size_t size);
|
||||
BSON_EXPORT (void)
|
||||
bson_json_data_reader_ingest (bson_json_reader_t *reader,
|
||||
const uint8_t *data,
|
||||
size_t len);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_JSON_H */
|
||||
41
include/libbson-1.0/bson/bson-keys.h
Normal file
41
include/libbson-1.0/bson/bson-keys.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_KEYS_H
|
||||
#define BSON_KEYS_H
|
||||
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
BSON_EXPORT (size_t)
|
||||
bson_uint32_to_string (uint32_t value,
|
||||
const char **strptr,
|
||||
char *str,
|
||||
size_t size);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_KEYS_H */
|
||||
293
include/libbson-1.0/bson/bson-macros.h
Normal file
293
include/libbson-1.0/bson/bson-macros.h
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_MACROS_H
|
||||
#define BSON_MACROS_H
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "bson/bson-config.h"
|
||||
|
||||
|
||||
#if BSON_OS == 1
|
||||
#define BSON_OS_UNIX
|
||||
#elif BSON_OS == 2
|
||||
#define BSON_OS_WIN32
|
||||
#else
|
||||
#error "Unknown operating system."
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define BSON_BEGIN_DECLS extern "C" {
|
||||
#define BSON_END_DECLS }
|
||||
#else
|
||||
#define BSON_BEGIN_DECLS
|
||||
#define BSON_END_DECLS
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define BSON_GNUC_CHECK_VERSION(major, minor) \
|
||||
((__GNUC__ > (major)) || \
|
||||
((__GNUC__ == (major)) && (__GNUC_MINOR__ >= (minor))))
|
||||
#else
|
||||
#define BSON_GNUC_CHECK_VERSION(major, minor) 0
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define BSON_GNUC_IS_VERSION(major, minor) \
|
||||
((__GNUC__ == (major)) && (__GNUC_MINOR__ == (minor)))
|
||||
#else
|
||||
#define BSON_GNUC_IS_VERSION(major, minor) 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Decorate public functions:
|
||||
* - if BSON_STATIC, we're compiling a program that uses libbson as a static
|
||||
* library, don't decorate functions
|
||||
* - else if BSON_COMPILATION, we're compiling a static or shared libbson, mark
|
||||
* public functions for export from the shared lib (which has no effect on
|
||||
* the static lib)
|
||||
* - else, we're compiling a program that uses libbson as a shared library,
|
||||
* mark public functions as DLL imports for Microsoft Visual C
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/*
|
||||
* Microsoft Visual C
|
||||
*/
|
||||
#ifdef BSON_STATIC
|
||||
#define BSON_API
|
||||
#elif defined(BSON_COMPILATION)
|
||||
#define BSON_API __declspec(dllexport)
|
||||
#else
|
||||
#define BSON_API __declspec(dllimport)
|
||||
#endif
|
||||
#define BSON_CALL __cdecl
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
/*
|
||||
* GCC
|
||||
*/
|
||||
#ifdef BSON_STATIC
|
||||
#define BSON_API
|
||||
#elif defined(BSON_COMPILATION)
|
||||
#define BSON_API __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define BSON_API
|
||||
#endif
|
||||
#define BSON_CALL
|
||||
|
||||
#else
|
||||
/*
|
||||
* Other compilers
|
||||
*/
|
||||
#define BSON_API
|
||||
#define BSON_CALL
|
||||
|
||||
#endif
|
||||
|
||||
#define BSON_EXPORT(type) BSON_API type BSON_CALL
|
||||
|
||||
|
||||
#ifdef MIN
|
||||
#define BSON_MIN MIN
|
||||
#elif defined(__cplusplus)
|
||||
#define BSON_MIN(a, b) ((std::min) (a, b))
|
||||
#elif defined(_MSC_VER)
|
||||
#define BSON_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#else
|
||||
#define BSON_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MAX
|
||||
#define BSON_MAX MAX
|
||||
#elif defined(__cplusplus)
|
||||
#define BSON_MAX(a, b) ((std::max) (a, b))
|
||||
#elif defined(_MSC_VER)
|
||||
#define BSON_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#else
|
||||
#define BSON_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ABS
|
||||
#define BSON_ABS ABS
|
||||
#else
|
||||
#define BSON_ABS(a) (((a) < 0) ? ((a) * -1) : (a))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN64
|
||||
#define BSON_ALIGN_OF_PTR 8
|
||||
#else
|
||||
#define BSON_ALIGN_OF_PTR 4
|
||||
#endif
|
||||
#else
|
||||
#define BSON_ALIGN_OF_PTR (sizeof (void *))
|
||||
#endif
|
||||
|
||||
#ifdef BSON_EXTRA_ALIGN
|
||||
#if defined(_MSC_VER)
|
||||
#define BSON_ALIGNED_BEGIN(_N) __declspec(align (_N))
|
||||
#define BSON_ALIGNED_END(_N)
|
||||
#else
|
||||
#define BSON_ALIGNED_BEGIN(_N)
|
||||
#define BSON_ALIGNED_END(_N) __attribute__ ((aligned (_N)))
|
||||
#endif
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#define BSON_ALIGNED_BEGIN(_N) __declspec(align (BSON_ALIGN_OF_PTR))
|
||||
#define BSON_ALIGNED_END(_N)
|
||||
#else
|
||||
#define BSON_ALIGNED_BEGIN(_N)
|
||||
#define BSON_ALIGNED_END(_N) \
|
||||
__attribute__ ( \
|
||||
(aligned ((_N) > BSON_ALIGN_OF_PTR ? BSON_ALIGN_OF_PTR : (_N))))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define bson_str_empty(s) (!s[0])
|
||||
#define bson_str_empty0(s) (!s || !s[0])
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define BSON_FUNC __FUNCTION__
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L
|
||||
#define BSON_FUNC __FUNCTION__
|
||||
#else
|
||||
#define BSON_FUNC __func__
|
||||
#endif
|
||||
|
||||
#define BSON_ASSERT(test) \
|
||||
do { \
|
||||
if (!(BSON_LIKELY (test))) { \
|
||||
fprintf (stderr, \
|
||||
"%s:%d %s(): precondition failed: %s\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
BSON_FUNC, \
|
||||
#test); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* obsolete macros, preserved for compatibility */
|
||||
#define BSON_STATIC_ASSERT(s) BSON_STATIC_ASSERT_ (s, __LINE__)
|
||||
#define BSON_STATIC_ASSERT_JOIN(a, b) BSON_STATIC_ASSERT_JOIN2 (a, b)
|
||||
#define BSON_STATIC_ASSERT_JOIN2(a, b) a##b
|
||||
#define BSON_STATIC_ASSERT_(s, l) \
|
||||
typedef char BSON_STATIC_ASSERT_JOIN (static_assert_test_, \
|
||||
__LINE__)[(s) ? 1 : -1]
|
||||
|
||||
/* modern macros */
|
||||
#define BSON_STATIC_ASSERT2(_name, _s) \
|
||||
BSON_STATIC_ASSERT2_ (_s, __LINE__, _name)
|
||||
#define BSON_STATIC_ASSERT_JOIN3(_a, _b, _name) \
|
||||
BSON_STATIC_ASSERT_JOIN4 (_a, _b, _name)
|
||||
#define BSON_STATIC_ASSERT_JOIN4(_a, _b, _name) _a##_b##_name
|
||||
#define BSON_STATIC_ASSERT2_(_s, _l, _name) \
|
||||
typedef char BSON_STATIC_ASSERT_JOIN3 ( \
|
||||
static_assert_test_, __LINE__, _name)[(_s) ? 1 : -1]
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define BSON_GNUC_PURE __attribute__ ((pure))
|
||||
#define BSON_GNUC_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
|
||||
#else
|
||||
#define BSON_GNUC_PURE
|
||||
#define BSON_GNUC_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_GNUC_CHECK_VERSION(4, 0) && !defined(_WIN32)
|
||||
#define BSON_GNUC_NULL_TERMINATED __attribute__ ((sentinel))
|
||||
#define BSON_GNUC_INTERNAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define BSON_GNUC_NULL_TERMINATED
|
||||
#define BSON_GNUC_INTERNAL
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define BSON_LIKELY(x) __builtin_expect (!!(x), 1)
|
||||
#define BSON_UNLIKELY(x) __builtin_expect (!!(x), 0)
|
||||
#else
|
||||
#define BSON_LIKELY(v) v
|
||||
#define BSON_UNLIKELY(v) v
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__clang__)
|
||||
#define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (printf, f, v)))
|
||||
#elif BSON_GNUC_CHECK_VERSION(4, 4)
|
||||
#define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (gnu_printf, f, v)))
|
||||
#else
|
||||
#define BSON_GNUC_PRINTF(f, v)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__LP64__) || defined(_LP64)
|
||||
#define BSON_WORD_SIZE 64
|
||||
#else
|
||||
#define BSON_WORD_SIZE 32
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define BSON_INLINE __inline
|
||||
#else
|
||||
#define BSON_INLINE __inline__
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define BSON_ENSURE_ARRAY_PARAM_SIZE(_n)
|
||||
#define BSON_TYPEOF decltype
|
||||
#else
|
||||
#define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) static(_n)
|
||||
#define BSON_TYPEOF typeof
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_GNUC_CHECK_VERSION(3, 1)
|
||||
#define BSON_GNUC_DEPRECATED __attribute__ ((__deprecated__))
|
||||
#else
|
||||
#define BSON_GNUC_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_GNUC_CHECK_VERSION(4, 5)
|
||||
#define BSON_GNUC_DEPRECATED_FOR(f) \
|
||||
__attribute__ ((deprecated ("Use " #f " instead")))
|
||||
#else
|
||||
#define BSON_GNUC_DEPRECATED_FOR(f) BSON_GNUC_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* BSON_MACROS_H */
|
||||
89
include/libbson-1.0/bson/bson-md5.h
Normal file
89
include/libbson-1.0/bson/bson-md5.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgement in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The following MD5 implementation has been modified to use types as
|
||||
* specified in libbson.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_MD5_H
|
||||
#define BSON_MD5_H
|
||||
|
||||
|
||||
#include "bson/bson-endian.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t count[2]; /* message length in bits, lsw first */
|
||||
uint32_t abcd[4]; /* digest buffer */
|
||||
uint8_t buf[64]; /* accumulate block */
|
||||
} bson_md5_t;
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_md5_init (bson_md5_t *pms) BSON_GNUC_DEPRECATED;
|
||||
BSON_EXPORT (void)
|
||||
bson_md5_append (bson_md5_t *pms,
|
||||
const uint8_t *data,
|
||||
uint32_t nbytes) BSON_GNUC_DEPRECATED;
|
||||
BSON_EXPORT (void)
|
||||
bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]) BSON_GNUC_DEPRECATED;
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_MD5_H */
|
||||
64
include/libbson-1.0/bson/bson-memory.h
Normal file
64
include/libbson-1.0/bson/bson-memory.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_MEMORY_H
|
||||
#define BSON_MEMORY_H
|
||||
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef void *(*bson_realloc_func) (void *mem, size_t num_bytes, void *ctx);
|
||||
|
||||
|
||||
typedef struct _bson_mem_vtable_t {
|
||||
void *(*malloc) (size_t num_bytes);
|
||||
void *(*calloc) (size_t n_members, size_t num_bytes);
|
||||
void *(*realloc) (void *mem, size_t num_bytes);
|
||||
void (*free) (void *mem);
|
||||
void *padding[4];
|
||||
} bson_mem_vtable_t;
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_mem_set_vtable (const bson_mem_vtable_t *vtable);
|
||||
BSON_EXPORT (void)
|
||||
bson_mem_restore_vtable (void);
|
||||
BSON_EXPORT (void *)
|
||||
bson_malloc (size_t num_bytes);
|
||||
BSON_EXPORT (void *)
|
||||
bson_malloc0 (size_t num_bytes);
|
||||
BSON_EXPORT (void *)
|
||||
bson_realloc (void *mem, size_t num_bytes);
|
||||
BSON_EXPORT (void *)
|
||||
bson_realloc_ctx (void *mem, size_t num_bytes, void *ctx);
|
||||
BSON_EXPORT (void)
|
||||
bson_free (void *mem);
|
||||
BSON_EXPORT (void)
|
||||
bson_zero_free (void *mem, size_t size);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_MEMORY_H */
|
||||
244
include/libbson-1.0/bson/bson-oid.h
Normal file
244
include/libbson-1.0/bson/bson-oid.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_OID_H
|
||||
#define BSON_OID_H
|
||||
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "bson/bson-context.h"
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
#include "bson/bson-endian.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
BSON_EXPORT (int)
|
||||
bson_oid_compare (const bson_oid_t *oid1, const bson_oid_t *oid2);
|
||||
BSON_EXPORT (void)
|
||||
bson_oid_copy (const bson_oid_t *src, bson_oid_t *dst);
|
||||
BSON_EXPORT (bool)
|
||||
bson_oid_equal (const bson_oid_t *oid1, const bson_oid_t *oid2);
|
||||
BSON_EXPORT (bool)
|
||||
bson_oid_is_valid (const char *str, size_t length);
|
||||
BSON_EXPORT (time_t)
|
||||
bson_oid_get_time_t (const bson_oid_t *oid);
|
||||
BSON_EXPORT (uint32_t)
|
||||
bson_oid_hash (const bson_oid_t *oid);
|
||||
BSON_EXPORT (void)
|
||||
bson_oid_init (bson_oid_t *oid, bson_context_t *context);
|
||||
BSON_EXPORT (void)
|
||||
bson_oid_init_from_data (bson_oid_t *oid, const uint8_t *data);
|
||||
BSON_EXPORT (void)
|
||||
bson_oid_init_from_string (bson_oid_t *oid, const char *str);
|
||||
BSON_EXPORT (void)
|
||||
bson_oid_init_sequence (bson_oid_t *oid,
|
||||
bson_context_t *context) BSON_GNUC_DEPRECATED;
|
||||
BSON_EXPORT (void)
|
||||
bson_oid_to_string (const bson_oid_t *oid, char str[25]);
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_compare_unsafe:
|
||||
* @oid1: A bson_oid_t.
|
||||
* @oid2: A bson_oid_t.
|
||||
*
|
||||
* Performs a qsort() style comparison between @oid1 and @oid2.
|
||||
*
|
||||
* This function is meant to be as fast as possible and therefore performs
|
||||
* no argument validation. That is the callers responsibility.
|
||||
*
|
||||
* Returns: An integer < 0 if @oid1 is less than @oid2. Zero if they are equal.
|
||||
* An integer > 0 if @oid1 is greater than @oid2.
|
||||
*/
|
||||
static BSON_INLINE int
|
||||
bson_oid_compare_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2)
|
||||
{
|
||||
return memcmp (oid1, oid2, sizeof *oid1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_equal_unsafe:
|
||||
* @oid1: A bson_oid_t.
|
||||
* @oid2: A bson_oid_t.
|
||||
*
|
||||
* Checks the equality of @oid1 and @oid2.
|
||||
*
|
||||
* This function is meant to be as fast as possible and therefore performs
|
||||
* no checks for argument validity. That is the callers responsibility.
|
||||
*
|
||||
* Returns: true if @oid1 and @oid2 are equal; otherwise false.
|
||||
*/
|
||||
static BSON_INLINE bool
|
||||
bson_oid_equal_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2)
|
||||
{
|
||||
return !memcmp (oid1, oid2, sizeof *oid1);
|
||||
}
|
||||
|
||||
/**
|
||||
* bson_oid_hash_unsafe:
|
||||
* @oid: A bson_oid_t.
|
||||
*
|
||||
* This function performs a DJB style hash upon the bytes contained in @oid.
|
||||
* The result is a hash key suitable for use in a hashtable.
|
||||
*
|
||||
* This function is meant to be as fast as possible and therefore performs no
|
||||
* validation of arguments. The caller is responsible to ensure they are
|
||||
* passing valid arguments.
|
||||
*
|
||||
* Returns: A uint32_t containing a hash code.
|
||||
*/
|
||||
static BSON_INLINE uint32_t
|
||||
bson_oid_hash_unsafe (const bson_oid_t *oid)
|
||||
{
|
||||
uint32_t hash = 5381;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < sizeof oid->bytes; i++) {
|
||||
hash = ((hash << 5) + hash) + oid->bytes[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_copy_unsafe:
|
||||
* @src: A bson_oid_t to copy from.
|
||||
* @dst: A bson_oid_t to copy into.
|
||||
*
|
||||
* Copies the contents of @src into @dst. This function is meant to be as
|
||||
* fast as possible and therefore performs no argument checking. It is the
|
||||
* callers responsibility to ensure they are passing valid data into the
|
||||
* function.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_oid_copy_unsafe (const bson_oid_t *src, bson_oid_t *dst)
|
||||
{
|
||||
memcpy (dst, src, sizeof *src);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_parse_hex_char:
|
||||
* @hex: A character to parse to its integer value.
|
||||
*
|
||||
* This function contains a jump table to return the integer value for a
|
||||
* character containing a hexadecimal value (0-9, a-f, A-F). If the character
|
||||
* is not a hexadecimal character then zero is returned.
|
||||
*
|
||||
* Returns: An integer between 0 and 15.
|
||||
*/
|
||||
static BSON_INLINE uint8_t
|
||||
bson_oid_parse_hex_char (char hex)
|
||||
{
|
||||
switch (hex) {
|
||||
case '0':
|
||||
return 0;
|
||||
case '1':
|
||||
return 1;
|
||||
case '2':
|
||||
return 2;
|
||||
case '3':
|
||||
return 3;
|
||||
case '4':
|
||||
return 4;
|
||||
case '5':
|
||||
return 5;
|
||||
case '6':
|
||||
return 6;
|
||||
case '7':
|
||||
return 7;
|
||||
case '8':
|
||||
return 8;
|
||||
case '9':
|
||||
return 9;
|
||||
case 'a':
|
||||
case 'A':
|
||||
return 0xa;
|
||||
case 'b':
|
||||
case 'B':
|
||||
return 0xb;
|
||||
case 'c':
|
||||
case 'C':
|
||||
return 0xc;
|
||||
case 'd':
|
||||
case 'D':
|
||||
return 0xd;
|
||||
case 'e':
|
||||
case 'E':
|
||||
return 0xe;
|
||||
case 'f':
|
||||
case 'F':
|
||||
return 0xf;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_init_from_string_unsafe:
|
||||
* @oid: A bson_oid_t to store the result.
|
||||
* @str: A 24-character hexadecimal encoded string.
|
||||
*
|
||||
* Parses a string containing 24 hexadecimal encoded bytes into a bson_oid_t.
|
||||
* This function is meant to be as fast as possible and inlined into your
|
||||
* code. For that purpose, the function does not perform any sort of bounds
|
||||
* checking and it is the callers responsibility to ensure they are passing
|
||||
* valid input to the function.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_oid_init_from_string_unsafe (bson_oid_t *oid, const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
oid->bytes[i] = ((bson_oid_parse_hex_char (str[2 * i]) << 4) |
|
||||
(bson_oid_parse_hex_char (str[2 * i + 1])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_get_time_t_unsafe:
|
||||
* @oid: A bson_oid_t.
|
||||
*
|
||||
* Fetches the time @oid was generated.
|
||||
*
|
||||
* Returns: A time_t containing the UNIX timestamp of generation.
|
||||
*/
|
||||
static BSON_INLINE time_t
|
||||
bson_oid_get_time_t_unsafe (const bson_oid_t *oid)
|
||||
{
|
||||
uint32_t t;
|
||||
|
||||
memcpy (&t, oid, sizeof (t));
|
||||
return BSON_UINT32_FROM_BE (t);
|
||||
}
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_OID_H */
|
||||
19
include/libbson-1.0/bson/bson-prelude.h
Normal file
19
include/libbson-1.0/bson/bson-prelude.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2018-present MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION)
|
||||
#error "Only <bson/bson.h> can be included directly."
|
||||
#endif
|
||||
117
include/libbson-1.0/bson/bson-reader.h
Normal file
117
include/libbson-1.0/bson/bson-reader.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_READER_H
|
||||
#define BSON_READER_H
|
||||
|
||||
|
||||
#include "bson/bson-compat.h"
|
||||
#include "bson/bson-oid.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_ERROR_READER_BADFD 1
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_read_func_t --
|
||||
*
|
||||
* This function is a callback used by bson_reader_t to read the
|
||||
* next chunk of data from the underlying opaque file descriptor.
|
||||
*
|
||||
* This function is meant to operate similar to the read() function
|
||||
* as part of libc on UNIX-like systems.
|
||||
*
|
||||
* Parameters:
|
||||
* @handle: The handle to read from.
|
||||
* @buf: The buffer to read into.
|
||||
* @count: The number of bytes to read.
|
||||
*
|
||||
* Returns:
|
||||
* 0 for end of stream.
|
||||
* -1 for read failure.
|
||||
* Greater than zero for number of bytes read into @buf.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef ssize_t (*bson_reader_read_func_t) (void *handle, /* IN */
|
||||
void *buf, /* IN */
|
||||
size_t count); /* IN */
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_destroy_func_t --
|
||||
*
|
||||
* Destroy callback to release any resources associated with the
|
||||
* opaque handle.
|
||||
*
|
||||
* Parameters:
|
||||
* @handle: the handle provided to bson_reader_new_from_handle().
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef void (*bson_reader_destroy_func_t) (void *handle); /* IN */
|
||||
|
||||
|
||||
BSON_EXPORT (bson_reader_t *)
|
||||
bson_reader_new_from_handle (void *handle,
|
||||
bson_reader_read_func_t rf,
|
||||
bson_reader_destroy_func_t df);
|
||||
BSON_EXPORT (bson_reader_t *)
|
||||
bson_reader_new_from_fd (int fd, bool close_on_destroy);
|
||||
BSON_EXPORT (bson_reader_t *)
|
||||
bson_reader_new_from_file (const char *path, bson_error_t *error);
|
||||
BSON_EXPORT (bson_reader_t *)
|
||||
bson_reader_new_from_data (const uint8_t *data, size_t length);
|
||||
BSON_EXPORT (void)
|
||||
bson_reader_destroy (bson_reader_t *reader);
|
||||
BSON_EXPORT (void)
|
||||
bson_reader_set_read_func (bson_reader_t *reader, bson_reader_read_func_t func);
|
||||
BSON_EXPORT (void)
|
||||
bson_reader_set_destroy_func (bson_reader_t *reader,
|
||||
bson_reader_destroy_func_t func);
|
||||
BSON_EXPORT (const bson_t *)
|
||||
bson_reader_read (bson_reader_t *reader, bool *reached_eof);
|
||||
BSON_EXPORT (off_t)
|
||||
bson_reader_tell (bson_reader_t *reader);
|
||||
BSON_EXPORT (void)
|
||||
bson_reader_reset (bson_reader_t *reader);
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_READER_H */
|
||||
84
include/libbson-1.0/bson/bson-string.h
Normal file
84
include/libbson-1.0/bson/bson-string.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_STRING_H
|
||||
#define BSON_STRING_H
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
uint32_t len;
|
||||
uint32_t alloc;
|
||||
} bson_string_t;
|
||||
|
||||
|
||||
BSON_EXPORT (bson_string_t *)
|
||||
bson_string_new (const char *str);
|
||||
BSON_EXPORT (char *)
|
||||
bson_string_free (bson_string_t *string, bool free_segment);
|
||||
BSON_EXPORT (void)
|
||||
bson_string_append (bson_string_t *string, const char *str);
|
||||
BSON_EXPORT (void)
|
||||
bson_string_append_c (bson_string_t *string, char str);
|
||||
BSON_EXPORT (void)
|
||||
bson_string_append_unichar (bson_string_t *string, bson_unichar_t unichar);
|
||||
BSON_EXPORT (void)
|
||||
bson_string_append_printf (bson_string_t *string, const char *format, ...)
|
||||
BSON_GNUC_PRINTF (2, 3);
|
||||
BSON_EXPORT (void)
|
||||
bson_string_truncate (bson_string_t *string, uint32_t len);
|
||||
BSON_EXPORT (char *)
|
||||
bson_strdup (const char *str);
|
||||
BSON_EXPORT (char *)
|
||||
bson_strdup_printf (const char *format, ...) BSON_GNUC_PRINTF (1, 2);
|
||||
BSON_EXPORT (char *)
|
||||
bson_strdupv_printf (const char *format, va_list args) BSON_GNUC_PRINTF (1, 0);
|
||||
BSON_EXPORT (char *)
|
||||
bson_strndup (const char *str, size_t n_bytes);
|
||||
BSON_EXPORT (void)
|
||||
bson_strncpy (char *dst, const char *src, size_t size);
|
||||
BSON_EXPORT (int)
|
||||
bson_vsnprintf (char *str, size_t size, const char *format, va_list ap)
|
||||
BSON_GNUC_PRINTF (3, 0);
|
||||
BSON_EXPORT (int)
|
||||
bson_snprintf (char *str, size_t size, const char *format, ...)
|
||||
BSON_GNUC_PRINTF (3, 4);
|
||||
BSON_EXPORT (void)
|
||||
bson_strfreev (char **strv);
|
||||
BSON_EXPORT (size_t)
|
||||
bson_strnlen (const char *s, size_t maxlen);
|
||||
BSON_EXPORT (int64_t)
|
||||
bson_ascii_strtoll (const char *str, char **endptr, int base);
|
||||
BSON_EXPORT (int)
|
||||
bson_strcasecmp (const char *s1, const char *s2);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_STRING_H */
|
||||
564
include/libbson-1.0/bson/bson-types.h
Normal file
564
include/libbson-1.0/bson/bson-types.h
Normal file
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_TYPES_H
|
||||
#define BSON_TYPES_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-config.h"
|
||||
#include "bson/bson-compat.h"
|
||||
#include "bson/bson-endian.h"
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_unichar_t --
|
||||
*
|
||||
* bson_unichar_t provides an unsigned 32-bit type for containing
|
||||
* unicode characters. When iterating UTF-8 sequences, this should
|
||||
* be used to avoid losing the high-bits of non-ascii characters.
|
||||
*
|
||||
* See also:
|
||||
* bson_string_append_unichar()
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef uint32_t bson_unichar_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_context_flags_t:
|
||||
*
|
||||
* This enumeration is used to configure a bson_context_t.
|
||||
*
|
||||
* %BSON_CONTEXT_NONE: Use default options.
|
||||
* %BSON_CONTEXT_THREAD_SAFE: Context will be called from multiple threads.
|
||||
* %BSON_CONTEXT_DISABLE_PID_CACHE: Call getpid() instead of caching the
|
||||
* result of getpid() when initializing the context.
|
||||
* %BSON_CONTEXT_DISABLE_HOST_CACHE: Call gethostname() instead of caching the
|
||||
* result of gethostname() when initializing the context.
|
||||
*/
|
||||
typedef enum {
|
||||
BSON_CONTEXT_NONE = 0,
|
||||
BSON_CONTEXT_THREAD_SAFE = (1 << 0),
|
||||
BSON_CONTEXT_DISABLE_HOST_CACHE = (1 << 1),
|
||||
BSON_CONTEXT_DISABLE_PID_CACHE = (1 << 2),
|
||||
#ifdef BSON_HAVE_SYSCALL_TID
|
||||
BSON_CONTEXT_USE_TASK_ID = (1 << 3),
|
||||
#endif
|
||||
} bson_context_flags_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_context_t:
|
||||
*
|
||||
* This structure manages context for the bson library. It handles
|
||||
* configuration for thread-safety and other performance related requirements.
|
||||
* Consumers will create a context and may use multiple under a variety of
|
||||
* situations.
|
||||
*
|
||||
* If your program calls fork(), you should initialize a new bson_context_t
|
||||
* using bson_context_init().
|
||||
*
|
||||
* If you are using threading, it is suggested that you use a bson_context_t
|
||||
* per thread for best performance. Alternatively, you can initialize the
|
||||
* bson_context_t with BSON_CONTEXT_THREAD_SAFE, although a performance penalty
|
||||
* will be incurred.
|
||||
*
|
||||
* Many functions will require that you provide a bson_context_t such as OID
|
||||
* generation.
|
||||
*
|
||||
* This structure is opaque in that you cannot see the contents of the
|
||||
* structure. However, it is stack allocatable in that enough padding is
|
||||
* provided in _bson_context_t to hold the structure.
|
||||
*/
|
||||
typedef struct _bson_context_t bson_context_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_t:
|
||||
*
|
||||
* This structure manages a buffer whose contents are a properly formatted
|
||||
* BSON document. You may perform various transforms on the BSON documents.
|
||||
* Additionally, it can be iterated over using bson_iter_t.
|
||||
*
|
||||
* See bson_iter_init() for iterating the contents of a bson_t.
|
||||
*
|
||||
* When building a bson_t structure using the various append functions,
|
||||
* memory allocations may occur. That is performed using power of two
|
||||
* allocations and realloc().
|
||||
*
|
||||
* See http://bsonspec.org for the BSON document spec.
|
||||
*
|
||||
* This structure is meant to fit in two sequential 64-byte cachelines.
|
||||
*/
|
||||
#ifdef BSON_MEMCHECK
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct _bson_t {
|
||||
uint32_t flags; /* Internal flags for the bson_t. */
|
||||
uint32_t len; /* Length of BSON data. */
|
||||
char *canary; /* For valgrind check */
|
||||
uint8_t padding[120 - sizeof (char*)];
|
||||
} bson_t BSON_ALIGNED_END (128);
|
||||
#else
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct _bson_t {
|
||||
uint32_t flags; /* Internal flags for the bson_t. */
|
||||
uint32_t len; /* Length of BSON data. */
|
||||
uint8_t padding[120]; /* Padding for stack allocation. */
|
||||
} bson_t BSON_ALIGNED_END (128);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* BSON_INITIALIZER:
|
||||
*
|
||||
* This macro can be used to initialize a #bson_t structure on the stack
|
||||
* without calling bson_init().
|
||||
*
|
||||
* |[
|
||||
* bson_t b = BSON_INITIALIZER;
|
||||
* ]|
|
||||
*/
|
||||
#ifdef BSON_MEMCHECK
|
||||
#define BSON_INITIALIZER \
|
||||
{ \
|
||||
3, 5, \
|
||||
bson_malloc (1), \
|
||||
{ \
|
||||
5 \
|
||||
}, \
|
||||
}
|
||||
#else
|
||||
#define BSON_INITIALIZER \
|
||||
{ \
|
||||
3, 5, \
|
||||
{ \
|
||||
5 \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT2 (bson_t, sizeof (bson_t) == 128);
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_t:
|
||||
*
|
||||
* This structure contains the binary form of a BSON Object Id as specified
|
||||
* on http://bsonspec.org. If you would like the bson_oid_t in string form
|
||||
* see bson_oid_to_string() or bson_oid_to_string_r().
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t bytes[12];
|
||||
} bson_oid_t;
|
||||
|
||||
BSON_STATIC_ASSERT2 (oid_t, sizeof (bson_oid_t) == 12);
|
||||
|
||||
/**
|
||||
* bson_decimal128_t:
|
||||
*
|
||||
* @high The high-order bytes of the decimal128. This field contains sign,
|
||||
* combination bits, exponent, and part of the coefficient continuation.
|
||||
* @low The low-order bytes of the decimal128. This field contains the second
|
||||
* part of the coefficient continuation.
|
||||
*
|
||||
* This structure is a boxed type containing the value for the BSON decimal128
|
||||
* type. The structure stores the 128 bits such that they correspond to the
|
||||
* native format for the IEEE decimal128 type, if it is implemented.
|
||||
**/
|
||||
typedef struct {
|
||||
#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN
|
||||
uint64_t high;
|
||||
uint64_t low;
|
||||
#endif
|
||||
} bson_decimal128_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_validate_flags_t:
|
||||
*
|
||||
* This enumeration is used for validation of BSON documents. It allows
|
||||
* selective control on what you wish to validate.
|
||||
*
|
||||
* %BSON_VALIDATE_NONE: No additional validation occurs.
|
||||
* %BSON_VALIDATE_UTF8: Check that strings are valid UTF-8.
|
||||
* %BSON_VALIDATE_DOLLAR_KEYS: Check that keys do not start with $.
|
||||
* %BSON_VALIDATE_DOT_KEYS: Check that keys do not contain a period.
|
||||
* %BSON_VALIDATE_UTF8_ALLOW_NULL: Allow NUL bytes in UTF-8 text.
|
||||
* %BSON_VALIDATE_EMPTY_KEYS: Prohibit zero-length field names
|
||||
*/
|
||||
typedef enum {
|
||||
BSON_VALIDATE_NONE = 0,
|
||||
BSON_VALIDATE_UTF8 = (1 << 0),
|
||||
BSON_VALIDATE_DOLLAR_KEYS = (1 << 1),
|
||||
BSON_VALIDATE_DOT_KEYS = (1 << 2),
|
||||
BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3),
|
||||
BSON_VALIDATE_EMPTY_KEYS = (1 << 4),
|
||||
} bson_validate_flags_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_type_t:
|
||||
*
|
||||
* This enumeration contains all of the possible types within a BSON document.
|
||||
* Use bson_iter_type() to fetch the type of a field while iterating over it.
|
||||
*/
|
||||
typedef enum {
|
||||
BSON_TYPE_EOD = 0x00,
|
||||
BSON_TYPE_DOUBLE = 0x01,
|
||||
BSON_TYPE_UTF8 = 0x02,
|
||||
BSON_TYPE_DOCUMENT = 0x03,
|
||||
BSON_TYPE_ARRAY = 0x04,
|
||||
BSON_TYPE_BINARY = 0x05,
|
||||
BSON_TYPE_UNDEFINED = 0x06,
|
||||
BSON_TYPE_OID = 0x07,
|
||||
BSON_TYPE_BOOL = 0x08,
|
||||
BSON_TYPE_DATE_TIME = 0x09,
|
||||
BSON_TYPE_NULL = 0x0A,
|
||||
BSON_TYPE_REGEX = 0x0B,
|
||||
BSON_TYPE_DBPOINTER = 0x0C,
|
||||
BSON_TYPE_CODE = 0x0D,
|
||||
BSON_TYPE_SYMBOL = 0x0E,
|
||||
BSON_TYPE_CODEWSCOPE = 0x0F,
|
||||
BSON_TYPE_INT32 = 0x10,
|
||||
BSON_TYPE_TIMESTAMP = 0x11,
|
||||
BSON_TYPE_INT64 = 0x12,
|
||||
BSON_TYPE_DECIMAL128 = 0x13,
|
||||
BSON_TYPE_MAXKEY = 0x7F,
|
||||
BSON_TYPE_MINKEY = 0xFF,
|
||||
} bson_type_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_subtype_t:
|
||||
*
|
||||
* This enumeration contains the various subtypes that may be used in a binary
|
||||
* field. See http://bsonspec.org for more information.
|
||||
*/
|
||||
typedef enum {
|
||||
BSON_SUBTYPE_BINARY = 0x00,
|
||||
BSON_SUBTYPE_FUNCTION = 0x01,
|
||||
BSON_SUBTYPE_BINARY_DEPRECATED = 0x02,
|
||||
BSON_SUBTYPE_UUID_DEPRECATED = 0x03,
|
||||
BSON_SUBTYPE_UUID = 0x04,
|
||||
BSON_SUBTYPE_MD5 = 0x05,
|
||||
BSON_SUBTYPE_USER = 0x80,
|
||||
} bson_subtype_t;
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_value_t --
|
||||
*
|
||||
* A boxed type to contain various bson_type_t types.
|
||||
*
|
||||
* See also:
|
||||
* bson_value_copy()
|
||||
* bson_value_destroy()
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
BSON_ALIGNED_BEGIN (8)
|
||||
typedef struct _bson_value_t {
|
||||
bson_type_t value_type;
|
||||
int32_t padding;
|
||||
union {
|
||||
bson_oid_t v_oid;
|
||||
int64_t v_int64;
|
||||
int32_t v_int32;
|
||||
int8_t v_int8;
|
||||
double v_double;
|
||||
bool v_bool;
|
||||
int64_t v_datetime;
|
||||
struct {
|
||||
uint32_t timestamp;
|
||||
uint32_t increment;
|
||||
} v_timestamp;
|
||||
struct {
|
||||
char *str;
|
||||
uint32_t len;
|
||||
} v_utf8;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
} v_doc;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
bson_subtype_t subtype;
|
||||
} v_binary;
|
||||
struct {
|
||||
char *regex;
|
||||
char *options;
|
||||
} v_regex;
|
||||
struct {
|
||||
char *collection;
|
||||
uint32_t collection_len;
|
||||
bson_oid_t oid;
|
||||
} v_dbpointer;
|
||||
struct {
|
||||
char *code;
|
||||
uint32_t code_len;
|
||||
} v_code;
|
||||
struct {
|
||||
char *code;
|
||||
uint8_t *scope_data;
|
||||
uint32_t code_len;
|
||||
uint32_t scope_len;
|
||||
} v_codewscope;
|
||||
struct {
|
||||
char *symbol;
|
||||
uint32_t len;
|
||||
} v_symbol;
|
||||
bson_decimal128_t v_decimal128;
|
||||
} value;
|
||||
} bson_value_t BSON_ALIGNED_END (8);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_t:
|
||||
*
|
||||
* This structure manages iteration over a bson_t structure. It keeps track
|
||||
* of the location of the current key and value within the buffer. Using the
|
||||
* various functions to get the value of the iter will read from these
|
||||
* locations.
|
||||
*
|
||||
* This structure is safe to discard on the stack. No cleanup is necessary
|
||||
* after using it.
|
||||
*/
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct {
|
||||
const uint8_t *raw; /* The raw buffer being iterated. */
|
||||
uint32_t len; /* The length of raw. */
|
||||
uint32_t off; /* The offset within the buffer. */
|
||||
uint32_t type; /* The offset of the type byte. */
|
||||
uint32_t key; /* The offset of the key byte. */
|
||||
uint32_t d1; /* The offset of the first data byte. */
|
||||
uint32_t d2; /* The offset of the second data byte. */
|
||||
uint32_t d3; /* The offset of the third data byte. */
|
||||
uint32_t d4; /* The offset of the fourth data byte. */
|
||||
uint32_t next_off; /* The offset of the next field. */
|
||||
uint32_t err_off; /* The offset of the error. */
|
||||
bson_value_t value; /* Internal value for various state. */
|
||||
} bson_iter_t BSON_ALIGNED_END (128);
|
||||
|
||||
|
||||
/**
|
||||
* bson_reader_t:
|
||||
*
|
||||
* This structure is used to iterate over a sequence of BSON documents. It
|
||||
* allows for them to be iterated with the possibility of no additional
|
||||
* memory allocations under certain circumstances such as reading from an
|
||||
* incoming mongo packet.
|
||||
*/
|
||||
|
||||
BSON_ALIGNED_BEGIN (BSON_ALIGN_OF_PTR)
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
/*< private >*/
|
||||
} bson_reader_t BSON_ALIGNED_END (BSON_ALIGN_OF_PTR);
|
||||
|
||||
|
||||
/**
|
||||
* bson_visitor_t:
|
||||
*
|
||||
* This structure contains a series of pointers that can be executed for
|
||||
* each field of a BSON document based on the field type.
|
||||
*
|
||||
* For example, if an int32 field is found, visit_int32 will be called.
|
||||
*
|
||||
* When visiting each field using bson_iter_visit_all(), you may provide a
|
||||
* data pointer that will be provided with each callback. This might be useful
|
||||
* if you are marshaling to another language.
|
||||
*
|
||||
* You may pre-maturely stop the visitation of fields by returning true in your
|
||||
* visitor. Returning false will continue visitation to further fields.
|
||||
*/
|
||||
BSON_ALIGNED_BEGIN (8)
|
||||
typedef struct {
|
||||
/* run before / after descending into a document */
|
||||
bool (*visit_before) (const bson_iter_t *iter, const char *key, void *data);
|
||||
bool (*visit_after) (const bson_iter_t *iter, const char *key, void *data);
|
||||
/* corrupt BSON, or unsupported type and visit_unsupported_type not set */
|
||||
void (*visit_corrupt) (const bson_iter_t *iter, void *data);
|
||||
/* normal bson field callbacks */
|
||||
bool (*visit_double) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
double v_double,
|
||||
void *data);
|
||||
bool (*visit_utf8) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_utf8_len,
|
||||
const char *v_utf8,
|
||||
void *data);
|
||||
bool (*visit_document) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_t *v_document,
|
||||
void *data);
|
||||
bool (*visit_array) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_t *v_array,
|
||||
void *data);
|
||||
bool (*visit_binary) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
bson_subtype_t v_subtype,
|
||||
size_t v_binary_len,
|
||||
const uint8_t *v_binary,
|
||||
void *data);
|
||||
/* normal field with deprecated "Undefined" BSON type */
|
||||
bool (*visit_undefined) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
bool (*visit_oid) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_oid_t *v_oid,
|
||||
void *data);
|
||||
bool (*visit_bool) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
bool v_bool,
|
||||
void *data);
|
||||
bool (*visit_date_time) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
int64_t msec_since_epoch,
|
||||
void *data);
|
||||
bool (*visit_null) (const bson_iter_t *iter, const char *key, void *data);
|
||||
bool (*visit_regex) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const char *v_regex,
|
||||
const char *v_options,
|
||||
void *data);
|
||||
bool (*visit_dbpointer) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_collection_len,
|
||||
const char *v_collection,
|
||||
const bson_oid_t *v_oid,
|
||||
void *data);
|
||||
bool (*visit_code) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_code_len,
|
||||
const char *v_code,
|
||||
void *data);
|
||||
bool (*visit_symbol) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_symbol_len,
|
||||
const char *v_symbol,
|
||||
void *data);
|
||||
bool (*visit_codewscope) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_code_len,
|
||||
const char *v_code,
|
||||
const bson_t *v_scope,
|
||||
void *data);
|
||||
bool (*visit_int32) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
int32_t v_int32,
|
||||
void *data);
|
||||
bool (*visit_timestamp) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
uint32_t v_timestamp,
|
||||
uint32_t v_increment,
|
||||
void *data);
|
||||
bool (*visit_int64) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
int64_t v_int64,
|
||||
void *data);
|
||||
bool (*visit_maxkey) (const bson_iter_t *iter, const char *key, void *data);
|
||||
bool (*visit_minkey) (const bson_iter_t *iter, const char *key, void *data);
|
||||
/* if set, called instead of visit_corrupt when an apparently valid BSON
|
||||
* includes an unrecognized field type (reading future version of BSON) */
|
||||
void (*visit_unsupported_type) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
uint32_t type_code,
|
||||
void *data);
|
||||
bool (*visit_decimal128) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_decimal128_t *v_decimal128,
|
||||
void *data);
|
||||
|
||||
void *padding[7];
|
||||
} bson_visitor_t BSON_ALIGNED_END (8);
|
||||
|
||||
#define BSON_ERROR_BUFFER_SIZE 504
|
||||
|
||||
BSON_ALIGNED_BEGIN (8)
|
||||
typedef struct _bson_error_t {
|
||||
uint32_t domain;
|
||||
uint32_t code;
|
||||
char message[BSON_ERROR_BUFFER_SIZE];
|
||||
} bson_error_t BSON_ALIGNED_END (8);
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT2 (error_t, sizeof (bson_error_t) == 512);
|
||||
|
||||
|
||||
/**
|
||||
* bson_next_power_of_two:
|
||||
* @v: A 32-bit unsigned integer of required bytes.
|
||||
*
|
||||
* Determines the next larger power of two for the value of @v
|
||||
* in a constant number of operations.
|
||||
*
|
||||
* It is up to the caller to guarantee this will not overflow.
|
||||
*
|
||||
* Returns: The next power of 2 from @v.
|
||||
*/
|
||||
static BSON_INLINE size_t
|
||||
bson_next_power_of_two (size_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
#if BSON_WORD_SIZE == 64
|
||||
v |= v >> 32;
|
||||
#endif
|
||||
v++;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static BSON_INLINE bool
|
||||
bson_is_power_of_two (uint32_t v)
|
||||
{
|
||||
return ((v != 0) && ((v & (v - 1)) == 0));
|
||||
}
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_TYPES_H */
|
||||
46
include/libbson-1.0/bson/bson-utf8.h
Normal file
46
include/libbson-1.0/bson/bson-utf8.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_UTF8_H
|
||||
#define BSON_UTF8_H
|
||||
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
BSON_EXPORT (bool)
|
||||
bson_utf8_validate (const char *utf8, size_t utf8_len, bool allow_null);
|
||||
BSON_EXPORT (char *)
|
||||
bson_utf8_escape_for_json (const char *utf8, ssize_t utf8_len);
|
||||
BSON_EXPORT (bson_unichar_t)
|
||||
bson_utf8_get_char (const char *utf8);
|
||||
BSON_EXPORT (const char *)
|
||||
bson_utf8_next_char (const char *utf8);
|
||||
BSON_EXPORT (void)
|
||||
bson_utf8_from_unichar (bson_unichar_t unichar, char utf8[6], uint32_t *len);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_UTF8_H */
|
||||
40
include/libbson-1.0/bson/bson-value.h
Normal file
40
include/libbson-1.0/bson/bson-value.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_VALUE_H
|
||||
#define BSON_VALUE_H
|
||||
|
||||
|
||||
#include "bson/bson-macros.h"
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
BSON_EXPORT (void)
|
||||
bson_value_copy (const bson_value_t *src, bson_value_t *dst);
|
||||
BSON_EXPORT (void)
|
||||
bson_value_destroy (bson_value_t *value);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_VALUE_H */
|
||||
41
include/libbson-1.0/bson/bson-version-functions.h
Normal file
41
include/libbson-1.0/bson/bson-version-functions.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2015 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_VERSION_FUNCTIONS_H
|
||||
#define BSON_VERSION_FUNCTIONS_H
|
||||
|
||||
#include "bson/bson-types.h"
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
BSON_EXPORT (int)
|
||||
bson_get_major_version (void);
|
||||
BSON_EXPORT (int)
|
||||
bson_get_minor_version (void);
|
||||
BSON_EXPORT (int)
|
||||
bson_get_micro_version (void);
|
||||
BSON_EXPORT (const char *)
|
||||
bson_get_version (void);
|
||||
BSON_EXPORT (bool)
|
||||
bson_check_version (int required_major, int required_minor, int required_micro);
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
#endif /* BSON_VERSION_FUNCTIONS_H */
|
||||
101
include/libbson-1.0/bson/bson-version.h
Normal file
101
include/libbson-1.0/bson/bson-version.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
#error "Only <bson/bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_VERSION_H
|
||||
#define BSON_VERSION_H
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MAJOR_VERSION:
|
||||
*
|
||||
* BSON major version component (e.g. 1 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MAJOR_VERSION (1)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MINOR_VERSION:
|
||||
*
|
||||
* BSON minor version component (e.g. 2 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MINOR_VERSION (14)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MICRO_VERSION:
|
||||
*
|
||||
* BSON micro version component (e.g. 3 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MICRO_VERSION (0)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_PRERELEASE_VERSION:
|
||||
*
|
||||
* BSON prerelease version component (e.g. pre if %BSON_VERSION is 1.2.3-pre)
|
||||
*/
|
||||
#define BSON_PRERELEASE_VERSION ()
|
||||
|
||||
/**
|
||||
* BSON_VERSION:
|
||||
*
|
||||
* BSON version.
|
||||
*/
|
||||
#define BSON_VERSION (1.14.0)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_VERSION_S:
|
||||
*
|
||||
* BSON version, encoded as a string, useful for printing and
|
||||
* concatenation.
|
||||
*/
|
||||
#define BSON_VERSION_S "1.14.0"
|
||||
|
||||
|
||||
/**
|
||||
* BSON_VERSION_HEX:
|
||||
*
|
||||
* BSON version, encoded as an hexadecimal number, useful for
|
||||
* integer comparisons.
|
||||
*/
|
||||
#define BSON_VERSION_HEX (BSON_MAJOR_VERSION << 24 | \
|
||||
BSON_MINOR_VERSION << 16 | \
|
||||
BSON_MICRO_VERSION << 8)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_CHECK_VERSION:
|
||||
* @major: required major version
|
||||
* @minor: required minor version
|
||||
* @micro: required micro version
|
||||
*
|
||||
* Compile-time version checking. Evaluates to %TRUE if the version
|
||||
* of BSON is greater than the required one.
|
||||
*/
|
||||
#define BSON_CHECK_VERSION(major,minor,micro) \
|
||||
(BSON_MAJOR_VERSION > (major) || \
|
||||
(BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION > (minor)) || \
|
||||
(BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION == (minor) && \
|
||||
BSON_MICRO_VERSION >= (micro)))
|
||||
|
||||
#endif /* BSON_VERSION_H */
|
||||
65
include/libbson-1.0/bson/bson-writer.h
Normal file
65
include/libbson-1.0/bson/bson-writer.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson/bson-prelude.h"
|
||||
|
||||
|
||||
#ifndef BSON_WRITER_H
|
||||
#define BSON_WRITER_H
|
||||
|
||||
|
||||
#include "bson/bson.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
/**
|
||||
* bson_writer_t:
|
||||
*
|
||||
* The bson_writer_t structure is a helper for writing a series of BSON
|
||||
* documents to a single malloc() buffer. You can provide a realloc() style
|
||||
* function to grow the buffer as you go.
|
||||
*
|
||||
* This is useful if you want to build a series of BSON documents right into
|
||||
* the target buffer for an outgoing packet. The offset parameter allows you to
|
||||
* start at an offset of the target buffer.
|
||||
*/
|
||||
typedef struct _bson_writer_t bson_writer_t;
|
||||
|
||||
|
||||
BSON_EXPORT (bson_writer_t *)
|
||||
bson_writer_new (uint8_t **buf,
|
||||
size_t *buflen,
|
||||
size_t offset,
|
||||
bson_realloc_func realloc_func,
|
||||
void *realloc_func_ctx);
|
||||
BSON_EXPORT (void)
|
||||
bson_writer_destroy (bson_writer_t *writer);
|
||||
BSON_EXPORT (size_t)
|
||||
bson_writer_get_length (bson_writer_t *writer);
|
||||
BSON_EXPORT (bool)
|
||||
bson_writer_begin (bson_writer_t *writer, bson_t **bson);
|
||||
BSON_EXPORT (void)
|
||||
bson_writer_end (bson_writer_t *writer);
|
||||
BSON_EXPORT (void)
|
||||
bson_writer_rollback (bson_writer_t *writer);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_WRITER_H */
|
||||
1150
include/libbson-1.0/bson/bson.h
Normal file
1150
include/libbson-1.0/bson/bson.h
Normal file
File diff suppressed because it is too large
Load Diff
857
include/libmseed.h
Normal file
857
include/libmseed.h
Normal file
@@ -0,0 +1,857 @@
|
||||
/***************************************************************************
|
||||
* libmseed.h:
|
||||
*
|
||||
* Interface declarations for the Mini-SEED library (libmseed).
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License (GNU-LGPL) for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) 2022 Chad Trabant
|
||||
* IRIS Data Management Center
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef LIBMSEED_H
|
||||
#define LIBMSEED_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LIBMSEED_VERSION "2.19.8"
|
||||
#define LIBMSEED_RELEASE "2022.087"
|
||||
|
||||
/* C99 standard headers */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* This library uses structs that map to SEED header/blockette
|
||||
structures that are required to have a layout exactly as specified,
|
||||
i.e. no padding.
|
||||
|
||||
If "ATTRIBUTE_PACKED" is defined at compile time (e.g. -DATTRIBUTE_PACKED)
|
||||
the preprocessor will use the define below to add the "packed" attribute
|
||||
to effected structs. This attribute is supported by GCC and increasingly
|
||||
more compilers.
|
||||
*/
|
||||
#if defined(ATTRIBUTE_PACKED)
|
||||
#define LMP_PACKED __attribute__((packed))
|
||||
#else
|
||||
#define LMP_PACKED
|
||||
#endif
|
||||
|
||||
/* Set platform specific defines */
|
||||
#if defined(__linux__) || defined(__linux) || defined(__CYGWIN__)
|
||||
#define LMP_LINUX 1
|
||||
#define LMP_GLIBC2 1 /* Deprecated */
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#define LMP_BSD 1
|
||||
#elif defined(__sun__) || defined(__sun)
|
||||
#define LMP_SOLARIS 1
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
#define LMP_WIN 1
|
||||
#define LMP_WIN32 1 /* Deprecated */
|
||||
#endif
|
||||
|
||||
/* Set platform specific features */
|
||||
#if defined(LMP_WIN)
|
||||
#include <windows.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* For MSVC 2012 and earlier define standard int types, otherwise use inttypes.h */
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int int16_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
/* For MSVC define PRId64 and SCNd64 if needed */
|
||||
#if defined(_MSC_VER)
|
||||
#if !defined(PRId64)
|
||||
#define PRId64 "I64d"
|
||||
#endif
|
||||
#if !defined(SCNd64)
|
||||
#define SCNd64 "I64d"
|
||||
#endif
|
||||
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#define strtoull _strtoui64
|
||||
#define strdup _strdup
|
||||
#define fileno _fileno
|
||||
#endif
|
||||
|
||||
/* Extras needed for MinGW */
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#include <fcntl.h>
|
||||
|
||||
#define fstat _fstat
|
||||
#define stat _stat
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
extern int LM_SIZEOF_OFF_T; /* Size of off_t data type determined at build time */
|
||||
|
||||
#define MINRECLEN 128 /* Minimum Mini-SEED record length, 2^7 bytes */
|
||||
/* Note: the SEED specification minimum is 256 */
|
||||
#define MAXRECLEN 1048576 /* Maximum Mini-SEED record length, 2^20 bytes */
|
||||
|
||||
/* SEED data encoding types */
|
||||
#define DE_ASCII 0
|
||||
#define DE_INT16 1
|
||||
#define DE_INT32 3
|
||||
#define DE_FLOAT32 4
|
||||
#define DE_FLOAT64 5
|
||||
#define DE_STEIM1 10
|
||||
#define DE_STEIM2 11
|
||||
#define DE_GEOSCOPE24 12
|
||||
#define DE_GEOSCOPE163 13
|
||||
#define DE_GEOSCOPE164 14
|
||||
#define DE_CDSN 16
|
||||
#define DE_SRO 30
|
||||
#define DE_DWWSSN 32
|
||||
|
||||
/* Library return and error code values, error values should always be negative */
|
||||
#define MS_ENDOFFILE 1 /* End of file reached return value */
|
||||
#define MS_NOERROR 0 /* No error */
|
||||
#define MS_GENERROR -1 /* Generic unspecified error */
|
||||
#define MS_NOTSEED -2 /* Data not SEED */
|
||||
#define MS_WRONGLENGTH -3 /* Length of data read was not correct */
|
||||
#define MS_OUTOFRANGE -4 /* SEED record length out of range */
|
||||
#define MS_UNKNOWNFORMAT -5 /* Unknown data encoding format */
|
||||
#define MS_STBADCOMPFLAG -6 /* Steim, invalid compression flag(s) */
|
||||
|
||||
/* Define the high precision time tick interval as 1/modulus seconds */
|
||||
/* Default modulus of 1000000 defines tick interval as a microsecond */
|
||||
#define HPTMODULUS 1000000
|
||||
|
||||
/* Error code for routines that normally return a high precision time.
|
||||
* The time value corresponds to '1902/1/1 00:00:00.000000' with the
|
||||
* default HPTMODULUS */
|
||||
#define HPTERROR -2145916800000000LL
|
||||
|
||||
/* Macros to scale between Unix/POSIX epoch time & high precision time */
|
||||
#define MS_EPOCH2HPTIME(X) (X) * (hptime_t) HPTMODULUS
|
||||
#define MS_HPTIME2EPOCH(X) (X) / HPTMODULUS
|
||||
|
||||
/* Macro to test a character for data record indicators */
|
||||
#define MS_ISDATAINDICATOR(X) (X=='D' || X=='R' || X=='Q' || X=='M')
|
||||
|
||||
/* Macro to test default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 */
|
||||
#define MS_ISRATETOLERABLE(A,B) (ms_dabs (1.0 - (A / B)) < 0.0001)
|
||||
|
||||
/* Macro to test for sane year and day values, used primarily to
|
||||
* determine if byte order swapping is needed.
|
||||
*
|
||||
* Year : between 1900 and 2100
|
||||
* Day : between 1 and 366
|
||||
*
|
||||
* This test is non-unique (non-deterministic) for days 1, 256 and 257
|
||||
* in the year 2056 because the swapped values are also within range.
|
||||
*/
|
||||
#define MS_ISVALIDYEARDAY(Y,D) (Y >= 1900 && Y <= 2100 && D >= 1 && D <= 366)
|
||||
|
||||
/* Macro to test memory for a SEED data record signature by checking
|
||||
* SEED data record header values at known byte offsets to determine
|
||||
* if the memory contains a valid record.
|
||||
*
|
||||
* Offset = Value
|
||||
* [0-5] = Digits, spaces or NULL, SEED sequence number
|
||||
* 6 = Data record quality indicator
|
||||
* 7 = Space or NULL [not valid SEED]
|
||||
* 24 = Start hour (0-23)
|
||||
* 25 = Start minute (0-59)
|
||||
* 26 = Start second (0-60)
|
||||
*
|
||||
* Usage:
|
||||
* MS_ISVALIDHEADER ((char *)X) X buffer must contain at least 27 bytes
|
||||
*/
|
||||
#define MS_ISVALIDHEADER(X) ( \
|
||||
(isdigit ((int) *(X)) || *(X) == ' ' || !*(X) ) && \
|
||||
(isdigit ((int) *(X+1)) || *(X+1) == ' ' || !*(X+1) ) && \
|
||||
(isdigit ((int) *(X+2)) || *(X+2) == ' ' || !*(X+2) ) && \
|
||||
(isdigit ((int) *(X+3)) || *(X+3) == ' ' || !*(X+3) ) && \
|
||||
(isdigit ((int) *(X+4)) || *(X+4) == ' ' || !*(X+4) ) && \
|
||||
(isdigit ((int) *(X+5)) || *(X+5) == ' ' || !*(X+5) ) && \
|
||||
MS_ISDATAINDICATOR(*(X+6)) && \
|
||||
(*(X+7) == ' ' || *(X+7) == '\0') && \
|
||||
(int)(*(X+24)) >= 0 && (int)(*(X+24)) <= 23 && \
|
||||
(int)(*(X+25)) >= 0 && (int)(*(X+25)) <= 59 && \
|
||||
(int)(*(X+26)) >= 0 && (int)(*(X+26)) <= 60 )
|
||||
|
||||
/* Macro to test memory for a blank/noise SEED data record signature
|
||||
* by checking for a valid SEED sequence number and padding characters
|
||||
* to determine if the memory contains a valid blank/noise record.
|
||||
*
|
||||
* Offset = Value
|
||||
* [0-5] = Digits or NULL, SEED sequence number
|
||||
* [6-47] = Space character (ASCII 32), remainder of fixed header
|
||||
*
|
||||
* Usage:
|
||||
* MS_ISVALIDBLANK ((char *)X) X buffer must contain at least 27 bytes
|
||||
*/
|
||||
#define MS_ISVALIDBLANK(X) ( \
|
||||
(isdigit ((int) *(X)) || !*(X) ) && \
|
||||
(isdigit ((int) *(X+1)) || !*(X+1) ) && \
|
||||
(isdigit ((int) *(X+2)) || !*(X+2) ) && \
|
||||
(isdigit ((int) *(X+3)) || !*(X+3) ) && \
|
||||
(isdigit ((int) *(X+4)) || !*(X+4) ) && \
|
||||
(isdigit ((int) *(X+5)) || !*(X+5) ) && \
|
||||
(*(X+6) ==' ') && (*(X+7) ==' ') && (*(X+8) ==' ') && \
|
||||
(*(X+9) ==' ') && (*(X+10)==' ') && (*(X+11)==' ') && \
|
||||
(*(X+12)==' ') && (*(X+13)==' ') && (*(X+14)==' ') && \
|
||||
(*(X+15)==' ') && (*(X+16)==' ') && (*(X+17)==' ') && \
|
||||
(*(X+18)==' ') && (*(X+19)==' ') && (*(X+20)==' ') && \
|
||||
(*(X+21)==' ') && (*(X+22)==' ') && (*(X+23)==' ') && \
|
||||
(*(X+24)==' ') && (*(X+25)==' ') && (*(X+26)==' ') && \
|
||||
(*(X+27)==' ') && (*(X+28)==' ') && (*(X+29)==' ') && \
|
||||
(*(X+30)==' ') && (*(X+31)==' ') && (*(X+32)==' ') && \
|
||||
(*(X+33)==' ') && (*(X+34)==' ') && (*(X+35)==' ') && \
|
||||
(*(X+36)==' ') && (*(X+37)==' ') && (*(X+38)==' ') && \
|
||||
(*(X+39)==' ') && (*(X+40)==' ') && (*(X+41)==' ') && \
|
||||
(*(X+42)==' ') && (*(X+43)==' ') && (*(X+44)==' ') && \
|
||||
(*(X+45)==' ') && (*(X+46)==' ') && (*(X+47)==' ') )
|
||||
|
||||
/* A simple bitwise AND test to return 0 or 1 */
|
||||
#define bit(x,y) (x&y)?1:0
|
||||
|
||||
/* Require a large (>= 64-bit) integer type for hptime_t */
|
||||
typedef int64_t hptime_t;
|
||||
|
||||
/* A single byte flag type */
|
||||
typedef int8_t flag;
|
||||
|
||||
/* SEED binary time */
|
||||
typedef struct btime_s
|
||||
{
|
||||
uint16_t year;
|
||||
uint16_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t unused;
|
||||
uint16_t fract;
|
||||
} LMP_PACKED
|
||||
BTime;
|
||||
|
||||
/* Fixed section data of header */
|
||||
struct fsdh_s
|
||||
{
|
||||
char sequence_number[6];
|
||||
char dataquality;
|
||||
char reserved;
|
||||
char station[5];
|
||||
char location[2];
|
||||
char channel[3];
|
||||
char network[2];
|
||||
BTime start_time;
|
||||
uint16_t numsamples;
|
||||
int16_t samprate_fact;
|
||||
int16_t samprate_mult;
|
||||
uint8_t act_flags;
|
||||
uint8_t io_flags;
|
||||
uint8_t dq_flags;
|
||||
uint8_t numblockettes;
|
||||
int32_t time_correct;
|
||||
uint16_t data_offset;
|
||||
uint16_t blockette_offset;
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 100, Sample Rate (without header) */
|
||||
struct blkt_100_s
|
||||
{
|
||||
float samprate;
|
||||
int8_t flags;
|
||||
uint8_t reserved[3];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 200, Generic Event Detection (without header) */
|
||||
struct blkt_200_s
|
||||
{
|
||||
float amplitude;
|
||||
float period;
|
||||
float background_estimate;
|
||||
uint8_t flags;
|
||||
uint8_t reserved;
|
||||
BTime time;
|
||||
char detector[24];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 201, Murdock Event Detection (without header) */
|
||||
struct blkt_201_s
|
||||
{
|
||||
float amplitude;
|
||||
float period;
|
||||
float background_estimate;
|
||||
uint8_t flags;
|
||||
uint8_t reserved;
|
||||
BTime time;
|
||||
uint8_t snr_values[6];
|
||||
uint8_t loopback;
|
||||
uint8_t pick_algorithm;
|
||||
char detector[24];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 300, Step Calibration (without header) */
|
||||
struct blkt_300_s
|
||||
{
|
||||
BTime time;
|
||||
uint8_t numcalibrations;
|
||||
uint8_t flags;
|
||||
uint32_t step_duration;
|
||||
uint32_t interval_duration;
|
||||
float amplitude;
|
||||
char input_channel[3];
|
||||
uint8_t reserved;
|
||||
uint32_t reference_amplitude;
|
||||
char coupling[12];
|
||||
char rolloff[12];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 310, Sine Calibration (without header) */
|
||||
struct blkt_310_s
|
||||
{
|
||||
BTime time;
|
||||
uint8_t reserved1;
|
||||
uint8_t flags;
|
||||
uint32_t duration;
|
||||
float period;
|
||||
float amplitude;
|
||||
char input_channel[3];
|
||||
uint8_t reserved2;
|
||||
uint32_t reference_amplitude;
|
||||
char coupling[12];
|
||||
char rolloff[12];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 320, Pseudo-random Calibration (without header) */
|
||||
struct blkt_320_s
|
||||
{
|
||||
BTime time;
|
||||
uint8_t reserved1;
|
||||
uint8_t flags;
|
||||
uint32_t duration;
|
||||
float ptp_amplitude;
|
||||
char input_channel[3];
|
||||
uint8_t reserved2;
|
||||
uint32_t reference_amplitude;
|
||||
char coupling[12];
|
||||
char rolloff[12];
|
||||
char noise_type[8];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 390, Generic Calibration (without header) */
|
||||
struct blkt_390_s
|
||||
{
|
||||
BTime time;
|
||||
uint8_t reserved1;
|
||||
uint8_t flags;
|
||||
uint32_t duration;
|
||||
float amplitude;
|
||||
char input_channel[3];
|
||||
uint8_t reserved2;
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 395, Calibration Abort (without header) */
|
||||
struct blkt_395_s
|
||||
{
|
||||
BTime time;
|
||||
uint8_t reserved[2];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 400, Beam (without header) */
|
||||
struct blkt_400_s
|
||||
{
|
||||
float azimuth;
|
||||
float slowness;
|
||||
uint16_t configuration;
|
||||
uint8_t reserved[2];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 405, Beam Delay (without header) */
|
||||
struct blkt_405_s
|
||||
{
|
||||
uint16_t delay_values[1];
|
||||
};
|
||||
|
||||
/* Blockette 500, Timing (without header) */
|
||||
struct blkt_500_s
|
||||
{
|
||||
float vco_correction;
|
||||
BTime time;
|
||||
int8_t usec;
|
||||
uint8_t reception_qual;
|
||||
uint32_t exception_count;
|
||||
char exception_type[16];
|
||||
char clock_model[32];
|
||||
char clock_status[128];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 1000, Data Only SEED (without header) */
|
||||
struct blkt_1000_s
|
||||
{
|
||||
uint8_t encoding;
|
||||
uint8_t byteorder;
|
||||
uint8_t reclen;
|
||||
uint8_t reserved;
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 1001, Data Extension (without header) */
|
||||
struct blkt_1001_s
|
||||
{
|
||||
uint8_t timing_qual;
|
||||
int8_t usec;
|
||||
uint8_t reserved;
|
||||
uint8_t framecnt;
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette 2000, Opaque Data (without header) */
|
||||
struct blkt_2000_s
|
||||
{
|
||||
uint16_t length;
|
||||
uint16_t data_offset;
|
||||
uint32_t recnum;
|
||||
uint8_t byteorder;
|
||||
uint8_t flags;
|
||||
uint8_t numheaders;
|
||||
char payload[1];
|
||||
} LMP_PACKED;
|
||||
|
||||
/* Blockette chain link, generic linkable blockette index */
|
||||
typedef struct blkt_link_s
|
||||
{
|
||||
uint16_t blktoffset; /* Offset to this blockette */
|
||||
uint16_t blkt_type; /* Blockette type */
|
||||
uint16_t next_blkt; /* Offset to next blockette */
|
||||
void *blktdata; /* Blockette data */
|
||||
uint16_t blktdatalen; /* Length of blockette data in bytes */
|
||||
struct blkt_link_s *next;
|
||||
}
|
||||
BlktLink;
|
||||
|
||||
typedef struct StreamState_s
|
||||
{
|
||||
int64_t packedrecords; /* Count of packed records */
|
||||
int64_t packedsamples; /* Count of packed samples */
|
||||
int32_t lastintsample; /* Value of last integer sample packed */
|
||||
flag comphistory; /* Control use of lastintsample for compression history */
|
||||
}
|
||||
StreamState;
|
||||
|
||||
typedef struct MSRecord_s {
|
||||
char *record; /* Mini-SEED record */
|
||||
int32_t reclen; /* Length of Mini-SEED record in bytes */
|
||||
|
||||
/* Pointers to SEED data record structures */
|
||||
struct fsdh_s *fsdh; /* Fixed Section of Data Header */
|
||||
BlktLink *blkts; /* Root of blockette chain */
|
||||
struct blkt_100_s *Blkt100; /* Blockette 100, if present */
|
||||
struct blkt_1000_s *Blkt1000; /* Blockette 1000, if present */
|
||||
struct blkt_1001_s *Blkt1001; /* Blockette 1001, if present */
|
||||
|
||||
/* Common header fields in accessible form */
|
||||
int32_t sequence_number; /* SEED record sequence number */
|
||||
char network[11]; /* Network designation, NULL terminated */
|
||||
char station[11]; /* Station designation, NULL terminated */
|
||||
char location[11]; /* Location designation, NULL terminated */
|
||||
char channel[11]; /* Channel designation, NULL terminated */
|
||||
char dataquality; /* Data quality indicator */
|
||||
hptime_t starttime; /* Record start time, corrected (first sample) */
|
||||
double samprate; /* Nominal sample rate (Hz) */
|
||||
int64_t samplecnt; /* Number of samples in record */
|
||||
int8_t encoding; /* Data encoding format */
|
||||
int8_t byteorder; /* Original/Final byte order of record */
|
||||
|
||||
/* Data sample fields */
|
||||
void *datasamples; /* Data samples, 'numsamples' of type 'sampletype'*/
|
||||
int64_t numsamples; /* Number of data samples in datasamples */
|
||||
char sampletype; /* Sample type code: a, i, f, d */
|
||||
|
||||
/* Stream oriented state information */
|
||||
StreamState *ststate; /* Stream processing state information */
|
||||
}
|
||||
MSRecord;
|
||||
|
||||
/* Container for a continuous trace, linkable */
|
||||
typedef struct MSTrace_s {
|
||||
char network[11]; /* Network designation, NULL terminated */
|
||||
char station[11]; /* Station designation, NULL terminated */
|
||||
char location[11]; /* Location designation, NULL terminated */
|
||||
char channel[11]; /* Channel designation, NULL terminated */
|
||||
char dataquality; /* Data quality indicator */
|
||||
char type; /* MSTrace type code */
|
||||
hptime_t starttime; /* Time of first sample */
|
||||
hptime_t endtime; /* Time of last sample */
|
||||
double samprate; /* Nominal sample rate (Hz) */
|
||||
int64_t samplecnt; /* Number of samples in trace coverage */
|
||||
void *datasamples; /* Data samples, 'numsamples' of type 'sampletype' */
|
||||
int64_t numsamples; /* Number of data samples in datasamples */
|
||||
char sampletype; /* Sample type code: a, i, f, d */
|
||||
void *prvtptr; /* Private pointer for general use, unused by libmseed */
|
||||
StreamState *ststate; /* Stream processing state information */
|
||||
struct MSTrace_s *next; /* Pointer to next trace */
|
||||
}
|
||||
MSTrace;
|
||||
|
||||
/* Container for a group (chain) of traces */
|
||||
typedef struct MSTraceGroup_s {
|
||||
int32_t numtraces; /* Number of MSTraces in the trace chain */
|
||||
struct MSTrace_s *traces; /* Root of the trace chain */
|
||||
}
|
||||
MSTraceGroup;
|
||||
|
||||
/* Container for a continuous trace segment, linkable */
|
||||
typedef struct MSTraceSeg_s {
|
||||
hptime_t starttime; /* Time of first sample */
|
||||
hptime_t endtime; /* Time of last sample */
|
||||
double samprate; /* Nominal sample rate (Hz) */
|
||||
int64_t samplecnt; /* Number of samples in trace coverage */
|
||||
void *datasamples; /* Data samples, 'numsamples' of type 'sampletype'*/
|
||||
int64_t numsamples; /* Number of data samples in datasamples */
|
||||
char sampletype; /* Sample type code: a, i, f, d */
|
||||
void *prvtptr; /* Private pointer for general use, unused by libmseed */
|
||||
struct MSTraceSeg_s *prev; /* Pointer to previous segment */
|
||||
struct MSTraceSeg_s *next; /* Pointer to next segment */
|
||||
}
|
||||
MSTraceSeg;
|
||||
|
||||
/* Container for a trace ID, linkable */
|
||||
typedef struct MSTraceID_s {
|
||||
char network[11]; /* Network designation, NULL terminated */
|
||||
char station[11]; /* Station designation, NULL terminated */
|
||||
char location[11]; /* Location designation, NULL terminated */
|
||||
char channel[11]; /* Channel designation, NULL terminated */
|
||||
char dataquality; /* Data quality indicator */
|
||||
char srcname[45]; /* Source name (Net_Sta_Loc_Chan_Qual), NULL terminated */
|
||||
char type; /* Trace type code */
|
||||
hptime_t earliest; /* Time of earliest sample */
|
||||
hptime_t latest; /* Time of latest sample */
|
||||
void *prvtptr; /* Private pointer for general use, unused by libmseed */
|
||||
int32_t numsegments; /* Number of segments for this ID */
|
||||
struct MSTraceSeg_s *first; /* Pointer to first of list of segments */
|
||||
struct MSTraceSeg_s *last; /* Pointer to last of list of segments */
|
||||
struct MSTraceID_s *next; /* Pointer to next trace */
|
||||
}
|
||||
MSTraceID;
|
||||
|
||||
/* Container for a continuous trace segment, linkable */
|
||||
typedef struct MSTraceList_s {
|
||||
int32_t numtraces; /* Number of traces in list */
|
||||
struct MSTraceID_s *traces; /* Pointer to list of traces */
|
||||
struct MSTraceID_s *last; /* Pointer to last used trace in list */
|
||||
}
|
||||
MSTraceList;
|
||||
|
||||
/* Data selection structure time window definition containers */
|
||||
typedef struct SelectTime_s {
|
||||
hptime_t starttime; /* Earliest data for matching channels */
|
||||
hptime_t endtime; /* Latest data for matching channels */
|
||||
struct SelectTime_s *next;
|
||||
} SelectTime;
|
||||
|
||||
/* Data selection structure definition containers */
|
||||
typedef struct Selections_s {
|
||||
char srcname[100]; /* Matching (globbing) source name: Net_Sta_Loc_Chan_Qual */
|
||||
struct SelectTime_s *timewindows;
|
||||
struct Selections_s *next;
|
||||
} Selections;
|
||||
|
||||
|
||||
/* Global variables (defined in pack.c) and macros to set/force
|
||||
* pack byte orders */
|
||||
extern flag packheaderbyteorder;
|
||||
extern flag packdatabyteorder;
|
||||
#define MS_PACKHEADERBYTEORDER(X) do { packheaderbyteorder = (X); } while(0)
|
||||
#define MS_PACKDATABYTEORDER(X) do { packdatabyteorder = (X); } while(0)
|
||||
|
||||
/* Global variables (defined in unpack.c) and macros to set/force
|
||||
* unpack byte orders */
|
||||
extern flag unpackheaderbyteorder;
|
||||
extern flag unpackdatabyteorder;
|
||||
#define MS_UNPACKHEADERBYTEORDER(X) do { unpackheaderbyteorder = (X); } while(0)
|
||||
#define MS_UNPACKDATABYTEORDER(X) do { unpackdatabyteorder = (X); } while(0)
|
||||
|
||||
/* Global variables (defined in unpack.c) and macros to set/force
|
||||
* encoding and fallback encoding */
|
||||
extern int unpackencodingformat;
|
||||
extern int unpackencodingfallback;
|
||||
#define MS_UNPACKENCODINGFORMAT(X) do { unpackencodingformat = (X); } while(0)
|
||||
#define MS_UNPACKENCODINGFALLBACK(X) do { unpackencodingfallback = (X); } while(0)
|
||||
|
||||
/* Mini-SEED record related functions */
|
||||
extern int msr_parse (char *record, int recbuflen, MSRecord **ppmsr, int reclen,
|
||||
flag dataflag, flag verbose);
|
||||
|
||||
extern int msr_parse_selection ( char *recbuf, int recbuflen, int64_t *offset,
|
||||
MSRecord **ppmsr, int reclen,
|
||||
Selections *selections, flag dataflag, flag verbose );
|
||||
|
||||
extern int msr_unpack (char *record, int reclen, MSRecord **ppmsr,
|
||||
flag dataflag, flag verbose);
|
||||
|
||||
extern int msr_pack (MSRecord *msr, void (*record_handler) (char *, int, void *),
|
||||
void *handlerdata, int64_t *packedsamples, flag flush, flag verbose );
|
||||
|
||||
extern int msr_pack_header (MSRecord *msr, flag normalize, flag verbose);
|
||||
|
||||
extern int msr_unpack_data (MSRecord *msr, int swapflag, flag verbose);
|
||||
|
||||
extern MSRecord* msr_init (MSRecord *msr);
|
||||
extern void msr_free (MSRecord **ppmsr);
|
||||
extern void msr_free_blktchain (MSRecord *msr);
|
||||
extern BlktLink* msr_addblockette (MSRecord *msr, char *blktdata, int length,
|
||||
int blkttype, int chainpos);
|
||||
extern int msr_normalize_header (MSRecord *msr, flag verbose);
|
||||
extern MSRecord* msr_duplicate (MSRecord *msr, flag datadup);
|
||||
extern double msr_samprate (MSRecord *msr);
|
||||
extern double msr_nomsamprate (MSRecord *msr);
|
||||
extern hptime_t msr_starttime (MSRecord *msr);
|
||||
extern hptime_t msr_starttime_uc (MSRecord *msr);
|
||||
extern hptime_t msr_endtime (MSRecord *msr);
|
||||
extern char* msr_srcname (MSRecord *msr, char *srcname, flag quality);
|
||||
extern void msr_print (MSRecord *msr, flag details);
|
||||
extern double msr_host_latency (MSRecord *msr);
|
||||
|
||||
extern int ms_detect (const char *record, int recbuflen);
|
||||
extern int ms_parse_raw (char *record, int maxreclen, flag details, flag swapflag);
|
||||
|
||||
|
||||
/* MSTrace related functions */
|
||||
extern MSTrace* mst_init (MSTrace *mst);
|
||||
extern void mst_free (MSTrace **ppmst);
|
||||
extern MSTraceGroup* mst_initgroup (MSTraceGroup *mstg);
|
||||
extern void mst_freegroup (MSTraceGroup **ppmstg);
|
||||
extern MSTrace* mst_findmatch (MSTrace *startmst, char dataquality,
|
||||
char *network, char *station, char *location, char *channel);
|
||||
extern MSTrace* mst_findadjacent (MSTraceGroup *mstg, flag *whence, char dataquality,
|
||||
char *network, char *station, char *location, char *channel,
|
||||
double samprate, double sampratetol,
|
||||
hptime_t starttime, hptime_t endtime, double timetol);
|
||||
extern int mst_addmsr (MSTrace *mst, MSRecord *msr, flag whence);
|
||||
extern int mst_addspan (MSTrace *mst, hptime_t starttime, hptime_t endtime,
|
||||
void *datasamples, int64_t numsamples,
|
||||
char sampletype, flag whence);
|
||||
extern MSTrace* mst_addmsrtogroup (MSTraceGroup *mstg, MSRecord *msr, flag dataquality,
|
||||
double timetol, double sampratetol);
|
||||
extern MSTrace* mst_addtracetogroup (MSTraceGroup *mstg, MSTrace *mst);
|
||||
extern int mst_groupheal (MSTraceGroup *mstg, double timetol, double sampratetol);
|
||||
extern int mst_groupsort (MSTraceGroup *mstg, flag quality);
|
||||
extern int mst_convertsamples (MSTrace *mst, char type, flag truncate);
|
||||
extern char * mst_srcname (MSTrace *mst, char *srcname, flag quality);
|
||||
extern void mst_printtracelist (MSTraceGroup *mstg, flag timeformat,
|
||||
flag details, flag gaps);
|
||||
extern void mst_printsynclist ( MSTraceGroup *mstg, char *dccid, flag subsecond );
|
||||
extern void mst_printgaplist (MSTraceGroup *mstg, flag timeformat,
|
||||
double *mingap, double *maxgap);
|
||||
extern int mst_pack (MSTrace *mst, void (*record_handler) (char *, int, void *),
|
||||
void *handlerdata, int reclen, flag encoding, flag byteorder,
|
||||
int64_t *packedsamples, flag flush, flag verbose,
|
||||
MSRecord *mstemplate);
|
||||
extern int mst_packgroup (MSTraceGroup *mstg, void (*record_handler) (char *, int, void *),
|
||||
void *handlerdata, int reclen, flag encoding, flag byteorder,
|
||||
int64_t *packedsamples, flag flush, flag verbose,
|
||||
MSRecord *mstemplate);
|
||||
|
||||
/* MSTraceList related functions */
|
||||
extern MSTraceList * mstl_init ( MSTraceList *mstl );
|
||||
extern void mstl_free ( MSTraceList **ppmstl, flag freeprvtptr );
|
||||
extern MSTraceSeg * mstl_addmsr ( MSTraceList *mstl, MSRecord *msr, flag dataquality,
|
||||
flag autoheal, double timetol, double sampratetol );
|
||||
extern int mstl_convertsamples ( MSTraceSeg *seg, char type, flag truncate );
|
||||
extern void mstl_printtracelist ( MSTraceList *mstl, flag timeformat,
|
||||
flag details, flag gaps );
|
||||
extern void mstl_printsynclist ( MSTraceList *mstl, char *dccid, flag subsecond );
|
||||
extern void mstl_printgaplist (MSTraceList *mstl, flag timeformat,
|
||||
double *mingap, double *maxgap);
|
||||
|
||||
/* Reading Mini-SEED records from files */
|
||||
typedef struct MSFileParam_s
|
||||
{
|
||||
FILE *fp;
|
||||
char filename[512];
|
||||
char *rawrec;
|
||||
int readlen;
|
||||
int readoffset;
|
||||
int packtype;
|
||||
off_t packhdroffset;
|
||||
off_t filepos;
|
||||
off_t filesize;
|
||||
int recordcount;
|
||||
} MSFileParam;
|
||||
|
||||
extern int ms_readmsr (MSRecord **ppmsr, const char *msfile, int reclen, off_t *fpos, int *last,
|
||||
flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readmsr_r (MSFileParam **ppmsfp, MSRecord **ppmsr, const char *msfile, int reclen,
|
||||
off_t *fpos, int *last, flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readmsr_main (MSFileParam **ppmsfp, MSRecord **ppmsr, const char *msfile, int reclen,
|
||||
off_t *fpos, int *last, flag skipnotdata, flag dataflag, Selections *selections, flag verbose);
|
||||
extern int ms_readtraces (MSTraceGroup **ppmstg, const char *msfile, int reclen, double timetol, double sampratetol,
|
||||
flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readtraces_timewin (MSTraceGroup **ppmstg, const char *msfile, int reclen, double timetol, double sampratetol,
|
||||
hptime_t starttime, hptime_t endtime, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readtraces_selection (MSTraceGroup **ppmstg, const char *msfile, int reclen, double timetol, double sampratetol,
|
||||
Selections *selections, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readtracelist (MSTraceList **ppmstl, const char *msfile, int reclen, double timetol, double sampratetol,
|
||||
flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readtracelist_timewin (MSTraceList **ppmstl, const char *msfile, int reclen, double timetol, double sampratetol,
|
||||
hptime_t starttime, hptime_t endtime, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
|
||||
extern int ms_readtracelist_selection (MSTraceList **ppmstl, const char *msfile, int reclen, double timetol, double sampratetol,
|
||||
Selections *selections, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
|
||||
|
||||
extern int msr_writemseed ( MSRecord *msr, const char *msfile, flag overwrite, int reclen,
|
||||
flag encoding, flag byteorder, flag verbose );
|
||||
extern int mst_writemseed ( MSTrace *mst, const char *msfile, flag overwrite, int reclen,
|
||||
flag encoding, flag byteorder, flag verbose );
|
||||
extern int mst_writemseedgroup ( MSTraceGroup *mstg, const char *msfile, flag overwrite,
|
||||
int reclen, flag encoding, flag byteorder, flag verbose );
|
||||
|
||||
/* General use functions */
|
||||
extern char* ms_recsrcname (char *record, char *srcname, flag quality);
|
||||
extern int ms_splitsrcname (char *srcname, char *net, char *sta, char *loc, char *chan, char *qual);
|
||||
extern int ms_strncpclean (char *dest, const char *source, int length);
|
||||
extern int ms_strncpcleantail (char *dest, const char *source, int length);
|
||||
extern int ms_strncpopen (char *dest, const char *source, int length);
|
||||
extern int ms_doy2md (int year, int jday, int *month, int *mday);
|
||||
extern int ms_md2doy (int year, int month, int mday, int *jday);
|
||||
extern hptime_t ms_btime2hptime (BTime *btime);
|
||||
extern char* ms_btime2isotimestr (BTime *btime, char *isotimestr);
|
||||
extern char* ms_btime2mdtimestr (BTime *btime, char *mdtimestr);
|
||||
extern char* ms_btime2seedtimestr (BTime *btime, char *seedtimestr);
|
||||
extern int ms_hptime2tomsusecoffset (hptime_t hptime, hptime_t *toms, int8_t *usecoffset);
|
||||
extern int ms_hptime2btime (hptime_t hptime, BTime *btime);
|
||||
extern char* ms_hptime2isotimestr (hptime_t hptime, char *isotimestr, flag subsecond);
|
||||
extern char* ms_hptime2mdtimestr (hptime_t hptime, char *mdtimestr, flag subsecond);
|
||||
extern char* ms_hptime2seedtimestr (hptime_t hptime, char *seedtimestr, flag subsecond);
|
||||
extern hptime_t ms_time2hptime (int year, int day, int hour, int min, int sec, int usec);
|
||||
extern hptime_t ms_seedtimestr2hptime (char *seedtimestr);
|
||||
extern hptime_t ms_timestr2hptime (char *timestr);
|
||||
extern double ms_nomsamprate (int factor, int multiplier);
|
||||
extern int ms_genfactmult (double samprate, int16_t *factor, int16_t *multiplier);
|
||||
extern int ms_ratapprox (double real, int *num, int *den, int maxval, double precision);
|
||||
extern int ms_bigendianhost (void);
|
||||
extern double ms_dabs (double val);
|
||||
extern double ms_rsqrt64 (double val);
|
||||
|
||||
|
||||
/* Lookup functions */
|
||||
extern uint8_t ms_samplesize (const char sampletype);
|
||||
extern char* ms_encodingstr (const char encoding);
|
||||
extern char* ms_blktdesc (uint16_t blkttype);
|
||||
extern uint16_t ms_blktlen (uint16_t blkttype, const char *blktdata, flag swapflag);
|
||||
extern char * ms_errorstr (int errorcode);
|
||||
|
||||
/* Logging facility */
|
||||
#define MAX_LOG_MSG_LENGTH 200 /* Maximum length of log messages */
|
||||
|
||||
/* Logging parameters */
|
||||
typedef struct MSLogParam_s
|
||||
{
|
||||
void (*log_print)(char*);
|
||||
const char *logprefix;
|
||||
void (*diag_print)(char*);
|
||||
const char *errprefix;
|
||||
} MSLogParam;
|
||||
|
||||
extern int ms_log (int level, ...);
|
||||
extern int ms_log_l (MSLogParam *logp, int level, ...);
|
||||
extern void ms_loginit (void (*log_print)(char*), const char *logprefix,
|
||||
void (*diag_print)(char*), const char *errprefix);
|
||||
extern MSLogParam *ms_loginit_l (MSLogParam *logp,
|
||||
void (*log_print)(char*), const char *logprefix,
|
||||
void (*diag_print)(char*), const char *errprefix);
|
||||
|
||||
/* Selection functions */
|
||||
extern Selections *ms_matchselect (Selections *selections, char *srcname,
|
||||
hptime_t starttime, hptime_t endtime, SelectTime **ppselecttime);
|
||||
extern Selections *msr_matchselect (Selections *selections, MSRecord *msr, SelectTime **ppselecttime);
|
||||
extern int ms_addselect (Selections **ppselections, char *srcname,
|
||||
hptime_t starttime, hptime_t endtime);
|
||||
extern int ms_addselect_comp (Selections **ppselections, char *net, char* sta, char *loc,
|
||||
char *chan, char *qual, hptime_t starttime, hptime_t endtime);
|
||||
extern int ms_readselectionsfile (Selections **ppselections, char *filename);
|
||||
extern void ms_freeselections (Selections *selections);
|
||||
extern void ms_printselections (Selections *selections);
|
||||
|
||||
/* Leap second declarations, implementation in gentutils.c */
|
||||
typedef struct LeapSecond_s
|
||||
{
|
||||
hptime_t leapsecond;
|
||||
int32_t TAIdelta;
|
||||
struct LeapSecond_s *next;
|
||||
} LeapSecond;
|
||||
|
||||
extern LeapSecond *leapsecondlist;
|
||||
extern int ms_readleapseconds (char *envvarname);
|
||||
extern int ms_readleapsecondfile (char *filename);
|
||||
|
||||
/* Generic byte swapping routines */
|
||||
extern void ms_gswap2 ( void *data2 );
|
||||
extern void ms_gswap3 ( void *data3 );
|
||||
extern void ms_gswap4 ( void *data4 );
|
||||
extern void ms_gswap8 ( void *data8 );
|
||||
|
||||
/* Generic byte swapping routines for memory aligned quantities; names exist
|
||||
* for backwards compatibility, but are the same as the generic routines. */
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) || defined (__clang__)
|
||||
__attribute__ ((deprecated("Use ms_gswap2 instead.")))
|
||||
extern void ms_gswap2a ( void *data2 );
|
||||
__attribute__ ((deprecated("Use ms_gswap4 instead.")))
|
||||
extern void ms_gswap4a ( void *data4 );
|
||||
__attribute__ ((deprecated("Use ms_gswap8 instead.")))
|
||||
extern void ms_gswap8a ( void *data8 );
|
||||
#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
|
||||
__declspec(deprecated("Use ms_gswap2 instead."))
|
||||
extern void ms_gswap2a ( void *data2 );
|
||||
__declspec(deprecated("Use ms_gswap4 instead."))
|
||||
extern void ms_gswap4a ( void *data4 );
|
||||
__declspec(deprecated("Use ms_gswap8 instead."))
|
||||
extern void ms_gswap8a ( void *data8 );
|
||||
#else
|
||||
extern void ms_gswap2a ( void *data2 );
|
||||
extern void ms_gswap4a ( void *data4 );
|
||||
extern void ms_gswap8a ( void *data8 );
|
||||
#endif
|
||||
|
||||
/* Byte swap macro for the BTime struct */
|
||||
#define MS_SWAPBTIME(x) \
|
||||
do { \
|
||||
ms_gswap2 (x.year); \
|
||||
ms_gswap2 (x.day); \
|
||||
ms_gswap2 (x.fract); \
|
||||
} while (0)
|
||||
|
||||
/* Platform portable functions */
|
||||
extern off_t lmp_ftello (FILE *stream);
|
||||
extern int lmp_fseeko (FILE *stream, off_t offset, int whence);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBMSEED_H */
|
||||
271
include/rapidjson/allocators.h
Normal file
271
include/rapidjson/allocators.h
Normal file
@@ -0,0 +1,271 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) {
|
||||
if (size) // behavior of malloc(0) is implementation defined.
|
||||
return std::malloc(size);
|
||||
else
|
||||
return NULL; // standardize to returning NULL.
|
||||
}
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
(void)originalSize;
|
||||
if (newSize == 0) {
|
||||
std::free(originalPtr);
|
||||
return NULL;
|
||||
}
|
||||
return std::realloc(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { std::free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
|
||||
return NULL;
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
originalSize = RAPIDJSON_ALIGN(originalSize);
|
||||
newSize = RAPIDJSON_ALIGN(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
if (void* newBuffer = Malloc(newSize)) {
|
||||
if (originalSize)
|
||||
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||
return newBuffer;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
\return true if success.
|
||||
*/
|
||||
bool AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
2575
include/rapidjson/document.h
Normal file
2575
include/rapidjson/document.h
Normal file
File diff suppressed because it is too large
Load Diff
299
include/rapidjson/encodedstream.h
Normal file
299
include/rapidjson/encodedstream.h
Normal file
@@ -0,0 +1,299 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "memorystream.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Input byte stream wrapper with a statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||
*/
|
||||
template <typename Encoding, typename InputByteStream>
|
||||
class EncodedInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||
current_ = Encoding::TakeBOM(is_);
|
||||
}
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
|
||||
InputByteStream& is_;
|
||||
Ch current_;
|
||||
};
|
||||
|
||||
//! Specialized for UTF8 MemoryStream.
|
||||
template <>
|
||||
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||
public:
|
||||
typedef UTF8<>::Ch Ch;
|
||||
|
||||
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||
}
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) {}
|
||||
void Flush() {}
|
||||
Ch* PutBegin() { return 0; }
|
||||
size_t PutEnd(Ch*) { return 0; }
|
||||
|
||||
MemoryStream& is_;
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||
if (putBOM)
|
||||
Encoding::PutBOM(os_);
|
||||
}
|
||||
|
||||
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||
void Flush() { os_.Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedOutputStream(const EncodedOutputStream&);
|
||||
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||
|
||||
OutputByteStream& os_;
|
||||
};
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for reading.
|
||||
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename InputByteStream>
|
||||
class AutoUTFInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
}
|
||||
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
InputByteStream* is_;
|
||||
UTFType type_;
|
||||
Ch current_;
|
||||
TakeFunc takeFunc_;
|
||||
bool hasBOM_;
|
||||
};
|
||||
|
||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam OutputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
716
include/rapidjson/encodings.h
Normal file
716
include/rapidjson/encodings.h
Normal file
@@ -0,0 +1,716 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ENCODINGS_H_
|
||||
#define RAPIDJSON_ENCODINGS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#elif defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
RAPIDJSON_DIAG_OFF(overflow)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encoding
|
||||
|
||||
/*! \class rapidjson::Encoding
|
||||
\brief Concept for encoding of Unicode characters.
|
||||
|
||||
\code
|
||||
concept Encoding {
|
||||
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||
|
||||
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||
|
||||
//! \brief Encode a Unicode codepoint to an output stream.
|
||||
//! \param os Output stream.
|
||||
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint);
|
||||
|
||||
//! \brief Decode a Unicode codepoint from an input stream.
|
||||
//! \param is Input stream.
|
||||
//! \param codepoint Output of the unicode codepoint.
|
||||
//! \return true if a valid codepoint can be decoded from the stream.
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||
|
||||
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||
//! \param is Input stream to obtain codepoint.
|
||||
//! \param os Output for copying one codepoint.
|
||||
//! \return true if it is valid.
|
||||
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os);
|
||||
|
||||
// The following functions are deal with byte streams.
|
||||
|
||||
//! Take a character from input byte stream, skip BOM if exist.
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is);
|
||||
|
||||
//! Take a character from input byte stream.
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is);
|
||||
|
||||
//! Put BOM to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os);
|
||||
|
||||
//! Put a character to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF8
|
||||
|
||||
//! UTF-8 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||
http://tools.ietf.org/html/rfc3629
|
||||
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (!(c & 0x80)) {
|
||||
*codepoint = static_cast<unsigned char>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||
if (type >= 32) {
|
||||
*codepoint = 0;
|
||||
} else {
|
||||
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
|
||||
}
|
||||
bool result = true;
|
||||
switch (type) {
|
||||
case 2: TAIL(); return result;
|
||||
case 3: TAIL(); TAIL(); return result;
|
||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef COPY
|
||||
#undef TRANS
|
||||
#undef TAIL
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
#define COPY() os.Put(c = is.Take())
|
||||
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c;
|
||||
COPY();
|
||||
if (!(c & 0x80))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||
case 2: TAIL(); return result;
|
||||
case 3: TAIL(); TAIL(); return result;
|
||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef COPY
|
||||
#undef TRANS
|
||||
#undef TAIL
|
||||
}
|
||||
|
||||
static unsigned char GetRange(unsigned char c) {
|
||||
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||
static const unsigned char type[] = {
|
||||
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,
|
||||
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
};
|
||||
return type[c];
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
typename InputByteStream::Ch c = Take(is);
|
||||
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||
c = is.Take();
|
||||
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||
c = is.Take();
|
||||
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||
c = is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF16
|
||||
|
||||
//! UTF-16 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||
http://tools.ietf.org/html/rfc2781
|
||||
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
os.Put((v & 0x3FF) | 0xDC00);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
PutUnsafe(os, (v & 0x3FF) | 0xDC00);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (c < 0xD800 || c > 0xDFFF) {
|
||||
*codepoint = static_cast<unsigned>(c);
|
||||
return true;
|
||||
}
|
||||
else if (c <= 0xDBFF) {
|
||||
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||
c = is.Take();
|
||||
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||
*codepoint += 0x10000;
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
typename InputStream::Ch c;
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||
if (c < 0xD800 || c > 0xDFFF)
|
||||
return true;
|
||||
else if (c <= 0xDBFF) {
|
||||
os.Put(c = is.Take());
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 little endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16LE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 big endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16BE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<uint8_t>(is.Take());
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF32
|
||||
|
||||
//! UTF-32 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(codepoint);
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
PutUnsafe(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c = is.Take();
|
||||
*codepoint = c;
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c;
|
||||
os.Put(c = is.Take());
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 little endian enocoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32LE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 big endian encoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32BE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ASCII
|
||||
|
||||
//! ASCII encoding.
|
||||
/*! http://en.wikipedia.org/wiki/ASCII
|
||||
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct ASCII {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 0 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
*codepoint = c;
|
||||
return c <= 0X7F;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||
return c <= 0x7F;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||
return static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
(void)os;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AutoUTF
|
||||
|
||||
//! Runtime-specified UTF encoding type of a stream.
|
||||
enum UTFType {
|
||||
kUTF8 = 0, //!< UTF-8.
|
||||
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||
};
|
||||
|
||||
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||
*/
|
||||
template<typename CharType>
|
||||
struct AutoUTF {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
template<typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||
return (*f[is.GetType()])(is, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||
return (*f[is.GetType()])(is, os);
|
||||
}
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Transcoder
|
||||
|
||||
//! Encoding conversion.
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder {
|
||||
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::Encode(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::EncodeUnsafe(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Validate one Unicode codepoint from an encoded stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||
}
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
template<typename Stream>
|
||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
|
||||
|
||||
//! Specialization of Transcoder with same source and target encoding.
|
||||
template<typename Encoding>
|
||||
struct Transcoder<Encoding, Encoding> {
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||
}
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
74
include/rapidjson/error/en.h
Normal file
74
include/rapidjson/error/en.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||
#define RAPIDJSON_ERROR_EN_H_
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_ERRORS
|
||||
\param parseErrorCode Error code obtained in parsing.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||
switch (parseErrorCode) {
|
||||
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
|
||||
|
||||
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||
|
||||
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||
|
||||
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||
|
||||
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||
|
||||
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||
|
||||
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
|
||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ERROR_EN_H_
|
||||
155
include/rapidjson/error/error.h
Normal file
155
include/rapidjson/error/error.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||
#define RAPIDJSON_ERROR_ERROR_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
/*! \file error.h */
|
||||
|
||||
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_CHARTYPE
|
||||
|
||||
//! Character type of error messages.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
The default character type is \c char.
|
||||
On Windows, user can define this macro as \c TCHAR for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_STRING
|
||||
|
||||
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
By default this conversion macro does nothing.
|
||||
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_STRING
|
||||
#define RAPIDJSON_ERROR_STRING(x) x
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseErrorCode
|
||||
|
||||
//! Error code of parsing.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
\see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||
*/
|
||||
enum ParseErrorCode {
|
||||
kParseErrorNone = 0, //!< No error.
|
||||
|
||||
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||
|
||||
kParseErrorValueInvalid, //!< Invalid value.
|
||||
|
||||
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||
|
||||
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||
|
||||
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||
|
||||
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||
|
||||
kParseErrorTermination, //!< Parsing was terminated.
|
||||
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
|
||||
};
|
||||
|
||||
//! Result of parsing (wraps ParseErrorCode)
|
||||
/*!
|
||||
\ingroup RAPIDJSON_ERRORS
|
||||
\code
|
||||
Document doc;
|
||||
ParseResult ok = doc.Parse("[42]");
|
||||
if (!ok) {
|
||||
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||
GetParseError_En(ok.Code()), ok.Offset());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
\endcode
|
||||
\see GenericReader::Parse, GenericDocument::Parse
|
||||
*/
|
||||
struct ParseResult {
|
||||
public:
|
||||
//! Default constructor, no error.
|
||||
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||
//! Constructor to set an error.
|
||||
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||
|
||||
//! Get the error code.
|
||||
ParseErrorCode Code() const { return code_; }
|
||||
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||
size_t Offset() const { return offset_; }
|
||||
|
||||
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||
operator bool() const { return !IsError(); }
|
||||
//! Whether the result is an error.
|
||||
bool IsError() const { return code_ != kParseErrorNone; }
|
||||
|
||||
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||
|
||||
//! Reset error code.
|
||||
void Clear() { Set(kParseErrorNone); }
|
||||
//! Update error code and offset.
|
||||
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||
|
||||
private:
|
||||
ParseErrorCode code_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
||||
//! Function pointer type of GetParseError().
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
|
||||
This is the prototype for \c GetParseError_X(), where \c X is a locale.
|
||||
User can dynamically change locale in runtime, e.g.:
|
||||
\code
|
||||
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||
\endcode
|
||||
*/
|
||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ERROR_ERROR_H_
|
||||
99
include/rapidjson/filereadstream.h
Normal file
99
include/rapidjson/filereadstream.h
Normal file
@@ -0,0 +1,99 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileReadStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type (byte).
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param fp File pointer opened for read.
|
||||
\param buffer user-supplied buffer.
|
||||
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||
*/
|
||||
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||
Read();
|
||||
}
|
||||
|
||||
Ch Peek() const { return *current_; }
|
||||
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return (current_ + 4 <= bufferLast_) ? current_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
if (current_ < bufferLast_)
|
||||
++current_;
|
||||
else if (!eof_) {
|
||||
count_ += readCount_;
|
||||
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (readCount_ < bufferSize_) {
|
||||
buffer_[readCount_] = '\0';
|
||||
++bufferLast_;
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
104
include/rapidjson/filewritestream.h
Normal file
104
include/rapidjson/filewritestream.h
Normal file
@@ -0,0 +1,104 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
std::memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
std::memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
}
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
std::FILE* fp_;
|
||||
char *buffer_;
|
||||
char *bufferEnd_;
|
||||
char *current_;
|
||||
};
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
151
include/rapidjson/fwd.h
Normal file
151
include/rapidjson/fwd.h
Normal file
@@ -0,0 +1,151 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FWD_H_
|
||||
#define RAPIDJSON_FWD_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
// encodings.h
|
||||
|
||||
template<typename CharType> struct UTF8;
|
||||
template<typename CharType> struct UTF16;
|
||||
template<typename CharType> struct UTF16BE;
|
||||
template<typename CharType> struct UTF16LE;
|
||||
template<typename CharType> struct UTF32;
|
||||
template<typename CharType> struct UTF32BE;
|
||||
template<typename CharType> struct UTF32LE;
|
||||
template<typename CharType> struct ASCII;
|
||||
template<typename CharType> struct AutoUTF;
|
||||
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder;
|
||||
|
||||
// allocators.h
|
||||
|
||||
class CrtAllocator;
|
||||
|
||||
template <typename BaseAllocator>
|
||||
class MemoryPoolAllocator;
|
||||
|
||||
// stream.h
|
||||
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream;
|
||||
|
||||
typedef GenericStringStream<UTF8<char> > StringStream;
|
||||
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream;
|
||||
|
||||
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
|
||||
|
||||
// stringbuffer.h
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericStringBuffer;
|
||||
|
||||
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
|
||||
|
||||
// filereadstream.h
|
||||
|
||||
class FileReadStream;
|
||||
|
||||
// filewritestream.h
|
||||
|
||||
class FileWriteStream;
|
||||
|
||||
// memorybuffer.h
|
||||
|
||||
template <typename Allocator>
|
||||
struct GenericMemoryBuffer;
|
||||
|
||||
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
|
||||
|
||||
// memorystream.h
|
||||
|
||||
struct MemoryStream;
|
||||
|
||||
// reader.h
|
||||
|
||||
template<typename Encoding, typename Derived>
|
||||
struct BaseReaderHandler;
|
||||
|
||||
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
|
||||
class GenericReader;
|
||||
|
||||
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
|
||||
|
||||
// writer.h
|
||||
|
||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||
class Writer;
|
||||
|
||||
// prettywriter.h
|
||||
|
||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||
class PrettyWriter;
|
||||
|
||||
// document.h
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
struct GenericMember;
|
||||
|
||||
template <bool Const, typename Encoding, typename Allocator>
|
||||
class GenericMemberIterator;
|
||||
|
||||
template<typename CharType>
|
||||
struct GenericStringRef;
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericValue;
|
||||
|
||||
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
|
||||
|
||||
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||
class GenericDocument;
|
||||
|
||||
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
|
||||
|
||||
// pointer.h
|
||||
|
||||
template <typename ValueType, typename Allocator>
|
||||
class GenericPointer;
|
||||
|
||||
typedef GenericPointer<Value, CrtAllocator> Pointer;
|
||||
|
||||
// schema.h
|
||||
|
||||
template <typename SchemaDocumentType>
|
||||
class IGenericRemoteSchemaDocumentProvider;
|
||||
|
||||
template <typename ValueT, typename Allocator>
|
||||
class GenericSchemaDocument;
|
||||
|
||||
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
|
||||
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
|
||||
|
||||
template <
|
||||
typename SchemaDocumentType,
|
||||
typename OutputHandler,
|
||||
typename StateAllocator>
|
||||
class GenericSchemaValidator;
|
||||
|
||||
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSONFWD_H_
|
||||
290
include/rapidjson/internal/biginteger.h
Normal file
290
include/rapidjson/internal/biginteger.h
Normal file
@@ -0,0 +1,290 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_BIGINTEGER_H_
|
||||
#define RAPIDJSON_BIGINTEGER_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#include <intrin.h> // for _umul128
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
class BigInteger {
|
||||
public:
|
||||
typedef uint64_t Type;
|
||||
|
||||
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
|
||||
explicit BigInteger(uint64_t u) : count_(1) {
|
||||
digits_[0] = u;
|
||||
}
|
||||
|
||||
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||
RAPIDJSON_ASSERT(length > 0);
|
||||
digits_[0] = 0;
|
||||
size_t i = 0;
|
||||
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
|
||||
while (length >= kMaxDigitPerIteration) {
|
||||
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
|
||||
length -= kMaxDigitPerIteration;
|
||||
i += kMaxDigitPerIteration;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
AppendDecimal64(decimals + i, decimals + i + length);
|
||||
}
|
||||
|
||||
BigInteger& operator=(const BigInteger &rhs)
|
||||
{
|
||||
if (this != &rhs) {
|
||||
count_ = rhs.count_;
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator=(uint64_t u) {
|
||||
digits_[0] = u;
|
||||
count_ = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator+=(uint64_t u) {
|
||||
Type backup = digits_[0];
|
||||
digits_[0] += u;
|
||||
for (size_t i = 0; i < count_ - 1; i++) {
|
||||
if (digits_[i] >= backup)
|
||||
return *this; // no carry
|
||||
backup = digits_[i + 1];
|
||||
digits_[i + 1] += 1;
|
||||
}
|
||||
|
||||
// Last carry
|
||||
if (digits_[count_ - 1] < backup)
|
||||
PushBack(1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator*=(uint64_t u) {
|
||||
if (u == 0) return *this = 0;
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
uint64_t hi;
|
||||
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
|
||||
k = hi;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
PushBack(k);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator*=(uint32_t u) {
|
||||
if (u == 0) return *this = 0;
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
const uint64_t c = digits_[i] >> 32;
|
||||
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||
const uint64_t uc = u * c;
|
||||
const uint64_t ud = u * d;
|
||||
const uint64_t p0 = ud + k;
|
||||
const uint64_t p1 = uc + (p0 >> 32);
|
||||
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
|
||||
k = p1 >> 32;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
PushBack(k);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator<<=(size_t shift) {
|
||||
if (IsZero() || shift == 0) return *this;
|
||||
|
||||
size_t offset = shift / kTypeBit;
|
||||
size_t interShift = shift % kTypeBit;
|
||||
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||
|
||||
if (interShift == 0) {
|
||||
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
|
||||
count_ += offset;
|
||||
}
|
||||
else {
|
||||
digits_[count_] = 0;
|
||||
for (size_t i = count_; i > 0; i--)
|
||||
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
|
||||
digits_[offset] = digits_[0] << interShift;
|
||||
count_ += offset;
|
||||
if (digits_[count_])
|
||||
count_++;
|
||||
}
|
||||
|
||||
std::memset(digits_, 0, offset * sizeof(Type));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const BigInteger& rhs) const {
|
||||
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
|
||||
}
|
||||
|
||||
bool operator==(const Type rhs) const {
|
||||
return count_ == 1 && digits_[0] == rhs;
|
||||
}
|
||||
|
||||
BigInteger& MultiplyPow5(unsigned exp) {
|
||||
static const uint32_t kPow5[12] = {
|
||||
5,
|
||||
5 * 5,
|
||||
5 * 5 * 5,
|
||||
5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
|
||||
};
|
||||
if (exp == 0) return *this;
|
||||
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
|
||||
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
|
||||
if (exp > 0) *this *= kPow5[exp - 1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Compute absolute difference of this and rhs.
|
||||
// Assume this != rhs
|
||||
bool Difference(const BigInteger& rhs, BigInteger* out) const {
|
||||
int cmp = Compare(rhs);
|
||||
RAPIDJSON_ASSERT(cmp != 0);
|
||||
const BigInteger *a, *b; // Makes a > b
|
||||
bool ret;
|
||||
if (cmp < 0) { a = &rhs; b = this; ret = true; }
|
||||
else { a = this; b = &rhs; ret = false; }
|
||||
|
||||
Type borrow = 0;
|
||||
for (size_t i = 0; i < a->count_; i++) {
|
||||
Type d = a->digits_[i] - borrow;
|
||||
if (i < b->count_)
|
||||
d -= b->digits_[i];
|
||||
borrow = (d > a->digits_[i]) ? 1 : 0;
|
||||
out->digits_[i] = d;
|
||||
if (d != 0)
|
||||
out->count_ = i + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Compare(const BigInteger& rhs) const {
|
||||
if (count_ != rhs.count_)
|
||||
return count_ < rhs.count_ ? -1 : 1;
|
||||
|
||||
for (size_t i = count_; i-- > 0;)
|
||||
if (digits_[i] != rhs.digits_[i])
|
||||
return digits_[i] < rhs.digits_[i] ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t GetCount() const { return count_; }
|
||||
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
|
||||
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||
|
||||
private:
|
||||
void AppendDecimal64(const char* begin, const char* end) {
|
||||
uint64_t u = ParseUint64(begin, end);
|
||||
if (IsZero())
|
||||
*this = u;
|
||||
else {
|
||||
unsigned exp = static_cast<unsigned>(end - begin);
|
||||
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
|
||||
}
|
||||
}
|
||||
|
||||
void PushBack(Type digit) {
|
||||
RAPIDJSON_ASSERT(count_ < kCapacity);
|
||||
digits_[count_++] = digit;
|
||||
}
|
||||
|
||||
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||
uint64_t r = 0;
|
||||
for (const char* p = begin; p != end; ++p) {
|
||||
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Assume a * b + k < 2^128
|
||||
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t low = _umul128(a, b, outHigh) + k;
|
||||
if (low < k)
|
||||
(*outHigh)++;
|
||||
return low;
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||
p += k;
|
||||
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||
return static_cast<uint64_t>(p);
|
||||
#else
|
||||
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
|
||||
x1 += (x0 >> 32); // can't give carry
|
||||
x1 += x2;
|
||||
if (x1 < x2)
|
||||
x3 += (static_cast<uint64_t>(1) << 32);
|
||||
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
|
||||
uint64_t hi = x3 + (x1 >> 32);
|
||||
|
||||
lo += k;
|
||||
if (lo < k)
|
||||
hi++;
|
||||
*outHigh = hi;
|
||||
return lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
|
||||
static const size_t kCapacity = kBitCount / sizeof(Type);
|
||||
static const size_t kTypeBit = sizeof(Type) * 8;
|
||||
|
||||
Type digits_[kCapacity];
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_BIGINTEGER_H_
|
||||
258
include/rapidjson/internal/diyfp.h
Normal file
258
include/rapidjson/internal/diyfp.h
Normal file
@@ -0,0 +1,258 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef RAPIDJSON_DIYFP_H_
|
||||
#define RAPIDJSON_DIYFP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanReverse64)
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
struct DiyFp {
|
||||
DiyFp() : f(), e() {}
|
||||
|
||||
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
|
||||
|
||||
explicit DiyFp(double d) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u = { d };
|
||||
|
||||
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||
if (biased_e != 0) {
|
||||
f = significand + kDpHiddenBit;
|
||||
e = biased_e - kDpExponentBias;
|
||||
}
|
||||
else {
|
||||
f = significand;
|
||||
e = kDpMinExponent + 1;
|
||||
}
|
||||
}
|
||||
|
||||
DiyFp operator-(const DiyFp& rhs) const {
|
||||
return DiyFp(f - rhs.f, e);
|
||||
}
|
||||
|
||||
DiyFp operator*(const DiyFp& rhs) const {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t h;
|
||||
uint64_t l = _umul128(f, rhs.f, &h);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||
uint64_t l = static_cast<uint64_t>(p);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#else
|
||||
const uint64_t M32 = 0xFFFFFFFF;
|
||||
const uint64_t a = f >> 32;
|
||||
const uint64_t b = f & M32;
|
||||
const uint64_t c = rhs.f >> 32;
|
||||
const uint64_t d = rhs.f & M32;
|
||||
const uint64_t ac = a * c;
|
||||
const uint64_t bc = b * c;
|
||||
const uint64_t ad = a * d;
|
||||
const uint64_t bd = b * d;
|
||||
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||
tmp += 1U << 31; /// mult_round
|
||||
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||
#endif
|
||||
}
|
||||
|
||||
DiyFp Normalize() const {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
unsigned long index;
|
||||
_BitScanReverse64(&index, f);
|
||||
return DiyFp(f << (63 - index), e - (63 - index));
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
int s = __builtin_clzll(f);
|
||||
return DiyFp(f << s, e - s);
|
||||
#else
|
||||
DiyFp res = *this;
|
||||
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
DiyFp NormalizeBoundary() const {
|
||||
DiyFp res = *this;
|
||||
while (!(res.f & (kDpHiddenBit << 1))) {
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||
mi.f <<= mi.e - pl.e;
|
||||
mi.e = pl.e;
|
||||
*plus = pl;
|
||||
*minus = mi;
|
||||
}
|
||||
|
||||
double ToDouble() const {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
}u;
|
||||
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||
static_cast<uint64_t>(e + kDpExponentBias);
|
||||
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static const int kDiySignificandSize = 64;
|
||||
static const int kDpSignificandSize = 52;
|
||||
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||
static const int kDpMinExponent = -kDpExponentBias;
|
||||
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
uint64_t f;
|
||||
int e;
|
||||
};
|
||||
|
||||
inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||
// 10^-348, 10^-340, ..., 10^340
|
||||
static const uint64_t kCachedPowers_F[] = {
|
||||
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||
};
|
||||
static const int16_t kCachedPowers_E[] = {
|
||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||
907, 933, 960, 986, 1013, 1039, 1066
|
||||
};
|
||||
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower(int e, int* K) {
|
||||
|
||||
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||
int k = static_cast<int>(dk);
|
||||
if (dk - k > 0.0)
|
||||
k++;
|
||||
|
||||
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
|
||||
*outExp = -348 + static_cast<int>(index) * 8;
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_DIYFP_H_
|
||||
245
include/rapidjson/internal/dtoa.h
Normal file
245
include/rapidjson/internal/dtoa.h
Normal file
@@ -0,0 +1,245 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef RAPIDJSON_DTOA_
|
||||
#define RAPIDJSON_DTOA_
|
||||
|
||||
#include "itoa.h" // GetDigitsLut()
|
||||
#include "diyfp.h"
|
||||
#include "ieee754.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
|
||||
#endif
|
||||
|
||||
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
||||
while (rest < wp_w && delta - rest >= ten_kappa &&
|
||||
(rest + ten_kappa < wp_w || /// closer
|
||||
wp_w - rest > rest + ten_kappa - wp_w)) {
|
||||
buffer[len - 1]--;
|
||||
rest += ten_kappa;
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned CountDecimalDigit32(uint32_t n) {
|
||||
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||
if (n < 10) return 1;
|
||||
if (n < 100) return 2;
|
||||
if (n < 1000) return 3;
|
||||
if (n < 10000) return 4;
|
||||
if (n < 100000) return 5;
|
||||
if (n < 1000000) return 6;
|
||||
if (n < 10000000) return 7;
|
||||
if (n < 100000000) return 8;
|
||||
// Will not reach 10 digits in DigitGen()
|
||||
//if (n < 1000000000) return 9;
|
||||
//return 10;
|
||||
return 9;
|
||||
}
|
||||
|
||||
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||
const DiyFp wp_w = Mp - W;
|
||||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||
uint64_t p2 = Mp.f & (one.f - 1);
|
||||
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||
*len = 0;
|
||||
|
||||
while (kappa > 0) {
|
||||
uint32_t d = 0;
|
||||
switch (kappa) {
|
||||
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
||||
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
||||
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
||||
case 6: d = p1 / 100000; p1 %= 100000; break;
|
||||
case 5: d = p1 / 10000; p1 %= 10000; break;
|
||||
case 4: d = p1 / 1000; p1 %= 1000; break;
|
||||
case 3: d = p1 / 100; p1 %= 100; break;
|
||||
case 2: d = p1 / 10; p1 %= 10; break;
|
||||
case 1: d = p1; p1 = 0; break;
|
||||
default:;
|
||||
}
|
||||
if (d || *len)
|
||||
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
|
||||
kappa--;
|
||||
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||
if (tmp <= delta) {
|
||||
*K += kappa;
|
||||
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// kappa = 0
|
||||
for (;;) {
|
||||
p2 *= 10;
|
||||
delta *= 10;
|
||||
char d = static_cast<char>(p2 >> -one.e);
|
||||
if (d || *len)
|
||||
buffer[(*len)++] = static_cast<char>('0' + d);
|
||||
p2 &= one.f - 1;
|
||||
kappa--;
|
||||
if (p2 < delta) {
|
||||
*K += kappa;
|
||||
int index = -static_cast<int>(kappa);
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
||||
const DiyFp v(value);
|
||||
DiyFp w_m, w_p;
|
||||
v.NormalizedBoundaries(&w_m, &w_p);
|
||||
|
||||
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||
const DiyFp W = v.Normalize() * c_mk;
|
||||
DiyFp Wp = w_p * c_mk;
|
||||
DiyFp Wm = w_m * c_mk;
|
||||
Wm.f++;
|
||||
Wp.f--;
|
||||
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||
}
|
||||
|
||||
inline char* WriteExponent(int K, char* buffer) {
|
||||
if (K < 0) {
|
||||
*buffer++ = '-';
|
||||
K = -K;
|
||||
}
|
||||
|
||||
if (K >= 100) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
|
||||
K %= 100;
|
||||
const char* d = GetDigitsLut() + K * 2;
|
||||
*buffer++ = d[0];
|
||||
*buffer++ = d[1];
|
||||
}
|
||||
else if (K >= 10) {
|
||||
const char* d = GetDigitsLut() + K * 2;
|
||||
*buffer++ = d[0];
|
||||
*buffer++ = d[1];
|
||||
}
|
||||
else
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
||||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||
|
||||
if (0 <= k && kk <= 21) {
|
||||
// 1234e7 -> 12340000000
|
||||
for (int i = length; i < kk; i++)
|
||||
buffer[i] = '0';
|
||||
buffer[kk] = '.';
|
||||
buffer[kk + 1] = '0';
|
||||
return &buffer[kk + 2];
|
||||
}
|
||||
else if (0 < kk && kk <= 21) {
|
||||
// 1234e-2 -> 12.34
|
||||
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||
buffer[kk] = '.';
|
||||
if (0 > k + maxDecimalPlaces) {
|
||||
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
||||
// Remove extra trailing zeros (at least one) after truncation.
|
||||
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
||||
if (buffer[i] != '0')
|
||||
return &buffer[i + 1];
|
||||
return &buffer[kk + 2]; // Reserve one zero
|
||||
}
|
||||
else
|
||||
return &buffer[length + 1];
|
||||
}
|
||||
else if (-6 < kk && kk <= 0) {
|
||||
// 1234e-6 -> 0.001234
|
||||
const int offset = 2 - kk;
|
||||
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 2; i < offset; i++)
|
||||
buffer[i] = '0';
|
||||
if (length - kk > maxDecimalPlaces) {
|
||||
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
|
||||
// Remove extra trailing zeros (at least one) after truncation.
|
||||
for (int i = maxDecimalPlaces + 1; i > 2; i--)
|
||||
if (buffer[i] != '0')
|
||||
return &buffer[i + 1];
|
||||
return &buffer[3]; // Reserve one zero
|
||||
}
|
||||
else
|
||||
return &buffer[length + offset];
|
||||
}
|
||||
else if (kk < -maxDecimalPlaces) {
|
||||
// Truncate to zero
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else if (length == 1) {
|
||||
// 1e30
|
||||
buffer[1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[2]);
|
||||
}
|
||||
else {
|
||||
// 1234e30 -> 1.234e33
|
||||
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||
buffer[1] = '.';
|
||||
buffer[length + 1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
|
||||
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
|
||||
Double d(value);
|
||||
if (d.IsZero()) {
|
||||
if (d.Sign())
|
||||
*buffer++ = '-'; // -0.0, Issue #289
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else {
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
value = -value;
|
||||
}
|
||||
int length, K;
|
||||
Grisu2(value, buffer, &length, &K);
|
||||
return Prettify(buffer, length, K, maxDecimalPlaces);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_DTOA_
|
||||
78
include/rapidjson/internal/ieee754.h
Normal file
78
include/rapidjson/internal/ieee754.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_IEEE754_
|
||||
#define RAPIDJSON_IEEE754_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
class Double {
|
||||
public:
|
||||
Double() {}
|
||||
Double(double d) : d_(d) {}
|
||||
Double(uint64_t u) : u_(u) {}
|
||||
|
||||
double Value() const { return d_; }
|
||||
uint64_t Uint64Value() const { return u_; }
|
||||
|
||||
double NextPositiveDouble() const {
|
||||
RAPIDJSON_ASSERT(!Sign());
|
||||
return Double(u_ + 1).Value();
|
||||
}
|
||||
|
||||
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||
|
||||
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
|
||||
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
|
||||
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
|
||||
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
|
||||
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||
|
||||
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||
|
||||
static unsigned EffectiveSignificandSize(int order) {
|
||||
if (order >= -1021)
|
||||
return 53;
|
||||
else if (order <= -1074)
|
||||
return 0;
|
||||
else
|
||||
return static_cast<unsigned>(order) + 1074;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kSignificandSize = 52;
|
||||
static const int kExponentBias = 0x3FF;
|
||||
static const int kDenormalExponent = 1 - kExponentBias;
|
||||
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
|
||||
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
union {
|
||||
double d_;
|
||||
uint64_t u_;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_IEEE754_
|
||||
304
include/rapidjson/internal/itoa.h
Normal file
304
include/rapidjson/internal/itoa.h
Normal file
@@ -0,0 +1,304 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ITOA_
|
||||
#define RAPIDJSON_ITOA_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
inline const char* GetDigitsLut() {
|
||||
static const char cDigitsLut[200] = {
|
||||
'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'
|
||||
};
|
||||
return cDigitsLut;
|
||||
}
|
||||
|
||||
inline char* u32toa(uint32_t value, char* buffer) {
|
||||
const char* cDigitsLut = GetDigitsLut();
|
||||
|
||||
if (value < 10000) {
|
||||
const uint32_t d1 = (value / 100) << 1;
|
||||
const uint32_t d2 = (value % 100) << 1;
|
||||
|
||||
if (value >= 1000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 100)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 10)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
}
|
||||
else if (value < 100000000) {
|
||||
// value = bbbbcccc
|
||||
const uint32_t b = value / 10000;
|
||||
const uint32_t c = value % 10000;
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
if (value >= 10000000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 1000000)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 100000)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
else {
|
||||
// value = aabbbbcccc in decimal
|
||||
|
||||
const uint32_t a = value / 100000000; // 1 to 42
|
||||
value %= 100000000;
|
||||
|
||||
if (a >= 10) {
|
||||
const unsigned i = a << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
|
||||
const uint32_t b = value / 10000; // 0 to 9999
|
||||
const uint32_t c = value % 10000; // 0 to 9999
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* i32toa(int32_t value, char* buffer) {
|
||||
uint32_t u = static_cast<uint32_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
|
||||
return u32toa(u, buffer);
|
||||
}
|
||||
|
||||
inline char* u64toa(uint64_t value, char* buffer) {
|
||||
const char* cDigitsLut = GetDigitsLut();
|
||||
const uint64_t kTen8 = 100000000;
|
||||
const uint64_t kTen9 = kTen8 * 10;
|
||||
const uint64_t kTen10 = kTen8 * 100;
|
||||
const uint64_t kTen11 = kTen8 * 1000;
|
||||
const uint64_t kTen12 = kTen8 * 10000;
|
||||
const uint64_t kTen13 = kTen8 * 100000;
|
||||
const uint64_t kTen14 = kTen8 * 1000000;
|
||||
const uint64_t kTen15 = kTen8 * 10000000;
|
||||
const uint64_t kTen16 = kTen8 * kTen8;
|
||||
|
||||
if (value < kTen8) {
|
||||
uint32_t v = static_cast<uint32_t>(value);
|
||||
if (v < 10000) {
|
||||
const uint32_t d1 = (v / 100) << 1;
|
||||
const uint32_t d2 = (v % 100) << 1;
|
||||
|
||||
if (v >= 1000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (v >= 100)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (v >= 10)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
}
|
||||
else {
|
||||
// value = bbbbcccc
|
||||
const uint32_t b = v / 10000;
|
||||
const uint32_t c = v % 10000;
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
if (value >= 10000000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 1000000)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 100000)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
}
|
||||
else if (value < kTen16) {
|
||||
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||
|
||||
const uint32_t b0 = v0 / 10000;
|
||||
const uint32_t c0 = v0 % 10000;
|
||||
|
||||
const uint32_t d1 = (b0 / 100) << 1;
|
||||
const uint32_t d2 = (b0 % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c0 / 100) << 1;
|
||||
const uint32_t d4 = (c0 % 100) << 1;
|
||||
|
||||
const uint32_t b1 = v1 / 10000;
|
||||
const uint32_t c1 = v1 % 10000;
|
||||
|
||||
const uint32_t d5 = (b1 / 100) << 1;
|
||||
const uint32_t d6 = (b1 % 100) << 1;
|
||||
|
||||
const uint32_t d7 = (c1 / 100) << 1;
|
||||
const uint32_t d8 = (c1 % 100) << 1;
|
||||
|
||||
if (value >= kTen15)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= kTen14)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= kTen13)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
if (value >= kTen12)
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
if (value >= kTen11)
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
if (value >= kTen10)
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
if (value >= kTen9)
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
if (value >= kTen8)
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d5];
|
||||
*buffer++ = cDigitsLut[d5 + 1];
|
||||
*buffer++ = cDigitsLut[d6];
|
||||
*buffer++ = cDigitsLut[d6 + 1];
|
||||
*buffer++ = cDigitsLut[d7];
|
||||
*buffer++ = cDigitsLut[d7 + 1];
|
||||
*buffer++ = cDigitsLut[d8];
|
||||
*buffer++ = cDigitsLut[d8 + 1];
|
||||
}
|
||||
else {
|
||||
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
|
||||
value %= kTen16;
|
||||
|
||||
if (a < 10)
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
else if (a < 100) {
|
||||
const uint32_t i = a << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else if (a < 1000) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
|
||||
|
||||
const uint32_t i = (a % 100) << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else {
|
||||
const uint32_t i = (a / 100) << 1;
|
||||
const uint32_t j = (a % 100) << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
*buffer++ = cDigitsLut[j];
|
||||
*buffer++ = cDigitsLut[j + 1];
|
||||
}
|
||||
|
||||
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||
|
||||
const uint32_t b0 = v0 / 10000;
|
||||
const uint32_t c0 = v0 % 10000;
|
||||
|
||||
const uint32_t d1 = (b0 / 100) << 1;
|
||||
const uint32_t d2 = (b0 % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c0 / 100) << 1;
|
||||
const uint32_t d4 = (c0 % 100) << 1;
|
||||
|
||||
const uint32_t b1 = v1 / 10000;
|
||||
const uint32_t c1 = v1 % 10000;
|
||||
|
||||
const uint32_t d5 = (b1 / 100) << 1;
|
||||
const uint32_t d6 = (b1 % 100) << 1;
|
||||
|
||||
const uint32_t d7 = (c1 / 100) << 1;
|
||||
const uint32_t d8 = (c1 % 100) << 1;
|
||||
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
*buffer++ = cDigitsLut[d5];
|
||||
*buffer++ = cDigitsLut[d5 + 1];
|
||||
*buffer++ = cDigitsLut[d6];
|
||||
*buffer++ = cDigitsLut[d6 + 1];
|
||||
*buffer++ = cDigitsLut[d7];
|
||||
*buffer++ = cDigitsLut[d7 + 1];
|
||||
*buffer++ = cDigitsLut[d8];
|
||||
*buffer++ = cDigitsLut[d8 + 1];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* i64toa(int64_t value, char* buffer) {
|
||||
uint64_t u = static_cast<uint64_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
|
||||
return u64toa(u, buffer);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ITOA_
|
||||
181
include/rapidjson/internal/meta.h
Normal file
181
include/rapidjson/internal/meta.h
Normal file
@@ -0,0 +1,181 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(6334)
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
//@cond RAPIDJSON_INTERNAL
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BoolType, TrueType, FalseType
|
||||
//
|
||||
template <bool Cond> struct BoolType {
|
||||
static const bool Value = Cond;
|
||||
typedef BoolType Type;
|
||||
};
|
||||
typedef BoolType<true> TrueType;
|
||||
typedef BoolType<false> FalseType;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||
//
|
||||
|
||||
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||
|
||||
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||
template <> struct AndExprCond<true, true> : TrueType {};
|
||||
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||
template <> struct OrExprCond<false, false> : FalseType {};
|
||||
|
||||
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AddConst, MaybeAddConst, RemoveConst
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||
//
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst
|
||||
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsBaseOf
|
||||
//
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||
|
||||
#else // simplified version adopted from Boost
|
||||
|
||||
template<typename B, typename D> struct IsBaseOfImpl {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||
|
||||
typedef char (&Yes)[1];
|
||||
typedef char (&No) [2];
|
||||
|
||||
template <typename T>
|
||||
static Yes Check(const D*, T);
|
||||
static No Check(const B*, int);
|
||||
|
||||
struct Host {
|
||||
operator const B*() const;
|
||||
operator const D*();
|
||||
};
|
||||
|
||||
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||
};
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||
|
||||
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EnableIf / DisableIf
|
||||
//
|
||||
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeTag {};
|
||||
template <typename T> struct RemoveSfinaeTag;
|
||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_DISABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
//@endcond
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||
55
include/rapidjson/internal/pow10.h
Normal file
55
include/rapidjson/internal/pow10.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n non-negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
|
||||
1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
|
||||
return e[n];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
701
include/rapidjson/internal/regex.h
Normal file
701
include/rapidjson/internal/regex.h
Normal file
@@ -0,0 +1,701 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
|
||||
#define RAPIDJSON_INTERNAL_REGEX_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "../stream.h"
|
||||
#include "stack.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_REGEX_VERBOSE
|
||||
#define RAPIDJSON_REGEX_VERBOSE 0
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericRegex
|
||||
|
||||
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
|
||||
static const SizeType kRegexInvalidRange = ~SizeType(0);
|
||||
|
||||
//! Regular expression engine with subset of ECMAscript grammar.
|
||||
/*!
|
||||
Supported regular expression syntax:
|
||||
- \c ab Concatenation
|
||||
- \c a|b Alternation
|
||||
- \c a? Zero or one
|
||||
- \c a* Zero or more
|
||||
- \c a+ One or more
|
||||
- \c a{3} Exactly 3 times
|
||||
- \c a{3,} At least 3 times
|
||||
- \c a{3,5} 3 to 5 times
|
||||
- \c (ab) Grouping
|
||||
- \c ^a At the beginning
|
||||
- \c a$ At the end
|
||||
- \c . Any character
|
||||
- \c [abc] Character classes
|
||||
- \c [a-c] Character class range
|
||||
- \c [a-z0-9_] Character class combination
|
||||
- \c [^abc] Negated character classes
|
||||
- \c [^a-c] Negated character class range
|
||||
- \c [\b] Backspace (U+0008)
|
||||
- \c \\| \\\\ ... Escape characters
|
||||
- \c \\f Form feed (U+000C)
|
||||
- \c \\n Line feed (U+000A)
|
||||
- \c \\r Carriage return (U+000D)
|
||||
- \c \\t Tab (U+0009)
|
||||
- \c \\v Vertical tab (U+000B)
|
||||
|
||||
\note This is a Thompson NFA engine, implemented with reference to
|
||||
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
|
||||
https://swtch.com/~rsc/regexp/regexp1.html
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericRegex {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
||||
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
||||
stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
|
||||
{
|
||||
GenericStringStream<Encoding> ss(source);
|
||||
DecodedStream<GenericStringStream<Encoding> > ds(ss);
|
||||
Parse(ds);
|
||||
}
|
||||
|
||||
~GenericRegex() {
|
||||
Allocator::Free(stateSet_);
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return root_ != kRegexInvalidState;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool Match(InputStream& is) const {
|
||||
return SearchWithAnchoring(is, true, true);
|
||||
}
|
||||
|
||||
bool Match(const Ch* s) const {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
return Match(is);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool Search(InputStream& is) const {
|
||||
return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
|
||||
}
|
||||
|
||||
bool Search(const Ch* s) const {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
return Search(is);
|
||||
}
|
||||
|
||||
private:
|
||||
enum Operator {
|
||||
kZeroOrOne,
|
||||
kZeroOrMore,
|
||||
kOneOrMore,
|
||||
kConcatenation,
|
||||
kAlternation,
|
||||
kLeftParenthesis
|
||||
};
|
||||
|
||||
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
|
||||
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
|
||||
static const unsigned kRangeNegationFlag = 0x80000000;
|
||||
|
||||
struct Range {
|
||||
unsigned start; //
|
||||
unsigned end;
|
||||
SizeType next;
|
||||
};
|
||||
|
||||
struct State {
|
||||
SizeType out; //!< Equals to kInvalid for matching state
|
||||
SizeType out1; //!< Equals to non-kInvalid for split
|
||||
SizeType rangeStart;
|
||||
unsigned codepoint;
|
||||
};
|
||||
|
||||
struct Frag {
|
||||
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
|
||||
SizeType start;
|
||||
SizeType out; //!< link-list of all output states
|
||||
SizeType minIndex;
|
||||
};
|
||||
|
||||
template <typename SourceStream>
|
||||
class DecodedStream {
|
||||
public:
|
||||
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
|
||||
unsigned Peek() { return codepoint_; }
|
||||
unsigned Take() {
|
||||
unsigned c = codepoint_;
|
||||
if (c) // No further decoding when '\0'
|
||||
Decode();
|
||||
return c;
|
||||
}
|
||||
|
||||
private:
|
||||
void Decode() {
|
||||
if (!Encoding::Decode(ss_, &codepoint_))
|
||||
codepoint_ = 0;
|
||||
}
|
||||
|
||||
SourceStream& ss_;
|
||||
unsigned codepoint_;
|
||||
};
|
||||
|
||||
State& GetState(SizeType index) {
|
||||
RAPIDJSON_ASSERT(index < stateCount_);
|
||||
return states_.template Bottom<State>()[index];
|
||||
}
|
||||
|
||||
const State& GetState(SizeType index) const {
|
||||
RAPIDJSON_ASSERT(index < stateCount_);
|
||||
return states_.template Bottom<State>()[index];
|
||||
}
|
||||
|
||||
Range& GetRange(SizeType index) {
|
||||
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||
return ranges_.template Bottom<Range>()[index];
|
||||
}
|
||||
|
||||
const Range& GetRange(SizeType index) const {
|
||||
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||
return ranges_.template Bottom<Range>()[index];
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
void Parse(DecodedStream<InputStream>& ds) {
|
||||
Allocator allocator;
|
||||
Stack<Allocator> operandStack(&allocator, 256); // Frag
|
||||
Stack<Allocator> operatorStack(&allocator, 256); // Operator
|
||||
Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
|
||||
|
||||
*atomCountStack.template Push<unsigned>() = 0;
|
||||
|
||||
unsigned codepoint;
|
||||
while (ds.Peek() != 0) {
|
||||
switch (codepoint = ds.Take()) {
|
||||
case '^':
|
||||
anchorBegin_ = true;
|
||||
break;
|
||||
|
||||
case '$':
|
||||
anchorEnd_ = true;
|
||||
break;
|
||||
|
||||
case '|':
|
||||
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
*operatorStack.template Push<Operator>() = kAlternation;
|
||||
*atomCountStack.template Top<unsigned>() = 0;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
*operatorStack.template Push<Operator>() = kLeftParenthesis;
|
||||
*atomCountStack.template Push<unsigned>() = 0;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
if (operatorStack.Empty())
|
||||
return;
|
||||
operatorStack.template Pop<Operator>(1);
|
||||
atomCountStack.template Pop<unsigned>(1);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
if (!Eval(operandStack, kZeroOrOne))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (!Eval(operandStack, kZeroOrMore))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (!Eval(operandStack, kOneOrMore))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
{
|
||||
unsigned n, m;
|
||||
if (!ParseUnsigned(ds, &n))
|
||||
return;
|
||||
|
||||
if (ds.Peek() == ',') {
|
||||
ds.Take();
|
||||
if (ds.Peek() == '}')
|
||||
m = kInfinityQuantifier;
|
||||
else if (!ParseUnsigned(ds, &m) || m < n)
|
||||
return;
|
||||
}
|
||||
else
|
||||
m = n;
|
||||
|
||||
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
|
||||
return;
|
||||
ds.Take();
|
||||
}
|
||||
break;
|
||||
|
||||
case '.':
|
||||
PushOperand(operandStack, kAnyCharacterClass);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
{
|
||||
SizeType range;
|
||||
if (!ParseRange(ds, &range))
|
||||
return;
|
||||
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
|
||||
GetState(s).rangeStart = range;
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||
}
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '\\': // Escape character
|
||||
if (!CharacterEscape(ds, &codepoint))
|
||||
return; // Unsupported escape character
|
||||
// fall through to default
|
||||
|
||||
default: // Pattern character
|
||||
PushOperand(operandStack, codepoint);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
}
|
||||
}
|
||||
|
||||
while (!operatorStack.Empty())
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
|
||||
// Link the operand to matching state.
|
||||
if (operandStack.GetSize() == sizeof(Frag)) {
|
||||
Frag* e = operandStack.template Pop<Frag>(1);
|
||||
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
|
||||
root_ = e->start;
|
||||
|
||||
#if RAPIDJSON_REGEX_VERBOSE
|
||||
printf("root: %d\n", root_);
|
||||
for (SizeType i = 0; i < stateCount_ ; i++) {
|
||||
State& s = GetState(i);
|
||||
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Preallocate buffer for SearchWithAnchoring()
|
||||
RAPIDJSON_ASSERT(stateSet_ == 0);
|
||||
if (stateCount_ > 0) {
|
||||
stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
|
||||
state0_.template Reserve<SizeType>(stateCount_);
|
||||
state1_.template Reserve<SizeType>(stateCount_);
|
||||
}
|
||||
}
|
||||
|
||||
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
|
||||
State* s = states_.template Push<State>();
|
||||
s->out = out;
|
||||
s->out1 = out1;
|
||||
s->codepoint = codepoint;
|
||||
s->rangeStart = kRegexInvalidRange;
|
||||
return stateCount_++;
|
||||
}
|
||||
|
||||
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
|
||||
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||
}
|
||||
|
||||
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
|
||||
if (*atomCountStack.template Top<unsigned>())
|
||||
*operatorStack.template Push<Operator>() = kConcatenation;
|
||||
(*atomCountStack.template Top<unsigned>())++;
|
||||
}
|
||||
|
||||
SizeType Append(SizeType l1, SizeType l2) {
|
||||
SizeType old = l1;
|
||||
while (GetState(l1).out != kRegexInvalidState)
|
||||
l1 = GetState(l1).out;
|
||||
GetState(l1).out = l2;
|
||||
return old;
|
||||
}
|
||||
|
||||
void Patch(SizeType l, SizeType s) {
|
||||
for (SizeType next; l != kRegexInvalidState; l = next) {
|
||||
next = GetState(l).out;
|
||||
GetState(l).out = s;
|
||||
}
|
||||
}
|
||||
|
||||
bool Eval(Stack<Allocator>& operandStack, Operator op) {
|
||||
switch (op) {
|
||||
case kConcatenation:
|
||||
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
|
||||
{
|
||||
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||
Patch(e1.out, e2.start);
|
||||
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
|
||||
}
|
||||
return true;
|
||||
|
||||
case kAlternation:
|
||||
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
|
||||
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(e1.start, e2.start, 0);
|
||||
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kZeroOrOne:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kZeroOrMore:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
Patch(e.out, s);
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
RAPIDJSON_ASSERT(op == kOneOrMore);
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
Patch(e.out, s);
|
||||
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
|
||||
RAPIDJSON_ASSERT(n <= m);
|
||||
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
|
||||
|
||||
if (n == 0) {
|
||||
if (m == 0) // a{0} not support
|
||||
return false;
|
||||
else if (m == kInfinityQuantifier)
|
||||
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
|
||||
else {
|
||||
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
|
||||
for (unsigned i = 0; i < m - 1; i++)
|
||||
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
|
||||
for (unsigned i = 0; i < m - 1; i++)
|
||||
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
|
||||
CloneTopOperand(operandStack);
|
||||
|
||||
if (m == kInfinityQuantifier)
|
||||
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
|
||||
else if (m > n) {
|
||||
CloneTopOperand(operandStack); // a{3,5} -> a a a a
|
||||
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
|
||||
for (unsigned i = n; i < m - 1; i++)
|
||||
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
|
||||
for (unsigned i = n; i < m; i++)
|
||||
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n - 1; i++)
|
||||
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
|
||||
|
||||
void CloneTopOperand(Stack<Allocator>& operandStack) {
|
||||
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
|
||||
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
|
||||
State* s = states_.template Push<State>(count);
|
||||
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
|
||||
for (SizeType j = 0; j < count; j++) {
|
||||
if (s[j].out != kRegexInvalidState)
|
||||
s[j].out += count;
|
||||
if (s[j].out1 != kRegexInvalidState)
|
||||
s[j].out1 += count;
|
||||
}
|
||||
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
|
||||
stateCount_ += count;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
|
||||
unsigned r = 0;
|
||||
if (ds.Peek() < '0' || ds.Peek() > '9')
|
||||
return false;
|
||||
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
|
||||
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
|
||||
return false; // overflow
|
||||
r = r * 10 + (ds.Take() - '0');
|
||||
}
|
||||
*u = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
|
||||
bool isBegin = true;
|
||||
bool negate = false;
|
||||
int step = 0;
|
||||
SizeType start = kRegexInvalidRange;
|
||||
SizeType current = kRegexInvalidRange;
|
||||
unsigned codepoint;
|
||||
while ((codepoint = ds.Take()) != 0) {
|
||||
if (isBegin) {
|
||||
isBegin = false;
|
||||
if (codepoint == '^') {
|
||||
negate = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (codepoint) {
|
||||
case ']':
|
||||
if (start == kRegexInvalidRange)
|
||||
return false; // Error: nothing inside []
|
||||
if (step == 2) { // Add trailing '-'
|
||||
SizeType r = NewRange('-');
|
||||
RAPIDJSON_ASSERT(current != kRegexInvalidRange);
|
||||
GetRange(current).next = r;
|
||||
}
|
||||
if (negate)
|
||||
GetRange(start).start |= kRangeNegationFlag;
|
||||
*range = start;
|
||||
return true;
|
||||
|
||||
case '\\':
|
||||
if (ds.Peek() == 'b') {
|
||||
ds.Take();
|
||||
codepoint = 0x0008; // Escape backspace character
|
||||
}
|
||||
else if (!CharacterEscape(ds, &codepoint))
|
||||
return false;
|
||||
// fall through to default
|
||||
|
||||
default:
|
||||
switch (step) {
|
||||
case 1:
|
||||
if (codepoint == '-') {
|
||||
step++;
|
||||
break;
|
||||
}
|
||||
// fall through to step 0 for other characters
|
||||
|
||||
case 0:
|
||||
{
|
||||
SizeType r = NewRange(codepoint);
|
||||
if (current != kRegexInvalidRange)
|
||||
GetRange(current).next = r;
|
||||
if (start == kRegexInvalidRange)
|
||||
start = r;
|
||||
current = r;
|
||||
}
|
||||
step = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
RAPIDJSON_ASSERT(step == 2);
|
||||
GetRange(current).end = codepoint;
|
||||
step = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SizeType NewRange(unsigned codepoint) {
|
||||
Range* r = ranges_.template Push<Range>();
|
||||
r->start = r->end = codepoint;
|
||||
r->next = kRegexInvalidRange;
|
||||
return rangeCount_++;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
|
||||
unsigned codepoint;
|
||||
switch (codepoint = ds.Take()) {
|
||||
case '^':
|
||||
case '$':
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case '?':
|
||||
case '*':
|
||||
case '+':
|
||||
case '.':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '\\':
|
||||
*escapedCodepoint = codepoint; return true;
|
||||
case 'f': *escapedCodepoint = 0x000C; return true;
|
||||
case 'n': *escapedCodepoint = 0x000A; return true;
|
||||
case 'r': *escapedCodepoint = 0x000D; return true;
|
||||
case 't': *escapedCodepoint = 0x0009; return true;
|
||||
case 'v': *escapedCodepoint = 0x000B; return true;
|
||||
default:
|
||||
return false; // Unsupported escape character
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
|
||||
RAPIDJSON_ASSERT(IsValid());
|
||||
DecodedStream<InputStream> ds(is);
|
||||
|
||||
state0_.Clear();
|
||||
Stack<Allocator> *current = &state0_, *next = &state1_;
|
||||
const size_t stateSetSize = GetStateSetSize();
|
||||
std::memset(stateSet_, 0, stateSetSize);
|
||||
|
||||
bool matched = AddState(*current, root_);
|
||||
unsigned codepoint;
|
||||
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
|
||||
std::memset(stateSet_, 0, stateSetSize);
|
||||
next->Clear();
|
||||
matched = false;
|
||||
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
|
||||
const State& sr = GetState(*s);
|
||||
if (sr.codepoint == codepoint ||
|
||||
sr.codepoint == kAnyCharacterClass ||
|
||||
(sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
|
||||
{
|
||||
matched = AddState(*next, sr.out) || matched;
|
||||
if (!anchorEnd && matched)
|
||||
return true;
|
||||
}
|
||||
if (!anchorBegin)
|
||||
AddState(*next, root_);
|
||||
}
|
||||
internal::Swap(current, next);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
size_t GetStateSetSize() const {
|
||||
return (stateCount_ + 31) / 32 * 4;
|
||||
}
|
||||
|
||||
// Return whether the added states is a match state
|
||||
bool AddState(Stack<Allocator>& l, SizeType index) const {
|
||||
RAPIDJSON_ASSERT(index != kRegexInvalidState);
|
||||
|
||||
const State& s = GetState(index);
|
||||
if (s.out1 != kRegexInvalidState) { // Split
|
||||
bool matched = AddState(l, s.out);
|
||||
return AddState(l, s.out1) || matched;
|
||||
}
|
||||
else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
|
||||
stateSet_[index >> 5] |= (1 << (index & 31));
|
||||
*l.template PushUnsafe<SizeType>() = index;
|
||||
}
|
||||
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
|
||||
}
|
||||
|
||||
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
|
||||
bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
|
||||
while (rangeIndex != kRegexInvalidRange) {
|
||||
const Range& r = GetRange(rangeIndex);
|
||||
if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
|
||||
return yes;
|
||||
rangeIndex = r.next;
|
||||
}
|
||||
return !yes;
|
||||
}
|
||||
|
||||
Stack<Allocator> states_;
|
||||
Stack<Allocator> ranges_;
|
||||
SizeType root_;
|
||||
SizeType stateCount_;
|
||||
SizeType rangeCount_;
|
||||
|
||||
static const unsigned kInfinityQuantifier = ~0u;
|
||||
|
||||
// For SearchWithAnchoring()
|
||||
uint32_t* stateSet_; // allocated by states_.GetAllocator()
|
||||
mutable Stack<Allocator> state0_;
|
||||
mutable Stack<Allocator> state1_;
|
||||
bool anchorBegin_;
|
||||
bool anchorEnd_;
|
||||
};
|
||||
|
||||
typedef GenericRegex<UTF8<> > Regex;
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_REGEX_H_
|
||||
230
include/rapidjson/internal/stack.h
Normal file
230
include/rapidjson/internal/stack.h
Normal file
@@ -0,0 +1,230 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "swap.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack(Stack&& rhs)
|
||||
: allocator_(rhs.allocator_),
|
||||
ownAllocator_(rhs.ownAllocator_),
|
||||
stack_(rhs.stack_),
|
||||
stackTop_(rhs.stackTop_),
|
||||
stackEnd_(rhs.stackEnd_),
|
||||
initialCapacity_(rhs.initialCapacity_)
|
||||
{
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Stack() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack& operator=(Stack&& rhs) {
|
||||
if (&rhs != this)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
allocator_ = rhs.allocator_;
|
||||
ownAllocator_ = rhs.ownAllocator_;
|
||||
stack_ = rhs.stack_;
|
||||
stackTop_ = rhs.stackTop_;
|
||||
stackEnd_ = rhs.stackEnd_;
|
||||
initialCapacity_ = rhs.initialCapacity_;
|
||||
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(stack_, rhs.stack_);
|
||||
internal::Swap(stackTop_, rhs.stackTop_);
|
||||
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||
}
|
||||
|
||||
void Clear() { stackTop_ = stack_; }
|
||||
|
||||
void ShrinkToFit() {
|
||||
if (Empty()) {
|
||||
// If the stack is empty, completely deallocate the memory.
|
||||
Allocator::Free(stack_);
|
||||
stack_ = 0;
|
||||
stackTop_ = 0;
|
||||
stackEnd_ = 0;
|
||||
}
|
||||
else
|
||||
Resize(GetSize());
|
||||
}
|
||||
|
||||
// Optimization note: try to minimize the size of this function for force inline.
|
||||
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
||||
Expand<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||
Reserve<T>(count);
|
||||
return PushUnsafe<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||
stackTop_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stackTop_ -= count * sizeof(T);
|
||||
return reinterpret_cast<T*>(stackTop_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Top() const {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
template<typename T>
|
||||
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
bool HasAllocator() const {
|
||||
return allocator_ != 0;
|
||||
}
|
||||
|
||||
Allocator& GetAllocator() {
|
||||
RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
|
||||
bool Empty() const { return stackTop_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void Expand(size_t count) {
|
||||
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||
size_t newCapacity;
|
||||
if (stack_ == 0) {
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||
newCapacity = initialCapacity_;
|
||||
} else {
|
||||
newCapacity = GetCapacity();
|
||||
newCapacity += (newCapacity + 1) / 2;
|
||||
}
|
||||
size_t newSize = GetSize() + sizeof(T) * count;
|
||||
if (newCapacity < newSize)
|
||||
newCapacity = newSize;
|
||||
|
||||
Resize(newCapacity);
|
||||
}
|
||||
|
||||
void Resize(size_t newCapacity) {
|
||||
const size_t size = GetSize(); // Backup the current size
|
||||
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||
stackTop_ = stack_ + size;
|
||||
stackEnd_ = stack_ + newCapacity;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
Allocator::Free(stack_);
|
||||
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
char *stack_;
|
||||
char *stackTop_;
|
||||
char *stackEnd_;
|
||||
size_t initialCapacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
55
include/rapidjson/internal/strfunc.h
Normal file
55
include/rapidjson/internal/strfunc.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
#include "../stream.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
//! Returns number of code points in a encoded string.
|
||||
template<typename Encoding>
|
||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
const typename Encoding::Ch* end = s + length;
|
||||
SizeType count = 0;
|
||||
while (is.src_ < end) {
|
||||
unsigned codepoint;
|
||||
if (!Encoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
*outCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
269
include/rapidjson/internal/strtod.h
Normal file
269
include/rapidjson/internal/strtod.h
Normal file
@@ -0,0 +1,269 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_STRTOD_
|
||||
#define RAPIDJSON_STRTOD_
|
||||
|
||||
#include "ieee754.h"
|
||||
#include "biginteger.h"
|
||||
#include "diyfp.h"
|
||||
#include "pow10.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
inline double FastPath(double significand, int exp) {
|
||||
if (exp < -308)
|
||||
return 0.0;
|
||||
else if (exp >= 0)
|
||||
return significand * internal::Pow10(exp);
|
||||
else
|
||||
return significand / internal::Pow10(-exp);
|
||||
}
|
||||
|
||||
inline double StrtodNormalPrecision(double d, int p) {
|
||||
if (p < -308) {
|
||||
// Prevent expSum < -308, making Pow10(p) = 0
|
||||
d = FastPath(d, -308);
|
||||
d = FastPath(d, p + 308);
|
||||
}
|
||||
else
|
||||
d = FastPath(d, p);
|
||||
return d;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Min3(T a, T b, T c) {
|
||||
T m = a;
|
||||
if (m > b) m = b;
|
||||
if (m > c) m = c;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||
const Double db(b);
|
||||
const uint64_t bInt = db.IntegerSignificand();
|
||||
const int bExp = db.IntegerExponent();
|
||||
const int hExp = bExp - 1;
|
||||
|
||||
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
|
||||
|
||||
// Adjust for decimal exponent
|
||||
if (dExp >= 0) {
|
||||
dS_Exp2 += dExp;
|
||||
dS_Exp5 += dExp;
|
||||
}
|
||||
else {
|
||||
bS_Exp2 -= dExp;
|
||||
bS_Exp5 -= dExp;
|
||||
hS_Exp2 -= dExp;
|
||||
hS_Exp5 -= dExp;
|
||||
}
|
||||
|
||||
// Adjust for binary exponent
|
||||
if (bExp >= 0)
|
||||
bS_Exp2 += bExp;
|
||||
else {
|
||||
dS_Exp2 -= bExp;
|
||||
hS_Exp2 -= bExp;
|
||||
}
|
||||
|
||||
// Adjust for half ulp exponent
|
||||
if (hExp >= 0)
|
||||
hS_Exp2 += hExp;
|
||||
else {
|
||||
dS_Exp2 -= hExp;
|
||||
bS_Exp2 -= hExp;
|
||||
}
|
||||
|
||||
// Remove common power of two factor from all three scaled values
|
||||
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
|
||||
dS_Exp2 -= common_Exp2;
|
||||
bS_Exp2 -= common_Exp2;
|
||||
hS_Exp2 -= common_Exp2;
|
||||
|
||||
BigInteger dS = d;
|
||||
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||
|
||||
BigInteger bS(bInt);
|
||||
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||
|
||||
BigInteger hS(1);
|
||||
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||
|
||||
BigInteger delta(0);
|
||||
dS.Difference(bS, &delta);
|
||||
|
||||
return delta.Compare(hS);
|
||||
}
|
||||
|
||||
inline bool StrtodFast(double d, int p, double* result) {
|
||||
// Use fast path for string-to-double conversion if possible
|
||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
if (p > 22 && p < 22 + 16) {
|
||||
// Fast Path Cases In Disguise
|
||||
d *= internal::Pow10(p - 22);
|
||||
p = 22;
|
||||
}
|
||||
|
||||
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||
*result = FastPath(d, p);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute an approximation and see if it is within 1/2 ULP
|
||||
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
||||
uint64_t significand = 0;
|
||||
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||
for (; i < length; i++) {
|
||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||
break;
|
||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||
}
|
||||
|
||||
if (i < length && decimals[i] >= '5') // Rounding
|
||||
significand++;
|
||||
|
||||
size_t remaining = length - i;
|
||||
const unsigned kUlpShift = 3;
|
||||
const unsigned kUlp = 1 << kUlpShift;
|
||||
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||
|
||||
DiyFp v(significand, 0);
|
||||
v = v.Normalize();
|
||||
error <<= -v.e;
|
||||
|
||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
|
||||
|
||||
int actualExp;
|
||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||
if (actualExp != dExp) {
|
||||
static const DiyFp kPow10[] = {
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
||||
};
|
||||
int adjustment = dExp - actualExp - 1;
|
||||
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
||||
v = v * kPow10[adjustment];
|
||||
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
||||
error += kUlp / 2;
|
||||
}
|
||||
|
||||
v = v * cachedPower;
|
||||
|
||||
error += kUlp + (error == 0 ? 0 : 1);
|
||||
|
||||
const int oldExp = v.e;
|
||||
v = v.Normalize();
|
||||
error <<= oldExp - v.e;
|
||||
|
||||
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
|
||||
unsigned precisionSize = 64 - effectiveSignificandSize;
|
||||
if (precisionSize + kUlpShift >= 64) {
|
||||
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
|
||||
v.f >>= scaleExp;
|
||||
v.e += scaleExp;
|
||||
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
|
||||
precisionSize -= scaleExp;
|
||||
}
|
||||
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
|
||||
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||
rounded.f++;
|
||||
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||
rounded.f >>= 1;
|
||||
rounded.e++;
|
||||
}
|
||||
}
|
||||
|
||||
*result = rounded.ToDouble();
|
||||
|
||||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||
}
|
||||
|
||||
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
const BigInteger dInt(decimals, length);
|
||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
|
||||
Double a(approx);
|
||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||
if (cmp < 0)
|
||||
return a.Value(); // within half ULP
|
||||
else if (cmp == 0) {
|
||||
// Round towards even
|
||||
if (a.Significand() & 1)
|
||||
return a.NextPositiveDouble();
|
||||
else
|
||||
return a.Value();
|
||||
}
|
||||
else // adjustment
|
||||
return a.NextPositiveDouble();
|
||||
}
|
||||
|
||||
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
RAPIDJSON_ASSERT(d >= 0.0);
|
||||
RAPIDJSON_ASSERT(length >= 1);
|
||||
|
||||
double result;
|
||||
if (StrtodFast(d, p, &result))
|
||||
return result;
|
||||
|
||||
// Trim leading zeros
|
||||
while (*decimals == '0' && length > 1) {
|
||||
length--;
|
||||
decimals++;
|
||||
decimalPosition--;
|
||||
}
|
||||
|
||||
// Trim trailing zeros
|
||||
while (decimals[length - 1] == '0' && length > 1) {
|
||||
length--;
|
||||
decimalPosition--;
|
||||
exp++;
|
||||
}
|
||||
|
||||
// Trim right-most digits
|
||||
const int kMaxDecimalDigit = 780;
|
||||
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
||||
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
||||
exp += delta;
|
||||
decimalPosition -= static_cast<unsigned>(delta);
|
||||
length = kMaxDecimalDigit;
|
||||
}
|
||||
|
||||
// If too small, underflow to zero
|
||||
if (int(length) + exp < -324)
|
||||
return 0.0;
|
||||
|
||||
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
|
||||
return result;
|
||||
|
||||
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_STRTOD_
|
||||
46
include/rapidjson/internal/swap.h
Normal file
46
include/rapidjson/internal/swap.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||
\note This has the same semantics as std::swap().
|
||||
*/
|
||||
template <typename T>
|
||||
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
||||
115
include/rapidjson/istreamwrapper.h
Normal file
115
include/rapidjson/istreamwrapper.h
Normal file
@@ -0,0 +1,115 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
#define RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
|
||||
/*!
|
||||
The classes can be wrapped including but not limited to:
|
||||
|
||||
- \c std::istringstream
|
||||
- \c std::stringstream
|
||||
- \c std::wistringstream
|
||||
- \c std::wstringstream
|
||||
- \c std::ifstream
|
||||
- \c std::fstream
|
||||
- \c std::wifstream
|
||||
- \c std::wfstream
|
||||
|
||||
\tparam StreamType Class derived from \c std::basic_istream.
|
||||
*/
|
||||
|
||||
template <typename StreamType>
|
||||
class BasicIStreamWrapper {
|
||||
public:
|
||||
typedef typename StreamType::char_type Ch;
|
||||
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
|
||||
|
||||
Ch Peek() const {
|
||||
typename StreamType::int_type c = stream_.peek();
|
||||
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
|
||||
}
|
||||
|
||||
Ch Take() {
|
||||
typename StreamType::int_type c = stream_.get();
|
||||
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
|
||||
count_++;
|
||||
return static_cast<Ch>(c);
|
||||
}
|
||||
else
|
||||
return '\0';
|
||||
}
|
||||
|
||||
// tellg() may return -1 when failed. So we count by ourself.
|
||||
size_t Tell() const { return count_; }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
|
||||
int i;
|
||||
bool hasError = false;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
typename StreamType::int_type c = stream_.get();
|
||||
if (c == StreamType::traits_type::eof()) {
|
||||
hasError = true;
|
||||
stream_.clear();
|
||||
break;
|
||||
}
|
||||
peekBuffer_[i] = static_cast<Ch>(c);
|
||||
}
|
||||
for (--i; i >= 0; --i)
|
||||
stream_.putback(peekBuffer_[i]);
|
||||
return !hasError ? peekBuffer_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
||||
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
||||
|
||||
StreamType& stream_;
|
||||
size_t count_; //!< Number of characters read. Note:
|
||||
mutable Ch peekBuffer_[4];
|
||||
};
|
||||
|
||||
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
||||
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
70
include/rapidjson/memorybuffer.h
Normal file
70
include/rapidjson/memorybuffer.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_MEMORYBUFFER_H_
|
||||
#define RAPIDJSON_MEMORYBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output byte stream.
|
||||
/*!
|
||||
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
|
||||
|
||||
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
|
||||
|
||||
Differences between MemoryBuffer and StringBuffer:
|
||||
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
|
||||
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
|
||||
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Allocator = CrtAllocator>
|
||||
struct GenericMemoryBuffer {
|
||||
typedef char Ch; // byte
|
||||
|
||||
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() { stack_.ShrinkToFit(); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||
|
||||
const Ch* GetBuffer() const {
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
typedef GenericMemoryBuffer<> MemoryBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
|
||||
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||
71
include/rapidjson/memorystream.h
Normal file
71
include/rapidjson/memorystream.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_MEMORYSTREAM_H_
|
||||
#define RAPIDJSON_MEMORYSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory input byte stream.
|
||||
/*!
|
||||
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
|
||||
|
||||
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
|
||||
|
||||
Differences between MemoryStream and StringStream:
|
||||
1. StringStream has encoding but MemoryStream is a byte stream.
|
||||
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
|
||||
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
|
||||
\note implements Stream concept
|
||||
*/
|
||||
struct MemoryStream {
|
||||
typedef char Ch; // byte
|
||||
|
||||
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
|
||||
|
||||
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
|
||||
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return Tell() + 4 <= size_ ? src_ : 0;
|
||||
}
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* begin_; //!< Original head of the string.
|
||||
const Ch* end_; //!< End of stream.
|
||||
size_t size_; //!< Size of the stream.
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||
316
include/rapidjson/msinttypes/inttypes.h
Normal file
316
include/rapidjson/msinttypes/inttypes.h
Normal file
@@ -0,0 +1,316 @@
|
||||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The above software in this distribution may have been modified by
|
||||
// THL A29 Limited ("Tencent Modifications").
|
||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// miloyip: VC supports inttypes.h since VC2013
|
||||
#if _MSC_VER >= 1800
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNdLEAST8 "d"
|
||||
#define SCNiLEAST8 "i"
|
||||
#define SCNdFAST8 "d"
|
||||
#define SCNiFAST8 "i"
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
#define SCNoLEAST8 "o"
|
||||
#define SCNuLEAST8 "u"
|
||||
#define SCNxLEAST8 "x"
|
||||
#define SCNXLEAST8 "X"
|
||||
#define SCNoFAST8 "o"
|
||||
#define SCNuFAST8 "u"
|
||||
#define SCNxFAST8 "x"
|
||||
#define SCNXFAST8 "X"
|
||||
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
#endif // _MSC_VER >= 1800
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
||||
300
include/rapidjson/msinttypes/stdint.h
Normal file
300
include/rapidjson/msinttypes/stdint.h
Normal file
@@ -0,0 +1,300 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The above software in this distribution may have been modified by
|
||||
// THL A29 Limited ("Tencent Modifications").
|
||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
|
||||
#if _MSC_VER >= 1600 // [
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
#undef INT8_C
|
||||
#undef INT16_C
|
||||
#undef INT32_C
|
||||
#undef INT64_C
|
||||
#undef UINT8_C
|
||||
#undef UINT16_C
|
||||
#undef UINT32_C
|
||||
#undef UINT64_C
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#else // ] _MSC_VER >= 1700 [
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler would give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#endif // _MSC_VER >= 1600 ]
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
81
include/rapidjson/ostreamwrapper.h
Normal file
81
include/rapidjson/ostreamwrapper.h
Normal file
@@ -0,0 +1,81 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
#define RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
|
||||
/*!
|
||||
The classes can be wrapped including but not limited to:
|
||||
|
||||
- \c std::ostringstream
|
||||
- \c std::stringstream
|
||||
- \c std::wpstringstream
|
||||
- \c std::wstringstream
|
||||
- \c std::ifstream
|
||||
- \c std::fstream
|
||||
- \c std::wofstream
|
||||
- \c std::wfstream
|
||||
|
||||
\tparam StreamType Class derived from \c std::basic_ostream.
|
||||
*/
|
||||
|
||||
template <typename StreamType>
|
||||
class BasicOStreamWrapper {
|
||||
public:
|
||||
typedef typename StreamType::char_type Ch;
|
||||
BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
|
||||
|
||||
void Put(Ch c) {
|
||||
stream_.put(c);
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
stream_.flush();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
BasicOStreamWrapper(const BasicOStreamWrapper&);
|
||||
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
|
||||
|
||||
StreamType& stream_;
|
||||
};
|
||||
|
||||
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
|
||||
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
1358
include/rapidjson/pointer.h
Normal file
1358
include/rapidjson/pointer.h
Normal file
File diff suppressed because it is too large
Load Diff
255
include/rapidjson/prettywriter.h
Normal file
255
include/rapidjson/prettywriter.h
Normal file
@@ -0,0 +1,255 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Combination of PrettyWriter format flags.
|
||||
/*! \see PrettyWriter::SetFormatOptions
|
||||
*/
|
||||
enum PrettyFormatOptions {
|
||||
kFormatDefault = 0, //!< Default pretty formatting.
|
||||
kFormatSingleLineArray = 1 //!< Format arrays on a single line.
|
||||
};
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam OutputStream Type of ouptut os.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
|
||||
public:
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
|
||||
|
||||
|
||||
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Set pretty writer formatting options.
|
||||
/*! \param options Formatting options.
|
||||
*/
|
||||
PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
|
||||
formatOptions_ = options;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! @name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
|
||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
|
||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
|
||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
|
||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
||||
|
||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kNumberType);
|
||||
return Base::WriteString(str, length);
|
||||
}
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::WriteString(str, length);
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& str) {
|
||||
return String(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool Key(const std::basic_string<Ch>& str) {
|
||||
return Key(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
bool ret = Base::WriteEndObject();
|
||||
(void)ret;
|
||||
RAPIDJSON_ASSERT(ret == true);
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
return Base::WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
bool ret = Base::WriteEndArray();
|
||||
(void)ret;
|
||||
RAPIDJSON_ASSERT(ret == true);
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
//! Write a raw JSON value.
|
||||
/*!
|
||||
For user to write a stringified JSON as a value.
|
||||
|
||||
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||
\param length Length of the json.
|
||||
\param type Type of the root of json.
|
||||
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
|
||||
*/
|
||||
bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
|
||||
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||
if (formatOptions_ & kFormatSingleLineArray)
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
|
||||
if (!(formatOptions_ & kFormatSingleLineArray)) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::os_->Put(',');
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::os_->Put(':');
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||
Base::hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
PrettyFormatOptions formatOptions_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
615
include/rapidjson/rapidjson.h
Normal file
615
include/rapidjson/rapidjson.h
Normal file
@@ -0,0 +1,615 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
/*!\file rapidjson.h
|
||||
\brief common definitions and configuration
|
||||
|
||||
\see RAPIDJSON_CONFIG
|
||||
*/
|
||||
|
||||
/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
|
||||
\brief Configuration macros for library features
|
||||
|
||||
Some RapidJSON features are configurable to adapt the library to a wide
|
||||
variety of platforms, environments and usage scenarios. Most of the
|
||||
features can be configured in terms of overriden or predefined
|
||||
preprocessor macros at compile-time.
|
||||
|
||||
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
|
||||
|
||||
\note These macros should be given on the compiler command-line
|
||||
(where applicable) to avoid inconsistent values when compiling
|
||||
different translation units of a single application.
|
||||
*/
|
||||
|
||||
#include <cstdlib> // malloc(), realloc(), free(), size_t
|
||||
#include <cstring> // memset(), memcpy(), memmove(), memcmp()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_VERSION_STRING
|
||||
//
|
||||
// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
|
||||
//
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
// token stringification
|
||||
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
|
||||
#define RAPIDJSON_DO_STRINGIFY(x) #x
|
||||
//!@endcond
|
||||
|
||||
/*! \def RAPIDJSON_MAJOR_VERSION
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Major version of RapidJSON in integer.
|
||||
*/
|
||||
/*! \def RAPIDJSON_MINOR_VERSION
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Minor version of RapidJSON in integer.
|
||||
*/
|
||||
/*! \def RAPIDJSON_PATCH_VERSION
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Patch version of RapidJSON in integer.
|
||||
*/
|
||||
/*! \def RAPIDJSON_VERSION_STRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
|
||||
*/
|
||||
#define RAPIDJSON_MAJOR_VERSION 1
|
||||
#define RAPIDJSON_MINOR_VERSION 1
|
||||
#define RAPIDJSON_PATCH_VERSION 0
|
||||
#define RAPIDJSON_VERSION_STRING \
|
||||
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NAMESPACE_(BEGIN|END)
|
||||
/*! \def RAPIDJSON_NAMESPACE
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief provide custom rapidjson namespace
|
||||
|
||||
In order to avoid symbol clashes and/or "One Definition Rule" errors
|
||||
between multiple inclusions of (different versions of) RapidJSON in
|
||||
a single binary, users can customize the name of the main RapidJSON
|
||||
namespace.
|
||||
|
||||
In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
|
||||
to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
|
||||
levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
|
||||
RAPIDJSON_NAMESPACE_END need to be defined as well:
|
||||
|
||||
\code
|
||||
// in some .cpp file
|
||||
#define RAPIDJSON_NAMESPACE my::rapidjson
|
||||
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
|
||||
#define RAPIDJSON_NAMESPACE_END } }
|
||||
#include "rapidjson/..."
|
||||
\endcode
|
||||
|
||||
\see rapidjson
|
||||
*/
|
||||
/*! \def RAPIDJSON_NAMESPACE_BEGIN
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief provide custom rapidjson namespace (opening expression)
|
||||
\see RAPIDJSON_NAMESPACE
|
||||
*/
|
||||
/*! \def RAPIDJSON_NAMESPACE_END
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief provide custom rapidjson namespace (closing expression)
|
||||
\see RAPIDJSON_NAMESPACE
|
||||
*/
|
||||
#ifndef RAPIDJSON_NAMESPACE
|
||||
#define RAPIDJSON_NAMESPACE rapidjson
|
||||
#endif
|
||||
#ifndef RAPIDJSON_NAMESPACE_BEGIN
|
||||
#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
|
||||
#endif
|
||||
#ifndef RAPIDJSON_NAMESPACE_END
|
||||
#define RAPIDJSON_NAMESPACE_END }
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||
#else
|
||||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||
#endif
|
||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable RapidJSON support for \c std::string
|
||||
|
||||
By defining this preprocessor symbol to \c 1, several convenience functions for using
|
||||
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
||||
for construction and comparison.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#endif // !defined(RAPIDJSON_HAS_STDSTRING)
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
#include <string>
|
||||
#endif // RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
/*! \def RAPIDJSON_NO_INT64DEFINE
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Use external 64-bit integer types.
|
||||
|
||||
RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
|
||||
to be available at global scope.
|
||||
|
||||
If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
|
||||
prevent RapidJSON from defining its own types.
|
||||
*/
|
||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
|
||||
#include "msinttypes/stdint.h"
|
||||
#include "msinttypes/inttypes.h"
|
||||
#else
|
||||
// Other compilers should have this.
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
//!@endcond
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_NO_INT64DEFINE
|
||||
#endif
|
||||
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_FORCEINLINE
|
||||
|
||||
#ifndef RAPIDJSON_FORCEINLINE
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#if defined(_MSC_VER) && defined(NDEBUG)
|
||||
#define RAPIDJSON_FORCEINLINE __forceinline
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
|
||||
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
|
||||
#else
|
||||
#define RAPIDJSON_FORCEINLINE
|
||||
#endif
|
||||
//!@endcond
|
||||
#endif // RAPIDJSON_FORCEINLINE
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ENDIAN
|
||||
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||
|
||||
//! Endianness of the machine.
|
||||
/*!
|
||||
\def RAPIDJSON_ENDIAN
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
|
||||
GCC 4.6 provided macro for detecting endianness of the target machine. But other
|
||||
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
|
||||
\ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
|
||||
|
||||
Default detection implemented with reference to
|
||||
\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
|
||||
\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
|
||||
*/
|
||||
#ifndef RAPIDJSON_ENDIAN
|
||||
// Detect with GCC 4.6's macro
|
||||
# ifdef __BYTE_ORDER__
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __BYTE_ORDER__
|
||||
// Detect with GLIBC's endian.h
|
||||
# elif defined(__GLIBC__)
|
||||
# include <endian.h>
|
||||
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __GLIBC__
|
||||
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
|
||||
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
// Detect with architecture macros
|
||||
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(_MSC_VER) && defined(_M_ARM)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||
# define RAPIDJSON_ENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif
|
||||
#endif // RAPIDJSON_ENDIAN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_64BIT
|
||||
|
||||
//! Whether using 64-bit architecture
|
||||
#ifndef RAPIDJSON_64BIT
|
||||
#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
|
||||
#define RAPIDJSON_64BIT 1
|
||||
#else
|
||||
#define RAPIDJSON_64BIT 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_64BIT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ALIGN
|
||||
|
||||
//! Data alignment of the machine.
|
||||
/*! \ingroup RAPIDJSON_CONFIG
|
||||
\param x pointer to align
|
||||
|
||||
Some machines require strict data alignment. Currently the default uses 4 bytes
|
||||
alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
|
||||
User can customize by defining the RAPIDJSON_ALIGN function macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ALIGN
|
||||
#if RAPIDJSON_64BIT == 1
|
||||
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
|
||||
#else
|
||||
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_UINT64_C2
|
||||
|
||||
//! Construct a 64-bit literal by a pair of 32-bit integer.
|
||||
/*!
|
||||
64-bit literal with or without ULL suffix is prone to compiler warnings.
|
||||
UINT64_C() is C macro which cause compilation problems.
|
||||
Use this macro to define 64-bit constants by a pair of 32-bit integer.
|
||||
*/
|
||||
#ifndef RAPIDJSON_UINT64_C2
|
||||
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
|
||||
//! Use only lower 48-bit address for some pointers.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
|
||||
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
|
||||
The higher 16-bit can be used for storing other data.
|
||||
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
|
||||
*/
|
||||
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
||||
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
|
||||
#else
|
||||
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
|
||||
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
|
||||
#if RAPIDJSON_64BIT != 1
|
||||
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
|
||||
#endif
|
||||
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
|
||||
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
|
||||
#else
|
||||
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
|
||||
#define RAPIDJSON_GETPOINTER(type, p) (p)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||
|
||||
/*! \def RAPIDJSON_SIMD
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable SSE2/SSE4.2 optimization.
|
||||
|
||||
RapidJSON supports optimized implementations for some parsing operations
|
||||
based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
|
||||
processors.
|
||||
|
||||
To enable these optimizations, two different symbols can be defined;
|
||||
\code
|
||||
// Enable SSE2 optimization.
|
||||
#define RAPIDJSON_SSE2
|
||||
|
||||
// Enable SSE4.2 optimization.
|
||||
#define RAPIDJSON_SSE42
|
||||
\endcode
|
||||
|
||||
\c RAPIDJSON_SSE42 takes precedence, if both are defined.
|
||||
|
||||
If any of these symbols is defined, RapidJSON defines the macro
|
||||
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
|
||||
*/
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
|
||||
|| defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||
#define RAPIDJSON_SIMD
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
|
||||
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief User-provided \c SizeType definition.
|
||||
|
||||
In order to avoid using 32-bit size types for indexing strings and arrays,
|
||||
define this preprocessor symbol and provide the type rapidjson::SizeType
|
||||
before including RapidJSON:
|
||||
\code
|
||||
#define RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
namespace rapidjson { typedef ::std::size_t SizeType; }
|
||||
#include "rapidjson/..."
|
||||
\endcode
|
||||
|
||||
\see rapidjson::SizeType
|
||||
*/
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
#endif
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
//! Size type (for string lengths, array sizes, etc.)
|
||||
/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
|
||||
instead of using \c size_t. Users may override the SizeType by defining
|
||||
\ref RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||
*/
|
||||
typedef unsigned SizeType;
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
#endif
|
||||
|
||||
// always import std::size_t to rapidjson namespace
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
using std::size_t;
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ASSERT
|
||||
|
||||
//! Assertion.
|
||||
/*! \ingroup RAPIDJSON_CONFIG
|
||||
By default, rapidjson uses C \c assert() for internal assertions.
|
||||
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||
|
||||
\note Parsing errors are handled and can be customized by the
|
||||
\ref RAPIDJSON_ERRORS APIs.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_STATIC_ASSERT
|
||||
|
||||
// Adopt from boost
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
#ifndef __clang__
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#endif
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||
template<int x> struct StaticAssertTest {};
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
|
||||
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
|
||||
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
||||
#else
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
#ifndef __clang__
|
||||
//!@endcond
|
||||
#endif
|
||||
|
||||
/*! \def RAPIDJSON_STATIC_ASSERT
|
||||
\brief (Internal) macro to check for conditions at compile-time
|
||||
\param x compile-time condition
|
||||
\hideinitializer
|
||||
*/
|
||||
#define RAPIDJSON_STATIC_ASSERT(x) \
|
||||
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
|
||||
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
|
||||
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
|
||||
|
||||
//! Compiler branching hint for expression with high probability to be true.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\param x Boolean expression likely to be true.
|
||||
*/
|
||||
#ifndef RAPIDJSON_LIKELY
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#else
|
||||
#define RAPIDJSON_LIKELY(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//! Compiler branching hint for expression with low probability to be true.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\param x Boolean expression unlikely to be true.
|
||||
*/
|
||||
#ifndef RAPIDJSON_UNLIKELY
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define RAPIDJSON_UNLIKELY(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
|
||||
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
|
||||
#define RAPIDJSON_MULTILINEMACRO_END \
|
||||
} while((void)0, 0)
|
||||
|
||||
// adopted from Boost
|
||||
#define RAPIDJSON_VERSION_CODE(x,y,z) \
|
||||
(((x)*100000) + ((y)*100) + (z))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define RAPIDJSON_GNUC \
|
||||
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
|
||||
|
||||
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
|
||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
|
||||
#define RAPIDJSON_DIAG_OFF(x) \
|
||||
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
|
||||
|
||||
// push/pop support in Clang and GCC>=4.6
|
||||
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
|
||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
#else // GCC >= 4.2, < 4.6
|
||||
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
// pragma (MSVC specific)
|
||||
#define RAPIDJSON_PRAGMA(x) __pragma(x)
|
||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
|
||||
|
||||
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
|
||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
|
||||
#else
|
||||
|
||||
#define RAPIDJSON_DIAG_OFF(x) /* ignored */
|
||||
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||
|
||||
#endif // RAPIDJSON_DIAG_*
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// C++11 features
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#if defined(__clang__)
|
||||
#if __has_feature(cxx_rvalue_references) && \
|
||||
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||
#endif
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1600)
|
||||
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#if defined(__clang__)
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||
#endif
|
||||
#endif
|
||||
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#define RAPIDJSON_NOEXCEPT noexcept
|
||||
#else
|
||||
#define RAPIDJSON_NOEXCEPT /* noexcept */
|
||||
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
|
||||
// no automatic detection, yet
|
||||
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||
#if defined(__clang__)
|
||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1700)
|
||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||
|
||||
//!@endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// new/delete
|
||||
|
||||
#ifndef RAPIDJSON_NEW
|
||||
///! customization point for global \c new
|
||||
#define RAPIDJSON_NEW(x) new x
|
||||
#endif
|
||||
#ifndef RAPIDJSON_DELETE
|
||||
///! customization point for global \c delete
|
||||
#define RAPIDJSON_DELETE(x) delete x
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Type
|
||||
|
||||
/*! \namespace rapidjson
|
||||
\brief main RapidJSON namespace
|
||||
\see RAPIDJSON_NAMESPACE
|
||||
*/
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Type of JSON value
|
||||
enum Type {
|
||||
kNullType = 0, //!< null
|
||||
kFalseType = 1, //!< false
|
||||
kTrueType = 2, //!< true
|
||||
kObjectType = 3, //!< object
|
||||
kArrayType = 4, //!< array
|
||||
kStringType = 5, //!< string
|
||||
kNumberType = 6 //!< number
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
1879
include/rapidjson/reader.h
Normal file
1879
include/rapidjson/reader.h
Normal file
File diff suppressed because it is too large
Load Diff
2006
include/rapidjson/schema.h
Normal file
2006
include/rapidjson/schema.h
Normal file
File diff suppressed because it is too large
Load Diff
179
include/rapidjson/stream.h
Normal file
179
include/rapidjson/stream.h
Normal file
@@ -0,0 +1,179 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifndef RAPIDJSON_STREAM_H_
|
||||
#define RAPIDJSON_STREAM_H_
|
||||
|
||||
#include "encodings.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stream
|
||||
|
||||
/*! \class rapidjson::Stream
|
||||
\brief Concept for reading and writing characters.
|
||||
|
||||
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
|
||||
|
||||
For write-only stream, only need to implement Put() and Flush().
|
||||
|
||||
\code
|
||||
concept Stream {
|
||||
typename Ch; //!< Character type of the stream.
|
||||
|
||||
//! Read the current character from stream without moving the read cursor.
|
||||
Ch Peek() const;
|
||||
|
||||
//! Read the current character from stream and moving the read cursor to next character.
|
||||
Ch Take();
|
||||
|
||||
//! Get the current read cursor.
|
||||
//! \return Number of characters read from start.
|
||||
size_t Tell();
|
||||
|
||||
//! Begin writing operation at the current read pointer.
|
||||
//! \return The begin writer pointer.
|
||||
Ch* PutBegin();
|
||||
|
||||
//! Write a character.
|
||||
void Put(Ch c);
|
||||
|
||||
//! Flush the buffer.
|
||||
void Flush();
|
||||
|
||||
//! End the writing operation.
|
||||
//! \param begin The begin write pointer returned by PutBegin().
|
||||
//! \return Number of characters written.
|
||||
size_t PutEnd(Ch* begin);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//! Provides additional information for stream.
|
||||
/*!
|
||||
By using traits pattern, this type provides a default configuration for stream.
|
||||
For custom stream, this type can be specialized for other configuration.
|
||||
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||
*/
|
||||
template<typename Stream>
|
||||
struct StreamTraits {
|
||||
//! Whether to make local copy of stream for optimization during parsing.
|
||||
/*!
|
||||
By default, for safety, streams do not use local copy optimization.
|
||||
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||
*/
|
||||
enum { copyOptimization = 0 };
|
||||
};
|
||||
|
||||
//! Reserve n characters for writing to a stream.
|
||||
template<typename Stream>
|
||||
inline void PutReserve(Stream& stream, size_t count) {
|
||||
(void)stream;
|
||||
(void)count;
|
||||
}
|
||||
|
||||
//! Write character to a stream, presuming buffer is reserved.
|
||||
template<typename Stream>
|
||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
PutReserve(stream, n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
PutUnsafe(stream, c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||
|
||||
Ch Peek() const { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* head_; //!< Original head of the string.
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! String stream with UTF8 encoding.
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||
|
||||
// Read
|
||||
Ch Peek() { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
// Write
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
|
||||
void Flush() {}
|
||||
|
||||
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
|
||||
void Pop(size_t count) { dst_ -= count; }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! Insitu string stream with UTF8 encoding.
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_STREAM_H_
|
||||
117
include/rapidjson/stringbuffer.h
Normal file
117
include/rapidjson/stringbuffer.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#endif
|
||||
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericStringBuffer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
|
||||
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
|
||||
if (&rhs != this)
|
||||
stack_ = std::move(rhs.stack_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.ShrinkToFit();
|
||||
stack_.template Pop<Ch>(1);
|
||||
}
|
||||
|
||||
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
|
||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||
|
||||
const Ch* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
GenericStringBuffer(const GenericStringBuffer&);
|
||||
GenericStringBuffer& operator=(const GenericStringBuffer&);
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||
stream.Reserve(count);
|
||||
}
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||
stream.PutUnsafe(c);
|
||||
}
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
610
include/rapidjson/writer.h
Normal file
610
include/rapidjson/writer.h
Normal file
@@ -0,0 +1,610 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_WRITER_H_
|
||||
#define RAPIDJSON_WRITER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include "internal/dtoa.h"
|
||||
#include "internal/itoa.h"
|
||||
#include "stringbuffer.h"
|
||||
#include <new> // placement new
|
||||
|
||||
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WriteFlag
|
||||
|
||||
/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief User-defined kWriteDefaultFlags definition.
|
||||
|
||||
User can define this as any \c WriteFlag combinations.
|
||||
*/
|
||||
#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
|
||||
#endif
|
||||
|
||||
//! Combination of writeFlags
|
||||
enum WriteFlag {
|
||||
kWriteNoFlags = 0, //!< No flags are set.
|
||||
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
|
||||
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
|
||||
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
};
|
||||
|
||||
//! JSON writer
|
||||
/*! Writer implements the concept Handler.
|
||||
It generates JSON text by events to an output os.
|
||||
|
||||
User may programmatically calls the functions of a writer to generate JSON text.
|
||||
|
||||
On the other side, a writer can also be passed to objects that generates events,
|
||||
|
||||
for example Reader::Parse() and Document::Accept().
|
||||
|
||||
\tparam OutputStream Type of output stream.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||
\note implements Handler concept
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||
class Writer {
|
||||
public:
|
||||
typedef typename SourceEncoding::Ch Ch;
|
||||
|
||||
static const int kDefaultMaxDecimalPlaces = 324;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param stackAllocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
explicit
|
||||
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
|
||||
|
||||
explicit
|
||||
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
|
||||
|
||||
//! Reset the writer with a new stream.
|
||||
/*!
|
||||
This function reset the writer with a new stream and default settings,
|
||||
in order to make a Writer object reusable for output multiple JSONs.
|
||||
|
||||
\param os New output stream.
|
||||
\code
|
||||
Writer<OutputStream> writer(os1);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
|
||||
writer.Reset(os2);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
\endcode
|
||||
*/
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
hasRoot_ = false;
|
||||
level_stack_.Clear();
|
||||
}
|
||||
|
||||
//! Checks whether the output is a complete JSON.
|
||||
/*!
|
||||
A complete JSON has a complete root object or array.
|
||||
*/
|
||||
bool IsComplete() const {
|
||||
return hasRoot_ && level_stack_.Empty();
|
||||
}
|
||||
|
||||
int GetMaxDecimalPlaces() const {
|
||||
return maxDecimalPlaces_;
|
||||
}
|
||||
|
||||
//! Sets the maximum number of decimal places for double output.
|
||||
/*!
|
||||
This setting truncates the output with specified number of decimal places.
|
||||
|
||||
For example,
|
||||
|
||||
\code
|
||||
writer.SetMaxDecimalPlaces(3);
|
||||
writer.StartArray();
|
||||
writer.Double(0.12345); // "0.123"
|
||||
writer.Double(0.0001); // "0.0"
|
||||
writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
|
||||
writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
|
||||
writer.EndArray();
|
||||
\endcode
|
||||
|
||||
The default setting does not truncate any decimal places. You can restore to this setting by calling
|
||||
\code
|
||||
writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
|
||||
\endcode
|
||||
*/
|
||||
void SetMaxDecimalPlaces(int maxDecimalPlaces) {
|
||||
maxDecimalPlaces_ = maxDecimalPlaces;
|
||||
}
|
||||
|
||||
/*!@name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
|
||||
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
|
||||
bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
|
||||
bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
|
||||
bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
|
||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
|
||||
|
||||
//! Writes the given \c double value to the stream
|
||||
/*!
|
||||
\param d The value to be written.
|
||||
\return Whether it is succeed.
|
||||
*/
|
||||
bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
|
||||
|
||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kNumberType);
|
||||
return EndValue(WriteString(str, length));
|
||||
}
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
return EndValue(WriteString(str, length));
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& str) {
|
||||
return String(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
return WriteStartObject();
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
return EndValue(WriteEndObject());
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
Prefix(kArrayType);
|
||||
new (level_stack_.template Push<Level>()) Level(true);
|
||||
return WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType elementCount = 0) {
|
||||
(void)elementCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
return EndValue(WriteEndArray());
|
||||
}
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
//! Write a raw JSON value.
|
||||
/*!
|
||||
For user to write a stringified JSON as a value.
|
||||
|
||||
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||
\param length Length of the json.
|
||||
\param type Type of the root of json.
|
||||
*/
|
||||
bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }
|
||||
|
||||
protected:
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
|
||||
size_t valueCount; //!< number of values in this level
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
};
|
||||
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
|
||||
bool WriteNull() {
|
||||
PutReserve(*os_, 4);
|
||||
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
|
||||
}
|
||||
|
||||
bool WriteBool(bool b) {
|
||||
if (b) {
|
||||
PutReserve(*os_, 4);
|
||||
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
|
||||
}
|
||||
else {
|
||||
PutReserve(*os_, 5);
|
||||
PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
char buffer[11];
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
char buffer[21];
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char* end = internal::u64toa(u64, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDouble(double d) {
|
||||
if (internal::Double(d).IsNanOrInf()) {
|
||||
if (!(writeFlags & kWriteNanAndInfFlag))
|
||||
return false;
|
||||
if (internal::Double(d).IsNan()) {
|
||||
PutReserve(*os_, 3);
|
||||
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||
return true;
|
||||
}
|
||||
if (internal::Double(d).Sign()) {
|
||||
PutReserve(*os_, 9);
|
||||
PutUnsafe(*os_, '-');
|
||||
}
|
||||
else
|
||||
PutReserve(*os_, 8);
|
||||
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
|
||||
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
|
||||
return true;
|
||||
}
|
||||
|
||||
char buffer[25];
|
||||
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
#undef Z16
|
||||
};
|
||||
|
||||
if (TargetEncoding::supportUnicode)
|
||||
PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
|
||||
else
|
||||
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
|
||||
|
||||
PutUnsafe(*os_, '\"');
|
||||
GenericStringStream<SourceEncoding> is(str);
|
||||
while (ScanWriteUnescapedString(is, length)) {
|
||||
const Ch c = is.Peek();
|
||||
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
|
||||
// Unicode escaping
|
||||
unsigned codepoint;
|
||||
if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
|
||||
return false;
|
||||
PutUnsafe(*os_, '\\');
|
||||
PutUnsafe(*os_, 'u');
|
||||
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
||||
PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
|
||||
// Surrogate pair
|
||||
unsigned s = codepoint - 0x010000;
|
||||
unsigned lead = (s >> 10) + 0xD800;
|
||||
unsigned trail = (s & 0x3FF) + 0xDC00;
|
||||
PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(lead ) & 15]);
|
||||
PutUnsafe(*os_, '\\');
|
||||
PutUnsafe(*os_, 'u');
|
||||
PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(trail ) & 15]);
|
||||
}
|
||||
}
|
||||
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
|
||||
is.Take();
|
||||
PutUnsafe(*os_, '\\');
|
||||
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
|
||||
if (escape[static_cast<unsigned char>(c)] == 'u') {
|
||||
PutUnsafe(*os_, '0');
|
||||
PutUnsafe(*os_, '0');
|
||||
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
|
||||
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
|
||||
}
|
||||
}
|
||||
else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
|
||||
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
|
||||
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||
return false;
|
||||
}
|
||||
PutUnsafe(*os_, '\"');
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
|
||||
bool WriteStartObject() { os_->Put('{'); return true; }
|
||||
bool WriteEndObject() { os_->Put('}'); return true; }
|
||||
bool WriteStartArray() { os_->Put('['); return true; }
|
||||
bool WriteEndArray() { os_->Put(']'); return true; }
|
||||
|
||||
bool WriteRawValue(const Ch* json, size_t length) {
|
||||
PutReserve(*os_, length);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
RAPIDJSON_ASSERT(json[i] != '\0');
|
||||
PutUnsafe(*os_, json[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Prefix(Type type) {
|
||||
(void)type;
|
||||
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
|
||||
Level* level = level_stack_.template Top<Level>();
|
||||
if (level->valueCount > 0) {
|
||||
if (level->inArray)
|
||||
os_->Put(','); // add comma if it is not the first element in array
|
||||
else // in object
|
||||
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
|
||||
hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the value if it is the top level one.
|
||||
bool EndValue(bool ret) {
|
||||
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
|
||||
os_->Flush();
|
||||
return ret;
|
||||
}
|
||||
|
||||
OutputStream* os_;
|
||||
internal::Stack<StackAllocator> level_stack_;
|
||||
int maxDecimalPlaces_;
|
||||
bool hasRoot_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Writer(const Writer&);
|
||||
Writer& operator=(const Writer&);
|
||||
};
|
||||
|
||||
// Full specialization for StringStream to prevent memory copying
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteInt(int i) {
|
||||
char *buffer = os_->Push(11);
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
os_->Pop(static_cast<size_t>(11 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
|
||||
char *buffer = os_->Push(10);
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
os_->Pop(static_cast<size_t>(10 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
|
||||
char *buffer = os_->Push(21);
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
os_->Pop(static_cast<size_t>(21 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
|
||||
char *buffer = os_->Push(20);
|
||||
const char* end = internal::u64toa(u, buffer);
|
||||
os_->Pop(static_cast<size_t>(20 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteDouble(double d) {
|
||||
if (internal::Double(d).IsNanOrInf()) {
|
||||
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
|
||||
if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
|
||||
return false;
|
||||
if (internal::Double(d).IsNan()) {
|
||||
PutReserve(*os_, 3);
|
||||
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||
return true;
|
||||
}
|
||||
if (internal::Double(d).Sign()) {
|
||||
PutReserve(*os_, 9);
|
||||
PutUnsafe(*os_, '-');
|
||||
}
|
||||
else
|
||||
PutReserve(*os_, 8);
|
||||
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
|
||||
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
|
||||
return true;
|
||||
}
|
||||
|
||||
char *buffer = os_->Push(25);
|
||||
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
|
||||
os_->Pop(static_cast<size_t>(25 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
|
||||
if (length < 16)
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
|
||||
if (!RAPIDJSON_LIKELY(is.Tell() < length))
|
||||
return false;
|
||||
|
||||
const char* p = is.src_;
|
||||
const char* end = is.head_ + length;
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
|
||||
if (nextAligned > end)
|
||||
return true;
|
||||
|
||||
while (p != nextAligned)
|
||||
if (*p < 0x20 || *p == '\"' || *p == '\\') {
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
else
|
||||
os_->PutUnsafe(*p++);
|
||||
|
||||
// The rest of string using SIMD
|
||||
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
|
||||
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
|
||||
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
|
||||
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
|
||||
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||
|
||||
for (; p != endAligned; p += 16) {
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
|
||||
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
|
||||
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||
SizeType len;
|
||||
#ifdef _MSC_VER // Find the index of first escaped
|
||||
unsigned long offset;
|
||||
_BitScanForward(&offset, r);
|
||||
len = offset;
|
||||
#else
|
||||
len = static_cast<SizeType>(__builtin_ffs(r) - 1);
|
||||
#endif
|
||||
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
|
||||
for (size_t i = 0; i < len; i++)
|
||||
q[i] = p[i];
|
||||
|
||||
p += len;
|
||||
break;
|
||||
}
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
|
||||
}
|
||||
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
219
include/seiscomp/broker/client.h
Normal file
219
include/seiscomp/broker/client.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_CLIENT_H__
|
||||
#define GEMPA_BROKER_CLIENT_H__
|
||||
|
||||
|
||||
#include <seiscomp/wired/devices/socket.h>
|
||||
#include <string>
|
||||
|
||||
#include <seiscomp/broker/message.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Message;
|
||||
class Group;
|
||||
class Queue;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The Client interface describes a client connected to a queue acting
|
||||
* as message subscriber.
|
||||
*
|
||||
* The only thing that a client does is to store a name which is being assigned
|
||||
* by the queue and publish messages. The publish method is abstract and needs
|
||||
* to be implemented by derived classes such as communication protocols.
|
||||
*/
|
||||
class SC_BROKER_API Client {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types and enumerations
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
enum Constants {
|
||||
MaxLocalHeapSize = 128
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! C'tor
|
||||
Client();
|
||||
|
||||
//! D'tor
|
||||
virtual ~Client();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
const std::string &name() const { return _name; }
|
||||
|
||||
/**
|
||||
* @brief Returns the absolute memory pointer of an local heap
|
||||
* offset
|
||||
* @param offset The offset in bytes
|
||||
* @return The pointer of the memory block
|
||||
*/
|
||||
void *memory(int offset);
|
||||
const void *memory(int offset) const;
|
||||
|
||||
/**
|
||||
* @return The time in UTC when the client has connected.
|
||||
*/
|
||||
const Core::Time &created() const;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Subscriber interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
bool setMembershipInformationEnabled(bool enable);
|
||||
bool wantsMembershipInformation() const;
|
||||
|
||||
/**
|
||||
* @brief Sets whether to discard messages where receiver equals
|
||||
* the sender or not.
|
||||
* @param enable The enable flag
|
||||
* @return Success flag
|
||||
*/
|
||||
bool setDiscardSelf(bool enable);
|
||||
bool discardSelf() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the number of messages required to send back an
|
||||
* acknoledgement.
|
||||
* @param numberOfMessages The window size
|
||||
*/
|
||||
void setAcknowledgeWindow(SequenceNumber numberOfMessages);
|
||||
|
||||
/**
|
||||
* @brief Returns the IP address connected to the client socket.
|
||||
* If the underlying transport does not implement IP socket
|
||||
* communication, it can return 0.
|
||||
* @return The IP address
|
||||
*/
|
||||
virtual Wired::Socket::IPAddress IPAddress() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Publishes a message
|
||||
*
|
||||
* This method has to be implemented by all subclasses to encode it
|
||||
* into their transport format and to send it.
|
||||
*
|
||||
* @param sender The sender of the message
|
||||
* @param msg The message
|
||||
* @return Number of bytes sent
|
||||
*/
|
||||
virtual size_t publish(Client *sender, Message *msg) = 0;
|
||||
|
||||
/**
|
||||
* @brief Notifies a client that a new member entered a group the client
|
||||
* is also member in.
|
||||
* @param group The group the new member entered.
|
||||
* @param newMember The client pointer to the new member.
|
||||
* @param msg The message to be sent.
|
||||
*/
|
||||
virtual void enter(const Group *group, const Client *newMember, Message *msg) = 0;
|
||||
|
||||
/**
|
||||
* @brief Notifies a client that a member left a group the client
|
||||
* is also member in.
|
||||
* @param group The group the member left.
|
||||
* @param oldMember The client pointer to the member.
|
||||
* @param msg The message to be sent.
|
||||
*/
|
||||
virtual void leave(const Group *group, const Client *oldMember, Message *msg) = 0;
|
||||
|
||||
virtual void disconnected(const Client *disconnectedClient, Message *msg) = 0;
|
||||
|
||||
//! Send acknowledgment to sender
|
||||
virtual void ack() = 0;
|
||||
|
||||
//! Remove the clients resources
|
||||
virtual void dispose() = 0;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Protected members
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
Queue *_queue{nullptr};
|
||||
Core::Time _created;
|
||||
Core::Time _lastSOHReceived;
|
||||
std::string _name;
|
||||
bool _wantsMembershipInformation{false};
|
||||
bool _discardSelf{false};
|
||||
SequenceNumber _sequenceNumber{0};
|
||||
SequenceNumber _acknowledgeWindow{20};
|
||||
SequenceNumber _acknowledgeCounter{20};
|
||||
Core::Time _ackInitiated;
|
||||
int _inactivityCounter{0}; // The number of seconds
|
||||
// of inactivity
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
// Local client heap to additional user data stored by e.g. plugins
|
||||
char _heap[MaxLocalHeapSize];
|
||||
|
||||
friend class Queue;
|
||||
};
|
||||
|
||||
|
||||
inline bool Client::wantsMembershipInformation() const {
|
||||
return _wantsMembershipInformation;
|
||||
}
|
||||
|
||||
inline bool Client::discardSelf() const {
|
||||
return _discardSelf;
|
||||
}
|
||||
|
||||
inline void *Client::memory(int offset) {
|
||||
return _heap + offset;
|
||||
}
|
||||
|
||||
inline const void *Client::memory(int offset) const {
|
||||
return _heap + offset;
|
||||
}
|
||||
|
||||
inline const Core::Time &Client::created() const {
|
||||
return _created;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
137
include/seiscomp/broker/group.h
Normal file
137
include/seiscomp/broker/group.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_GROUP_H__
|
||||
#define GEMPA_BROKER_GROUP_H__
|
||||
|
||||
|
||||
#include <seiscomp/core/baseobject.h>
|
||||
#include <string>
|
||||
|
||||
#include <seiscomp/broker/hashset.h>
|
||||
#include <seiscomp/broker/statistics.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Client;
|
||||
class Queue;
|
||||
|
||||
|
||||
DEFINE_SMARTPOINTER(Group);
|
||||
|
||||
/**
|
||||
* @brief The Group class implements a particular group (or channel/topic) of
|
||||
* a queue.
|
||||
*
|
||||
* Each group can have members. A member is a client. This class is nothing
|
||||
* else than a manager of members in an efficient way. It implements a very
|
||||
* fast hashset (KHash) of its members which makes member tests very fast and
|
||||
* does not make it necessary to manage additional complicated lookup
|
||||
* structures.
|
||||
*/
|
||||
class SC_BROKER_API Group : public Core::BaseObject {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
typedef KHashSet<Client*> Members;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! C'tor
|
||||
explicit Group(const char *name);
|
||||
|
||||
//! D'tor
|
||||
~Group();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! Returns the name of the group.
|
||||
const std::string &name() const;
|
||||
|
||||
//! Returns the number of members.
|
||||
size_t memberCount() const;
|
||||
|
||||
/**
|
||||
* @brief Adds a member to the group if it is not yet.
|
||||
* @param client The pointer identifying a unique client
|
||||
* @return true on success, false otherwise e.g. duplicates
|
||||
*/
|
||||
bool addMember(Client *client);
|
||||
|
||||
/**
|
||||
* @brief Removes a member from the group.
|
||||
* @param client The pointer identifying a unique client
|
||||
* @return true on success, false otherwise e.g. does not exist
|
||||
*/
|
||||
bool removeMember(Client *client);
|
||||
|
||||
//! Returns if a client is a member of not.
|
||||
bool hasMember(const Client *client) const;
|
||||
|
||||
//! Removes all members.
|
||||
void clearMembers() { _members.clear(); }
|
||||
|
||||
const Members &members() const;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
std::string _name;
|
||||
Members _members;
|
||||
mutable Tx _txMessages;
|
||||
mutable Tx _txBytes;
|
||||
mutable Tx _txPayload;
|
||||
|
||||
|
||||
friend class Queue;
|
||||
};
|
||||
|
||||
|
||||
inline const std::string &Group::name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
inline const Group::Members &Group::members() const {
|
||||
return _members;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
666
include/seiscomp/broker/hashset.h
Normal file
666
include/seiscomp/broker/hashset.h
Normal file
@@ -0,0 +1,666 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_HASHSET_H
|
||||
#define GEMPA_BROKER_HASHSET_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
#include <seiscomp/broker/api.h>
|
||||
#include <seiscomp/broker/utils/khash.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
|
||||
|
||||
KHASH_SET_INIT_INT(int)
|
||||
KHASH_SET_INIT_INT64(int64)
|
||||
KHASH_SET_INIT_STR(str)
|
||||
KHASH_MAP_INIT_STR(m_str, void*)
|
||||
|
||||
|
||||
template <typename T>
|
||||
class KHashSet {};
|
||||
|
||||
template <typename K, typename V>
|
||||
class KHashMap {};
|
||||
|
||||
|
||||
template <>
|
||||
class KHashSet<uint32_t> {
|
||||
public:
|
||||
struct iterator {
|
||||
iterator() {}
|
||||
iterator(const iterator &other) : h(other.h), k(other.k) {}
|
||||
iterator(khash_t(int) *h_, unsigned k_) : h(h_), k(k_) {}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return k == other.k;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return k != other.k;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
iterator &operator++() {
|
||||
++k;
|
||||
while ( k != kh_end(h) && !kh_exist(h, k) )
|
||||
++k;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix
|
||||
iterator operator++(int) {
|
||||
iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint32_t operator*() const {
|
||||
return kh_key(h, k);
|
||||
}
|
||||
|
||||
khash_t(int) *h;
|
||||
unsigned k;
|
||||
};
|
||||
|
||||
|
||||
KHashSet() {
|
||||
_h = kh_init(int);
|
||||
}
|
||||
|
||||
~KHashSet() {
|
||||
kh_destroy(int, _h);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
unsigned k = kh_begin(_h);
|
||||
while ( k != kh_end(_h) && !kh_exist(_h, k) )
|
||||
++k;
|
||||
return iterator(_h, k);
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return iterator(_h, kh_end(_h));
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return kh_size(_h);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
kh_clear(int, _h);
|
||||
}
|
||||
|
||||
int insert(uint32_t v) {
|
||||
int ret;
|
||||
kh_put(int, _h, v, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator find(uint32_t v) const {
|
||||
return iterator(_h, kh_get(int, _h, v));
|
||||
}
|
||||
|
||||
void erase(iterator it) {
|
||||
kh_del(int, _h, it.k);
|
||||
}
|
||||
|
||||
bool contains(uint32_t v) const {
|
||||
return find(v) != end();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
khash_t(int) *_h;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class KHashSet<uint64_t> {
|
||||
public:
|
||||
struct iterator {
|
||||
iterator() {}
|
||||
iterator(const iterator &other) : h(other.h), k(other.k) {}
|
||||
iterator(khash_t(int64) *h_, unsigned k_) : h(h_), k(k_) {}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return k == other.k;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return k != other.k;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
iterator &operator++() {
|
||||
++k;
|
||||
while ( k != kh_end(h) && !kh_exist(h, k) )
|
||||
++k;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix
|
||||
iterator operator++(int) {
|
||||
iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint64_t operator*() const {
|
||||
return kh_key(h, k);
|
||||
}
|
||||
|
||||
khash_t(int64) *h;
|
||||
unsigned k;
|
||||
};
|
||||
|
||||
|
||||
KHashSet() {
|
||||
_h = kh_init(int64);
|
||||
}
|
||||
|
||||
~KHashSet() {
|
||||
kh_destroy(int64, _h);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
unsigned k = kh_begin(_h);
|
||||
while ( k != kh_end(_h) && !kh_exist(_h, k) )
|
||||
++k;
|
||||
return iterator(_h, k);
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return iterator(_h, kh_end(_h));
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return kh_size(_h);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
kh_clear(int64, _h);
|
||||
}
|
||||
|
||||
int insert(uint64_t v) {
|
||||
int ret;
|
||||
kh_put(int64, _h, v, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator find(uint64_t v) const {
|
||||
return iterator(_h, kh_get(int64, _h, v));
|
||||
}
|
||||
|
||||
void erase(iterator it) {
|
||||
kh_del(int64, _h, it.k);
|
||||
}
|
||||
|
||||
bool contains(uint64_t v) const {
|
||||
return find(v) != end();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
khash_t(int64) *_h;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class KHashSet<const char*> {
|
||||
public:
|
||||
struct iterator {
|
||||
iterator() {}
|
||||
iterator(const iterator &other) : h(other.h), k(other.k) {}
|
||||
iterator(khash_t(str) *h_, unsigned k_) : h(h_), k(k_) {}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return k == other.k;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return k != other.k;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
iterator &operator++() {
|
||||
++k;
|
||||
while ( k != kh_end(h) && !kh_exist(h, k) )
|
||||
++k;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix
|
||||
iterator operator++(int) {
|
||||
iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char *operator*() const {
|
||||
return kh_key(h, k);
|
||||
}
|
||||
|
||||
khash_t(str) *h;
|
||||
unsigned k;
|
||||
};
|
||||
|
||||
|
||||
KHashSet() {
|
||||
_h = kh_init(str);
|
||||
}
|
||||
|
||||
~KHashSet() {
|
||||
kh_destroy(str, _h);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
unsigned k = kh_begin(_h);
|
||||
while ( k != kh_end(_h) && !kh_exist(_h, k) )
|
||||
++k;
|
||||
return iterator(_h, k);
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return iterator(_h, kh_end(_h));
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return kh_size(_h);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
kh_clear(str, _h);
|
||||
}
|
||||
|
||||
int insert(const char *v) {
|
||||
int ret;
|
||||
kh_put(str, _h, v, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator find(const char *str) const {
|
||||
return iterator(_h, kh_get(str, _h, str));
|
||||
}
|
||||
|
||||
iterator find(const std::string &str) const {
|
||||
return iterator(_h, kh_get(str, _h, str.c_str()));
|
||||
}
|
||||
|
||||
void erase(iterator it) {
|
||||
kh_del(str, _h, it.k);
|
||||
}
|
||||
|
||||
bool contains(const char *str) const {
|
||||
return find(str) != end();
|
||||
}
|
||||
|
||||
bool contains(const std::string &str) const {
|
||||
return find(str) != end();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
khash_t(str) *_h;
|
||||
};
|
||||
|
||||
|
||||
template <typename V>
|
||||
class KHashMap<const char*, V*> {
|
||||
public:
|
||||
struct iterator {
|
||||
iterator() {}
|
||||
iterator(const iterator &other) : h(other.h), k(other.k) {}
|
||||
iterator(khash_t(m_str) *h_, unsigned k_) : h(h_), k(k_) {}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return k == other.k;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return k != other.k;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
iterator &operator++() {
|
||||
++k;
|
||||
while ( k != kh_end(h) && !kh_exist(h, k) )
|
||||
++k;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix
|
||||
iterator operator++(int) {
|
||||
iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char *operator*() const {
|
||||
return kh_key(h, k);
|
||||
}
|
||||
|
||||
const char *key() const {
|
||||
return kh_key(h, k);
|
||||
}
|
||||
|
||||
V *value() const {
|
||||
return (V*)kh_value(h, k);
|
||||
}
|
||||
|
||||
khash_t(m_str) *h;
|
||||
unsigned k;
|
||||
};
|
||||
|
||||
|
||||
KHashMap() {
|
||||
_h = kh_init(m_str);
|
||||
}
|
||||
|
||||
~KHashMap() {
|
||||
kh_destroy(m_str, _h);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
unsigned k = kh_begin(_h);
|
||||
while ( k != kh_end(_h) && !kh_exist(_h, k) )
|
||||
++k;
|
||||
return iterator(_h, k);
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return iterator(_h, kh_end(_h));
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return kh_size(_h);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
kh_clear(m_str, _h);
|
||||
}
|
||||
|
||||
int insert(const char *v, V *value) {
|
||||
int ret;
|
||||
khiter_t k = kh_put(m_str, _h, v, &ret);
|
||||
if ( k >= 0 )
|
||||
kh_value(_h, k) = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator find(const char *str) const {
|
||||
return iterator(_h, kh_get(m_str, _h, str));
|
||||
}
|
||||
|
||||
iterator find(const std::string &str) const {
|
||||
return iterator(_h, kh_get(m_str, _h, str.c_str()));
|
||||
}
|
||||
|
||||
void erase(iterator it) {
|
||||
kh_del(m_str, _h, it.k);
|
||||
}
|
||||
|
||||
bool contains(const char *str) const {
|
||||
return find(str) != end();
|
||||
}
|
||||
|
||||
bool contains(const std::string &str) const {
|
||||
return find(str) != end();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
khash_t(m_str) *_h;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T, int BYTES>
|
||||
class KHashSetPtrBase {};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class KHashSetPtrBase<T, 4> {
|
||||
public:
|
||||
struct iterator {
|
||||
iterator() {}
|
||||
iterator(const iterator &other) : h(other.h), k(other.k) {}
|
||||
iterator(khash_t(int) *h_, unsigned k_) : h(h_), k(k_) {}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return k == other.k;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return k != other.k;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
iterator &operator++() {
|
||||
++k;
|
||||
while ( k != kh_end(h) && !kh_exist(h, k) )
|
||||
++k;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix
|
||||
iterator operator++(int) {
|
||||
iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T operator*() const {
|
||||
return (T)kh_key(h, k);
|
||||
}
|
||||
|
||||
khash_t(int) *h;
|
||||
unsigned k;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
KHashSetPtrBase() {
|
||||
_h = kh_init(int);
|
||||
}
|
||||
|
||||
~KHashSetPtrBase() {
|
||||
kh_destroy(int, _h);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
unsigned k = kh_begin(_h);
|
||||
while ( k != kh_end(_h) && !kh_exist(_h, k) )
|
||||
++k;
|
||||
return iterator(_h, k);
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return iterator(_h, kh_end(_h));
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return kh_size(_h);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
kh_clear(int, _h);
|
||||
}
|
||||
|
||||
int insert(T v) {
|
||||
int ret;
|
||||
kh_put(int, _h, (uintptr_t)v, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator find(const void *v) const {
|
||||
return iterator(_h, kh_get(int, _h, (uintptr_t)v));
|
||||
}
|
||||
|
||||
void erase(iterator it) {
|
||||
kh_del(int, _h, it.k);
|
||||
}
|
||||
|
||||
bool contains(const void *v) const {
|
||||
return kh_get(int, _h, (uintptr_t)v) != kh_end(_h);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
khash_t(int) *_h;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class KHashSetPtrBase<T, 8> {
|
||||
public:
|
||||
struct iterator {
|
||||
iterator() {}
|
||||
iterator(const iterator &other) : h(other.h), k(other.k) {}
|
||||
iterator(khash_t(int64) *h_, unsigned k_) : h(h_), k(k_) {}
|
||||
|
||||
bool operator==(const iterator &other) const {
|
||||
return k == other.k;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
return k != other.k;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
iterator &operator++() {
|
||||
++k;
|
||||
while ( k != kh_end(h) && !kh_exist(h, k) )
|
||||
++k;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix
|
||||
iterator operator++(int) {
|
||||
iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T operator*() const {
|
||||
return (T)kh_key(h, k);
|
||||
}
|
||||
|
||||
khash_t(int64) *h;
|
||||
unsigned k;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
KHashSetPtrBase() {
|
||||
_h = kh_init(int64);
|
||||
}
|
||||
|
||||
~KHashSetPtrBase() {
|
||||
kh_destroy(int64, _h);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
iterator begin() const {
|
||||
unsigned k = kh_begin(_h);
|
||||
while ( k != kh_end(_h) && !kh_exist(_h, k) )
|
||||
++k;
|
||||
return iterator(_h, k);
|
||||
}
|
||||
|
||||
iterator end() const {
|
||||
return iterator(_h, kh_end(_h));
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return kh_size(_h);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
kh_clear(int64, _h);
|
||||
}
|
||||
|
||||
int insert(T v) {
|
||||
int ret;
|
||||
kh_put(int64, _h, (uintptr_t)v, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator find(const void *v) const {
|
||||
return iterator(_h, kh_get(int64, _h, (uintptr_t)v));
|
||||
}
|
||||
|
||||
void erase(iterator it) {
|
||||
kh_del(int64, _h, it.k);
|
||||
}
|
||||
|
||||
bool contains(const void *v) const {
|
||||
return kh_get(int64, _h, (uintptr_t)v) != kh_end(_h);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
khash_t(int64) *_h;
|
||||
};
|
||||
|
||||
|
||||
struct Arch {
|
||||
enum {
|
||||
PtrSize = sizeof(intptr_t)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class KHashSet<T*> : public KHashSetPtrBase<T*, Arch::PtrSize> {
|
||||
public:
|
||||
KHashSet() {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
164
include/seiscomp/broker/message.h
Normal file
164
include/seiscomp/broker/message.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_MESSAGE_H__
|
||||
#define GEMPA_BROKER_MESSAGE_H__
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <seiscomp/core/enumeration.h>
|
||||
#include <seiscomp/wired/buffer.h>
|
||||
|
||||
#include <seiscomp/broker/api.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Group;
|
||||
|
||||
|
||||
typedef uint64_t SequenceNumber;
|
||||
#define INVALID_SEQUENCE_NUMBER Seiscomp::Messaging::Broker::SequenceNumber(-1)
|
||||
|
||||
|
||||
MAKEENUM(
|
||||
ContentEncoding,
|
||||
EVALUES(
|
||||
Identity,
|
||||
Deflate,
|
||||
GZip,
|
||||
LZ4
|
||||
),
|
||||
ENAMES(
|
||||
"identity",
|
||||
"deflate",
|
||||
"gzip",
|
||||
"lz4"
|
||||
)
|
||||
);
|
||||
|
||||
MAKEENUM(
|
||||
MimeType,
|
||||
EVALUES(
|
||||
Binary,
|
||||
JSON,
|
||||
BSON,
|
||||
XML,
|
||||
IMPORTED_XML,
|
||||
Text
|
||||
),
|
||||
ENAMES(
|
||||
"application/x-sc-bin",
|
||||
"text/json",
|
||||
"application/x-sc-bson",
|
||||
"application/x-sc-xml",
|
||||
"text/xml",
|
||||
"text/plain"
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
DEFINE_SMARTPOINTER(Message);
|
||||
/**
|
||||
* @brief The Message class implements the message structure.
|
||||
*
|
||||
* A message contains meta data and a payload. Since each protocol has to
|
||||
* encode the message differently a cached version for each protocol is also
|
||||
* stored. That buffer can be sent without further modifications. This is
|
||||
* in particular helpful if a message is going to be sent to hundreds of
|
||||
* clients connected through the same protocol. The message has to be encoded
|
||||
* only once and not hundred times. This cache is lazy and will only be
|
||||
* populated at the first send operation.
|
||||
*/
|
||||
class SC_BROKER_API Message : public Seiscomp::Core::BaseObject {
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! C'tor
|
||||
Message();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @brief Decodes a message if object is NULL according to the payload
|
||||
* and format
|
||||
* @return true if msg->object is a valid pointer or false otherwise.
|
||||
*/
|
||||
bool decode();
|
||||
|
||||
/**
|
||||
* @brief Encodes a message if object is not NULL and saves the
|
||||
* encoded buffer in payload.
|
||||
* @return true if payload is not empty, false otherwise.
|
||||
*/
|
||||
bool encode();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Members
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
enum struct Type {
|
||||
Unspecified,
|
||||
Regular,
|
||||
Transient, // From this enumeration messages are not processed
|
||||
Status
|
||||
};
|
||||
|
||||
std::string sender; //!< The sender
|
||||
std::string target; //!< The target group/topic
|
||||
std::string encoding; //!< The encoding of the data
|
||||
std::string mimeType; //!< The mime type of the data
|
||||
std::string payload; //!< The payload bytes
|
||||
Core::BaseObjectPtr object; //!< The decoded object
|
||||
Core::Version schemaVersion; //!< The schema version of the payload after decoding
|
||||
Seiscomp::Core::Time timestamp; //!< The received time
|
||||
Type type; //!< The message type
|
||||
bool selfDiscard; //!< Whether self discard should be checked or not
|
||||
bool processed;
|
||||
/** The assigned sequence number */
|
||||
SequenceNumber sequenceNumber;
|
||||
|
||||
/** Cached encoded version for different protocols */
|
||||
Wired::BufferPtr encodingWebSocket;
|
||||
|
||||
/** Cache of the target group */
|
||||
Group *_internalGroupPtr;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
94
include/seiscomp/broker/messagedispatcher.h
Normal file
94
include/seiscomp/broker/messagedispatcher.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_MESSAGEDISPATCHER_H__
|
||||
#define GEMPA_BROKER_MESSAGEDISPATCHER_H__
|
||||
|
||||
|
||||
#include <seiscomp/broker/api.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Client;
|
||||
class Message;
|
||||
class Queue;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The MessageDispatcher class is used to forward processed messages
|
||||
* from another thread.
|
||||
*
|
||||
* Since it is not safe to call publish on all registered subscribers, the
|
||||
* dispatcher class is provide safe handling within a given framework.
|
||||
*/
|
||||
class SC_BROKER_API MessageDispatcher {
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! C'tor
|
||||
MessageDispatcher() {}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Dispatcher interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @brief Sends a message thread-safe.
|
||||
* @param sender The sender of the message
|
||||
* @param message The message itself which must not be managed
|
||||
* by the caller.
|
||||
*/
|
||||
virtual void sendMessage(Client *sender, Message *message) = 0;
|
||||
|
||||
/**
|
||||
* @brief Notifies the dispatcher about a new message. If the message
|
||||
* should be published, dispatch() must be called.
|
||||
* @param queue The queue that got a new message to be dispatched
|
||||
*/
|
||||
virtual void messageAvailable(Queue *queue) = 0;
|
||||
|
||||
/**
|
||||
* @brief Dispatches a message from the process-ready-queue.
|
||||
*
|
||||
* This call may block if not issued after the messageAvailable()
|
||||
* signal.
|
||||
* @param queue The target queue
|
||||
*/
|
||||
void flushMessages(Queue *queue) {
|
||||
queue->flushProcessedMessages();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
145
include/seiscomp/broker/messageprocessor.h
Normal file
145
include/seiscomp/broker/messageprocessor.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_MESSAGEPROCESSOR_H__
|
||||
#define GEMPA_BROKER_MESSAGEPROCESSOR_H__
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
#include <seiscomp/core/baseobject.h>
|
||||
#include <seiscomp/core/interfacefactory.h>
|
||||
#include <seiscomp/config/config.h>
|
||||
|
||||
#include <seiscomp/broker/processor.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Client;
|
||||
class Message;
|
||||
|
||||
|
||||
DEFINE_SMARTPOINTER(MessageProcessor);
|
||||
|
||||
/**
|
||||
* @brief The MessageProcessor class is used inside the broker to process
|
||||
* messages in any way. The most important use case for such a
|
||||
* processor is to store the message in the database if it suffices a
|
||||
* certain format. Once could think of other use cases such as
|
||||
* building statistics.
|
||||
*/
|
||||
class SC_BROKER_API MessageProcessor : public Processor {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
enum Constants {
|
||||
MaxAdditionalParams = 100
|
||||
};
|
||||
|
||||
enum Mode {
|
||||
None = 0x00,
|
||||
Messages = 0x01,
|
||||
Connections = 0x02
|
||||
};
|
||||
|
||||
using KeyValueCStrPair = std::pair<const char*,const char*>;
|
||||
using KeyCStrValues = KeyValueCStrPair *;
|
||||
|
||||
using KeyValuePair = std::pair<std::string,std::string>;
|
||||
using KeyValues = std::vector<KeyValuePair>;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
MessageProcessor();
|
||||
virtual ~MessageProcessor();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public virtual interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
virtual bool acceptConnection(Client *client,
|
||||
const KeyCStrValues inParams, int inParamCount,
|
||||
KeyValues &outParams) = 0;
|
||||
|
||||
virtual void dropConnection(Client *client) = 0;
|
||||
|
||||
virtual bool process(Message *msg) = 0;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
int mode() const { return _mode; }
|
||||
|
||||
/**
|
||||
* @brief Returns whether the processor want to process messages.
|
||||
* @return Flag
|
||||
*/
|
||||
bool isMessageProcessingEnabled() const { return _mode & Messages; }
|
||||
|
||||
/**
|
||||
* @brief Returns whether the processor want to process connections..
|
||||
* @return Flag
|
||||
*/
|
||||
bool isConnectionProcessingEnabled() const { return _mode & Connections; }
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Protected methods
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
void setMode(int mode);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
int _mode;
|
||||
};
|
||||
|
||||
|
||||
DEFINE_INTERFACE_FACTORY(MessageProcessor);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define REGISTER_BROKER_MESSAGE_PROCESSOR(Class, Service) \
|
||||
Seiscomp::Core::Generic::InterfaceFactory<Seiscomp::Messaging::Broker::MessageProcessor, Class> __##Class##InterfaceFactory__(Service)
|
||||
|
||||
|
||||
#endif
|
||||
103
include/seiscomp/broker/processor.h
Normal file
103
include/seiscomp/broker/processor.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_PROCESSOR_H__
|
||||
#define GEMPA_BROKER_PROCESSOR_H__
|
||||
|
||||
|
||||
#include <seiscomp/core/baseobject.h>
|
||||
#include <seiscomp/config/config.h>
|
||||
|
||||
#include <seiscomp/broker/api.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Queue;
|
||||
|
||||
|
||||
DEFINE_SMARTPOINTER(Processor);
|
||||
|
||||
class SC_BROKER_API Processor : public Core::BaseObject {
|
||||
public:
|
||||
Processor();
|
||||
virtual ~Processor();
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Initiales the configuration of a processor from a config object
|
||||
* and a given parameter name prefix.
|
||||
* @param conf The configuration file object
|
||||
* @param configPrefix The prefix that must be preprended to all
|
||||
* parameters.
|
||||
* @return Success flag.
|
||||
*/
|
||||
virtual bool init(const Config::Config &conf, const std::string &configPrefix) = 0;
|
||||
|
||||
/**
|
||||
* @brief When a processor has been added to a queue, this method will be
|
||||
* called. The default implementation does nothing. This method
|
||||
* can be used to e.g. allocate additional client memory of
|
||||
* the local client heap.
|
||||
* @param queue The queue the processor was attached to.
|
||||
*/
|
||||
virtual bool attach(Queue *queue);
|
||||
|
||||
/**
|
||||
* @brief Shuts down the processor.
|
||||
* @return Success flag.
|
||||
*/
|
||||
virtual bool close() = 0;
|
||||
|
||||
/**
|
||||
* @brief Add information to a state of health message
|
||||
* @param timestamp The timestamp of the information
|
||||
* @param os The output stream to write to
|
||||
*/
|
||||
virtual void getInfo(const Core::Time ×tamp, std::ostream &os) = 0;
|
||||
|
||||
Queue *queue() const;
|
||||
|
||||
|
||||
private:
|
||||
Queue *_queue;
|
||||
|
||||
friend class Queue;
|
||||
};
|
||||
|
||||
|
||||
inline Queue *Processor::queue() const {
|
||||
return _queue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
343
include/seiscomp/broker/protocol.h
Normal file
343
include/seiscomp/broker/protocol.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_BROKER_PROTOCOL_H__
|
||||
#define GEMPA_BROKER_PROTOCOL_H__
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
namespace Protocol {
|
||||
|
||||
|
||||
// Defines do not make much sense inside namespaces but they are placed here
|
||||
// to stay close to future variable declarations.
|
||||
|
||||
/**
|
||||
* It follows a list of definitions for all protocol commands and replies and
|
||||
* their headers. They are being used in the code and changing them here will
|
||||
* cause a change in behaviour of the server.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ```
|
||||
* CONNECT
|
||||
* Ack-Window: [number of messages after which an ack will be send from the server]
|
||||
* Membership-Info: 1
|
||||
* Queue: [name of queue]
|
||||
* Client-Name: [name of client]
|
||||
* Subscriptions: [list of groups]
|
||||
* Seq-No: [last seen sequence number]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*
|
||||
* The *Seq-No* header contains the last sequence number the client has seen from
|
||||
* that queue. That header is optional. If subscriptions are given then the
|
||||
* client will receive an **ENTER** frame for each group it subscribed to. If any
|
||||
* of the requested groups does not exist, an **ERROR** frame is sent and the
|
||||
* connection is closed.
|
||||
*
|
||||
* The order of messages looks as follows:
|
||||
*
|
||||
* 1. CONNECT
|
||||
* 2. CONNECTED
|
||||
* 3. ENTER
|
||||
* 4. RECV
|
||||
*
|
||||
* Step 3 repeats for as many groups as given in the subscription list. Step 4
|
||||
* repeats for all messages received during the lifetime of the connection.
|
||||
*/
|
||||
#define SCMP_PROTO_CMD_CONNECT "CONNECT"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_QUEUE "Queue"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_CLIENT_NAME "Client-Name"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_MEMBERSHIP_INFO "Membership-Info"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_SELF_DISCARD "Self-Discard"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_ACK_WINDOW "Ack-Window"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_SEQ_NUMBER "Seq-No"
|
||||
#define SCMP_PROTO_CMD_CONNECT_HEADER_SUBSCRIPTIONS "Subscriptions"
|
||||
|
||||
/**
|
||||
* ```
|
||||
* DISCONNECT
|
||||
* Receipt: [id]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*
|
||||
* The DISCONNECT command ask the server to gracefully shutdown the connection
|
||||
* and free all associated resources.
|
||||
*/
|
||||
#define SCMP_PROTO_CMD_DISCONNECT "DISCONNECT"
|
||||
#define SCMP_PROTO_CMD_DISCONNECT_HEADER_RECEIPT "Receipt"
|
||||
|
||||
/**
|
||||
* ```
|
||||
* SUBSCRIBE
|
||||
* Groups: [list of groups]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
* Subscribes to a specific group which must exist on the server. In response
|
||||
* either an **ENTER** or **ERROR** frame will be received.
|
||||
*/
|
||||
#define SCMP_PROTO_CMD_SUBSCRIBE "SUBSCRIBE"
|
||||
#define SCMP_PROTO_CMD_SUBSCRIBE_HEADER_GROUPS "Groups"
|
||||
|
||||
/**
|
||||
* ```
|
||||
* UNSUBSCRIBE
|
||||
* Groups: [list of groups]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*
|
||||
* Unsubscribes from a specific group which must exist on the server. In
|
||||
* response either a **LEAVE** or **ERROR** frame will be received.
|
||||
*/
|
||||
#define SCMP_PROTO_CMD_UNSUBSCRIBE "UNSUBSCRIBE"
|
||||
#define SCMP_PROTO_CMD_UNSUBSCRIBE_HEADER_GROUPS SCMP_PROTO_CMD_SUBSCRIBE_HEADER_GROUPS
|
||||
|
||||
/**
|
||||
* Sends a message to a group or a client (peer-to-peer).
|
||||
*
|
||||
* ```
|
||||
* SEND
|
||||
* D: [name of group or the client]
|
||||
* T: [MIME type]
|
||||
* E: [transfer encoding]
|
||||
* L: [length of content]
|
||||
*
|
||||
* [payload]^@
|
||||
* ```
|
||||
*
|
||||
* Each message sent will increase the private sequence number counter for this
|
||||
* connection starting with 0. So the first message will get assigned the
|
||||
* sequence number 1. That counter must be maintained by the client and the
|
||||
* server to correctly synchronize acknowledgements. If the message is rejected
|
||||
* an **ERROR** frame will be sent to the client and the connection will be
|
||||
* closed.
|
||||
*/
|
||||
#define SCMP_PROTO_CMD_SEND "SEND"
|
||||
#define SCMP_PROTO_CMD_SEND_HEADER_DESTINATION "D"
|
||||
#define SCMP_PROTO_CMD_SEND_HEADER_CONTENT_LENGTH "L"
|
||||
#define SCMP_PROTO_CMD_SEND_HEADER_ENCODING "E"
|
||||
#define SCMP_PROTO_CMD_SEND_HEADER_MIMETYPE "T"
|
||||
#define SCMP_PROTO_CMD_SEND_HEADER_TRANSIENT "Transient"
|
||||
|
||||
|
||||
/**
|
||||
* A member notifies the server about its state including memory consumption,
|
||||
* cpu usage, uptime and so on. The payload is always a key-value list
|
||||
* separated by '&'.
|
||||
*
|
||||
* ```
|
||||
* STATE
|
||||
* D: [name of group or the client]
|
||||
* L: [length of content]
|
||||
*
|
||||
* hostname=localhost&totalmemory=8589934592&clientmemoryusage=68891443...^@
|
||||
* ```
|
||||
*/
|
||||
#define SCMP_PROTO_CMD_STATE "STATE"
|
||||
#define SCMP_PROTO_CMD_STATE_HEADER_DESTINATION "D"
|
||||
#define SCMP_PROTO_CMD_STATE_HEADER_CONTENT_LENGTH "L"
|
||||
|
||||
#define SCMP_PROTO_CMD_FIRST_CHARS "CDSU"
|
||||
|
||||
/**
|
||||
* ```
|
||||
* CONNECTED
|
||||
* Queue: [name of queue]
|
||||
* Server: SeisComP/2017.334
|
||||
* Version: [server protocol version]
|
||||
* Client-Name: [client name, either auto assigned or requested by the client]
|
||||
* Authentication: [16 byte hex random NaCL nonce prefix]
|
||||
* [32 byte hex NaCL public server key]
|
||||
* [16 byte hex encrypted buffer: "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"]
|
||||
* Groups: [list of available groups]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*
|
||||
* In return to a **CONNECT** frame the server responds with a **CONNECTED**
|
||||
* frame. It reports the client name in use for this connection and a list of
|
||||
* available groups.
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_CONNECT "CONNECTED"
|
||||
#define SCMP_PROTO_REPLY_CONNECT_HEADER_VERSION "Version"
|
||||
#define SCMP_PROTO_REPLY_CONNECT_HEADER_SCHEMA_VERSION "Schema-Version"
|
||||
#define SCMP_PROTO_REPLY_CONNECT_HEADER_QUEUE SCMP_PROTO_CMD_CONNECT_HEADER_QUEUE
|
||||
#define SCMP_PROTO_REPLY_CONNECT_HEADER_CLIENT_NAME SCMP_PROTO_CMD_CONNECT_HEADER_CLIENT_NAME
|
||||
#define SCMP_PROTO_REPLY_CONNECT_HEADER_ACK_WINDOW SCMP_PROTO_CMD_CONNECT_HEADER_ACK_WINDOW
|
||||
#define SCMP_PROTO_REPLY_CONNECT_HEADER_GROUPS "Groups"
|
||||
|
||||
/**
|
||||
* The probably most important part of the protocol is receiving a message from
|
||||
* a group or a client (peer-to-peer).
|
||||
*
|
||||
* ```
|
||||
* RECV
|
||||
* C: [client name of sender]
|
||||
* D: [name of group or the client]
|
||||
* T: [MIME type]
|
||||
* E: [transfer encoding]
|
||||
* N: [message sequence number]
|
||||
* L: [length of content]
|
||||
*
|
||||
* [payload]^@
|
||||
* ```
|
||||
*
|
||||
* The payload can be anything, binary data or text. Optionally the *Content-Type*
|
||||
* header is set to inform the client about the format.
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_SEND "RECV"
|
||||
#define SCMP_PROTO_REPLY_SEND_HEADER_SENDER "C"
|
||||
#define SCMP_PROTO_REPLY_SEND_HEADER_SEQ_NUMBER "N"
|
||||
#define SCMP_PROTO_REPLY_SEND_HEADER_DESTINATION SCMP_PROTO_CMD_SEND_HEADER_DESTINATION
|
||||
#define SCMP_PROTO_REPLY_SEND_HEADER_CONTENT_LENGTH SCMP_PROTO_CMD_SEND_HEADER_CONTENT_LENGTH
|
||||
#define SCMP_PROTO_REPLY_SEND_HEADER_ENCODING SCMP_PROTO_CMD_SEND_HEADER_ENCODING
|
||||
#define SCMP_PROTO_REPLY_SEND_HEADER_MIMETYPE SCMP_PROTO_CMD_SEND_HEADER_MIMETYPE
|
||||
|
||||
/**
|
||||
* ```
|
||||
* ACK
|
||||
* N: [connection specific sequence number]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*
|
||||
* The server sends according to the configured acknoledgement window an
|
||||
* acknowledgement frame to signal that all messages prior to the given sequence
|
||||
* number have been processed and that the current sequence number is expected
|
||||
* to be the one sent. It will do that as well after 1 second the client
|
||||
* hasn't sent any further messages.
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_ACK "ACK"
|
||||
#define SCMP_PROTO_REPLY_ACK_HEADER_SEQ_NUMBER SCMP_PROTO_REPLY_SEND_HEADER_SEQ_NUMBER
|
||||
|
||||
/**
|
||||
* ```
|
||||
* RECEIPT
|
||||
* Receipt-Id: [id]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*
|
||||
* A receipt can basically be sent for anything which has an id. A receipt is
|
||||
* being sent definitely after a disconnect request. In that case the receipt
|
||||
* id is the username.
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_RECEIPT "RECEIPT"
|
||||
#define SCMP_PROTO_REPLY_RECEIPT_HEADER_ID "Receipt-Id"
|
||||
|
||||
/**
|
||||
* A members enters a group. In response to a **SUBSCRIBE** command, the complete
|
||||
* group information will be sent to the client. Specifically if
|
||||
* ```Member == self```. Otherwise only the group and member information will be
|
||||
* sent from the server to all clients that are subscribed to that group. The
|
||||
* client needs to update its internal cache and the frame body is empty in that
|
||||
* case.
|
||||
*
|
||||
* ```
|
||||
* ENTER
|
||||
* D: [name of group]
|
||||
* C: [name of client]
|
||||
*
|
||||
* clientA, clientB, ...
|
||||
* }^@
|
||||
* ```
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_ENTER "ENTER"
|
||||
#define SCMP_PROTO_REPLY_ENTER_HEADER_GROUP "D"
|
||||
#define SCMP_PROTO_REPLY_ENTER_HEADER_MEMBER "C"
|
||||
|
||||
/**
|
||||
* A member leaves a group. This message will sent from the server to all clients
|
||||
* that are subscribed to the group in question.
|
||||
*
|
||||
* ```
|
||||
* LEAVE
|
||||
* D: [name of group]
|
||||
* C: [name of client]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_LEAVE "LEAVE"
|
||||
#define SCMP_PROTO_REPLY_LEAVE_HEADER_GROUP SCMP_PROTO_REPLY_ENTER_HEADER_GROUP
|
||||
#define SCMP_PROTO_REPLY_LEAVE_HEADER_MEMBER SCMP_PROTO_REPLY_ENTER_HEADER_MEMBER
|
||||
|
||||
/**
|
||||
* A member state of health information or simply its state including
|
||||
* memory consumption, cpu usage, uptime and so on. The payload is always
|
||||
* a key-value list separated by '&'.
|
||||
*
|
||||
* ```
|
||||
* STATE
|
||||
* L: [length of content]
|
||||
* D: [name of group or the client]
|
||||
* C: [name of client]
|
||||
*
|
||||
* hostname=localhost&totalmemory=8589934592&clientmemoryusage=68891443...^@
|
||||
* ```
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_STATE "STATE"
|
||||
#define SCMP_PROTO_REPLY_STATE_HEADER_DESTINATION "D"
|
||||
#define SCMP_PROTO_REPLY_STATE_HEADER_CLIENT "C"
|
||||
#define SCMP_PROTO_REPLY_STATE_HEADER_CONTENT_LENGTH SCMP_PROTO_CMD_SEND_HEADER_CONTENT_LENGTH
|
||||
|
||||
/**
|
||||
* A client was disconnected. This message will sent from the server to all
|
||||
* clients currently connected.
|
||||
*
|
||||
* ```
|
||||
* DISCONNECTED
|
||||
* C: [name of client]
|
||||
*
|
||||
* ^@
|
||||
* ```
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_DISCONNECTED "DISCONNECTED"
|
||||
#define SCMP_PROTO_REPLY_DISCONNECTED_HEADER_CLIENT SCMP_PROTO_REPLY_STATE_HEADER_CLIENT
|
||||
|
||||
/**
|
||||
* ```
|
||||
* ERROR
|
||||
* N: [connection specific sequence number]
|
||||
*
|
||||
* Error message ...^@
|
||||
* ```
|
||||
*/
|
||||
#define SCMP_PROTO_REPLY_ERROR "ERROR"
|
||||
#define SCMP_PROTO_REPLY_ERROR_HEADER_SEQ_NUMBER SCMP_PROTO_REPLY_SEND_HEADER_SEQ_NUMBER
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
419
include/seiscomp/broker/queue.h
Normal file
419
include/seiscomp/broker/queue.h
Normal file
@@ -0,0 +1,419 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_BROKER_QUEUE_H__
|
||||
#define SEISCOMP_BROKER_QUEUE_H__
|
||||
|
||||
|
||||
#include <seiscomp/core/enumeration.h>
|
||||
#include <seiscomp/core/message.h>
|
||||
|
||||
#include <seiscomp/broker/messageprocessor.h>
|
||||
#include <seiscomp/broker/hashset.h>
|
||||
#include <seiscomp/broker/group.h>
|
||||
#include <seiscomp/broker/message.h>
|
||||
#include <seiscomp/broker/statistics.h>
|
||||
|
||||
#include <seiscomp/broker/utils/utils.h>
|
||||
#include <seiscomp/broker/utils/circular.h>
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
class Client;
|
||||
class MessageDispatcher;
|
||||
|
||||
DEFINE_SMARTPOINTER(MessageProcessor);
|
||||
|
||||
|
||||
/**
|
||||
* @brief The Queue class implements the central messaging service.
|
||||
*
|
||||
* The Queue receives messages, queues them and distributes them to subscribed
|
||||
* clients.
|
||||
*/
|
||||
class SC_BROKER_API Queue {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
using StringList = std::vector<std::string>;
|
||||
using MessageProcessors = std::vector<MessageProcessorPtr>;
|
||||
|
||||
using KeyValueCStrPair = MessageProcessor::KeyValueCStrPair;
|
||||
using KeyCStrValues = MessageProcessor::KeyCStrValues;
|
||||
|
||||
using KeyValuePair = MessageProcessor::KeyValuePair;
|
||||
using KeyValues = MessageProcessor::KeyValues;
|
||||
|
||||
enum Constants {
|
||||
MaxAdditionalParams = MessageProcessor::MaxAdditionalParams
|
||||
};
|
||||
|
||||
MAKEENUM(
|
||||
Result,
|
||||
EVALUES(
|
||||
Success,
|
||||
InternalError,
|
||||
ClientNameNotUnique,
|
||||
ClientNotAccepted,
|
||||
GroupNameNotUnique,
|
||||
GroupDoesNotExist,
|
||||
GroupAlreadySubscribed,
|
||||
GroupNotSubscribed,
|
||||
MessageNotAccepted,
|
||||
MessageDecodingFailed,
|
||||
MessageEncodingFailed,
|
||||
NotEnoughClientHeap
|
||||
),
|
||||
ENAMES(
|
||||
"Success",
|
||||
"Internal error",
|
||||
"Client name is not unique",
|
||||
"Client was not accepted",
|
||||
"Group name is not unique",
|
||||
"Group does not exist",
|
||||
"Already subscribed to group",
|
||||
"Not subscribed to group",
|
||||
"Message not accepted",
|
||||
"Message could not be decoded",
|
||||
"Message could not be encoded",
|
||||
"Not enough client heap"
|
||||
)
|
||||
);
|
||||
|
||||
const std::string StatusGroup = "STATUS_GROUP";
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! C'tor
|
||||
Queue(const std::string &name, uint64_t maxPayloadSize);
|
||||
~Queue();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @return The queue name
|
||||
*/
|
||||
const std::string &name() const;
|
||||
|
||||
/**
|
||||
* @brief Adds a message processor to the list of processors.
|
||||
* @param proc The processor instance which is managed by the queue
|
||||
* with a smart pointer.
|
||||
* @return Success flag
|
||||
*/
|
||||
bool add(MessageProcessor *proc);
|
||||
|
||||
/**
|
||||
* @brief Adds a group/topic to the queue.
|
||||
* @param name The name of the group
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
Result addGroup(const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Returns a list of available group names
|
||||
* @return The list of names
|
||||
*/
|
||||
const StringList &groups() const { return _groupNames; }
|
||||
|
||||
/**
|
||||
* @brief Return the sender name of the queue.
|
||||
* @return A NULL terminated const string
|
||||
*/
|
||||
const char *senderName() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the message dispatcher for thread synchronisation.
|
||||
*
|
||||
* The queue runs a thread to process messages via plugins. If the
|
||||
* message is processed the thread notifies the queue about it. The
|
||||
* queue could now call publish but that is probably not thread-safe
|
||||
* and inefficient to implement on each subscriber. The message
|
||||
* dispatcher receives a notification about a new message and can then
|
||||
* implement any inter-thread communication to publish the message in
|
||||
* the same context as it has been created.
|
||||
*
|
||||
* @param dispatcher The dispatcher instance not managed by the queue.
|
||||
*/
|
||||
void setMessageDispatcher(MessageDispatcher *dispatcher);
|
||||
|
||||
/**
|
||||
* @brief Subscribe a client to a particular group
|
||||
* @param client The client
|
||||
* @param group The name of the group
|
||||
* @return The result code
|
||||
*/
|
||||
Result subscribe(Client *client, const std::string &group);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribes a client from a particular group
|
||||
* @param client The client
|
||||
* @param group The name of the group
|
||||
* @return The result code
|
||||
*/
|
||||
Result unsubscribe(Client *client, const std::string &group);
|
||||
|
||||
/**
|
||||
* @brief Returns a buffered message after a particular sequence number
|
||||
* @param sequenceNumber The sequence number to continue with.
|
||||
*
|
||||
* The returned message must have a sequence number greater than
|
||||
* this parameter or lower if a wrap has occured but never the
|
||||
* same.
|
||||
* @param client The client instance to filter subscriptions for
|
||||
* @return A message pointer or NULL if no message is available
|
||||
*/
|
||||
Message *getMessage(SequenceNumber sequenceNumber,
|
||||
const Client *client) const;
|
||||
|
||||
/**
|
||||
* @brief Pushes a message from a client to the queue
|
||||
*
|
||||
* This method is called from Client subclasses that received a message
|
||||
* through their transport protocol. The message pointer will either
|
||||
* be managed in a smart pointer or deleted. If false is returned the
|
||||
* caller must take care of deleting the message.
|
||||
*
|
||||
* @param sender The sender instance
|
||||
* @param msg The message
|
||||
* @param packetLength The size in bytes of the received packet including
|
||||
* protocol specific header data. This is only
|
||||
* used for statistics.
|
||||
* @return The result code
|
||||
*/
|
||||
Result push(Client *sender, Message *msg, int packetSize = 0);
|
||||
|
||||
/**
|
||||
* @brief Dispatches a message via a message dispatcher. If none is
|
||||
* set then this call is equal to push.
|
||||
* @param sender The sender instance
|
||||
* @param msg The message
|
||||
* @return The result code
|
||||
*/
|
||||
Result dispatch(Client *sender, Message *msg);
|
||||
|
||||
/**
|
||||
* @brief Activates the queue and starts the processing thread.
|
||||
*/
|
||||
void activate();
|
||||
|
||||
/**
|
||||
* @brief Shutdown the queue and finished the processing thread if
|
||||
* running.
|
||||
*
|
||||
* This will also shutdown all processors associated with the queue.
|
||||
*
|
||||
* Note that this call can block depending how many plugins are
|
||||
* running and currently processing a message. This method waits until
|
||||
* the processing thread is finished.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief Callback to notify the queue about some timeout.
|
||||
*
|
||||
* This function is used to check expiration of outstanding
|
||||
* acknowledgement messages. This function is not thread-safe and
|
||||
* must be called from within the thread the queue is running in.
|
||||
*/
|
||||
void timeout();
|
||||
|
||||
/**
|
||||
* @brief Populates the passed statistics structure.
|
||||
* @param stats[out] The target structure
|
||||
* @param reset[in] Whether to reset the internal statistics or not.
|
||||
*/
|
||||
void getStatisticsSnapshot(QueueStatistics &stats, bool reset = true);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Client memory interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @brief Allocates additional client heap. Once allocated the heap
|
||||
* cannot be free'd anymore. This is mainly used for plugins
|
||||
* that are initialized once and need to store additional
|
||||
* data in a client structure.
|
||||
* @param bytes The number of bytes to allocate
|
||||
* @return An offset to the local client heap or a negative number
|
||||
* in case of an error. The absolute value (-result) of the
|
||||
* error translates to a status code (@Result).
|
||||
*/
|
||||
int allocateClientHeap(int bytes);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Publisher interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @brief Registers a client in the queue and sets up the PubSub
|
||||
* connections.
|
||||
*
|
||||
* This is called when the client calls connect and is part of the
|
||||
* PublisherBase interface.
|
||||
* @param client The client to be registered
|
||||
* @param slot The slot
|
||||
* @return The result code
|
||||
*/
|
||||
Result connect(Client *client, const KeyCStrValues params, int paramCount,
|
||||
KeyValues &outParams);
|
||||
|
||||
/**
|
||||
* @brief Deregisters a client from the queue and clears the PubSub
|
||||
* connections.
|
||||
*
|
||||
* This is called when the client calls disconnect and is part of the
|
||||
* PublisherBase interface.
|
||||
* @param client The client to be deregistered
|
||||
* @return The result code
|
||||
*/
|
||||
Result disconnect(Client *client);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Settings interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
uint64_t maxPayloadSize() const;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private interface
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
using ProcessingTask = std::pair<Client*,Message*>;
|
||||
using TaskQueue = Utils::BlockingDequeue<ProcessingTask>;
|
||||
|
||||
/**
|
||||
* @brief Publishes a message from a client to all registered clients
|
||||
*
|
||||
* This method is called from Client subclasses that received a message
|
||||
* through their transport protocol.
|
||||
*
|
||||
* @param sender The sender instance
|
||||
* @param msg The message
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool publish(Client *sender, Message *msg);
|
||||
|
||||
/**
|
||||
* @brief Pops all messages from the processing queue and publishes them.
|
||||
*
|
||||
* This call does not block.
|
||||
*/
|
||||
void flushProcessedMessages();
|
||||
|
||||
/**
|
||||
* @brief The processing loop running in a different thread.
|
||||
*/
|
||||
void processingLoop();
|
||||
|
||||
/**
|
||||
* @brief Processes a message e.g. via plugins.
|
||||
* @param task The task to be processed
|
||||
*/
|
||||
void process(ProcessingTask &task);
|
||||
|
||||
/**
|
||||
* @brief Called from the processing thread informing the queue that
|
||||
* the message is processed and can be forwarded to clients.
|
||||
* @param task The task
|
||||
*/
|
||||
void taskReady(const ProcessingTask &task);
|
||||
|
||||
/**
|
||||
* @brief Replaces the incoming message with a response
|
||||
* @param task The task to be updated
|
||||
*/
|
||||
void returnToSender(Message *msg, Core::BaseObject *obj);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
using Groups = std::map<std::string, GroupPtr>;
|
||||
using MessageRing = circular_buffer<MessagePtr>;
|
||||
using ClientNames = KHashSet<const char*>;
|
||||
using Clients = KHashMap<const char*, Client*>;
|
||||
|
||||
std::string _name;
|
||||
MessageProcessors _processors;
|
||||
MessageProcessors _connectionProcessors;
|
||||
MessageProcessors _messageProcessors;
|
||||
MessageDispatcher *_processedMessageDispatcher;
|
||||
SequenceNumber _sequenceNumber;
|
||||
Groups _groups;
|
||||
StringList _groupNames;
|
||||
MessageRing _messages;
|
||||
Clients _clients;
|
||||
std::thread *_messageProcessor;
|
||||
TaskQueue _tasks;
|
||||
TaskQueue _results;
|
||||
Core::Time _created;
|
||||
Core::Time _lastSOHTimestamp;
|
||||
int _allocatedClientHeap;
|
||||
int _sohInterval;
|
||||
int _inactivityLimit;
|
||||
uint64_t _maxPayloadSize;
|
||||
mutable Tx _txMessages;
|
||||
mutable Tx _txBytes;
|
||||
mutable Tx _txPayload;
|
||||
|
||||
|
||||
friend class MessageDispatcher;
|
||||
};
|
||||
|
||||
|
||||
inline const std::string &Queue::name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t Queue::maxPayloadSize() const {
|
||||
return _maxPayloadSize;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
109
include/seiscomp/broker/statistics.h
Normal file
109
include/seiscomp/broker/statistics.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_BROKER_STATISTICS_H__
|
||||
#define SEISCOMP_BROKER_STATISTICS_H__
|
||||
|
||||
|
||||
#include <seiscomp/core/baseobject.h>
|
||||
#include <seiscomp/broker/api.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Messaging {
|
||||
namespace Broker {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Simple structure to store transfer counts.
|
||||
* The unit of the counters is not defined. It can be counts or
|
||||
* bytes or something different. That depends on the context.
|
||||
*/
|
||||
struct SC_BROKER_API Tx : Core::BaseObject {
|
||||
Tx() : received(0), sent(0) {}
|
||||
|
||||
double received; //!< Number of items received
|
||||
double sent; //!< Number of items sent
|
||||
|
||||
Tx &operator+=(const Tx &other) {
|
||||
received += other.received;
|
||||
sent += other.sent;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DECLARE_SERIALIZATION {
|
||||
ar
|
||||
& NAMED_OBJECT("recv", received)
|
||||
& NAMED_OBJECT("sent", sent)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GroupStatistics : Core::BaseObject {
|
||||
std::string name;
|
||||
Tx messages;
|
||||
Tx bytes;
|
||||
Tx payload;
|
||||
|
||||
DECLARE_SERIALIZATION {
|
||||
ar
|
||||
& NAMED_OBJECT("name", name)
|
||||
& NAMED_OBJECT_HINT("messages", messages, Archive::STATIC_TYPE)
|
||||
& NAMED_OBJECT_HINT("bytes", bytes, Archive::STATIC_TYPE)
|
||||
& NAMED_OBJECT_HINT("payload", payload, Archive::STATIC_TYPE)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DEFINE_SMARTPOINTER(QueueStatistics);
|
||||
struct SC_BROKER_API QueueStatistics : Core::BaseObject {
|
||||
typedef std::vector<GroupStatistics> Groups;
|
||||
std::string name;
|
||||
Groups groups;
|
||||
Tx messages;
|
||||
Tx bytes;
|
||||
Tx payload;
|
||||
|
||||
QueueStatistics &operator+=(const QueueStatistics &stats);
|
||||
|
||||
DECLARE_SERIALIZATION {
|
||||
ar
|
||||
& NAMED_OBJECT("name", name)
|
||||
& NAMED_OBJECT_HINT("messages", messages, Archive::STATIC_TYPE)
|
||||
& NAMED_OBJECT_HINT("bytes", bytes, Archive::STATIC_TYPE)
|
||||
& NAMED_OBJECT_HINT("payload", payload, Archive::STATIC_TYPE)
|
||||
& NAMED_OBJECT_HINT("groups", groups, Archive::STATIC_TYPE)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
496
include/seiscomp/broker/utils/circular.h
Normal file
496
include/seiscomp/broker/utils/circular.h
Normal file
@@ -0,0 +1,496 @@
|
||||
/******************************************************************************
|
||||
* Author: Pete Goodliffe
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright 2002 Pete Goodliffe All rights reserved.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Purpose: STL-style circular buffer
|
||||
*
|
||||
* Formatting changed by <Jan Becker, gempa GmbH> jabe@gempa.de
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef CIRCULAR_BUFFER_H
|
||||
#define CIRCULAR_BUFFER_H
|
||||
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Iterators
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Iterator type for the circular_buffer class.
|
||||
*
|
||||
* This one template class provides all variants of forward/reverse
|
||||
* const/non const iterators through plentiful template magic.
|
||||
*
|
||||
* You don't need to instantiate it directly, use the good public functions
|
||||
* availble in circular_buffer.
|
||||
*/
|
||||
template<typename T, //circular_buffer type
|
||||
//(incl const)
|
||||
typename T_nonconst, //with any consts
|
||||
typename elem_type = typename T::value_type> //+ const for const iter
|
||||
class circular_buffer_iterator {
|
||||
public:
|
||||
typedef circular_buffer_iterator<T, T_nonconst, elem_type> self_type;
|
||||
typedef T cbuf_type;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef typename cbuf_type::value_type value_type;
|
||||
typedef typename cbuf_type::size_type size_type;
|
||||
typedef typename cbuf_type::pointer pointer;
|
||||
typedef typename cbuf_type::const_pointer const_pointer;
|
||||
typedef typename cbuf_type::reference reference;
|
||||
typedef typename cbuf_type::const_reference const_reference;
|
||||
typedef typename cbuf_type::difference_type difference_type;
|
||||
|
||||
circular_buffer_iterator(cbuf_type *b, size_type p)
|
||||
: buf_(b), pos_(p) {}
|
||||
|
||||
// Converting a non-const iterator to a const iterator
|
||||
circular_buffer_iterator(const circular_buffer_iterator<T_nonconst, T_nonconst, typename T_nonconst::value_type> &other)
|
||||
: buf_(other.buf_), pos_(other.pos_) {}
|
||||
|
||||
friend class circular_buffer_iterator<const T, T, const elem_type> ;
|
||||
|
||||
// Use compiler generated copy ctor, copy assignment operator and dtor
|
||||
|
||||
elem_type &operator*() {
|
||||
return (*buf_)[pos_];
|
||||
}
|
||||
|
||||
elem_type *operator->() {
|
||||
return &(operator*());
|
||||
}
|
||||
|
||||
self_type &operator++() {
|
||||
pos_ += 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type operator++(int) {
|
||||
self_type tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
self_type &operator--() {
|
||||
pos_ -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type operator--(int) {
|
||||
self_type tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
self_type operator+(difference_type n) const {
|
||||
self_type tmp(*this);
|
||||
tmp.pos_ += n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
self_type &operator+=(difference_type n) {
|
||||
pos_ += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type operator-(difference_type n) const {
|
||||
self_type tmp(*this);
|
||||
tmp.pos_ -= n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
self_type &operator-=(difference_type n) {
|
||||
pos_ -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
difference_type operator-(const self_type &c) const {
|
||||
return pos_ - c.pos_;
|
||||
}
|
||||
|
||||
bool operator==(const self_type &other) const {
|
||||
return pos_ == other.pos_ && buf_ == other.buf_;
|
||||
}
|
||||
bool operator!=(const self_type &other) const {
|
||||
return pos_ != other.pos_ && buf_ == other.buf_;
|
||||
}
|
||||
bool operator>(const self_type &other) const {
|
||||
return pos_ > other.pos_;
|
||||
}
|
||||
bool operator>=(const self_type &other) const {
|
||||
return pos_ >= other.pos_;
|
||||
}
|
||||
bool operator<(const self_type &other) const {
|
||||
return pos_ < other.pos_;
|
||||
}
|
||||
bool operator<=(const self_type &other) const {
|
||||
return pos_ <= other.pos_;
|
||||
}
|
||||
|
||||
private:
|
||||
cbuf_type *buf_;
|
||||
size_type pos_;
|
||||
};
|
||||
|
||||
|
||||
template<typename circular_buffer_iterator_t>
|
||||
circular_buffer_iterator_t operator+(
|
||||
const typename circular_buffer_iterator_t::difference_type &a,
|
||||
const circular_buffer_iterator_t &b) {
|
||||
return circular_buffer_iterator_t(a) + b;
|
||||
}
|
||||
|
||||
template<typename circular_buffer_iterator_t>
|
||||
circular_buffer_iterator_t operator-(
|
||||
const typename circular_buffer_iterator_t::difference_type &a,
|
||||
const circular_buffer_iterator_t &b) {
|
||||
return circular_buffer_iterator_t(a) - b;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* circular_buffer
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* This class provides a circular buffer in the STL style.
|
||||
*
|
||||
* You can add data to the end using the @ref push_back function, read data
|
||||
* using @ref front() and remove data using @ref pop_front().
|
||||
*
|
||||
* The class also provides random access through the @ref operator[]()
|
||||
* function and its random access iterator. Subscripting the array with
|
||||
* an invalid (out of range) index number leads to undefined results, both
|
||||
* for reading and writing.
|
||||
*
|
||||
* This class template accepts three template parameters:
|
||||
* <li> T The type of object contained
|
||||
* <li> always_accept_data_when_full Determines the behaviour of
|
||||
* @ref push_back when the buffer is full.
|
||||
* Set to true new data is always added, the
|
||||
* old "end" data is thrown away.
|
||||
* Set to false, the new data is not added.
|
||||
* No error is returned neither is an
|
||||
* exception raised.
|
||||
* <li> Alloc Allocator type to use (in line with other
|
||||
* STL containers).
|
||||
*
|
||||
* @short STL style circule buffer
|
||||
* @author Pete Goodliffe
|
||||
* @version 1.00
|
||||
*/
|
||||
template<typename T, bool always_accept_data_when_full = true,
|
||||
typename Alloc = std::allocator<T> >
|
||||
class circular_buffer {
|
||||
public:
|
||||
enum {
|
||||
version_major = 1, version_minor = 0
|
||||
};
|
||||
|
||||
// Typedefs
|
||||
typedef circular_buffer<T, always_accept_data_when_full, Alloc> self_type;
|
||||
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename Alloc::value_type value_type;
|
||||
typedef typename Alloc::pointer pointer;
|
||||
typedef typename Alloc::const_pointer const_pointer;
|
||||
typedef typename Alloc::reference reference;
|
||||
typedef typename Alloc::const_reference const_reference;
|
||||
|
||||
typedef typename Alloc::size_type size_type;
|
||||
typedef typename Alloc::difference_type difference_type;
|
||||
|
||||
typedef circular_buffer_iterator<self_type, self_type> iterator;
|
||||
typedef circular_buffer_iterator<const self_type, self_type,
|
||||
const value_type> const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
// Lifetime
|
||||
enum {
|
||||
default_capacity = 100
|
||||
};
|
||||
|
||||
explicit circular_buffer(size_type capacity = default_capacity)
|
||||
: array_(alloc_.allocate(capacity))
|
||||
, array_size_(capacity)
|
||||
, head_(1)
|
||||
, tail_(0)
|
||||
, contents_size_(0) {}
|
||||
|
||||
circular_buffer(const circular_buffer &other)
|
||||
: array_(alloc_.allocate(other.array_size_))
|
||||
, array_size_(other.array_size_), head_(other.head_)
|
||||
, tail_(other.tail_), contents_size_(other.contents_size_) {
|
||||
try {
|
||||
assign_into(other.begin(), other.end());
|
||||
}
|
||||
catch ( ... ) {
|
||||
destroy_all_elements();
|
||||
alloc_.deallocate(array_, array_size_);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<class InputIterator>
|
||||
circular_buffer(InputIterator from, InputIterator to)
|
||||
: array_(alloc_.allocate(1)), array_size_(1)
|
||||
, head_(1), tail_(0), contents_size_(0) {
|
||||
circular_buffer tmp;
|
||||
tmp.assign_into_reserving(from, to);
|
||||
swap(tmp);
|
||||
}
|
||||
|
||||
~circular_buffer() {
|
||||
destroy_all_elements();
|
||||
alloc_.deallocate(array_, array_size_);
|
||||
}
|
||||
|
||||
circular_buffer &operator=(const self_type &other) {
|
||||
circular_buffer tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(circular_buffer &other) {
|
||||
std::swap(array_, other.array_);
|
||||
std::swap(array_size_, other.array_size_);
|
||||
std::swap(head_, other.head_);
|
||||
std::swap(tail_, other.tail_);
|
||||
std::swap(contents_size_, other.contents_size_);
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const {
|
||||
return alloc_;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
iterator begin() {
|
||||
return iterator(this, 0);
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(this, size());
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(this, 0);
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(this, size());
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
// Size
|
||||
size_type size() const {
|
||||
return contents_size_;
|
||||
}
|
||||
|
||||
size_type capacity() const {
|
||||
return array_size_;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return !contents_size_;
|
||||
}
|
||||
|
||||
size_type max_size() const {
|
||||
return alloc_.max_size();
|
||||
}
|
||||
|
||||
void reserve(size_type new_size) {
|
||||
if ( capacity() < new_size ) {
|
||||
circular_buffer tmp(new_size);
|
||||
tmp.assign_into(begin(), end());
|
||||
swap(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// Accessing
|
||||
reference front() {
|
||||
return array_[head_];
|
||||
}
|
||||
|
||||
reference back() {
|
||||
return array_[tail_];
|
||||
}
|
||||
|
||||
const_reference front() const {
|
||||
return array_[head_];
|
||||
}
|
||||
|
||||
const_reference back() const {
|
||||
return array_[tail_];
|
||||
}
|
||||
|
||||
void push_back(const value_type &item) {
|
||||
size_type next = next_tail();
|
||||
if ( contents_size_ == array_size_ ) {
|
||||
if ( always_accept_data_when_full ) {
|
||||
array_[next] = item;
|
||||
increment_head();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alloc_.construct(array_ + next, item);
|
||||
}
|
||||
increment_tail();
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
size_type destroy_pos = head_;
|
||||
increment_head();
|
||||
alloc_.destroy(array_ + destroy_pos);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for ( size_type n = 0; n < contents_size_; ++n ) {
|
||||
alloc_.destroy(array_ + index_to_subscript(n));
|
||||
}
|
||||
head_ = 1;
|
||||
tail_ = contents_size_ = 0;
|
||||
}
|
||||
|
||||
reference operator[](size_type n) {
|
||||
return at_unchecked(n);
|
||||
}
|
||||
|
||||
const_reference operator[](size_type n) const {
|
||||
return at_unchecked(n);
|
||||
}
|
||||
|
||||
reference at(size_type n) {
|
||||
return at_checked(n);
|
||||
}
|
||||
|
||||
const_reference at(size_type n) const {
|
||||
return at_checked(n);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
reference at_unchecked(size_type index) const {
|
||||
return array_[index_to_subscript(index)];
|
||||
}
|
||||
|
||||
reference at_checked(size_type index) const {
|
||||
if ( index >= contents_size_ ) {
|
||||
throw std::out_of_range("index out of bounds");
|
||||
}
|
||||
return at_unchecked(index);
|
||||
}
|
||||
|
||||
// Rounds an unbounded to an index into array_
|
||||
size_type normalise(size_type n) const {
|
||||
return n % array_size_;
|
||||
}
|
||||
|
||||
// Converts external index to an array subscript
|
||||
size_type index_to_subscript(size_type index) const {
|
||||
return normalise(index + head_);
|
||||
}
|
||||
|
||||
void increment_tail() {
|
||||
++contents_size_;
|
||||
tail_ = next_tail();
|
||||
}
|
||||
|
||||
size_type next_tail() {
|
||||
return (tail_ + 1 == array_size_) ? 0 : tail_ + 1;
|
||||
}
|
||||
|
||||
void increment_head() {
|
||||
// precondition: !empty()
|
||||
++head_;
|
||||
--contents_size_;
|
||||
if ( head_ == array_size_ )
|
||||
head_ = 0;
|
||||
}
|
||||
|
||||
template<typename f_iter>
|
||||
void assign_into(f_iter from, f_iter to) {
|
||||
if ( contents_size_ )
|
||||
clear();
|
||||
while ( from != to ) {
|
||||
push_back(*from);
|
||||
++from;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename f_iter>
|
||||
void assign_into_reserving(f_iter from, f_iter to) {
|
||||
if ( contents_size_ )
|
||||
clear();
|
||||
|
||||
while ( from != to ) {
|
||||
if ( contents_size_ == array_size_ ) {
|
||||
reserve(static_cast<size_type>(array_size_ * 1.5));
|
||||
}
|
||||
|
||||
push_back(*from);
|
||||
++from;
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_all_elements() {
|
||||
for ( size_type n = 0; n < contents_size_; ++n ) {
|
||||
alloc_.destroy(array_ + index_to_subscript(n));
|
||||
}
|
||||
}
|
||||
|
||||
allocator_type alloc_;
|
||||
value_type *array_;
|
||||
size_type array_size_;
|
||||
size_type head_;
|
||||
size_type tail_;
|
||||
size_type contents_size_;
|
||||
};
|
||||
|
||||
|
||||
template<typename T, bool consume_policy, typename Alloc>
|
||||
bool operator==(const circular_buffer<T, consume_policy, Alloc> &a,
|
||||
const circular_buffer<T, consume_policy, Alloc> &b) {
|
||||
return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
template<typename T, bool consume_policy, typename Alloc>
|
||||
bool operator!=(const circular_buffer<T, consume_policy, Alloc> &a,
|
||||
const circular_buffer<T, consume_policy, Alloc> &b) {
|
||||
return a.size() != b.size() || !std::equal(a.begin(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
template<typename T, bool consume_policy, typename Alloc>
|
||||
bool operator<(const circular_buffer<T, consume_policy, Alloc> &a,
|
||||
const circular_buffer<T, consume_policy, Alloc> &b) {
|
||||
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
627
include/seiscomp/broker/utils/khash.h
Normal file
627
include/seiscomp/broker/utils/khash.h
Normal file
@@ -0,0 +1,627 @@
|
||||
/* The MIT License
|
||||
|
||||
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
An example:
|
||||
|
||||
#include "khash.h"
|
||||
KHASH_MAP_INIT_INT(32, char)
|
||||
int main() {
|
||||
int ret, is_missing;
|
||||
khiter_t k;
|
||||
khash_t(32) *h = kh_init(32);
|
||||
k = kh_put(32, h, 5, &ret);
|
||||
kh_value(h, k) = 10;
|
||||
k = kh_get(32, h, 10);
|
||||
is_missing = (k == kh_end(h));
|
||||
k = kh_get(32, h, 5);
|
||||
kh_del(32, h, k);
|
||||
for (k = kh_begin(h); k != kh_end(h); ++k)
|
||||
if (kh_exist(h, k)) kh_value(h, k) = 1;
|
||||
kh_destroy(32, h);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
2013-05-02 (0.2.8):
|
||||
|
||||
* Use quadratic probing. When the capacity is power of 2, stepping function
|
||||
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
|
||||
hashing on cache performance and is more robust than linear probing.
|
||||
|
||||
In theory, double hashing should be more robust than quadratic probing.
|
||||
However, my implementation is probably not for large hash tables, because
|
||||
the second hash function is closely tied to the first hash function,
|
||||
which reduce the effectiveness of double hashing.
|
||||
|
||||
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
|
||||
|
||||
2011-12-29 (0.2.7):
|
||||
|
||||
* Minor code clean up; no actual effect.
|
||||
|
||||
2011-09-16 (0.2.6):
|
||||
|
||||
* The capacity is a power of 2. This seems to dramatically improve the
|
||||
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
|
||||
|
||||
- http://code.google.com/p/ulib/
|
||||
- http://nothings.org/computer/judy/
|
||||
|
||||
* Allow to optionally use linear probing which usually has better
|
||||
performance for random input. Double hashing is still the default as it
|
||||
is more robust to certain non-random input.
|
||||
|
||||
* Added Wang's integer hash function (not used by default). This hash
|
||||
function is more robust to certain non-random input.
|
||||
|
||||
2011-02-14 (0.2.5):
|
||||
|
||||
* Allow to declare global functions.
|
||||
|
||||
2009-09-26 (0.2.4):
|
||||
|
||||
* Improve portability
|
||||
|
||||
2008-09-19 (0.2.3):
|
||||
|
||||
* Corrected the example
|
||||
* Improved interfaces
|
||||
|
||||
2008-09-11 (0.2.2):
|
||||
|
||||
* Improved speed a little in kh_put()
|
||||
|
||||
2008-09-10 (0.2.1):
|
||||
|
||||
* Added kh_clear()
|
||||
* Fixed a compiling error
|
||||
|
||||
2008-09-02 (0.2.0):
|
||||
|
||||
* Changed to token concatenation which increases flexibility.
|
||||
|
||||
2008-08-31 (0.1.2):
|
||||
|
||||
* Fixed a bug in kh_get(), which has not been tested previously.
|
||||
|
||||
2008-08-31 (0.1.1):
|
||||
|
||||
* Added destructor
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AC_KHASH_H
|
||||
#define __AC_KHASH_H
|
||||
|
||||
/*!
|
||||
@header
|
||||
|
||||
Generic hash table library.
|
||||
*/
|
||||
|
||||
#define AC_VERSION_KHASH_H "0.2.8"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* compiler specific configuration */
|
||||
|
||||
#if UINT_MAX == 0xffffffffu
|
||||
typedef unsigned int khint32_t;
|
||||
#elif ULONG_MAX == 0xffffffffu
|
||||
typedef unsigned long khint32_t;
|
||||
#endif
|
||||
|
||||
#if ULONG_MAX == ULLONG_MAX
|
||||
typedef unsigned long khint64_t;
|
||||
#else
|
||||
typedef unsigned long long khint64_t;
|
||||
#endif
|
||||
|
||||
#ifndef kh_inline
|
||||
#ifdef _MSC_VER
|
||||
#define kh_inline __inline
|
||||
#else
|
||||
#define kh_inline inline
|
||||
#endif
|
||||
#endif /* kh_inline */
|
||||
|
||||
#ifndef klib_unused
|
||||
#if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
|
||||
#define klib_unused __attribute__ ((__unused__))
|
||||
#else
|
||||
#define klib_unused
|
||||
#endif
|
||||
#endif /* klib_unused */
|
||||
|
||||
typedef khint32_t khint_t;
|
||||
typedef khint_t khiter_t;
|
||||
|
||||
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
|
||||
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
|
||||
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
|
||||
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
|
||||
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
|
||||
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
|
||||
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
|
||||
|
||||
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
|
||||
|
||||
#ifndef kroundup32
|
||||
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
|
||||
#endif
|
||||
|
||||
#ifndef kcalloc
|
||||
#define kcalloc(N,Z) calloc(N,Z)
|
||||
#endif
|
||||
#ifndef kmalloc
|
||||
#define kmalloc(Z) malloc(Z)
|
||||
#endif
|
||||
#ifndef krealloc
|
||||
#define krealloc(P,Z) realloc(P,Z)
|
||||
#endif
|
||||
#ifndef kfree
|
||||
#define kfree(P) free(P)
|
||||
#endif
|
||||
|
||||
static const double __ac_HASH_UPPER = 0.77;
|
||||
|
||||
#define __KHASH_TYPE(name, khkey_t, khval_t) \
|
||||
typedef struct kh_##name##_s { \
|
||||
khint_t n_buckets, size, n_occupied, upper_bound; \
|
||||
khint32_t *flags; \
|
||||
khkey_t *keys; \
|
||||
khval_t *vals; \
|
||||
} kh_##name##_t;
|
||||
|
||||
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
|
||||
extern kh_##name##_t *kh_init_##name(void); \
|
||||
extern void kh_destroy_##name(kh_##name##_t *h); \
|
||||
extern void kh_clear_##name(kh_##name##_t *h); \
|
||||
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
|
||||
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
|
||||
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
|
||||
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
|
||||
|
||||
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||
SCOPE kh_##name##_t *kh_init_##name(void) { \
|
||||
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
|
||||
} \
|
||||
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
|
||||
{ \
|
||||
if (h) { \
|
||||
kfree((void *)h->keys); kfree(h->flags); \
|
||||
kfree((void *)h->vals); \
|
||||
kfree(h); \
|
||||
} \
|
||||
} \
|
||||
SCOPE void kh_clear_##name(kh_##name##_t *h) \
|
||||
{ \
|
||||
if (h && h->flags) { \
|
||||
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
|
||||
h->size = h->n_occupied = 0; \
|
||||
} \
|
||||
} \
|
||||
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
|
||||
{ \
|
||||
if (h->n_buckets) { \
|
||||
khint_t k, i, last, mask, step = 0; \
|
||||
mask = h->n_buckets - 1; \
|
||||
k = __hash_func(key); i = k & mask; \
|
||||
last = i; \
|
||||
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
||||
i = (i + (++step)) & mask; \
|
||||
if (i == last) return h->n_buckets; \
|
||||
} \
|
||||
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
|
||||
} else return 0; \
|
||||
} \
|
||||
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
|
||||
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
|
||||
khint32_t *new_flags = 0; \
|
||||
khint_t j = 1; \
|
||||
{ \
|
||||
kroundup32(new_n_buckets); \
|
||||
if (new_n_buckets < 4) new_n_buckets = 4; \
|
||||
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
|
||||
else { /* hash table size to be changed (shrink or expand); rehash */ \
|
||||
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
||||
if (!new_flags) return -1; \
|
||||
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
||||
if (h->n_buckets < new_n_buckets) { /* expand */ \
|
||||
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
|
||||
if (!new_keys) { kfree(new_flags); return -1; } \
|
||||
h->keys = new_keys; \
|
||||
if (kh_is_map) { \
|
||||
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
|
||||
if (!new_vals) { kfree(new_flags); return -1; } \
|
||||
h->vals = new_vals; \
|
||||
} \
|
||||
} /* otherwise shrink */ \
|
||||
} \
|
||||
} \
|
||||
if (j) { /* rehashing is needed */ \
|
||||
for (j = 0; j != h->n_buckets; ++j) { \
|
||||
if (__ac_iseither(h->flags, j) == 0) { \
|
||||
khkey_t key = h->keys[j]; \
|
||||
khval_t val; \
|
||||
khint_t new_mask; \
|
||||
new_mask = new_n_buckets - 1; \
|
||||
if (kh_is_map) val = h->vals[j]; \
|
||||
__ac_set_isdel_true(h->flags, j); \
|
||||
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
|
||||
khint_t k, i, step = 0; \
|
||||
k = __hash_func(key); \
|
||||
i = k & new_mask; \
|
||||
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
|
||||
__ac_set_isempty_false(new_flags, i); \
|
||||
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
|
||||
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
|
||||
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
|
||||
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
|
||||
} else { /* write the element and jump out of the loop */ \
|
||||
h->keys[i] = key; \
|
||||
if (kh_is_map) h->vals[i] = val; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
|
||||
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
|
||||
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
|
||||
} \
|
||||
kfree(h->flags); /* free the working space */ \
|
||||
h->flags = new_flags; \
|
||||
h->n_buckets = new_n_buckets; \
|
||||
h->n_occupied = h->size; \
|
||||
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
|
||||
{ \
|
||||
khint_t x; \
|
||||
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
|
||||
if (h->n_buckets > (h->size<<1)) { \
|
||||
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
|
||||
*ret = -1; return h->n_buckets; \
|
||||
} \
|
||||
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
|
||||
*ret = -1; return h->n_buckets; \
|
||||
} \
|
||||
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
|
||||
{ \
|
||||
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
|
||||
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
|
||||
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
|
||||
else { \
|
||||
last = i; \
|
||||
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
||||
if (__ac_isdel(h->flags, i)) site = i; \
|
||||
i = (i + (++step)) & mask; \
|
||||
if (i == last) { x = site; break; } \
|
||||
} \
|
||||
if (x == h->n_buckets) { \
|
||||
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
|
||||
else x = i; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
|
||||
h->keys[x] = key; \
|
||||
__ac_set_isboth_false(h->flags, x); \
|
||||
++h->size; ++h->n_occupied; \
|
||||
*ret = 1; \
|
||||
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
|
||||
h->keys[x] = key; \
|
||||
__ac_set_isboth_false(h->flags, x); \
|
||||
++h->size; \
|
||||
*ret = 2; \
|
||||
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
|
||||
return x; \
|
||||
} \
|
||||
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
|
||||
{ \
|
||||
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
|
||||
__ac_set_isdel_true(h->flags, x); \
|
||||
--h->size; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define KHASH_DECLARE(name, khkey_t, khval_t) \
|
||||
__KHASH_TYPE(name, khkey_t, khval_t) \
|
||||
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
|
||||
|
||||
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||
__KHASH_TYPE(name, khkey_t, khval_t) \
|
||||
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
|
||||
|
||||
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||
KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
|
||||
|
||||
/* --- BEGIN OF HASH FUNCTIONS --- */
|
||||
|
||||
/*! @function
|
||||
@abstract Integer hash function
|
||||
@param key The integer [khint32_t]
|
||||
@return The hash value [khint_t]
|
||||
*/
|
||||
#define kh_int_hash_func(key) (khint32_t)(key)
|
||||
/*! @function
|
||||
@abstract Integer comparison function
|
||||
*/
|
||||
#define kh_int_hash_equal(a, b) ((a) == (b))
|
||||
/*! @function
|
||||
@abstract 64-bit integer hash function
|
||||
@param key The integer [khint64_t]
|
||||
@return The hash value [khint_t]
|
||||
*/
|
||||
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
|
||||
/*! @function
|
||||
@abstract 64-bit integer comparison function
|
||||
*/
|
||||
#define kh_int64_hash_equal(a, b) ((a) == (b))
|
||||
/*! @function
|
||||
@abstract const char* hash function
|
||||
@param s Pointer to a null terminated string
|
||||
@return The hash value
|
||||
*/
|
||||
static kh_inline khint_t __ac_X31_hash_string(const char *s)
|
||||
{
|
||||
khint_t h = (khint_t)*s;
|
||||
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
|
||||
return h;
|
||||
}
|
||||
/*! @function
|
||||
@abstract Another interface to const char* hash function
|
||||
@param key Pointer to a null terminated string [const char*]
|
||||
@return The hash value [khint_t]
|
||||
*/
|
||||
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
|
||||
/*! @function
|
||||
@abstract Const char* comparison function
|
||||
*/
|
||||
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
|
||||
|
||||
static kh_inline khint_t __ac_Wang_hash(khint_t key)
|
||||
{
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
return key;
|
||||
}
|
||||
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
|
||||
|
||||
/* --- END OF HASH FUNCTIONS --- */
|
||||
|
||||
/* Other convenient macros... */
|
||||
|
||||
/*!
|
||||
@abstract Type of the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define khash_t(name) kh_##name##_t
|
||||
|
||||
/*! @function
|
||||
@abstract Initiate a hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@return Pointer to the hash table [khash_t(name)*]
|
||||
*/
|
||||
#define kh_init(name) kh_init_##name()
|
||||
|
||||
/*! @function
|
||||
@abstract Destroy a hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
*/
|
||||
#define kh_destroy(name, h) kh_destroy_##name(h)
|
||||
|
||||
/*! @function
|
||||
@abstract Reset a hash table without deallocating memory.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
*/
|
||||
#define kh_clear(name, h) kh_clear_##name(h)
|
||||
|
||||
/*! @function
|
||||
@abstract Resize a hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param s New size [khint_t]
|
||||
*/
|
||||
#define kh_resize(name, h, s) kh_resize_##name(h, s)
|
||||
|
||||
/*! @function
|
||||
@abstract Insert a key to the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param k Key [type of keys]
|
||||
@param r Extra return code: -1 if the operation failed;
|
||||
0 if the key is present in the hash table;
|
||||
1 if the bucket is empty (never used); 2 if the element in
|
||||
the bucket has been deleted [int*]
|
||||
@return Iterator to the inserted element [khint_t]
|
||||
*/
|
||||
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
|
||||
|
||||
/*! @function
|
||||
@abstract Retrieve a key from the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param k Key [type of keys]
|
||||
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
|
||||
*/
|
||||
#define kh_get(name, h, k) kh_get_##name(h, k)
|
||||
|
||||
/*! @function
|
||||
@abstract Remove a key from the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param k Iterator to the element to be deleted [khint_t]
|
||||
*/
|
||||
#define kh_del(name, h, k) kh_del_##name(h, k)
|
||||
|
||||
/*! @function
|
||||
@abstract Test whether a bucket contains data.
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param x Iterator to the bucket [khint_t]
|
||||
@return 1 if containing data; 0 otherwise [int]
|
||||
*/
|
||||
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
|
||||
|
||||
/*! @function
|
||||
@abstract Get key given an iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param x Iterator to the bucket [khint_t]
|
||||
@return Key [type of keys]
|
||||
*/
|
||||
#define kh_key(h, x) ((h)->keys[x])
|
||||
|
||||
/*! @function
|
||||
@abstract Get value given an iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param x Iterator to the bucket [khint_t]
|
||||
@return Value [type of values]
|
||||
@discussion For hash sets, calling this results in segfault.
|
||||
*/
|
||||
#define kh_val(h, x) ((h)->vals[x])
|
||||
|
||||
/*! @function
|
||||
@abstract Alias of kh_val()
|
||||
*/
|
||||
#define kh_value(h, x) ((h)->vals[x])
|
||||
|
||||
/*! @function
|
||||
@abstract Get the start iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return The start iterator [khint_t]
|
||||
*/
|
||||
#define kh_begin(h) (khint_t)(0)
|
||||
|
||||
/*! @function
|
||||
@abstract Get the end iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return The end iterator [khint_t]
|
||||
*/
|
||||
#define kh_end(h) ((h)->n_buckets)
|
||||
|
||||
/*! @function
|
||||
@abstract Get the number of elements in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return Number of elements in the hash table [khint_t]
|
||||
*/
|
||||
#define kh_size(h) ((h)->size)
|
||||
|
||||
/*! @function
|
||||
@abstract Get the number of buckets in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return Number of buckets in the hash table [khint_t]
|
||||
*/
|
||||
#define kh_n_buckets(h) ((h)->n_buckets)
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the entries in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param kvar Variable to which key will be assigned
|
||||
@param vvar Variable to which value will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(kvar) = kh_key(h,__i); \
|
||||
(vvar) = kh_val(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the values in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param vvar Variable to which value will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(vvar) = kh_val(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/* More conenient interfaces */
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash set containing integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define KHASH_SET_INIT_INT(name) \
|
||||
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
@param khval_t Type of values [type]
|
||||
*/
|
||||
#define KHASH_MAP_INIT_INT(name, khval_t) \
|
||||
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing 64-bit integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define KHASH_SET_INIT_INT64(name) \
|
||||
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing 64-bit integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
@param khval_t Type of values [type]
|
||||
*/
|
||||
#define KHASH_MAP_INIT_INT64(name, khval_t) \
|
||||
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
|
||||
|
||||
typedef const char *kh_cstr_t;
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing const char* keys
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define KHASH_SET_INIT_STR(name) \
|
||||
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing const char* keys
|
||||
@param name Name of the hash table [symbol]
|
||||
@param khval_t Type of values [type]
|
||||
*/
|
||||
#define KHASH_MAP_INIT_STR(name, khval_t) \
|
||||
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
|
||||
|
||||
#endif /* __AC_KHASH_H */
|
||||
442
include/seiscomp/broker/utils/utils.h
Normal file
442
include/seiscomp/broker/utils/utils.h
Normal file
@@ -0,0 +1,442 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* Author: Jan Becker *
|
||||
* Email: jabe@gempa.de *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_MESSAGESERVER_UTILS_H__
|
||||
#define GEMPA_MESSAGESERVER_UTILS_H__
|
||||
|
||||
|
||||
#include <seiscomp/core/exceptions.h>
|
||||
#include <seiscomp/broker/api.h>
|
||||
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <type_traits>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Utils {
|
||||
|
||||
|
||||
/**
|
||||
* @brief The Randomizer class generated random data of arbitrary length.
|
||||
*
|
||||
* This class utilized /dev/urandom under Unix. Other operating systems are
|
||||
* not yet supported. Randomizer is implemented as a singleton. The usage
|
||||
* is as simple as:
|
||||
*
|
||||
* \code
|
||||
* if ( !Randomizer::Instance().fillData(data, len) )
|
||||
* cerr << "Failed to generate random data" << endl;
|
||||
* \endcode
|
||||
*
|
||||
* A helper template method Randomizer::fill is provided which takes an
|
||||
* argument of arbitrary type and fills it with random data.
|
||||
*
|
||||
* \code
|
||||
* int id;
|
||||
* if ( !Randomizer::Instance().fill(id) )
|
||||
* cerr << "Failed to generate id" << endl;
|
||||
* \endcode
|
||||
*/
|
||||
class SC_BROKER_API Randomizer {
|
||||
// ----------------------------------------------------------------------
|
||||
// Destruction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! D'tor
|
||||
~Randomizer();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @brief Returns the singleton instance.
|
||||
* @return The singleton instance
|
||||
*/
|
||||
static Randomizer &Instance() { return _instance; }
|
||||
|
||||
/**
|
||||
* @brief Fills a value with random data.
|
||||
* @param target The value to be filled.
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
template <typename T>
|
||||
bool fill(T &target);
|
||||
|
||||
/**
|
||||
* @brief Fills a block of data with random data
|
||||
* @param data The pointer to the memory block
|
||||
* @param len The length in bytes of the memory block
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool fillData(void *data, size_t len);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private interface
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
//! Private constructor
|
||||
Randomizer();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
static Randomizer _instance;
|
||||
FILE *_randomFd;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool Randomizer::fill(T &target) {
|
||||
return fillData(&target, sizeof(target));
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
class BlockingDequeue : private boost::noncopyable {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
typedef std::unique_lock<std::mutex> lock;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
BlockingDequeue();
|
||||
BlockingDequeue(int n);
|
||||
~BlockingDequeue();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Blocking interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
void resize(int n);
|
||||
|
||||
bool canPush() const;
|
||||
bool push(T v);
|
||||
|
||||
bool canPop() const;
|
||||
T pop();
|
||||
|
||||
bool pop(T &);
|
||||
|
||||
void close();
|
||||
void reopen();
|
||||
|
||||
size_t size() const;
|
||||
|
||||
void lockBuffer();
|
||||
void unlockBuffer();
|
||||
|
||||
//! Requires lockBuffer to be called
|
||||
size_t buffered() const;
|
||||
|
||||
//! Requires lockBuffer to be called
|
||||
T &operator[](size_t idx);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
volatile int _begin, _end;
|
||||
volatile size_t _buffered;
|
||||
volatile bool _closed;
|
||||
std::vector<T> _buffer;
|
||||
std::condition_variable _notFull, _notEmpty;
|
||||
mutable std::mutex _monitor;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T, int IsPtr>
|
||||
struct BlockingDequeueHelper {};
|
||||
|
||||
template <typename T>
|
||||
struct BlockingDequeueHelper<T,0> {
|
||||
static void clean(const std::vector<T> &) {}
|
||||
static T defaultValue() { return T(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BlockingDequeueHelper<T,1> {
|
||||
static void clean(const std::vector<T> &b) {
|
||||
for ( size_t i = 0; i < b.size(); ++i ) {
|
||||
if ( b[i] ) delete b[i];
|
||||
}
|
||||
}
|
||||
|
||||
static T defaultValue() { return NULL; }
|
||||
};
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
BlockingDequeue<T>::BlockingDequeue() :
|
||||
_begin(0), _end(0),
|
||||
_buffered(0), _closed(false), _buffer(0)
|
||||
{}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
BlockingDequeue<T>::BlockingDequeue(int n) :
|
||||
_begin(0), _end(0),
|
||||
_buffered(0), _closed(false), _buffer(n)
|
||||
{}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
BlockingDequeue<T>::~BlockingDequeue() {
|
||||
close();
|
||||
BlockingDequeueHelper<T, std::is_pointer<T>::value>::clean(_buffer);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void BlockingDequeue<T>::resize(int n) {
|
||||
lock lk(_monitor);
|
||||
_buffer.resize(n);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool BlockingDequeue<T>::canPush() const {
|
||||
lock lk(_monitor);
|
||||
|
||||
if ( _closed )
|
||||
throw Core::GeneralException("Queue has been closed");
|
||||
|
||||
return _buffered < _buffer.size();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool BlockingDequeue<T>::push(T v) {
|
||||
lock lk(_monitor);
|
||||
while (_buffered == _buffer.size() && !_closed)
|
||||
_notFull.wait(lk);
|
||||
if ( _closed ) {
|
||||
_notEmpty.notify_all();
|
||||
return false;
|
||||
}
|
||||
_buffer[_end] = v;
|
||||
_end = (_end+1) % _buffer.size();
|
||||
++_buffered;
|
||||
_notEmpty.notify_all();
|
||||
return true;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool BlockingDequeue<T>::canPop() const {
|
||||
lock lk(_monitor);
|
||||
|
||||
if ( _closed )
|
||||
throw Core::GeneralException("Queue has been closed");
|
||||
|
||||
return _buffered > 0;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
T BlockingDequeue<T>::pop() {
|
||||
lock lk(_monitor);
|
||||
while (_buffered == 0 && !_closed) {
|
||||
_notEmpty.wait(lk);
|
||||
}
|
||||
if ( _closed )
|
||||
throw Core::GeneralException("Queue has been closed");
|
||||
T v = _buffer[_begin];
|
||||
_buffer[_begin] = BlockingDequeueHelper<T, std::is_pointer<T>::value>::defaultValue();
|
||||
_begin = (_begin+1) % _buffer.size();
|
||||
--_buffered;
|
||||
_notFull.notify_all();
|
||||
return v;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool BlockingDequeue<T>::pop(T &v) {
|
||||
lock lk(_monitor);
|
||||
|
||||
if ( _closed )
|
||||
throw Core::GeneralException("Queue has been closed");
|
||||
|
||||
if ( _buffered > 0 ) {
|
||||
v = _buffer[_begin];
|
||||
_buffer[_begin] = BlockingDequeueHelper<T, std::is_pointer<T>::value>::defaultValue();
|
||||
_begin = (_begin+1) % _buffer.size();
|
||||
--_buffered;
|
||||
_notFull.notify_all();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void BlockingDequeue<T>::close() {
|
||||
lock lk(_monitor);
|
||||
if ( _closed ) return;
|
||||
_closed = true;
|
||||
_notFull.notify_all();
|
||||
_notEmpty.notify_all();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void BlockingDequeue<T>::reopen() {
|
||||
lock lk(_monitor);
|
||||
_closed = false;
|
||||
if ( !_buffered )
|
||||
_notFull.notify_all();
|
||||
else
|
||||
_notEmpty.notify_all();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
size_t BlockingDequeue<T>::size() const {
|
||||
lock lk(_monitor);
|
||||
return _buffered;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void BlockingDequeue<T>::lockBuffer() {
|
||||
_monitor.lock();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void BlockingDequeue<T>::unlockBuffer() {
|
||||
_monitor.unlock();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
size_t BlockingDequeue<T>::buffered() const {
|
||||
return _buffered;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
T &BlockingDequeue<T>::operator[](size_t idx) {
|
||||
idx += _begin;
|
||||
if ( idx >= _buffer.size() )
|
||||
idx -= _buffer.size();
|
||||
|
||||
return _buffer[idx];
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
17
include/seiscomp/client.h
Normal file
17
include/seiscomp/client.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef SC_SYSTEM_CLIENT_API_H
|
||||
#define SC_SYSTEM_CLIENT_API_H
|
||||
|
||||
#if defined(WIN32) && (defined(SC_SYSTEM_CLIENT_SHARED) || defined(SC_ALL_SHARED))
|
||||
# if defined(SC_SYSTEM_CLIENT_EXPORTS)
|
||||
# define SC_SYSTEM_CLIENT_API __declspec(dllexport)
|
||||
# define SC_SYSTEM_CLIENT_TEMPLATE_EXPORT
|
||||
# else
|
||||
# define SC_SYSTEM_CLIENT_API __declspec(dllimport)
|
||||
# define SC_SYSTEM_CLIENT_TEMPLATE_EXPORT extern
|
||||
# endif
|
||||
#else
|
||||
# define SC_SYSTEM_CLIENT_API
|
||||
# define SC_SYSTEM_CLIENT_TEMPLATE_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
780
include/seiscomp/client/application.h
Normal file
780
include/seiscomp/client/application.h
Normal file
@@ -0,0 +1,780 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_CLIENT_APPLICATION_H
|
||||
#define SEISCOMP_CLIENT_APPLICATION_H
|
||||
|
||||
|
||||
#include <seiscomp/system/application.h>
|
||||
|
||||
#include <seiscomp/core/message.h>
|
||||
|
||||
#include <seiscomp/client/queue.h>
|
||||
#include <seiscomp/client/monitor.h>
|
||||
#include <seiscomp/client/inventory.h>
|
||||
#include <seiscomp/client.h>
|
||||
|
||||
#include <seiscomp/datamodel/databasequery.h>
|
||||
#include <seiscomp/datamodel/notifier.h>
|
||||
#include <seiscomp/datamodel/configmodule.h>
|
||||
|
||||
#include <seiscomp/math/coord.h>
|
||||
|
||||
#include <seiscomp/messaging/connection.h>
|
||||
|
||||
#include <seiscomp/utils/timer.h>
|
||||
#include <seiscomp/utils/stringfirewall.h>
|
||||
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
#define SCCoreApp (Seiscomp::Client::Application::Instance())
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
|
||||
namespace Logging {
|
||||
class Output;
|
||||
}
|
||||
|
||||
namespace Client {
|
||||
|
||||
|
||||
MAKEENUM(
|
||||
ApplicationStatus,
|
||||
EVALUES(
|
||||
STARTED,
|
||||
FINISHED
|
||||
),
|
||||
ENAMES(
|
||||
"started",
|
||||
"finished"
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
class SC_SYSTEM_CLIENT_API ApplicationStatusMessage : public Core::Message {
|
||||
DECLARE_SC_CLASS(ApplicationStatusMessage);
|
||||
DECLARE_SERIALIZATION;
|
||||
|
||||
public:
|
||||
ApplicationStatusMessage();
|
||||
ApplicationStatusMessage(const std::string &module,
|
||||
ApplicationStatus status);
|
||||
|
||||
ApplicationStatusMessage(const std::string &module,
|
||||
const std::string &username,
|
||||
ApplicationStatus status);
|
||||
|
||||
|
||||
public:
|
||||
virtual bool empty() const;
|
||||
|
||||
const std::string &module() const;
|
||||
const std::string &username() const;
|
||||
ApplicationStatus status() const;
|
||||
|
||||
|
||||
private:
|
||||
std::string _module;
|
||||
std::string _username;
|
||||
ApplicationStatus _status;
|
||||
};
|
||||
|
||||
|
||||
struct SC_SYSTEM_CLIENT_API Notification {
|
||||
//! Declares the application internal notification types.
|
||||
//! Custom types can be used with negative values.
|
||||
enum Type {
|
||||
Object,
|
||||
Disconnect,
|
||||
Reconnect,
|
||||
Close,
|
||||
Timeout,
|
||||
AcquisitionFinished,
|
||||
StateOfHealth
|
||||
};
|
||||
|
||||
Notification() : object(nullptr), type(Object) {}
|
||||
Notification(Core::BaseObject * o) : object(o), type(Object) {}
|
||||
Notification(int t) : object(nullptr), type(t) {}
|
||||
Notification(int t, Core::BaseObject * o) : object(o), type(t) {}
|
||||
|
||||
Core::BaseObject *object;
|
||||
int type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Application class to write commandline clients easily which are
|
||||
* connected to the messaging and need database access.
|
||||
*
|
||||
* In addition to @ref System::Application it adds the method
|
||||
* @ref handleMessage which must be implemented to handle receives
|
||||
* messages. An additional abstraction layer is implemented which already
|
||||
* checks the message for notifier objects, extracts them and calls respective
|
||||
* callbacks:
|
||||
* * @ref addObject()
|
||||
* * @ref removeObject()
|
||||
* * @ref updateObject()
|
||||
*/
|
||||
class SC_SYSTEM_CLIENT_API Application : public System::Application {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
typedef ObjectMonitor::Log ObjectLog;
|
||||
|
||||
//! Initialization stages used when reporting errors
|
||||
enum ClientStage {
|
||||
MESSAGING = System::Application::ST_QUANTITY,
|
||||
DATABASE = System::Application::ST_QUANTITY + 1,
|
||||
CONFIGMODULE = System::Application::ST_QUANTITY + 2,
|
||||
INVENTORY = System::Application::ST_QUANTITY + 3,
|
||||
CST_QUANTITY
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
Application(int argc, char **argv);
|
||||
~Application();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public functions
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! Returns the configured agencyID
|
||||
const std::string &agencyID() const;
|
||||
|
||||
//! Returns the configured author
|
||||
const std::string &author() const;
|
||||
|
||||
/**
|
||||
* Returns according to the configured white- and blacklist of
|
||||
* agencyID's whether the passed agencyID is allowed or not
|
||||
* @param agencyID The agencyID to check
|
||||
* @return The boolean result
|
||||
*/
|
||||
bool isAgencyIDAllowed(const std::string &agencyID) const;
|
||||
|
||||
/**
|
||||
* Returns !isAgencyIDAllowed(agencyID)
|
||||
* @param agencyID The agencyID to check
|
||||
* @return !isAgencyIDAllowed(agencyID)
|
||||
*/
|
||||
bool isAgencyIDBlocked(const std::string &agencyID) const;
|
||||
|
||||
/**
|
||||
* Exit the application and set the returnCode.
|
||||
* @param returnCode The value returned from exec()
|
||||
*/
|
||||
virtual void exit(int returnCode);
|
||||
|
||||
//! Returns the application's messaging connection interface
|
||||
Client::Connection *connection() const;
|
||||
|
||||
//! Returns the configured database type
|
||||
const std::string &databaseType() const;
|
||||
|
||||
//! Returns the configured database connection parameters
|
||||
const std::string &databaseParameters() const;
|
||||
|
||||
//! Returns the application's database interface
|
||||
IO::DatabaseInterface *database() const;
|
||||
|
||||
void setDatabaseURI(const std::string &uri);
|
||||
//! Returns the application's database URI
|
||||
const std::string &databaseURI() const;
|
||||
|
||||
//! Returns the application's database query interface
|
||||
DataModel::DatabaseQuery *query() const;
|
||||
|
||||
void setRecordStreamURL(const std::string &url);
|
||||
//! Returns the configures recordstream URL to be used by
|
||||
//! RecordStream::Open()
|
||||
const std::string &recordStreamURL() const;
|
||||
|
||||
//! Returns the list of configured points of interest
|
||||
const std::vector<Math::Geo::CityD> &cities() const;
|
||||
|
||||
//! Returns the nearest city with respect to lat/lon and
|
||||
//! a given maximum distance and minimum population
|
||||
const Math::Geo::CityD *nearestCity(double lat, double lon,
|
||||
double maxDist, double minPopulation,
|
||||
double *dist, double *azi) const;
|
||||
|
||||
//! Returns the config module object if available
|
||||
DataModel::ConfigModule *configModule() const;
|
||||
|
||||
//! Returns the state of a station
|
||||
bool isStationEnabled(const std::string& networkCode,
|
||||
const std::string& stationCode);
|
||||
|
||||
//! Returns the messaging-server
|
||||
const std::string &messagingURL() const;
|
||||
|
||||
|
||||
//! Returns the filename of the OpenSSL certificate or
|
||||
//! the certificate data Base64 encoded. The Base64 encoded
|
||||
//! data starts with the special DataTag.
|
||||
//! If no certificate is used the method returns an empty
|
||||
//! string.
|
||||
const std::string &messagingCertificate() const;
|
||||
|
||||
//! Enables a timer that calls every n seconds the
|
||||
//! handleTimeout() methods
|
||||
//! A value of 0 seconds disables the timer
|
||||
void enableTimer(unsigned int seconds);
|
||||
|
||||
//! Disables the timer
|
||||
void disableTimer();
|
||||
|
||||
//! Sends a notification to the application. If used in derived
|
||||
//! classes to send custom notifications use negative notification
|
||||
//! types and reimplement dispatchNotification(...).
|
||||
void sendNotification(const Notification &);
|
||||
|
||||
bool waitEvent();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Initialization configuration methods
|
||||
// These methods have to be called before the init() method.
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! Sets the primary messaging group
|
||||
void setPrimaryMessagingGroup(const std::string&);
|
||||
|
||||
//! Returns the set primary messaging group
|
||||
const std::string &primaryMessagingGroup() const;
|
||||
|
||||
//! Sets the username used for the messaging connection
|
||||
void setMessagingUsername(const std::string&);
|
||||
|
||||
/**
|
||||
* Adds a group to subscribe to. This is only a default group.
|
||||
* If another group or groups are given via commandline or config
|
||||
* file this subscription will be overriden completely.
|
||||
*/
|
||||
void addMessagingSubscription(const std::string&);
|
||||
|
||||
//! Initialize the database, default = true, true
|
||||
void setDatabaseEnabled(bool enable, bool tryToFetch);
|
||||
bool isDatabaseEnabled() const;
|
||||
|
||||
//! Returns whether the inventory should be loaded from a
|
||||
//! file (false) or from the database (true)
|
||||
bool isInventoryDatabaseEnabled() const;
|
||||
|
||||
//! Returns whether the config module should be loaded from a
|
||||
//! file (false) or from the database (true)
|
||||
bool isConfigDatabaseEnabled() const;
|
||||
|
||||
//! Initialize the messaging, default = true
|
||||
void setMessagingEnabled(bool enable);
|
||||
bool isMessagingEnabled() const;
|
||||
|
||||
/**
|
||||
* @brief Toggles receiption of messaging membership messages. The
|
||||
* default is false.
|
||||
* @param enable Flag
|
||||
*/
|
||||
void setMembershipMessagesEnabled(bool enable);
|
||||
bool areMembershipMessagesEnabled() const;
|
||||
|
||||
//! Enables/disables sending of start/stop messages.
|
||||
//! If enabled, a start message (at startup) and a
|
||||
//! stop message (at shutdown) will be sent to the
|
||||
//! STATUS group. Default = false
|
||||
void setStartStopMessagesEnabled(bool enable);
|
||||
bool areStartStopMessagesEnabled() const;
|
||||
|
||||
//! Enables/disables auto shutdown caused by
|
||||
//! the shutdown of a definable master module or
|
||||
//! master username. If both values are set the
|
||||
//! one coming first is used.
|
||||
void setAutoShutdownEnabled(bool enable);
|
||||
bool isAutoShutdownEnabled() const;
|
||||
|
||||
//! Enables recordstream URL option, default = true
|
||||
void setRecordStreamEnabled(bool enable);
|
||||
bool isRecordStreamEnabled() const;
|
||||
|
||||
//! Load the stations from the inventory at startup, default = false
|
||||
void setLoadStationsEnabled(bool enable);
|
||||
bool isLoadStationsEnabled() const;
|
||||
|
||||
//! Load the complete inventory at startup, default = false
|
||||
void setLoadInventoryEnabled(bool enable);
|
||||
bool isLoadInventoryEnabled() const;
|
||||
|
||||
//! Load the configmodule from the database at startup, default = false
|
||||
void setLoadConfigModuleEnabled(bool enable);
|
||||
bool isLoadConfigModuleEnabled() const;
|
||||
|
||||
//! Load the cities.xml file, default = false
|
||||
void setLoadCitiesEnabled(bool enable);
|
||||
bool isLoadCitiesEnabled() const;
|
||||
|
||||
//! Load the custom defined fep regions in ~/.seiscomp/fep or
|
||||
//! ~/seiscomp/trunk/share/fep, default = false
|
||||
void setLoadRegionsEnabled(bool enable);
|
||||
bool isLoadRegionsEnabled() const;
|
||||
|
||||
//! Sets whether the received notifier are applied automatically
|
||||
//! or not, default: true
|
||||
|
||||
/**
|
||||
* Sets whether the received notifier are applied automatically
|
||||
* or not, default: true
|
||||
* When AutoApplyNotifier is enabled a received message will
|
||||
* be handled in two passes:
|
||||
* 1. pass: Apply all attached notifier
|
||||
* 2. pass: Interpret all notifier
|
||||
*
|
||||
* So when using an object in an interprete callback it is
|
||||
* garantueed that all child objects that also has been sent
|
||||
* inside the message are attached to it.
|
||||
*/
|
||||
void setAutoApplyNotifierEnabled(bool enable);
|
||||
bool isAutoApplyNotifierEnabled() const;
|
||||
|
||||
/**
|
||||
* Sets whether the received notifier will be interpreted or not.
|
||||
* Default: true
|
||||
* When this option is enabled, the callback methods
|
||||
* addObject(), updateObject() and removeObject() will be
|
||||
* called after a notifier has been received.
|
||||
*/
|
||||
void setInterpretNotifierEnabled(bool enable);
|
||||
bool isInterpretNotifierEnabled() const;
|
||||
|
||||
/** Returns whether a custom publicID pattern has been configured
|
||||
or not */
|
||||
bool hasCustomPublicIDPattern() const;
|
||||
|
||||
/**
|
||||
* Sets the number of retries if a connection fails.
|
||||
* The default value is 0xFFFFFFFF and should be understood
|
||||
* as "keep on trying".
|
||||
*/
|
||||
void setConnectionRetries(unsigned int);
|
||||
|
||||
//! Sets the config module name to use when reading
|
||||
//! the database configuration. An empty module name
|
||||
//! means: read all available modules.
|
||||
//! The default module is "trunk".
|
||||
void setConfigModuleName(const std::string &module);
|
||||
const std::string &configModuleName() const;
|
||||
|
||||
//! Sets the master module used when auto shutdown
|
||||
//! is activated.
|
||||
void setShutdownMasterModule(const std::string &module);
|
||||
|
||||
//! Sets the master username used when auto shutdown
|
||||
//! is activated.
|
||||
void setShutdownMasterUsername(const std::string &username);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public methods
|
||||
// These methods have to be called after the init() method.
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* Adds a logger for an input object flow.
|
||||
* This method must be called after Application::init().
|
||||
* The returned pointer is managed by the Application and must not
|
||||
* be deleted.
|
||||
*/
|
||||
ObjectLog *
|
||||
addInputObjectLog(const std::string &name,
|
||||
const std::string &channel = "");
|
||||
|
||||
/**
|
||||
* Adds a logger for an output object flow.
|
||||
* This method must be called after Application::init().
|
||||
* The returned pointer is managed by the Application and must not
|
||||
* be deleted.
|
||||
*/
|
||||
ObjectLog *
|
||||
addOutputObjectLog(const std::string &name,
|
||||
const std::string &channel = "");
|
||||
|
||||
/**
|
||||
* Logs input/output object throughput.
|
||||
* @param log Pointer returned by addInputObjectLog or addOutputObjectLog
|
||||
* @param timestamp The timestamp to be logged
|
||||
*/
|
||||
void logObject(ObjectLog *log, const Core::Time ×tamp,
|
||||
size_t count = 1);
|
||||
|
||||
/**
|
||||
* Reloads the application inventory from either an XML file or
|
||||
* the database.
|
||||
*/
|
||||
bool reloadInventory();
|
||||
|
||||
/**
|
||||
* Reloads the application configuration (bindings) from either an
|
||||
* XML file or the database.
|
||||
*/
|
||||
bool reloadBindings();
|
||||
|
||||
/**
|
||||
* @brief Injects a message from outside. The message will actually
|
||||
* take the same path as when it would have been received via
|
||||
* the messaging.
|
||||
* @param msg The message. The ownership if left to the caller.
|
||||
* @param pkt The optional network packet. The ownership is left to
|
||||
* the caller.
|
||||
*/
|
||||
void injectMessage(Core::Message *msg, Packet *pkt = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Routes a notifier to either add/update or removeObject.
|
||||
* @param notifier The notifier pointer which must not be nullptr
|
||||
*/
|
||||
void handleNotifier(DataModel::Notifier *notifier);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Static public members
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
//! Returns the pointer to the application's instance.
|
||||
static Application *Instance();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Protected functions
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
virtual bool validateParameters() override;
|
||||
virtual bool handlePreFork() override;
|
||||
|
||||
virtual bool init() override;
|
||||
|
||||
/**
|
||||
* Starts the mainloop until exit() or quit() is called.
|
||||
* The default implementation waits for messages in blocking mode
|
||||
* and calls handleMessage() whenever a new message arrives.
|
||||
*/
|
||||
virtual bool run() override;
|
||||
|
||||
//! This method gets called when all messages has been read or
|
||||
//! the connection is invalid
|
||||
virtual void idle();
|
||||
|
||||
//! Cleanup method called before exec() returns.
|
||||
virtual void done() override;
|
||||
|
||||
//! Opens the configuration file and reads the state variables
|
||||
virtual bool initConfiguration() override;
|
||||
|
||||
//! Initialized the database
|
||||
virtual bool initDatabase();
|
||||
|
||||
//! Sets the database interface and creates a database query object
|
||||
void setDatabase(IO::DatabaseInterface* db);
|
||||
|
||||
/**
|
||||
* Reads the requested subscriptions from the configuration file
|
||||
* and apply them to the messaging connection.
|
||||
*/
|
||||
virtual bool initSubscriptions();
|
||||
|
||||
const std::set<std::string> &subscribedGroups() const;
|
||||
|
||||
/**
|
||||
* Called when the application received the AcquisitionFinished event.
|
||||
* This is most likely send from the readRecords thread of the
|
||||
* StreamApplication. The default implementation does nothing.
|
||||
*/
|
||||
virtual void handleEndAcquisition();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Messaging handlers
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
virtual bool dispatch(Core::BaseObject*);
|
||||
|
||||
//! Custom dispatch method for notifications with negative (< 0)
|
||||
//! types. The default implementation return false.
|
||||
virtual bool dispatchNotification(int type, Core::BaseObject*);
|
||||
|
||||
/**
|
||||
* Reads messages from the connection.
|
||||
* @return true, if successfull, false if not. When returning false,
|
||||
* the mainloop will stop and the program is going to
|
||||
* terminate.
|
||||
*/
|
||||
bool readMessages();
|
||||
|
||||
void stateOfHealth();
|
||||
|
||||
/**
|
||||
* This method gets called when a previously started timer timeout's.
|
||||
* The timer has to be started by enableTimer(timeout).
|
||||
*/
|
||||
virtual void handleTimeout();
|
||||
|
||||
/**
|
||||
* This method is called when close event is sent to the application.
|
||||
* The default handler returns true and causes the event queue to
|
||||
* shutdown and to exit the application.
|
||||
* It false is returned the close event is ignored.
|
||||
*/
|
||||
virtual bool handleClose();
|
||||
|
||||
/**
|
||||
* This methods gets called when an auto shutdown has been
|
||||
* initiated. The default implementation just quits.
|
||||
*/
|
||||
virtual void handleAutoShutdown();
|
||||
|
||||
/**
|
||||
* This methods gets called when an the log interval is reached
|
||||
* and the application should prepare its logging information. This
|
||||
* method can be used to sync logs.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
virtual void handleMonitorLog(const Core::Time ×tamp);
|
||||
|
||||
/**
|
||||
* This method gets called after the connection got lost.
|
||||
*/
|
||||
virtual void handleDisconnect();
|
||||
|
||||
/**
|
||||
* This method gets called after the connection got reestablished.
|
||||
*/
|
||||
virtual void handleReconnect();
|
||||
|
||||
/**
|
||||
* Handles receiption of a network packet which is a candidate
|
||||
* for message decoding. Special service messages such as ENTER or
|
||||
* LEAVE will not cause a message to be created. This method is always
|
||||
* called *before* a message should be handled.
|
||||
*/
|
||||
virtual void handleNetworkMessage(const Client::Packet *msg);
|
||||
|
||||
/**
|
||||
* This method gets called whenever a new message arrives. Derived
|
||||
* classes have to implement this method to receive messages.
|
||||
* To enable autoapplying and notifier interpreting call this method
|
||||
* inside the reimplemented version.
|
||||
* @param msg The message. A smartpointer may be stored for
|
||||
* future use. The pointer must not be deleted!
|
||||
*/
|
||||
virtual void handleMessage(Core::Message *msg);
|
||||
|
||||
//! Callback for interpret notifier
|
||||
virtual void addObject(const std::string &parentID, DataModel::Object*) {}
|
||||
|
||||
//! Callback for interpret notifier
|
||||
virtual void removeObject(const std::string &parentID, DataModel::Object*) {}
|
||||
|
||||
//! Callback for interpret notifier
|
||||
virtual void updateObject(const std::string &parentID, DataModel::Object*) {}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private functions
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
bool initMessaging();
|
||||
|
||||
bool loadConfig(const std::string &configDB);
|
||||
bool loadInventory(const std::string &inventoryDB);
|
||||
|
||||
void startMessageThread();
|
||||
void runMessageThread();
|
||||
|
||||
bool processEvent();
|
||||
|
||||
void timeout();
|
||||
void stateOfHealthTimeout();
|
||||
|
||||
void monitorLog(const Core::Time ×tamp, std::ostream &os);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Implementation
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
DataModel::DatabaseQueryPtr _query;
|
||||
DataModel::ConfigModulePtr _configModule;
|
||||
|
||||
std::vector<Math::Geo::CityD> _cities;
|
||||
std::set<std::string> _messagingSubscriptions;
|
||||
|
||||
|
||||
private:
|
||||
static Application *_instance;
|
||||
|
||||
|
||||
protected:
|
||||
using StringVector = std::vector<std::string>;
|
||||
|
||||
struct AppSettings : AbstractSettings {
|
||||
int objectLogTimeWindow{60};
|
||||
|
||||
std::string agencyID{"UNSET"};
|
||||
std::string author{"@appname@@@@hostname@"};
|
||||
|
||||
bool enableLoadRegions{false};
|
||||
std::string customPublicIDPattern;
|
||||
std::string configModuleName{"trunk"};
|
||||
|
||||
bool enableFetchDatabase{true};
|
||||
bool enableLoadStations{false};
|
||||
bool enableLoadInventory{false};
|
||||
bool enableLoadConfigModule{false};
|
||||
bool enableAutoApplyNotifier{true};
|
||||
bool enableInterpretNotifier{true};
|
||||
|
||||
unsigned int retryCount{0xFFFFFFFF};
|
||||
|
||||
Util::StringFirewall networkTypeFirewall;
|
||||
Util::StringFirewall stationTypeFirewall;
|
||||
|
||||
struct SOH {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
int interval{60};
|
||||
} soh;
|
||||
|
||||
struct Database {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
bool enable{true};
|
||||
bool showDrivers{false};
|
||||
|
||||
std::string type;
|
||||
std::string parameters;
|
||||
std::string URI;
|
||||
|
||||
std::string inventoryDB;
|
||||
std::string configDB;
|
||||
} database;
|
||||
|
||||
struct Inventory {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
StringVector netTypeAllowlist;
|
||||
StringVector netTypeBlocklist;
|
||||
StringVector staTypeAllowlist;
|
||||
StringVector staTypeBlocklist;
|
||||
} inventory;
|
||||
|
||||
// Messaging
|
||||
struct Messaging {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
bool enable{true};
|
||||
bool membershipMessages{false};
|
||||
|
||||
std::string user;
|
||||
std::string URL{"localhost/production"};
|
||||
std::string primaryGroup{Protocol::LISTENER_GROUP};
|
||||
std::string contentType;
|
||||
unsigned int timeout{3};
|
||||
std::string certificate;
|
||||
|
||||
StringVector subscriptions;
|
||||
|
||||
} messaging;
|
||||
|
||||
struct Client {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
bool startStopMessages{false};
|
||||
bool autoShutdown{false};
|
||||
std::string shutdownMasterModule;
|
||||
std::string shutdownMasterUsername;
|
||||
} client;
|
||||
|
||||
struct RecordStream {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
bool enable{false};
|
||||
bool showDrivers{false};
|
||||
|
||||
std::string URI;
|
||||
std::string file;
|
||||
std::string fileType;
|
||||
} recordstream;
|
||||
|
||||
struct Processing {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
StringVector agencyAllowlist;
|
||||
StringVector agencyBlocklist;
|
||||
Util::StringFirewall firewall;
|
||||
StringVector magnitudeAliases;
|
||||
|
||||
} processing;
|
||||
|
||||
struct Cities {
|
||||
void accept(SettingsLinker &linker);
|
||||
|
||||
bool enable{false};
|
||||
std::string db;
|
||||
} cities;
|
||||
|
||||
void accept(SettingsLinker &linker) override;
|
||||
};
|
||||
|
||||
AppSettings _settings;
|
||||
|
||||
ObjectMonitor *_inputMonitor;
|
||||
ObjectMonitor *_outputMonitor;
|
||||
|
||||
ThreadedQueue<Notification> _queue;
|
||||
std::thread *_messageThread;
|
||||
|
||||
ConnectionPtr _connection;
|
||||
IO::DatabaseInterfacePtr _database;
|
||||
Util::Timer _userTimer;
|
||||
Util::Timer _sohTimer;
|
||||
Core::Time _sohLastUpdate;
|
||||
|
||||
std::mutex _objectLogMutex;
|
||||
};
|
||||
|
||||
|
||||
inline bool Application::waitEvent() {
|
||||
return processEvent();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
81
include/seiscomp/client/configdb.h
Normal file
81
include/seiscomp/client/configdb.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_CLIENT_CONFIG_H
|
||||
#define SEISCOMP_CLIENT_CONFIG_H
|
||||
|
||||
|
||||
#include <seiscomp/datamodel/config.h>
|
||||
#include <seiscomp/datamodel/configmodule.h>
|
||||
#include <seiscomp/datamodel/configstation.h>
|
||||
#include <seiscomp/datamodel/parameterset.h>
|
||||
#include <seiscomp/datamodel/databasereader.h>
|
||||
#include <seiscomp/client.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Client {
|
||||
|
||||
|
||||
class SC_SYSTEM_CLIENT_API ConfigDB {
|
||||
private:
|
||||
ConfigDB();
|
||||
|
||||
public:
|
||||
static ConfigDB* Instance();
|
||||
static void Reset();
|
||||
|
||||
void load(DataModel::DatabaseReader* reader,
|
||||
const OPT(std::string)& moduleName = Seiscomp::Core::None,
|
||||
const OPT(std::string)& networkCode = Seiscomp::Core::None,
|
||||
const OPT(std::string)& stationCode = Seiscomp::Core::None,
|
||||
const OPT(std::string)& setupName = Seiscomp::Core::None,
|
||||
const std::set<std::string>& parameterNames = std::set<std::string>());
|
||||
|
||||
void load(const char *xml);
|
||||
|
||||
DataModel::Config *config();
|
||||
|
||||
private:
|
||||
std::map<int, DataModel::ConfigModulePtr> _configModules;
|
||||
std::map<int, DataModel::ConfigStationPtr> _configStations;
|
||||
std::map<int, DataModel::ParameterSetPtr> _parameterSets;
|
||||
DataModel::ConfigPtr _config;
|
||||
static ConfigDB *_instance;
|
||||
|
||||
DataModel::DatabaseIterator getConfigObjects(DataModel::DatabaseReader* reader,
|
||||
const Core::RTTI& classType,
|
||||
const OPT(std::string)& moduleName,
|
||||
const OPT(std::string)& networkCode,
|
||||
const OPT(std::string)& stationCode,
|
||||
const OPT(std::string)& setupName,
|
||||
const std::set<std::string>& parameterNames);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
156
include/seiscomp/client/inventory.h
Normal file
156
include/seiscomp/client/inventory.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_CLIENT_INVENTORY_H
|
||||
#define SEISCOMP_CLIENT_INVENTORY_H
|
||||
|
||||
|
||||
#include <seiscomp/datamodel/inventory.h>
|
||||
#include <seiscomp/datamodel/pick.h>
|
||||
#include <seiscomp/datamodel/databasereader.h>
|
||||
#include <seiscomp/datamodel/utils.h>
|
||||
#include <seiscomp/utils/stringfirewall.h>
|
||||
#include <seiscomp/client.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Client {
|
||||
|
||||
|
||||
struct SC_SYSTEM_CLIENT_API StationLocation {
|
||||
StationLocation();
|
||||
StationLocation(double lat, double lon, double elevation);
|
||||
|
||||
double latitude;
|
||||
double longitude;
|
||||
double elevation;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<Seiscomp::DataModel::Station*> StationList;
|
||||
|
||||
class SC_SYSTEM_CLIENT_API Inventory {
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
//! Private c'tor. This class implements the singleton pattern and
|
||||
//! can be accessed through the static Instance() method.
|
||||
Inventory();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
static Inventory* Instance();
|
||||
static void Reset();
|
||||
|
||||
void load(const char *filename);
|
||||
void load(DataModel::DatabaseReader*);
|
||||
void setInventory(DataModel::Inventory*);
|
||||
|
||||
int filter(const Util::StringFirewall *networkTypeFW,
|
||||
const Util::StringFirewall *stationTypeFW);
|
||||
|
||||
void loadStations(DataModel::DatabaseReader*);
|
||||
|
||||
//! Returns the station location for a network- and stationcode and
|
||||
//! a time. If the station has not been found a ValueException will
|
||||
//! be thrown.
|
||||
StationLocation stationLocation(const std::string& networkCode,
|
||||
const std::string& stationCode,
|
||||
const Core::Time&) const;
|
||||
|
||||
//! Returns the station for a network- and stationcode and
|
||||
//! a time. If the station has not been found nullptr will be returned.
|
||||
DataModel::Station* getStation(const std::string &networkCode,
|
||||
const std::string &stationCode,
|
||||
const Core::Time &,
|
||||
DataModel::InventoryError *error = nullptr) const;
|
||||
|
||||
//! Returns the sensorlocation for a network-, station- and locationcode and
|
||||
//! a time. If the sensorlocation has not been found nullptr will be returned.
|
||||
DataModel::SensorLocation* getSensorLocation(const std::string &networkCode,
|
||||
const std::string &stationCode,
|
||||
const std::string &locationCode,
|
||||
const Core::Time &,
|
||||
DataModel::InventoryError *error = nullptr) const;
|
||||
|
||||
//! Returns the stream for a network-, station-, location- and channelcode and
|
||||
//! a time. If the stream has not been found nullptr will be returned.
|
||||
DataModel::Stream* getStream(const std::string &networkCode,
|
||||
const std::string &stationCode,
|
||||
const std::string &locationCode,
|
||||
const std::string &channelCode,
|
||||
const Core::Time &,
|
||||
DataModel::InventoryError *error = nullptr) const;
|
||||
|
||||
//! Returns the three streams (vertical, horizontal1, horizontal2) corresponding
|
||||
//! to the given network-, station-, location- and channel code
|
||||
DataModel::ThreeComponents getThreeComponents(const std::string& networkCode,
|
||||
const std::string& stationCode,
|
||||
const std::string& locationCode,
|
||||
const std::string& channelCode,
|
||||
const Core::Time&) const;
|
||||
|
||||
//! Returns the station used for a pick. If the station has not been found
|
||||
//! nullptr will be returned.
|
||||
DataModel::Station* getStation(const DataModel::Pick*) const;
|
||||
|
||||
//! Returns the sensor location used for a pick. If the sensor location has
|
||||
//! not been found nullptr will be returned.
|
||||
DataModel::SensorLocation* getSensorLocation(const DataModel::Pick*) const;
|
||||
|
||||
DataModel::Stream* getStream(const DataModel::Pick*) const;
|
||||
|
||||
//! Returns the three streams (vertical, horizontal1, horizontal2) corresponding
|
||||
//! to the picked stream.
|
||||
DataModel::ThreeComponents getThreeComponents(const DataModel::Pick*) const;
|
||||
|
||||
double getGain(const std::string& networkCode,
|
||||
const std::string& stationCode,
|
||||
const std::string& locationCode,
|
||||
const std::string& channelCode,
|
||||
const Core::Time&);
|
||||
|
||||
//! Returns all defined stations for the given time
|
||||
int getAllStations(StationList&, const Core::Time&);
|
||||
|
||||
DataModel::Inventory* inventory();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
DataModel::InventoryPtr _inventory;
|
||||
static Inventory _instance;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
114
include/seiscomp/client/monitor.h
Normal file
114
include/seiscomp/client/monitor.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_UTILS_MONITOR_H
|
||||
#define SEISCOMP_UTILS_MONITOR_H
|
||||
|
||||
#include <seiscomp/client.h>
|
||||
#include <seiscomp/core/datetime.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Client {
|
||||
|
||||
|
||||
//! A running average calculator that logs the number of
|
||||
//! objects/thingies in a certain interval. The accuracy is
|
||||
//! a second.
|
||||
class SC_SYSTEM_CLIENT_API RunningAverage {
|
||||
public:
|
||||
RunningAverage(int timeSpanInSeconds);
|
||||
|
||||
|
||||
public:
|
||||
int timeSpan() const { return _timeSpan; }
|
||||
|
||||
void push(const Core::Time &time, size_t count = 1);
|
||||
|
||||
//! Returns the current count per time span.
|
||||
int count(const Core::Time &time) const;
|
||||
|
||||
//! Returns the value (average) per time span.
|
||||
double value(const Core::Time &time) const;
|
||||
|
||||
//! Returns the timestamp of the last values pushed
|
||||
Core::Time last() const;
|
||||
|
||||
void dumpBins() const;
|
||||
|
||||
|
||||
private:
|
||||
Core::Time _first;
|
||||
Core::Time _last;
|
||||
size_t _timeSpan;
|
||||
double _scale;
|
||||
mutable
|
||||
double _shift;
|
||||
mutable
|
||||
std::vector<size_t> _bins;
|
||||
size_t _front;
|
||||
};
|
||||
|
||||
|
||||
class SC_SYSTEM_CLIENT_API ObjectMonitor {
|
||||
public:
|
||||
typedef RunningAverage Log;
|
||||
|
||||
ObjectMonitor(int timeSpanInSeconds);
|
||||
~ObjectMonitor();
|
||||
|
||||
|
||||
public:
|
||||
Log *add(const std::string &name, const std::string &channel = "");
|
||||
void update(const Core::Time &time);
|
||||
|
||||
|
||||
public:
|
||||
struct Test {
|
||||
std::string name;
|
||||
std::string channel;
|
||||
Core::Time updateTime;
|
||||
size_t count;
|
||||
Log *test;
|
||||
};
|
||||
|
||||
typedef std::list<Test> Tests;
|
||||
typedef Tests::const_iterator const_iterator;
|
||||
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
|
||||
private:
|
||||
Tests _tests;
|
||||
int _timeSpan;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
157
include/seiscomp/client/queue.h
Normal file
157
include/seiscomp/client/queue.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_CLIENT_QUEUE_H
|
||||
#define SEISCOMP_CLIENT_QUEUE_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
#include <seiscomp/core/baseobject.h>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Client {
|
||||
|
||||
class QueueClosedException : public Core::GeneralException {
|
||||
public:
|
||||
QueueClosedException() : Core::GeneralException("Queue has been closed") {}
|
||||
QueueClosedException(const std::string& str ) : Core::GeneralException(str) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ThreadedQueue {
|
||||
// ----------------------------------------------------------------------
|
||||
// Public types
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
typedef std::unique_lock<std::mutex> lock;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Non copyable
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
ThreadedQueue(const ThreadedQueue&) = delete;
|
||||
ThreadedQueue &operator=(const ThreadedQueue&) = delete;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
ThreadedQueue();
|
||||
ThreadedQueue(int n);
|
||||
~ThreadedQueue();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Interface
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* @brief Resizes the queue to hold a maximum of n items before
|
||||
* blocking.
|
||||
* @param n The number of items to queue before blocking occurs.
|
||||
*/
|
||||
void resize(int n);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the queue can take new items without blocking.
|
||||
* @return true if non-blocking push is possible, false otherwise.
|
||||
*/
|
||||
bool canPush() const;
|
||||
|
||||
/**
|
||||
* @brief Appends a new item to the end of the queue. If the queue is
|
||||
* full then it will block until a consumer has popped an item.
|
||||
* @param v The new item.
|
||||
* @return true if successful, false if queue is closed.
|
||||
*/
|
||||
bool push(T v);
|
||||
|
||||
/**
|
||||
* @brief Checks with equality operator if the item is already queued
|
||||
* and if not, pushes it to the end of the queue.
|
||||
* @param v The new item.
|
||||
* @return true if successful which also covers the case that the item
|
||||
* is already queued. False if the queue is closed.
|
||||
*/
|
||||
bool pushUnique(T v);
|
||||
|
||||
/**
|
||||
* @brief Checks whether an item can be popped or not.
|
||||
* Actually it returns whether the queue is empty or not.
|
||||
* @return true if not empty, false if empty.
|
||||
*/
|
||||
bool canPop() const;
|
||||
|
||||
/**
|
||||
* @brief Pops an items from the queue. If the queue is empty then
|
||||
* it blocks until a producer pushed an item.
|
||||
* @return The popped item.
|
||||
*/
|
||||
T pop();
|
||||
|
||||
/**
|
||||
* @brief Close the queue and cause all subsequent calls to push and
|
||||
* pop to fail.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* @brief Returns whether the queue is closed or not.
|
||||
* @return The closed flag.
|
||||
*/
|
||||
bool isClosed() const;
|
||||
|
||||
/**
|
||||
* @brief Query the number of queued items.
|
||||
* @return The number of currently queued items.
|
||||
*/
|
||||
size_t size() const;
|
||||
|
||||
/**
|
||||
* @brief Resets the queue which incorporates resetting the buffer
|
||||
* insertations and the closed state.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Private members
|
||||
// ----------------------------------------------------------------------
|
||||
private:
|
||||
volatile int _begin, _end;
|
||||
volatile size_t _buffered;
|
||||
volatile bool _closed;
|
||||
std::vector<T> _buffer;
|
||||
std::condition_variable _notFull, _notEmpty;
|
||||
mutable std::mutex _monitor;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
266
include/seiscomp/client/queue.ipp
Normal file
266
include/seiscomp/client/queue.ipp
Normal file
@@ -0,0 +1,266 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SEISCOMP_CLIENT_QUEUE_IPP
|
||||
#define SEISCOMP_CLIENT_QUEUE_IPP
|
||||
|
||||
|
||||
#include <seiscomp/core/exceptions.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Client {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T, int IsPtr>
|
||||
struct QueueHelper {};
|
||||
|
||||
template <typename T>
|
||||
struct QueueHelper<T,0> {
|
||||
static void clean(const std::vector<T> &) {}
|
||||
static T defaultValue() { return T(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QueueHelper<T,1> {
|
||||
static void clean(const std::vector<T> &b) {
|
||||
for ( size_t i = 0; i < b.size(); ++i ) {
|
||||
if ( b[i] ) delete b[i];
|
||||
}
|
||||
}
|
||||
|
||||
static T defaultValue() { return nullptr; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
ThreadedQueue<T>::ThreadedQueue() :
|
||||
_begin(0), _end(0),
|
||||
_buffered(0), _closed(false), _buffer(0)
|
||||
{}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
ThreadedQueue<T>::ThreadedQueue(int n) :
|
||||
_begin(0), _end(0),
|
||||
_buffered(0), _closed(false), _buffer(n)
|
||||
{}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
ThreadedQueue<T>::~ThreadedQueue() {
|
||||
close();
|
||||
QueueHelper<T, std::is_pointer<T>::value>::clean(_buffer);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void ThreadedQueue<T>::resize(int n) {
|
||||
lock lk(_monitor);
|
||||
_buffer.resize(n);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool ThreadedQueue<T>::canPush() const {
|
||||
lock lk(_monitor);
|
||||
|
||||
if ( _closed )
|
||||
throw QueueClosedException();
|
||||
|
||||
return _buffered < _buffer.size();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool ThreadedQueue<T>::push(T v) {
|
||||
lock lk(_monitor);
|
||||
while (_buffered == _buffer.size() && !_closed)
|
||||
_notFull.wait(lk);
|
||||
if ( _closed ) {
|
||||
_notEmpty.notify_all();
|
||||
return false;
|
||||
}
|
||||
_buffer[_end] = v;
|
||||
_end = (_end+1) % _buffer.size();
|
||||
++_buffered;
|
||||
_notEmpty.notify_all();
|
||||
return true;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool ThreadedQueue<T>::pushUnique(T v) {
|
||||
lock lk(_monitor);
|
||||
// Find existing item
|
||||
auto it = _begin;
|
||||
while ( it != _end ) {
|
||||
if ( _buffer[it] == v ) {
|
||||
return true;
|
||||
}
|
||||
it = (it + 1) % _buffer.size();
|
||||
}
|
||||
|
||||
while (_buffered == _buffer.size() && !_closed)
|
||||
_notFull.wait(lk);
|
||||
if ( _closed ) {
|
||||
_notEmpty.notify_all();
|
||||
return false;
|
||||
}
|
||||
_buffer[_end] = v;
|
||||
_end = (_end+1) % _buffer.size();
|
||||
++_buffered;
|
||||
_notEmpty.notify_all();
|
||||
return true;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool ThreadedQueue<T>::canPop() const {
|
||||
lock lk(_monitor);
|
||||
|
||||
if ( _closed )
|
||||
throw QueueClosedException();
|
||||
|
||||
return _buffered > 0;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
T ThreadedQueue<T>::pop() {
|
||||
lock lk(_monitor);
|
||||
while (_buffered == 0 && !_closed) {
|
||||
_notEmpty.wait(lk);
|
||||
}
|
||||
if ( _closed )
|
||||
throw QueueClosedException();
|
||||
T v = _buffer[_begin];
|
||||
_buffer[_begin] = QueueHelper<T, std::is_pointer<T>::value>::defaultValue();
|
||||
_begin = (_begin+1) % _buffer.size();
|
||||
--_buffered;
|
||||
_notFull.notify_all();
|
||||
return v;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void ThreadedQueue<T>::close() {
|
||||
lock lk(_monitor);
|
||||
if ( _closed ) return;
|
||||
_closed = true;
|
||||
_notFull.notify_all();
|
||||
_notEmpty.notify_all();
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
bool ThreadedQueue<T>::isClosed() const {
|
||||
lock lk(_monitor);
|
||||
return _closed;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
size_t ThreadedQueue<T>::size() const {
|
||||
lock lk(_monitor);
|
||||
return _buffered;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
template <typename T>
|
||||
void ThreadedQueue<T>::reset() {
|
||||
lock lk(_monitor);
|
||||
_closed = false;
|
||||
_begin = _end = 0;
|
||||
_buffered = 0;
|
||||
QueueHelper<T, std::is_pointer<T>::value>::clean(_buffer);
|
||||
std::fill(_buffer.begin(), _buffer.end(), QueueHelper<T, std::is_pointer<T>::value>::defaultValue());
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
142
include/seiscomp/client/streamapplication.h
Normal file
142
include/seiscomp/client/streamapplication.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SEISCOMP_CLIENT_STREAM_APPLICATION_H
|
||||
#define SEISCOMP_CLIENT_STREAM_APPLICATION_H
|
||||
|
||||
|
||||
#include <seiscomp/client/application.h>
|
||||
#include <seiscomp/core/record.h>
|
||||
#include <seiscomp/io/recordstream.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Client {
|
||||
|
||||
|
||||
class SC_SYSTEM_CLIENT_API StreamApplication : public Application {
|
||||
// ----------------------------------------------------------------------
|
||||
// X'truction
|
||||
// ----------------------------------------------------------------------
|
||||
public:
|
||||
StreamApplication(int argc, char **argv);
|
||||
~StreamApplication();
|
||||
|
||||
|
||||
public:
|
||||
bool openStream();
|
||||
void closeStream();
|
||||
|
||||
IO::RecordStream* recordStream() const;
|
||||
|
||||
bool addStation(const std::string& networkCode,
|
||||
const std::string& stationCode);
|
||||
bool addStream(const std::string& networkCode,
|
||||
const std::string& stationCode,
|
||||
const std::string& locationCode,
|
||||
const std::string& channelCode);
|
||||
|
||||
void setStartTime(const Seiscomp::Core::Time&);
|
||||
void setEndTime(const Seiscomp::Core::Time&);
|
||||
bool setTimeWindow(const Seiscomp::Core::TimeWindow&);
|
||||
|
||||
//! Sets whether to start the acquisition automatically
|
||||
//! before the run loop or not. This method has to be called before run().
|
||||
//! The default is true. If set to false then the acquisition needs
|
||||
//! to be started with readRecords or startRecordThread and
|
||||
//! autoCloseOnAcquisitionFinished is also set to false.
|
||||
void setAutoAcquisitionStart(bool);
|
||||
|
||||
//! Sets the application close flag when acquisition is finished.
|
||||
//! The default is true as auto start is true. If setAutoAcquisitionStart
|
||||
//! is changed this flag is set as well.
|
||||
void setAutoCloseOnAcquisitionFinished(bool);
|
||||
|
||||
//! Sets the storage hint of incoming records.
|
||||
//! The default is: DATA_ONLY
|
||||
void setRecordInputHint(Record::Hint hint);
|
||||
|
||||
//! Sets the data type of read records.
|
||||
//! The default is: FLOAT
|
||||
void setRecordDatatype(Array::DataType datatype);
|
||||
|
||||
//! Returns the data type of the internal record sample buffer
|
||||
Array::DataType recordDataType() const { return _recordDatatype; }
|
||||
|
||||
void startRecordThread();
|
||||
void waitForRecordThread();
|
||||
bool isRecordThreadActive() const;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Protected interface
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
bool init();
|
||||
bool run();
|
||||
void done();
|
||||
void exit(int returnCode);
|
||||
|
||||
bool dispatch(Core::BaseObject* obj);
|
||||
|
||||
void readRecords(bool sendEndNotification);
|
||||
|
||||
//! This method gets called when the acquisition is finished
|
||||
//! The default implementation closes the objects queue and
|
||||
//! finishes the application
|
||||
virtual void acquisitionFinished();
|
||||
|
||||
//! This method gets called when a new record has been received
|
||||
//! by recordstream thread.
|
||||
//! The default implementation stores it in the threaded object
|
||||
//! queue which gets read by the main thread.
|
||||
//! The input record is not managed and ownership is transferred
|
||||
//! to this method.
|
||||
virtual bool storeRecord(Record *rec);
|
||||
|
||||
//! This method gets called when a record has been popped from
|
||||
//! the event queue in the main thread. The ownership of the
|
||||
//! pointer is transferred to this method. An empty function
|
||||
//! body override would cause a memory leak.
|
||||
virtual void handleRecord(Record *rec) = 0;
|
||||
|
||||
//! Logs the received records for the last period
|
||||
virtual void handleMonitorLog(const Core::Time ×tamp);
|
||||
|
||||
|
||||
private:
|
||||
bool _startAcquisition;
|
||||
bool _closeOnAcquisitionFinished;
|
||||
Record::Hint _recordInputHint;
|
||||
Array::DataType _recordDatatype;
|
||||
IO::RecordStreamPtr _recordStream;
|
||||
std::thread *_recordThread;
|
||||
size_t _receivedRecords;
|
||||
ObjectLog *_logRecords;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
17
include/seiscomp/config/api.h
Normal file
17
include/seiscomp/config/api.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef SC_CONFIG_API_H
|
||||
#define SC_CONFIG_API_H
|
||||
|
||||
#if defined(WIN32) && (defined(SC_CONFIG_SHARED) || defined(SC_ALL_SHARED))
|
||||
# if defined(SC_CONFIG_EXPORTS)
|
||||
# define SC_CONFIG_API __declspec(dllexport)
|
||||
# define SC_CONFIG_TEMPLATE_EXPORT
|
||||
# else
|
||||
# define SC_CONFIG_API __declspec(dllimport)
|
||||
# define SC_CONFIG_TEMPLATE_EXPORT extern
|
||||
# endif
|
||||
#else
|
||||
# define SC_CONFIG_API
|
||||
# define SC_CONFIG_TEMPLATE_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
349
include/seiscomp/config/config.h
Normal file
349
include/seiscomp/config/config.h
Normal file
@@ -0,0 +1,349 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __SEISCOMP_CONFIG_H__
|
||||
#define __SEISCOMP_CONFIG_H__
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
#include <seiscomp/config/log.h>
|
||||
#include <seiscomp/config/exceptions.h>
|
||||
#include <seiscomp/config/symboltable.h>
|
||||
|
||||
namespace Seiscomp {
|
||||
namespace Config {
|
||||
|
||||
/**
|
||||
* Mapping of configuration variable to type
|
||||
*/
|
||||
typedef std::map<std::string, std::string> Variables;
|
||||
|
||||
|
||||
/**
|
||||
* This is a class for reading and writing configuration files. Currently the
|
||||
* following datatypes are supported: bool, int, double and std::string as well as
|
||||
* lists of the datatypes
|
||||
*/
|
||||
class SC_CONFIG_API Config {
|
||||
// ------------------------------------------------------------------------
|
||||
// X'struction
|
||||
// ------------------------------------------------------------------------
|
||||
public:
|
||||
Config();
|
||||
~Config();
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Public interface
|
||||
// ------------------------------------------------------------------------
|
||||
public:
|
||||
/** When names are queried and this check is enabled, it will
|
||||
* throw an exception if the same name is defined in a later stage
|
||||
* with respect to case insensitive name comparison.
|
||||
* This allows to check for parameter inconsistencies that are
|
||||
* hard to track otherwise.
|
||||
*/
|
||||
void setCaseSensitivityCheck(bool);
|
||||
|
||||
/** Reads the given configuration file.
|
||||
* @param file name of the configuration files
|
||||
* @param stage Optional stage value to be set to each read symbol
|
||||
* @param raw Raw mode which does not resolv references like ${var}
|
||||
* @return true on success
|
||||
*/
|
||||
bool readConfig(const std::string& file, int stage=-1, bool raw=false);
|
||||
|
||||
/** Writes the configuration to the given configuration file.
|
||||
* @param file name of the configuarion files
|
||||
* @param localOnly write only value read from this file and
|
||||
* new entries
|
||||
* @return true on success
|
||||
*/
|
||||
bool writeConfig(const std::string& file, bool localOny = true,
|
||||
bool multilineLists = false);
|
||||
|
||||
/** Writes the configuration to the file which was given to
|
||||
* readConfing
|
||||
* @return true on success
|
||||
*/
|
||||
bool writeConfig(bool localOnly = true);
|
||||
|
||||
/** Sets the current logger. The ownership does not go to the config
|
||||
* object. It is up to the caller to free resources.
|
||||
* @param logger A logger implementation
|
||||
*/
|
||||
void setLogger(Logger *logger);
|
||||
|
||||
/** Returns the symboltabel as string */
|
||||
std::string symbolsToString();
|
||||
|
||||
/** Returns the names of parameters */
|
||||
std::vector<std::string> names() const;
|
||||
|
||||
/** Returns the names of the visited files */
|
||||
std::string visitedFilesToString();
|
||||
|
||||
//! Gets an integer from the configuration file
|
||||
//! @param name name of the element
|
||||
//! @return value
|
||||
int getInt(const std::string& name) const;
|
||||
int getInt(const std::string& name, bool* error) const;
|
||||
bool getInt(int& value, const std::string& name) const;
|
||||
|
||||
bool setInt(const std::string& name, int value);
|
||||
|
||||
/** Gets a double from the configuration file
|
||||
* @param name name of the element
|
||||
* @return double
|
||||
*/
|
||||
double getDouble(const std::string& name) const;
|
||||
double getDouble(const std::string& name, bool* error) const;
|
||||
bool getDouble(double& value, const std::string& name) const;
|
||||
|
||||
bool setDouble(const std::string& name, double value);
|
||||
|
||||
/** Gets an boolean from the configuration file
|
||||
* @param name name of the element
|
||||
* @return boolean
|
||||
*/
|
||||
bool getBool(const std::string& name) const;
|
||||
bool getBool(const std::string& name, bool* error) const;
|
||||
bool getBool(bool& value, const std::string& name) const;
|
||||
|
||||
bool setBool(const std::string& name, bool value);
|
||||
|
||||
/** Gets a string from the configuration file
|
||||
* @param name name of the element
|
||||
* @return string
|
||||
*/
|
||||
std::string getString(const std::string& name) const;
|
||||
std::string getString(const std::string& name, bool* error) const;
|
||||
bool getString(std::string& value, const std::string& name) const;
|
||||
|
||||
bool setString(const std::string& name, const std::string& value);
|
||||
|
||||
/** Removes the symbol with the given name from the symboltable.
|
||||
* @param name Symbol to be removed
|
||||
*/
|
||||
bool remove(const std::string& name);
|
||||
|
||||
std::vector<int> getInts(const std::string& name) const;
|
||||
|
||||
std::vector<int> getInts(const std::string& name, bool* error) const;
|
||||
|
||||
bool setInts(const std::string& name, const std::vector<int>& values);
|
||||
|
||||
std::vector<double> getDoubles(const std::string& name) const;
|
||||
|
||||
std::vector<double> getDoubles(const std::string& name, bool* error) const;
|
||||
|
||||
bool setDoubles(const std::string& name, const std::vector<double>& values);
|
||||
|
||||
std::vector<bool> getBools(const std::string& name) const;
|
||||
|
||||
std::vector<bool> getBools(const std::string& name, bool* error) const;
|
||||
|
||||
bool setBools(const std::string& name, const std::vector<bool>& values);
|
||||
|
||||
std::vector<std::string> getStrings(const std::string& name) const;
|
||||
std::vector<std::string> getStrings(const std::string& name, bool* error) const;
|
||||
bool getStrings(std::vector<std::string>& value, const std::string& name) const;
|
||||
|
||||
bool setStrings(const std::string& name, const std::vector<std::string>& values);
|
||||
|
||||
SymbolTable *symbolTable() const;
|
||||
|
||||
/** Evaluates a rvalue string and writes the output in result.
|
||||
* The symbol table is taken from this instance.
|
||||
* @param rvalue The value string to be parsed
|
||||
* @param result The result string vector
|
||||
* @param resolveReference Should references be resolved or not (eg
|
||||
* environment variables).
|
||||
* @return Success or error
|
||||
*/
|
||||
bool eval(const std::string &rvalue,
|
||||
std::vector<std::string> &result,
|
||||
bool resolveReferences = true,
|
||||
std::string *errmsg = NULL);
|
||||
|
||||
/** Evaluates a rvalue string and writes the output in result.
|
||||
* The symbol table is taken from this instance.
|
||||
* @param rvalue The value string to be parsed
|
||||
* @param result The result string vector
|
||||
* @param resolveReference Should references be resolved or not (eg
|
||||
* environment variables).
|
||||
* @param The symbol table to be used to resolve references if enabled.
|
||||
* @return Success or error
|
||||
*/
|
||||
static bool Eval(const std::string &rvalue,
|
||||
std::vector<std::string> &result,
|
||||
bool resolveReferences = true,
|
||||
SymbolTable *symtab = NULL,
|
||||
std::string *errmsg = NULL);
|
||||
|
||||
/** Writes the values of a symbol to an output stream. No new line
|
||||
* is appended.
|
||||
*/
|
||||
static void writeValues(std::ostream &os, const Symbol *symbol,
|
||||
bool multilineLists = false);
|
||||
|
||||
/** Writes the content of the symbol to an output stream. No new line
|
||||
* is appended.
|
||||
*/
|
||||
static void writeContent(std::ostream &os, const Symbol *symbol,
|
||||
bool multilineLists = false);
|
||||
|
||||
/** Writes a symbol to an output stream including the symbol
|
||||
* name and a equal sign. A new line is appended.
|
||||
*/
|
||||
static void writeSymbol(std::ostream &os, const Symbol *symbol,
|
||||
bool multilineLists = false);
|
||||
|
||||
/**
|
||||
* @brief Escapes an identifier (symbol name).
|
||||
* @return The escaped string
|
||||
*/
|
||||
static std::string escapeIdentifier(const std::string &);
|
||||
|
||||
/** Enables/disables tracking of configuration variables.
|
||||
*/
|
||||
void trackVariables(bool enabled);
|
||||
|
||||
/** Returns all configuration variables read by an application mapped
|
||||
* to a type
|
||||
*/
|
||||
const Variables& getVariables() const;
|
||||
|
||||
/**
|
||||
* @brief Escapes a string value that it can be stored in the
|
||||
* configuration file without further modifications.
|
||||
* @return The escaped string inside double quotes if necessary
|
||||
*/
|
||||
std::string escape(const std::string &) const;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Operators
|
||||
// ------------------------------------------------------------------------
|
||||
public:
|
||||
Config &operator=(Config &&other);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Protected interface
|
||||
// ----------------------------------------------------------------------
|
||||
protected:
|
||||
/** Parses the given file
|
||||
* @return true on success false on failure
|
||||
*/
|
||||
bool parseFile(std::istream &is); // virtual candidate
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Private interface
|
||||
// ------------------------------------------------------------------------
|
||||
private:
|
||||
void init();
|
||||
bool handleEntry(const std::string& entry, const std::string& comment);
|
||||
bool handleInclude(const std::string& fileName);
|
||||
void handleAssignment(const std::string& name, const std::string& content,
|
||||
std::vector<std::string>& values,
|
||||
const std::string& comment);
|
||||
std::vector<std::string> tokenize(const std::string& entry);
|
||||
static bool reference(const std::string &name,
|
||||
std::vector<std::string> &value,
|
||||
const SymbolTable *symtab);
|
||||
static bool parseRValue(const std::string& entry,
|
||||
std::vector<std::string>& parsedValues,
|
||||
const SymbolTable *symtab,
|
||||
bool resolveReferences,
|
||||
bool rawMode,
|
||||
std::string *errmsg);
|
||||
|
||||
bool readInternalConfig(const std::string &file, SymbolTable *symbolTable,
|
||||
const std::string &namespacePrefix,
|
||||
int stage = -1, bool raw = false);
|
||||
|
||||
template <typename T>
|
||||
T get(const std::string& name) const;
|
||||
|
||||
template <typename T>
|
||||
T get(const std::string& name, bool* error) const;
|
||||
|
||||
template <typename T>
|
||||
bool get(T& value, const std::string& name) const;
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> getVec(const std::string& name) const;
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> getVec(const std::string& name, bool* error) const;
|
||||
|
||||
template <typename T>
|
||||
void add(const std::string& name, const T& value);
|
||||
|
||||
template <typename T>
|
||||
void add(const std::string& name, const std::vector<T>& values);
|
||||
|
||||
/** Sets an value in the configuration file
|
||||
* @param element name of the element
|
||||
* @param value value for the element */
|
||||
template <typename T>
|
||||
bool set(const std::string& name, const T& value);
|
||||
|
||||
template <typename T>
|
||||
bool set(const std::string& name, const std::vector<T>& values);
|
||||
|
||||
inline void addVariable(const std::string &name, const char *type) const;
|
||||
|
||||
void releaseSymbolTable();
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Private data members
|
||||
// ------------------------------------------------------------------------
|
||||
private:
|
||||
typedef std::deque<std::string> Namespaces;
|
||||
int _stage;
|
||||
int _line;
|
||||
bool _resolveReferences;
|
||||
std::string _fileName;
|
||||
Namespaces _namespaces;
|
||||
std::string _namespacePrefix;
|
||||
std::string _defaultNamespacePrefix;
|
||||
Logger *_logger;
|
||||
|
||||
SymbolTable *_symbolTable;
|
||||
bool _trackVariables;
|
||||
Variables _variables;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Config
|
||||
} // namespace Seiscomp
|
||||
|
||||
#endif
|
||||
220
include/seiscomp/config/config.ipp
Normal file
220
include/seiscomp/config/config.ipp
Normal file
@@ -0,0 +1,220 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) gempa GmbH *
|
||||
* All rights reserved. *
|
||||
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||||
* *
|
||||
* GNU Affero General Public License Usage *
|
||||
* This file may be used under the terms of the GNU Affero *
|
||||
* Public License version 3.0 as published by the Free Software Foundation *
|
||||
* and appearing in the file LICENSE included in the packaging of this *
|
||||
* file. Please review the following information to ensure the GNU Affero *
|
||||
* Public License version 3.0 requirements will be met: *
|
||||
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||||
* *
|
||||
* Other Usage *
|
||||
* Alternatively, this file may be used in accordance with the terms and *
|
||||
* conditions contained in a signed written agreement between you and *
|
||||
* gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
void Config::add(const std::string &name, const T &value) {
|
||||
Symbol symbol;
|
||||
symbol.name = name;
|
||||
symbol.values.push_back(Private::toString(value));
|
||||
symbol.uri = "";
|
||||
|
||||
_symbolTable->add(symbol);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <>
|
||||
void Config::add<std::string>(const std::string &name, const std::string &value) {
|
||||
Symbol symbol;
|
||||
symbol.name = name;
|
||||
symbol.values.push_back(value);
|
||||
symbol.uri = "";
|
||||
|
||||
_symbolTable->add(symbol);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
void Config::add(const std::string &name, const std::vector<T> &values) {
|
||||
Symbol symbol;
|
||||
symbol.name = name;
|
||||
for ( size_t i = 0; i < values.size(); ++i ) {
|
||||
symbol.values.push_back(Private::toString(values[i]));
|
||||
}
|
||||
symbol.uri = "";
|
||||
|
||||
_symbolTable->add(symbol);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <>
|
||||
void Config::add<std::string>(const std::string &name, const std::vector<std::string> &values) {
|
||||
Symbol symbol;
|
||||
symbol.name = name;
|
||||
for ( size_t i = 0; i < values.size(); ++i ) {
|
||||
symbol.values.push_back(values[i]);
|
||||
}
|
||||
symbol.uri = "";
|
||||
|
||||
_symbolTable->add(symbol);
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
bool Config::set(const std::string &name, const T &value) {
|
||||
Symbol* symbol = _symbolTable->get(name);
|
||||
if ( !symbol ) {
|
||||
add<T>(name, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
symbol->values.clear();
|
||||
symbol->values.push_back(Private::toString(value));
|
||||
symbol->uri = "";
|
||||
|
||||
return true;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
bool Config::set(const std::string &name, const std::vector<T> &values) {
|
||||
Symbol *symbol = _symbolTable->get(name);
|
||||
if ( !symbol ) {
|
||||
add<T>(name, values);
|
||||
return true;
|
||||
}
|
||||
|
||||
symbol->values.clear();
|
||||
for ( size_t i = 0; i < values.size(); ++i ) {
|
||||
symbol->values.push_back(Private::toString(values[i]));
|
||||
}
|
||||
|
||||
symbol->uri = "";
|
||||
return true;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
T Config::get(const std::string& name) const {
|
||||
const Symbol *symbol = _symbolTable->get(name);
|
||||
if ( !symbol ) {
|
||||
throw OptionNotFoundException(name);
|
||||
}
|
||||
|
||||
T value = T();
|
||||
if ( !Private::fromString(value, symbol->values[0]) ) {
|
||||
throw TypeConversionException(symbol->values[0]);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
std::vector<T> Config::getVec(const std::string& name) const {
|
||||
const Symbol *symbol = _symbolTable->get(name);
|
||||
if ( !symbol ) {
|
||||
throw OptionNotFoundException(name);
|
||||
}
|
||||
|
||||
std::vector<T> values;
|
||||
for ( size_t i = 0; i < symbol->values.size(); ++i ) {
|
||||
T tmp = T();
|
||||
if ( !Private::fromString(tmp, symbol->values[i]) ) {
|
||||
throw TypeConversionException(symbol->values[i]);
|
||||
}
|
||||
values.push_back(tmp);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
T Config::get(const std::string &name, bool *error) const {
|
||||
*error = false;
|
||||
try {
|
||||
return get<T>(name);
|
||||
}
|
||||
catch (...) {
|
||||
*error = true;
|
||||
return T();
|
||||
}
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
bool Config::get(T &value, const std::string &name) const {
|
||||
try {
|
||||
value = get<T>(name);
|
||||
return true;
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
template <typename T>
|
||||
std::vector<T> Config::getVec(const std::string &name, bool *error) const {
|
||||
*error = false;
|
||||
try {
|
||||
return getVec<T>(name);
|
||||
}
|
||||
catch (...) {
|
||||
*error = true;
|
||||
return std::vector<T>();
|
||||
}
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user