nicole mazzuca 6a41626eaf
[vcpkg] Format the C++ in CI (#11655)
* [vcpkg] Format the C++ in the CI

* format the C++

* CR
2020-07-06 16:45:34 -07:00

415 lines
14 KiB
C++

#pragma once
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <vcpkg/base/expected.h>
#include <vcpkg/base/files.h>
#include <vcpkg/base/parse.h>
#include <vcpkg/base/stringview.h>
namespace vcpkg::Json
{
struct JsonStyle
{
enum class Newline
{
Lf,
CrLf
} newline_kind = Newline::Lf;
constexpr JsonStyle() noexcept = default;
static JsonStyle with_tabs() noexcept { return JsonStyle{-1}; }
static JsonStyle with_spaces(int indent) noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, indent >= 0);
return JsonStyle{indent};
}
void set_tabs() noexcept { this->indent = -1; }
void set_spaces(int indent_) noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, indent >= 0);
this->indent = indent_;
}
bool use_tabs() const noexcept { return indent == -1; }
bool use_spaces() const noexcept { return indent >= 0; }
int spaces() const noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, indent >= 0);
return indent;
}
const char* newline() const noexcept
{
switch (this->newline_kind)
{
case Newline::Lf: return "\n";
case Newline::CrLf: return "\r\n";
default: Checks::exit_fail(VCPKG_LINE_INFO);
}
}
private:
constexpr explicit JsonStyle(int indent) : indent(indent) { }
// -1 for tab, >=0 gives # of spaces
int indent = 2;
};
struct Array;
struct Object;
enum class ValueKind
{
Null,
Boolean,
Integer,
Number,
String,
Array,
Object
};
namespace impl
{
struct ValueImpl;
struct SyntaxErrorImpl;
}
struct Value
{
Value() noexcept; // equivalent to Value::null()
Value(Value&&) noexcept;
Value& operator=(Value&&) noexcept;
~Value();
Value clone() const noexcept;
ValueKind kind() const noexcept;
bool is_null() const noexcept;
bool is_boolean() const noexcept;
bool is_integer() const noexcept;
// either integer _or_ number
bool is_number() const noexcept;
bool is_string() const noexcept;
bool is_array() const noexcept;
bool is_object() const noexcept;
// a.x() asserts when !a.is_x()
bool boolean() const noexcept;
int64_t integer() const noexcept;
double number() const noexcept;
StringView string() const noexcept;
const Array& array() const& noexcept;
Array& array() & noexcept;
Array&& array() && noexcept;
const Object& object() const& noexcept;
Object& object() & noexcept;
Object&& object() && noexcept;
static Value null(std::nullptr_t) noexcept;
static Value boolean(bool) noexcept;
static Value integer(int64_t i) noexcept;
static Value number(double d) noexcept;
static Value string(StringView) noexcept;
static Value array(Array&&) noexcept;
static Value object(Object&&) noexcept;
private:
friend struct impl::ValueImpl;
std::unique_ptr<impl::ValueImpl> underlying_;
};
struct Array
{
private:
using underlying_t = std::vector<Value>;
public:
Array() = default;
Array(Array const&) = delete;
Array(Array&&) = default;
Array& operator=(Array const&) = delete;
Array& operator=(Array&&) = default;
~Array() = default;
Array clone() const noexcept;
using iterator = underlying_t::iterator;
using const_iterator = underlying_t::const_iterator;
Value& push_back(Value&& value);
Object& push_back(Object&& value);
Array& push_back(Array&& value);
Value& insert_before(iterator it, Value&& value);
Object& insert_before(iterator it, Object&& value);
Array& insert_before(iterator it, Array&& value);
std::size_t size() const noexcept { return this->underlying_.size(); }
// asserts idx < size
Value& operator[](std::size_t idx) noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, idx < this->size());
return this->underlying_[idx];
}
const Value& operator[](std::size_t idx) const noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, idx < this->size());
return this->underlying_[idx];
}
iterator begin() { return underlying_.begin(); }
iterator end() { return underlying_.end(); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
const_iterator cbegin() const { return underlying_.cbegin(); }
const_iterator cend() const { return underlying_.cend(); }
private:
underlying_t underlying_;
};
struct Object
{
private:
using underlying_t = std::vector<std::pair<std::string, Value>>;
underlying_t::const_iterator internal_find_key(StringView key) const noexcept;
public:
// these are here for better diagnostics
Object() = default;
Object(Object const&) = delete;
Object(Object&&) = default;
Object& operator=(Object const&) = delete;
Object& operator=(Object&&) = default;
~Object() = default;
Object clone() const noexcept;
// asserts if the key is found
Value& insert(std::string key, Value&& value);
Object& insert(std::string key, Object&& value);
Array& insert(std::string key, Array&& value);
// replaces the value if the key is found, otherwise inserts a new
// value.
Value& insert_or_replace(std::string key, Value&& value);
Object& insert_or_replace(std::string key, Object&& value);
Array& insert_or_replace(std::string key, Array&& value);
// returns whether the key existed
bool remove(StringView key) noexcept;
// asserts on lookup failure
Value& operator[](StringView key) noexcept
{
auto res = this->get(key);
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, res);
return *res;
}
const Value& operator[](StringView key) const noexcept
{
auto res = this->get(key);
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, res);
return *res;
}
Value* get(StringView key) noexcept;
const Value* get(StringView key) const noexcept;
bool contains(StringView key) const noexcept { return this->get(key); }
std::size_t size() const noexcept { return this->underlying_.size(); }
struct const_iterator
{
using value_type = std::pair<StringView, const Value&>;
using reference = value_type;
using iterator_category = std::forward_iterator_tag;
value_type operator*() const noexcept { return *underlying_; }
const_iterator& operator++() noexcept
{
++underlying_;
return *this;
}
const_iterator operator++(int) noexcept
{
auto res = *this;
++underlying_;
return res;
}
bool operator==(const_iterator other) const noexcept { return this->underlying_ == other.underlying_; }
bool operator!=(const_iterator other) const noexcept { return !(this->underlying_ == other.underlying_); }
private:
friend struct Object;
explicit const_iterator(const underlying_t::const_iterator& it) : underlying_(it) { }
underlying_t::const_iterator underlying_;
};
using iterator = const_iterator;
const_iterator begin() const noexcept { return this->cbegin(); }
const_iterator end() const noexcept { return this->cend(); }
const_iterator cbegin() const noexcept { return const_iterator{this->underlying_.begin()}; }
const_iterator cend() const noexcept { return const_iterator{this->underlying_.end()}; }
private:
underlying_t underlying_;
};
struct ReaderError
{
virtual void add_missing_field(std::string&& type, std::string&& key) = 0;
virtual void add_expected_type(std::string&& key, std::string&& expected_type) = 0;
virtual void add_extra_fields(std::string&& type, std::vector<std::string>&& fields) = 0;
virtual void add_mutually_exclusive_fields(std::string&& type, std::vector<std::string>&& fields) = 0;
virtual ~ReaderError() = default;
};
struct Reader
{
explicit Reader(ReaderError* err) : err(err) { }
ReaderError& error() const { return *err; }
private:
ReaderError* err;
template<class Visitor>
using VisitorType = typename std::remove_reference_t<Visitor>::type;
template<class Visitor>
Optional<VisitorType<Visitor>> internal_visit(const Value& value, StringView key, Visitor& visitor)
{
switch (value.kind())
{
using VK = Json::ValueKind;
case VK::Null: return visitor.visit_null(*this, key);
case VK::Boolean: return visitor.visit_boolean(*this, key, value.boolean());
case VK::Integer: return visitor.visit_integer(*this, key, value.integer());
case VK::Number: return visitor.visit_number(*this, key, value.number());
case VK::String: return visitor.visit_string(*this, key, value.string());
case VK::Array: return visitor.visit_array(*this, key, value.array());
case VK::Object: return visitor.visit_object(*this, key, value.object());
}
vcpkg::Checks::exit_fail(VCPKG_LINE_INFO);
}
// returns whether the field was found, not whether it was valid
template<class Visitor>
bool internal_field(const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor& visitor)
{
auto value = obj.get(key);
if (!value)
{
return false;
}
Optional<VisitorType<Visitor>> opt = internal_visit(*value, key, visitor);
if (auto val = opt.get())
{
place = std::move(*val);
}
else
{
err->add_expected_type(key.to_string(), visitor.type_name().to_string());
}
return true;
}
public:
template<class Visitor>
void required_object_field(
StringView type, const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor&& visitor)
{
if (!internal_field(obj, key, place, visitor))
{
err->add_missing_field(type.to_string(), key.to_string());
}
}
template<class Visitor>
void optional_object_field(const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor&& visitor)
{
internal_field(obj, key, place, visitor);
}
template<class Visitor>
Optional<std::vector<VisitorType<Visitor>>> array_elements(const Array& arr, StringView key, Visitor&& visitor)
{
std::vector<VisitorType<Visitor>> result;
for (const auto& el : arr)
{
auto opt = internal_visit(el, key, visitor);
if (auto p = opt.get())
{
result.push_back(std::move(*p));
}
else
{
return nullopt;
}
}
return std::move(result);
}
};
// Warning: NEVER use this type except as a CRTP base
template<class Underlying>
struct VisitorCrtpBase
{
// the following function must be defined by the Underlying class
// const char* type_name();
// We do this auto dance since function bodies are checked _after_ typedefs in the superclass,
// but function declarations are checked beforehand. Therefore, we can get C++ to use this typedef
// only once the function bodies are checked by returning `auto` and specifying the
// return type in the function body.
auto visit_null(Reader&, StringView) { return Optional<typename Underlying::type>(nullopt); }
auto visit_boolean(Reader&, StringView, bool) { return Optional<typename Underlying::type>(nullopt); }
auto visit_integer(Reader& r, StringView field_name, int64_t i)
{
return static_cast<Underlying&>(*this).visit_number(r, field_name, static_cast<double>(i));
}
auto visit_number(Reader&, StringView, double) { return Optional<typename Underlying::type>(nullopt); }
auto visit_string(Reader&, StringView, StringView) { return Optional<typename Underlying::type>(nullopt); }
auto visit_array(Reader&, StringView, const Json::Array&)
{
return Optional<typename Underlying::type>(nullopt);
}
auto visit_object(Reader&, StringView, const Json::Object&)
{
return Optional<typename Underlying::type>(nullopt);
}
// we can't make the SMFs protected because of an issue with /permissive mode
};
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse_file(
const Files::Filesystem&, const fs::path&, std::error_code& ec) noexcept;
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse(
StringView text, const fs::path& filepath = {}) noexcept;
std::string stringify(const Value&, JsonStyle style);
std::string stringify(const Object&, JsonStyle style);
std::string stringify(const Array&, JsonStyle style);
}