mirror of https://github.com/JAJames/jessilib.git
Jessica James
6 years ago
16 changed files with 2351 additions and 13 deletions
@ -0,0 +1,147 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "config.hpp" |
|||
#include <cstring> |
|||
#include <fstream> |
|||
#include "assert.hpp" |
|||
#include "serialize.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
/** Error types */ |
|||
|
|||
config::file_error::file_error() |
|||
: std::runtime_error{ std::strerror(errno) } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
config::file_error::file_error(const std::filesystem::path& in_filename) |
|||
: std::runtime_error{ "Error openening file \"" + std::string{ in_filename } + "\". Error: " + std::strerror(errno) } { |
|||
// Empty ctor body
|
|||
}; |
|||
|
|||
/** config */ |
|||
|
|||
object config::data() const { |
|||
std::shared_lock<std::shared_mutex> guard{ m_mutex }; |
|||
return m_data; |
|||
} |
|||
|
|||
std::filesystem::path config::filename() const { |
|||
std::shared_lock<std::shared_mutex> guard{ m_mutex }; |
|||
return m_filename; |
|||
} |
|||
|
|||
std::string config::format() const { |
|||
std::shared_lock<std::shared_mutex> guard{ m_mutex }; |
|||
return m_format; |
|||
} |
|||
|
|||
/** Modifiers */ |
|||
void config::set_data(const object& in_data) { |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
m_data = in_data; |
|||
} |
|||
|
|||
/** File I/O */ |
|||
void config::load(const std::filesystem::path& in_filename, const std::string& in_format) { |
|||
jessilib_assert(!in_filename.empty()); |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
// Determine format
|
|||
m_filename = in_filename; |
|||
m_format = get_format(m_filename, in_format); |
|||
|
|||
// Load
|
|||
m_data = read_object(m_filename, m_format); |
|||
} |
|||
|
|||
void config::reload() { |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
if (jessilib_debug_assert(!m_filename.empty()) |
|||
&& jessilib_debug_assert(!m_format.empty())) { |
|||
// Load data from disk
|
|||
m_data = read_object(m_filename, m_format); |
|||
} |
|||
} |
|||
|
|||
void config::write() const { |
|||
std::shared_lock<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
if (jessilib_debug_assert(!m_filename.empty()) |
|||
&& jessilib_debug_assert(!m_format.empty())) { |
|||
// Write data to disk
|
|||
write_object(m_data, m_filename, m_format); |
|||
} |
|||
} |
|||
|
|||
void config::write(const std::filesystem::path& in_filename , const std::string& in_format) { |
|||
jessilib_assert(!in_filename.empty()); |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
// Setup
|
|||
m_filename = in_filename; |
|||
m_format = get_format(m_filename, in_format); |
|||
|
|||
// Write
|
|||
write_object(m_data, m_filename, m_format); |
|||
} |
|||
|
|||
/** Static File I/O */ |
|||
object config::read_object(const std::filesystem::path& in_filename, const std::string& in_format) { |
|||
// Open up file for reading
|
|||
std::ifstream file{ in_filename, std::ios::in | std::ios::binary }; |
|||
if (!file) { |
|||
// Failed to open the file; throw file_error
|
|||
throw file_error( in_filename ); |
|||
} |
|||
|
|||
// Deserialize1
|
|||
return deserialize_object(file, in_format); |
|||
} |
|||
|
|||
void config::write_object(const object& in_object, const std::filesystem::path& in_filename, const std::string& in_format) { |
|||
// Open up file for writing
|
|||
std::ofstream file{ in_filename, std::ios::out | std::ios::binary }; |
|||
if (!file) { |
|||
// Failed to open the file; throw file_error
|
|||
throw file_error( in_filename ); |
|||
} |
|||
|
|||
// Deserialize1
|
|||
return serialize_object(file, in_object, in_format); |
|||
} |
|||
|
|||
std::string get_format(const std::filesystem::path& in_filename, const std::string& in_format) { |
|||
if (!in_format.empty()) { |
|||
// Use specified format
|
|||
return in_format; |
|||
} |
|||
|
|||
// Try to determine format from filename
|
|||
std::string extension = in_filename.extension(); |
|||
if jessilib_assert(!extension.empty()) { |
|||
return extension.substr(1); |
|||
} |
|||
|
|||
return extension; |
|||
} |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,102 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "object.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
object::object(const object& in_object) { |
|||
m_value = in_object.m_value; |
|||
} |
|||
|
|||
object::object(object&& in_object) { |
|||
m_value = std::move(in_object.m_value); |
|||
} |
|||
|
|||
object::object(const char* in_str) |
|||
: m_value{ std::string{ in_str } } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
object::object(const std::string_view& in_str) |
|||
: m_value{ std::string{ in_str.begin(), in_str.end() } } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
/** Accessors */ |
|||
|
|||
bool object::null() const { |
|||
// There's something funny about variants holding nullptr_t
|
|||
return std::holds_alternative<nullptr_t>(m_value); |
|||
} |
|||
|
|||
size_t object::size() const { |
|||
// If we're null, we don't have any members
|
|||
if (null()) { |
|||
return 0; |
|||
} |
|||
|
|||
// Try array
|
|||
{ |
|||
const array_t* array = std::get_if<array_t>(&m_value); |
|||
if (array != nullptr) { |
|||
return array->size(); |
|||
} |
|||
} |
|||
|
|||
// Try map
|
|||
{ |
|||
const map_t* map = std::get_if<map_t>(&m_value); |
|||
if (map != nullptr) { |
|||
return map->size(); |
|||
} |
|||
} |
|||
|
|||
// We're a single value
|
|||
return 1; |
|||
} |
|||
|
|||
const object& object::operator[](const std::string& in_key) const { |
|||
auto result = std::get_if<map_t>(&m_value); |
|||
if (result != nullptr) { |
|||
auto itr = result->find(in_key); |
|||
if (itr != result->end()) { |
|||
return itr->second; |
|||
} |
|||
} |
|||
|
|||
static const object s_null_object; |
|||
return s_null_object; |
|||
} |
|||
|
|||
object& object::operator[](const std::string& in_key) { |
|||
if (null()) { |
|||
return m_value.emplace<map_t>()[in_key]; |
|||
} |
|||
|
|||
auto result = std::get_if<map_t>(&m_value); |
|||
if (result != nullptr) { |
|||
return result->operator[](in_key); |
|||
} |
|||
|
|||
static thread_local object s_null_object; |
|||
s_null_object.m_value.emplace<nullptr_t>(); |
|||
return s_null_object; |
|||
} |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,42 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "parser.hpp" |
|||
#include <istream> |
|||
|
|||
namespace jessilib { |
|||
|
|||
object parser::deserialize(std::istream& in_stream) { |
|||
std::vector<char> data; |
|||
|
|||
// Read entire stream into data
|
|||
char buffer[1024]; |
|||
while(!in_stream.eof()) { |
|||
in_stream.read(buffer, sizeof(buffer)); |
|||
data.insert(data.end(), buffer, buffer + in_stream.gcount()); |
|||
} |
|||
|
|||
// Pass data to deserialize
|
|||
return deserialize(std::string_view{ &data.front(), data.size() }); |
|||
} |
|||
|
|||
void parser::serialize(std::ostream& in_stream, const object& in_object) { |
|||
in_stream << serialize(in_object); |
|||
} |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,121 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "impl/parser_manager.hpp" |
|||
#include "parser.hpp" |
|||
#include "assert.hpp" |
|||
|
|||
namespace jessilib { |
|||
namespace impl { |
|||
|
|||
parser_manager::registration::registration(id in_id) |
|||
: m_id{ in_id } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
parser_manager::registration::registration(const std::string& in_format) |
|||
: m_format{ in_format } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
parser_manager::registration::registration(id in_id, const std::string& in_format) |
|||
: m_id{ in_id }, |
|||
m_format{ in_format } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
bool parser_manager::registration::operator<(const registration& rhs) const { |
|||
if (m_id != 0 && rhs.m_id) { |
|||
// Both registrations have an ID; this is a search by ID
|
|||
return m_id < rhs.m_id; |
|||
} |
|||
|
|||
// One of the registrations lacked an ID; this must be a search by format
|
|||
return m_format < rhs.m_format; |
|||
} |
|||
|
|||
parser_manager::id parser_manager::register_parser(std::shared_ptr<parser> in_parser, const std::string& in_format, bool in_force) { |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
// Check for any existing parser
|
|||
auto itr = m_parsers.find(in_format); |
|||
if (itr != m_parsers.end()) { |
|||
// A parser already exists; return or replace
|
|||
if (!in_force) { |
|||
return bad_id; |
|||
} |
|||
|
|||
// Remove existing parser and registration
|
|||
m_parsers.erase(itr); |
|||
m_registrations.erase(registration{ in_format }); |
|||
} |
|||
|
|||
// Register our new parser
|
|||
id parser_id = ++m_last_id; |
|||
m_parsers.emplace(in_format, in_parser); |
|||
m_registrations.emplace(parser_id, in_format); |
|||
|
|||
// Our parser is registered; return the parser ID we just registered
|
|||
return parser_id; |
|||
} |
|||
|
|||
void parser_manager::unregister_parser(id in_id) { |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
// Search for registration
|
|||
auto itr = m_registrations.find(registration{ in_id }); |
|||
if (itr == m_registrations.end()) { |
|||
// Parser already unregistered; do nothing
|
|||
return; |
|||
} |
|||
|
|||
// Unregister
|
|||
registration removed_registration = *itr; |
|||
m_registrations.erase(itr); |
|||
m_parsers.erase(removed_registration.m_format); |
|||
} |
|||
|
|||
std::shared_ptr<parser> parser_manager::find_parser(const std::string& in_format) { |
|||
std::shared_lock<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
// Search for the parser by key
|
|||
auto itr = m_parsers.find(in_format); |
|||
if (itr != m_parsers.end()) { |
|||
// Found our parser; return
|
|||
return itr->second; |
|||
} |
|||
|
|||
// No parser exists for the given format
|
|||
return nullptr; |
|||
} |
|||
|
|||
void parser_manager::clear() { |
|||
std::lock_guard<std::shared_mutex> guard{ m_mutex }; |
|||
|
|||
m_parsers.clear(); |
|||
m_registrations.clear(); |
|||
} |
|||
|
|||
/** Singleton */ |
|||
parser_manager& parser_manager::instance() { |
|||
static parser_manager s_parser_manager{}; |
|||
return s_parser_manager; |
|||
} |
|||
|
|||
} // namespace jessilib
|
|||
} // namespace jessilib
|
@ -0,0 +1,69 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "serialize.hpp" |
|||
#include "impl/parser_manager.hpp" |
|||
#include "parser.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
/** Exception types */ |
|||
|
|||
format_not_available::format_not_available(const std::string& in_format) |
|||
: std::runtime_error{ "Format \"" + in_format + "\"not recognized" } { |
|||
// Empty ctor body
|
|||
}; |
|||
|
|||
/** Helpers */ |
|||
|
|||
std::shared_ptr<parser> get_parser(const std::string& in_format) { |
|||
auto parser = impl::parser_manager::instance().find_parser(in_format); |
|||
if (parser == nullptr) { |
|||
throw format_not_available{ in_format }; |
|||
} |
|||
|
|||
return parser; |
|||
} |
|||
|
|||
/** Deserialization */ |
|||
object deserialize_object(const std::string& in_data, const std::string& in_format) { |
|||
return deserialize_object(std::string_view{ &in_data.front(), in_data.size() }, in_format); |
|||
} |
|||
|
|||
object deserialize_object(const std::vector<char>& in_data, const std::string& in_format) { |
|||
return deserialize_object(std::string_view{ &in_data.front(), in_data.size() }, in_format); |
|||
} |
|||
|
|||
object deserialize_object(std::string_view in_data, const std::string& in_format) { |
|||
return get_parser(in_format)->deserialize(in_data); |
|||
} |
|||
|
|||
object deserialize_object(std::istream& in_stream, const std::string& in_format) { |
|||
return get_parser(in_format)->deserialize(in_stream); |
|||
} |
|||
|
|||
/** Serialization */ |
|||
std::string serialize_object(const object& in_object, const std::string& in_format) { |
|||
return get_parser(in_format)->serialize(in_object); |
|||
} |
|||
|
|||
void serialize_object(std::ostream& in_stream, const object& in_object, const std::string& in_format) { |
|||
get_parser(in_format)->serialize(in_stream, in_object); |
|||
} |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,68 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <string> |
|||
#include <istream> |
|||
#include <filesystem> |
|||
#include <shared_mutex> |
|||
#include "object.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
class config { |
|||
public: |
|||
/** Types */ |
|||
|
|||
class file_error : public std::runtime_error { |
|||
public: |
|||
file_error(); |
|||
file_error(const std::filesystem::path& in_filename); |
|||
}; |
|||
|
|||
/** Accessors */ |
|||
object data() const; |
|||
std::filesystem::path filename() const; |
|||
std::string format() const; |
|||
|
|||
/** Modifiers */ |
|||
void set_data(const object& in_data); |
|||
|
|||
/** File I/O */ |
|||
void load(const std::filesystem::path& in_filename, const std::string& in_format = {}); |
|||
void reload(); |
|||
void write() const; |
|||
void write(const std::filesystem::path& in_filename , const std::string& in_format = {}); |
|||
|
|||
/** Static File I/O */ |
|||
static object read_object(const std::filesystem::path& in_filename, const std::string& in_format = {}); |
|||
static void write_object(const object& in_object, const std::filesystem::path& in_filename, const std::string& in_format = {}); |
|||
|
|||
/** Static helpers */ |
|||
static std::string get_format(const std::filesystem::path& in_filename, const std::string& in_format = {}); |
|||
|
|||
private: |
|||
mutable std::shared_mutex m_mutex; |
|||
object m_data; |
|||
std::string m_format; |
|||
std::filesystem::path m_filename; |
|||
}; |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,77 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <memory> |
|||
#include <unordered_map> |
|||
#include <set> |
|||
#include <shared_mutex> |
|||
|
|||
namespace jessilib { |
|||
|
|||
class parser; |
|||
|
|||
namespace impl { |
|||
|
|||
class parser_manager { |
|||
public: |
|||
/** Types */ |
|||
using id = size_t; |
|||
|
|||
/** Constants */ |
|||
static constexpr id bad_id = 0; |
|||
|
|||
/** Methods */ |
|||
id register_parser(std::shared_ptr<parser> in_parser, const std::string& in_format, bool in_force = false); |
|||
void unregister_parser(id in_id); |
|||
std::shared_ptr<parser> find_parser(const std::string& in_format); |
|||
void clear(); |
|||
|
|||
/** Singleton */ |
|||
static parser_manager& instance(); |
|||
|
|||
private: |
|||
class registration { |
|||
public: |
|||
registration() = default; |
|||
registration(const registration&) = default; |
|||
registration(registration&&) = default; |
|||
|
|||
explicit registration(id in_id); |
|||
explicit registration(const std::string& in_format); |
|||
registration(id in_id, const std::string& in_format); |
|||
|
|||
registration& operator=(const registration&) = default; |
|||
registration& operator=(registration&&) = default; |
|||
|
|||
bool operator<(const registration& rhs) const; |
|||
|
|||
id m_id{}; |
|||
std::string m_format; |
|||
}; |
|||
|
|||
std::shared_mutex m_mutex; |
|||
id m_last_id{}; |
|||
std::set<registration> m_registrations; // This set and map could be condensed into a bimap
|
|||
std::unordered_map<std::string, std::shared_ptr<parser>> m_parsers; |
|||
}; // parser_manager
|
|||
|
|||
} // namespace impl
|
|||
} // namespace jessilib
|
@ -0,0 +1,436 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <string> |
|||
#include <vector> |
|||
#include <map> |
|||
#include <variant> |
|||
#include <utility> |
|||
#include "util.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
class object { |
|||
public: |
|||
using array_t = std::vector<object>; |
|||
using map_t = std::map<std::string, object>; |
|||
|
|||
/** is_backing */ |
|||
|
|||
template<typename T, typename enable = void> |
|||
struct is_backing { |
|||
static constexpr bool value = false; |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_backing<T, typename std::enable_if<std::is_same<T, bool>::value>::type> { |
|||
static constexpr bool value = true; |
|||
using type = bool; |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_backing<T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value>::type> { |
|||
static constexpr bool value = true; |
|||
using type = intmax_t; |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_backing<T, typename std::enable_if<std::is_floating_point<T>::value>::type> { |
|||
static constexpr bool value = true; |
|||
using type = long double; |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_backing<T, typename std::enable_if<std::is_same<T, std::string>::value>::type> { |
|||
static constexpr bool value = true; |
|||
using type = std::string; |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_backing<T, typename std::enable_if<is_sequence_container<T>::value>::type> { |
|||
static constexpr bool value = true; |
|||
using type = array_t; |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_backing<T, typename std::enable_if<std::is_same<T, map_t>::value>::type> { |
|||
static constexpr bool value = true; |
|||
using type = map_t; |
|||
}; |
|||
|
|||
// Standard constructors
|
|||
object() = default; |
|||
object(const object& in_config); |
|||
object(object&& in_config); |
|||
~object() = default; |
|||
|
|||
// Value constructors
|
|||
template<typename T, |
|||
typename std::enable_if<is_backing<typename std::decay<T>::type>::value |
|||
&& !is_sequence_container<typename std::decay<T>::type>::value>::type* = nullptr> |
|||
object(T&& in_value) |
|||
: m_value{ typename is_backing<typename std::decay<T>::type>::type{ std::forward<T>(in_value) } } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
template<typename T, |
|||
typename std::enable_if<is_sequence_container<typename std::decay<T>::type>::value |
|||
&& !std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> |
|||
object(T&& in_value) |
|||
: m_value{ array_t{ in_value.begin(), in_value.end() } } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
// std::vector<bool>
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> |
|||
object(T&& in_value) |
|||
: m_value{ array_t{} } { |
|||
auto& array = std::get<array_t>(m_value); |
|||
array.reserve(in_value.size()); |
|||
|
|||
for (const auto& item : in_value) { |
|||
array.emplace_back(bool{item}); |
|||
} |
|||
} |
|||
|
|||
object(const char* in_str); |
|||
object(const std::string_view& in_str); |
|||
|
|||
// Comparison operators
|
|||
bool operator==(const object& rhs) const { |
|||
return m_value == rhs.m_value; |
|||
} |
|||
|
|||
bool operator!=(const object& rhs) const { |
|||
return m_value != rhs.m_value; |
|||
} |
|||
|
|||
bool operator<(const object& rhs) const { |
|||
return m_value < rhs.m_value; |
|||
} |
|||
|
|||
bool operator>(const object& rhs) const { |
|||
return m_value > rhs.m_value; |
|||
} |
|||
|
|||
bool operator<=(const object& rhs) const { |
|||
return m_value <= rhs.m_value; |
|||
} |
|||
|
|||
bool operator>=(const object& rhs) const { |
|||
return m_value >= rhs.m_value; |
|||
} |
|||
|
|||
// Assignment operators
|
|||
object& operator=(const object& in_config) = default; |
|||
object& operator=(object&& in_config) = default; |
|||
|
|||
// Non-copy/move assignment operator; forwards to set()
|
|||
template<typename T, |
|||
typename std::enable_if<!std::is_same<typename std::decay<T>::type, object>::value>::type* = nullptr> |
|||
object& operator=(T&& in) { |
|||
set(std::forward<T>(in)); |
|||
return *this; |
|||
} |
|||
|
|||
const object& operator[](const std::string& in_key) const; |
|||
object& operator[](const std::string& in_key); |
|||
|
|||
/** Accessors */ |
|||
|
|||
bool null() const; |
|||
size_t size() const; |
|||
|
|||
template<typename T> |
|||
bool has() const { |
|||
using backing_t = typename is_backing<T>::type; |
|||
return std::holds_alternative<backing_t>(m_value); |
|||
} |
|||
|
|||
/** arithmetic types (numbers, bool) */ |
|||
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr> |
|||
T get(T in_default_value = {}) const { |
|||
using backing_t = typename is_backing<T>::type; |
|||
|
|||
const backing_t* result = std::get_if<backing_t>(&m_value); |
|||
if (result != nullptr) { |
|||
return static_cast<T>(*result); |
|||
} |
|||
|
|||
return in_default_value; |
|||
} |
|||
|
|||
/** strings */ |
|||
|
|||
// TODO: support other basic_string types
|
|||
template<typename T, typename DefaultT = T, |
|||
typename std::enable_if<std::is_same<T, std::string>::value && std::is_convertible<typename std::decay<DefaultT>::type, T>::value>::type* = nullptr> |
|||
T get(DefaultT&& in_default_value = {}) const { |
|||
const std::string* result = std::get_if<std::string>(&m_value); |
|||
if (result != nullptr) { |
|||
return *result; |
|||
} |
|||
|
|||
return std::forward<DefaultT>(in_default_value); |
|||
} |
|||
|
|||
// TODO: support other basic_string_view types
|
|||
template<typename T, typename DefaultT = T, |
|||
typename std::enable_if<std::is_same<T, std::string>::value && std::is_same<typename std::decay<DefaultT>::type, std::string_view>::value>::type* = nullptr> |
|||
T get(DefaultT&& in_default_value) const { |
|||
const std::string* result = std::get_if<std::string>(&m_value); |
|||
if (result != nullptr) { |
|||
return *result; |
|||
} |
|||
|
|||
return { in_default_value.begin(), in_default_value.end() }; |
|||
} |
|||
|
|||
/** arrays */ |
|||
|
|||
// reference getter (array_t)
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<T, array_t>::value>::type* = nullptr> |
|||
const T& get(const T& in_default_value) const { |
|||
const array_t* result = std::get_if<array_t>(&m_value); |
|||
if (result != nullptr) { |
|||
return *result; |
|||
} |
|||
|
|||
return in_default_value; |
|||
} |
|||
|
|||
// copy getter (array_t)
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<T, array_t>::value>::type* = nullptr> |
|||
T get(T&& in_default_value = {}) const { |
|||
const array_t* result = std::get_if<array_t>(&m_value); |
|||
if (result != nullptr) { |
|||
return *result; |
|||
} |
|||
|
|||
return std::move(in_default_value); |
|||
} |
|||
|
|||
// conversion getter (non-array_t)
|
|||
template<typename T, typename DefaultT = T, |
|||
typename std::enable_if<is_sequence_container<T>::value && !std::is_same<T, array_t>::value && std::is_same<typename std::decay<DefaultT>::type, T>::value>::type* = nullptr> |
|||
T get(DefaultT&& in_default_value = {}) const { |
|||
using backing_t = typename is_sequence_container<T>::type; |
|||
|
|||
const array_t* array = std::get_if<array_t>(&m_value); |
|||
if (array != nullptr) { |
|||
T result; |
|||
// Expand capacity to fit values (if possible)
|
|||
if constexpr (is_vector<T>::value) { |
|||
result.reserve(array->size()); |
|||
} |
|||
|
|||
// Populate result from array
|
|||
if constexpr (is_forward_list<T>::value) { |
|||
// forward_list
|
|||
if constexpr (std::is_same<backing_t, class object>::value) { |
|||
// forward_list<object>
|
|||
result.insert_after(result.begin(), array->begin(), array->end()); |
|||
} |
|||
else { |
|||
for (auto itr = array->rend(); itr != array->rbegin(); ++itr) { |
|||
if (itr->has<backing_t>()) { |
|||
result.push_front(itr->get<backing_t>()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
else if constexpr (is_set<T>::value || is_multiset<T>::value || is_unordered_set<T>::value || is_unordered_multiset<T>::value) { |
|||
// set, unordered_set, multiset, unordered_multiset
|
|||
if constexpr (std::is_same<backing_t, class object>::value) { |
|||
// <object>
|
|||
result.insert(array->begin(), array->end()); |
|||
} |
|||
else { |
|||
for (auto& object : *array) { |
|||
if (object.has<backing_t>()) { |
|||
result.insert(object.get<backing_t>()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
else { |
|||
// vector, list, etc
|
|||
for (auto& object : *array) { |
|||
if constexpr (std::is_same<backing_t, class object>::value) { |
|||
// <object>
|
|||
result.push_back(object); |
|||
} |
|||
else if (object.has<backing_t>()) { |
|||
result.push_back(object.get<backing_t>()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
return std::forward<DefaultT>(in_default_value); |
|||
} |
|||
|
|||
/** maps */ |
|||
|
|||
// TODO: implement in a way that does not require exposing map_t
|
|||
|
|||
// reference getter (map_t)
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<T, map_t>::value>::type* = nullptr> |
|||
const T& get(const T& in_default_value) const { |
|||
const map_t* result = std::get_if<map_t>(&m_value); |
|||
if (result != nullptr) { |
|||
return *result; |
|||
} |
|||
|
|||
return in_default_value; |
|||
} |
|||
|
|||
// copy getter (map_t)
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<T, map_t>::value>::type* = nullptr> |
|||
T get(T&& in_default_value = {}) const { |
|||
const map_t* result = std::get_if<map_t>(&m_value); |
|||
if (result != nullptr) { |
|||
return *result; |
|||
} |
|||
|
|||
return std::move(in_default_value); |
|||
} |
|||
|
|||
// TODO: conversion getter (non-map_t, i.e: unordered_map)
|
|||
|
|||
/** set */ |
|||
|
|||
// arithmetic types
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr> |
|||
void set(T in_value) { |
|||
using backing_t = typename is_backing<T>::type; |
|||
|
|||
m_value.emplace<backing_t>(in_value); |
|||
} |
|||
|
|||
// string
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_convertible<typename std::decay<T>::type, std::string>::value>::type* = nullptr> |
|||
void set(T&& in_value) { |
|||
m_value.emplace<std::string>(std::forward<T>(in_value)); |
|||
} |
|||
|
|||
// string_view
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<T, std::string_view>::value>::type* = nullptr> |
|||
void set(const T& in_value) { |
|||
m_value.emplace<std::string>(in_value.begin(), in_value.end()); |
|||
} |
|||
|
|||
// array_t
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<typename std::decay<T>::type, array_t>::value>::type* = nullptr> |
|||
void set(T&& in_value) { |
|||
m_value.emplace<array_t>(std::forward<T>(in_value)); |
|||
} |
|||
|
|||
// is_sequence_container
|
|||
template<typename T, |
|||
typename std::enable_if<is_sequence_container<typename std::decay<T>::type>::value |
|||
&& !std::is_same<typename std::decay<T>::type, array_t>::value |
|||
&& !std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> |
|||
void set(T&& in_value) { |
|||
m_value.emplace<array_t>(in_value.begin(), in_value.end()); |
|||
} |
|||
|
|||
// std::vector<bool>
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> |
|||
void set(T&& in_value) { |
|||
auto& array = m_value.emplace<array_t>(); |
|||
array.reserve(in_value.size()); |
|||
|
|||
for (const auto& item : in_value) { |
|||
array.emplace_back(bool{item}); |
|||
} |
|||
} |
|||
|
|||
// object
|
|||
template<typename T, |
|||
typename std::enable_if<std::is_same<typename std::decay<T>::type, object>::value>::type* = nullptr> |
|||
void set(T&& in_value) { |
|||
operator=(std::forward<T>(in_value)); |
|||
} |
|||
|
|||
size_t hash() const { |
|||
return std::visit([this](auto&& value) -> size_t { |
|||
using T = typename std::decay<decltype(value)>::type; |
|||
|
|||
if constexpr (std::is_same<T, nullptr_t>::value) { |
|||
return 0; |
|||
} |
|||
else if constexpr (std::is_same<T, array_t>::value) { |
|||
size_t result{}; |
|||
for (auto& obj : value) { |
|||
result += obj.hash(); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
else if constexpr (std::is_same<T, map_t>::value) { |
|||
size_t result{}; |
|||
for (auto& pair : value) { |
|||
result += std::hash<std::string>{}(pair.first); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
else { |
|||
return std::hash<T>{}(std::forward<decltype(value)>(value)); |
|||
} |
|||
}, m_value); |
|||
} |
|||
|
|||
private: |
|||
std::variant<nullptr_t, bool, intmax_t, long double, std::string, array_t, map_t> m_value; |
|||
}; // object
|
|||
|
|||
} // namespace jessilib
|
|||
|
|||
|
|||
namespace std { |
|||
|
|||
template<> |
|||
struct hash<jessilib::object> { |
|||
using argument_type = jessilib::object; |
|||
using result_type = size_t; |
|||
|
|||
result_type operator()(const argument_type& in_object) const noexcept { |
|||
return in_object.hash(); |
|||
} |
|||
}; |
|||
|
|||
} // namepsace std
|
@ -0,0 +1,58 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include "object.hpp" |
|||
#include "impl/parser_manager.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
class parser { |
|||
public: |
|||
/** Interface methods */ |
|||
|
|||
/**
|
|||
* Deserializes an object directly from a stream |
|||
* May throw: invalid_argument |
|||
* |
|||
* @param in_stream Stream to deserialize object from |
|||
* @return A valid (possibly null) object |
|||
*/ |
|||
virtual object deserialize(std::istream& in_stream); |
|||
virtual object deserialize(std::string_view in_data) = 0; |
|||
virtual void serialize(std::ostream& in_stream, const object& in_object); |
|||
virtual std::string serialize(const object& in_object) = 0; |
|||
}; // parser
|
|||
|
|||
template<typename T> |
|||
class parser_registration { |
|||
public: |
|||
parser_registration(std::string in_format, bool in_force = false) { |
|||
m_id = impl::parser_manager::instance().register_parser(std::make_shared<T>(), in_format, in_force); |
|||
} |
|||
|
|||
~parser_registration() { |
|||
impl::parser_manager::instance().unregister_parser(m_id); |
|||
} |
|||
|
|||
impl::parser_manager::id m_id; |
|||
}; // parser_registration
|
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,41 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <istream> |
|||
#include "object.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
class format_not_available : public std::runtime_error { |
|||
public: |
|||
format_not_available(const std::string& in_format); |
|||
}; |
|||
|
|||
/** Deserialization */ |
|||
object deserialize_object(const std::string& in_data, const std::string& in_format); |
|||
object deserialize_object(const std::vector<char>& in_data, const std::string& in_format); |
|||
object deserialize_object(std::string_view in_data, const std::string& in_format); |
|||
object deserialize_object(std::istream& in_stream, const std::string& in_format); |
|||
|
|||
/** Serialization */ |
|||
std::string serialize_object(const object& in_object, const std::string& in_format); |
|||
void serialize_object(std::ostream& in_stream, const object& in_object, const std::string& in_format); |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,215 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstddef> |
|||
#include <type_traits> |
|||
#include <vector> |
|||
#include <list> |
|||
#include <forward_list> |
|||
#include <set> |
|||
#include <unordered_set> |
|||
#include <map> |
|||
#include <unordered_map> |
|||
|
|||
/** Macros */ |
|||
|
|||
#define JESSILIB_FILENAME \ |
|||
(::jessilib::impl::filename_from_string(__FILE__)) |
|||
|
|||
namespace jessilib { |
|||
|
|||
/** is_vector */ |
|||
|
|||
template<typename T> |
|||
struct is_vector : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_vector<std::vector<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_list */ |
|||
|
|||
template<typename T> |
|||
struct is_list : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_list<std::list<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_forward_list */ |
|||
|
|||
template<typename T> |
|||
struct is_forward_list : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_forward_list<std::forward_list<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_set */ |
|||
|
|||
template<typename T> |
|||
struct is_set : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_set<std::set<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_multiset */ |
|||
|
|||
template<typename T> |
|||
struct is_multiset : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_multiset<std::multiset<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_unordered_set */ |
|||
|
|||
template<typename T> |
|||
struct is_unordered_set : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_unordered_set<std::unordered_set<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_unordered_set */ |
|||
|
|||
template<typename T> |
|||
struct is_unordered_multiset : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_unordered_multiset<std::unordered_multiset<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** is_sequence_container */ |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container : std::false_type {}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::vector<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::list<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::forward_list<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::set<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::multiset<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::unordered_set<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct is_sequence_container<std::unordered_multiset<T>> { |
|||
using type = T; |
|||
static constexpr bool value{ true }; |
|||
constexpr operator bool() const noexcept { return true; } |
|||
constexpr bool operator()() const noexcept { return true; } |
|||
}; |
|||
|
|||
/** Implementation details */ |
|||
|
|||
|
|||
namespace impl { |
|||
|
|||
template<size_t in_filename_length> |
|||
constexpr const char* filename_from_string(const char (&in_filename)[in_filename_length]) { |
|||
const char* filename_itr = in_filename; |
|||
const char* filename_end = filename_itr + in_filename_length; |
|||
const char* result = filename_itr; |
|||
|
|||
while (filename_itr != filename_end) { |
|||
if (*filename_itr == '/' || *filename_itr == '\\') { |
|||
++filename_itr; |
|||
result = filename_itr; |
|||
} |
|||
else { |
|||
++filename_itr; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
} // namespace impl
|
|||
} // namespace jessilib
|
@ -0,0 +1,932 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include <chrono> |
|||
#include "test.hpp" |
|||
#include "object.hpp" |
|||
|
|||
using namespace jessilib; |
|||
using namespace std::literals; |
|||
|
|||
void object_compilation_test() { |
|||
object config {}; |
|||
|
|||
// Map accessor
|
|||
config["bob"]["builder"].get<std::string>(""s); |
|||
config["bob"]["builder"] = "whatever"; |
|||
} |
|||
|
|||
using signed_char_t = signed char; |
|||
using unsigned_char_t = unsigned char; |
|||
using long_long_t = long long; |
|||
using long_double_t = long double; |
|||
|
|||
/** basic tests; these test function calls against null objects and heavily test for compilation errors */ |
|||
|
|||
TEST(ObjectTest, basic) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.null()); |
|||
EXPECT_EQ(obj.size(), 0U); |
|||
} |
|||
|
|||
/** basic_has tests */ |
|||
|
|||
TEST(ObjectTest, basic_has) { |
|||
object obj; |
|||
|
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.has<signed char>()); |
|||
EXPECT_FALSE(obj.has<unsigned char>()); |
|||
EXPECT_FALSE(obj.has<short>()); |
|||
EXPECT_FALSE(obj.has<int>()); |
|||
EXPECT_FALSE(obj.has<long>()); |
|||
EXPECT_FALSE(obj.has<long long>()); |
|||
EXPECT_FALSE(obj.has<intmax_t>()); |
|||
EXPECT_FALSE(obj.has<float>()); |
|||
EXPECT_FALSE(obj.has<double>()); |
|||
EXPECT_FALSE(obj.has<long double>()); |
|||
EXPECT_FALSE(obj.has<std::string>()); |
|||
EXPECT_FALSE(obj.has<object::array_t>()); |
|||
EXPECT_FALSE(obj.has<object::map_t>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_has_vector) { |
|||
object obj; |
|||
|
|||
EXPECT_FALSE(obj.has<std::vector<bool>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<signed char>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<unsigned char>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<short>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<int>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<long>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<long long>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<intmax_t>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<float>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<double>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<long double>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<std::string>>()); |
|||
EXPECT_FALSE(obj.has<std::vector<object>>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_has_list) { |
|||
object obj; |
|||
|
|||
EXPECT_FALSE(obj.has<std::list<bool>>()); |
|||
EXPECT_FALSE(obj.has<std::list<signed char>>()); |
|||
EXPECT_FALSE(obj.has<std::list<unsigned char>>()); |
|||
EXPECT_FALSE(obj.has<std::list<short>>()); |
|||
EXPECT_FALSE(obj.has<std::list<int>>()); |
|||
EXPECT_FALSE(obj.has<std::list<long>>()); |
|||
EXPECT_FALSE(obj.has<std::list<long long>>()); |
|||
EXPECT_FALSE(obj.has<std::list<intmax_t>>()); |
|||
EXPECT_FALSE(obj.has<std::list<float>>()); |
|||
EXPECT_FALSE(obj.has<std::list<double>>()); |
|||
EXPECT_FALSE(obj.has<std::list<long double>>()); |
|||
EXPECT_FALSE(obj.has<std::list<std::string>>()); |
|||
EXPECT_FALSE(obj.has<std::list<object>>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_has_forward_list) { |
|||
object obj; |
|||
|
|||
EXPECT_FALSE(obj.has<std::forward_list<bool>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<signed char>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<unsigned char>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<short>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<int>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<long>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<long long>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<intmax_t>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<float>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<double>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<long double>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<std::string>>()); |
|||
EXPECT_FALSE(obj.has<std::forward_list<object>>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_has_set) { |
|||
object obj; |
|||
|
|||
EXPECT_FALSE(obj.has<std::set<bool>>()); |
|||
EXPECT_FALSE(obj.has<std::set<signed char>>()); |
|||
EXPECT_FALSE(obj.has<std::set<unsigned char>>()); |
|||
EXPECT_FALSE(obj.has<std::set<short>>()); |
|||
EXPECT_FALSE(obj.has<std::set<int>>()); |
|||
EXPECT_FALSE(obj.has<std::set<long>>()); |
|||
EXPECT_FALSE(obj.has<std::set<long long>>()); |
|||
EXPECT_FALSE(obj.has<std::set<intmax_t>>()); |
|||
EXPECT_FALSE(obj.has<std::set<float>>()); |
|||
EXPECT_FALSE(obj.has<std::set<double>>()); |
|||
EXPECT_FALSE(obj.has<std::set<long double>>()); |
|||
EXPECT_FALSE(obj.has<std::set<std::string>>()); |
|||
EXPECT_FALSE(obj.has<std::set<object>>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_has_unordered_set) { |
|||
object obj; |
|||
|
|||
EXPECT_FALSE(obj.has<std::unordered_set<bool>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<signed char>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<unsigned char>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<short>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<int>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<long>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<long long>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<intmax_t>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<float>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<double>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<long double>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<std::string>>()); |
|||
EXPECT_FALSE(obj.has<std::unordered_set<object>>()); |
|||
} |
|||
|
|||
/** basic_get tests */ |
|||
|
|||
TEST(ObjectTest, basic_get) { |
|||
object obj; |
|||
|
|||
EXPECT_EQ(obj.get<bool>(), bool{}); |
|||
EXPECT_EQ(obj.get<signed char>(), signed_char_t{}); |
|||
EXPECT_EQ(obj.get<unsigned char>(), unsigned_char_t{}); |
|||
EXPECT_EQ(obj.get<short>(), short{}); |
|||
EXPECT_EQ(obj.get<int>(), int{}); |
|||
EXPECT_EQ(obj.get<long>(), long{}); |
|||
EXPECT_EQ(obj.get<long long>(), long_long_t{}); |
|||
EXPECT_EQ(obj.get<intmax_t>(), intmax_t{}); |
|||
EXPECT_EQ(obj.get<float>(), float{}); |
|||
EXPECT_EQ(obj.get<double>(), double{}); |
|||
EXPECT_EQ(obj.get<long double>(), long_double_t{}); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
EXPECT_TRUE(obj.get<object::array_t>().empty()); |
|||
EXPECT_TRUE(obj.get<object::map_t>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_vector) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::vector<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::vector<object>>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_list) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::list<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::list<object>>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_forward_list) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::forward_list<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::forward_list<object>>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_set) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::set<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::set<object>>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_multiset) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::multiset<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::multiset<object>>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_unordered_set) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::unordered_set<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<object>>().empty()); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_get_unordered_multiset) { |
|||
object obj; |
|||
|
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<bool>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<signed char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<unsigned char>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<short>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<int>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<long long>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<intmax_t>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<float>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<long double>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_multiset<std::string>>().empty()); |
|||
EXPECT_TRUE(obj.get<std::unordered_set<object>>().empty()); |
|||
} |
|||
|
|||
/** basic_value_constructor */ |
|||
|
|||
#define OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(in_type) \ |
|||
{ object test_object__{ in_type {} }; \ |
|||
EXPECT_TRUE(test_object__ .has< in_type >()); \ |
|||
EXPECT_EQ(test_object__.get< in_type >(), in_type {} ); } |
|||
|
|||
// asdf
|
|||
|
|||
TEST(ObjectTest, basic_value_constructor) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(bool); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(signed_char_t); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(unsigned_char_t); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(short); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(int); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(long); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(long_long_t); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(intmax_t); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(float); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(double); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(long_double_t); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::string); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(object::array_t); |
|||
|
|||
// const char*
|
|||
{ |
|||
object obj{ "" }; |
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
} |
|||
|
|||
// std::string_view
|
|||
{ |
|||
object obj{ ""sv }; |
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
} |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_vector) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::vector<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_list) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::list<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_forward_list) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::forward_list<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_set) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::set<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_multiset) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::multiset<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_unordered_set) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_value_constructor_unordered_multiset) { |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<bool>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<signed char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<unsigned char>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<short>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<int>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<long long>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<intmax_t>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<float>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<long double>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_multiset<std::string>); |
|||
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::unordered_set<object>); |
|||
} |
|||
|
|||
/** basic_set */ |
|||
|
|||
#define OBJECT_BASIC_SET_TEST(in_object, in_type) \ |
|||
in_object .set< in_type >( in_type {} ); \ |
|||
EXPECT_TRUE(in_object .has< in_type >()); \ |
|||
EXPECT_EQ(in_object .get< in_type >(), in_type {} ) |
|||
|
|||
TEST(ObjectTest, basic_set) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, bool); |
|||
OBJECT_BASIC_SET_TEST(obj, signed_char_t); |
|||
OBJECT_BASIC_SET_TEST(obj, unsigned_char_t); |
|||
OBJECT_BASIC_SET_TEST(obj, short); |
|||
OBJECT_BASIC_SET_TEST(obj, int); |
|||
OBJECT_BASIC_SET_TEST(obj, long); |
|||
OBJECT_BASIC_SET_TEST(obj, long_long_t); |
|||
OBJECT_BASIC_SET_TEST(obj, intmax_t); |
|||
OBJECT_BASIC_SET_TEST(obj, float); |
|||
OBJECT_BASIC_SET_TEST(obj, double); |
|||
OBJECT_BASIC_SET_TEST(obj, long_double_t); |
|||
OBJECT_BASIC_SET_TEST(obj, std::string); |
|||
OBJECT_BASIC_SET_TEST(obj, object::array_t); |
|||
|
|||
// const char*
|
|||
obj.set(""); |
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
|
|||
// std::string_view
|
|||
obj.set(""sv); |
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_vector) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::vector<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_list) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::list<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::list<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_forward_list) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::forward_list<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_set) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::set<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::set<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_multiset) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::multiset<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_unordered_set) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_set_unordered_multiset) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<bool>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<signed char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<unsigned char>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<short>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<int>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<long long>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<intmax_t>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<float>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<long double>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_multiset<std::string>); |
|||
OBJECT_BASIC_SET_TEST(obj, std::unordered_set<object>); |
|||
} |
|||
|
|||
/** basic_assignment_operator */ |
|||
|
|||
#define OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(in_object, in_type) \ |
|||
in_object = in_type {}; \ |
|||
EXPECT_TRUE(in_object .has< in_type >()); \ |
|||
EXPECT_EQ(in_object .get< in_type >(), in_type {} ) |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, bool); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, signed_char_t); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, unsigned_char_t); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, short); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, int); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, long); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, long_long_t); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, intmax_t); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, float); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, double); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, long_double_t); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::string); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, object::array_t); |
|||
|
|||
// const char*
|
|||
obj = ""; |
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
|
|||
// std::string_view
|
|||
obj = ""sv; |
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), std::string{}); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_vector) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::vector<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_list) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::list<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_forward_list) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::forward_list<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_set) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::set<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_multiset) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::multiset<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_unordered_set) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<object>); |
|||
} |
|||
|
|||
TEST(ObjectTest, basic_assignment_operator_unordered_multiset) { |
|||
object obj; |
|||
|
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<bool>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<signed char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<unsigned char>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<short>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<int>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<long long>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<intmax_t>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<float>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<long double>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_multiset<std::string>); |
|||
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::unordered_set<object>); |
|||
} |
|||
|
|||
/** basic_access_operator */ |
|||
|
|||
TEST(ObjectTest, basic_access_operator) { |
|||
object obj; |
|||
|
|||
obj["test"] = 1234; |
|||
EXPECT_EQ(obj["test"].get<int>(), 1234); |
|||
EXPECT_EQ(obj["test2"].get<int>(), 0); |
|||
|
|||
obj["test"] = 4567; |
|||
EXPECT_EQ(obj["test"].get<int>(), 4567); |
|||
EXPECT_EQ(obj["test2"].get<int>(), 0); |
|||
|
|||
obj["test2"] = 1234; |
|||
EXPECT_EQ(obj["test"].get<int>(), 4567); |
|||
EXPECT_EQ(obj["test2"].get<int>(), 1234); |
|||
} |
|||
|
|||
/** end basic tests */ |
|||
|
|||
TEST(ObjectTest, set_bool) { |
|||
object obj; |
|||
|
|||
obj.set(true); |
|||
|
|||
EXPECT_TRUE(obj.has<bool>()); |
|||
EXPECT_TRUE(obj.get<bool>()); |
|||
EXPECT_FALSE(obj.has<int>()); |
|||
EXPECT_EQ(obj.get<int>(), 0); |
|||
|
|||
obj.set(false); |
|||
|
|||
EXPECT_TRUE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
EXPECT_FALSE(obj.has<int>()); |
|||
EXPECT_EQ(obj.get<int>(), 0); |
|||
} |
|||
|
|||
TEST(ObjectTest, set_int) { |
|||
object obj; |
|||
|
|||
obj.set(1337); |
|||
|
|||
EXPECT_TRUE(obj.has<int>()); |
|||
EXPECT_EQ(obj.get<int>(), 1337); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set(7331); |
|||
|
|||
EXPECT_TRUE(obj.has<int>()); |
|||
EXPECT_EQ(obj.get<int>(), 7331); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set(0); |
|||
|
|||
EXPECT_TRUE(obj.has<int>()); |
|||
EXPECT_EQ(obj.get<int>(), 0); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, set_float) { |
|||
object obj; |
|||
|
|||
obj.set(13.37); |
|||
|
|||
EXPECT_TRUE(obj.has<double>()); |
|||
EXPECT_EQ(obj.get<double>(), 13.37); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set(73.31); |
|||
|
|||
EXPECT_TRUE(obj.has<double>()); |
|||
EXPECT_EQ(obj.get<double>(), 73.31); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set(0.0); |
|||
|
|||
EXPECT_TRUE(obj.has<double>()); |
|||
EXPECT_EQ(obj.get<double>(), 0.0); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, set_string) { |
|||
object obj; |
|||
|
|||
obj.set("Jessica"); |
|||
|
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), "Jessica"); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set("was"s); |
|||
|
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), "was"); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set("here"sv); |
|||
|
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), "here"); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set(""); |
|||
|
|||
EXPECT_TRUE(obj.has<std::string>()); |
|||
EXPECT_EQ(obj.get<std::string>(), ""); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, set_vector) { |
|||
object obj; |
|||
|
|||
obj.set(std::vector<bool>{ true }); |
|||
|
|||
EXPECT_TRUE(obj.has<std::vector<bool>>()); |
|||
EXPECT_EQ(obj.get<std::vector<bool>>(), std::vector<bool>{ true }); |
|||
EXPECT_TRUE(obj.has<std::vector<object>>()); |
|||
EXPECT_EQ(obj.get<std::vector<object>>().size(), 1U); |
|||
EXPECT_TRUE(obj.has<std::vector<int>>()); |
|||
EXPECT_EQ(obj.get<std::vector<int>>().size(), 0U); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
|
|||
obj.set(std::vector<bool>{}); |
|||
|
|||
EXPECT_TRUE(obj.has<std::vector<bool>>()); |
|||
EXPECT_EQ(obj.get<std::vector<bool>>().size(), 0U); |
|||
EXPECT_TRUE(obj.has<std::vector<object>>()); |
|||
EXPECT_EQ(obj.get<std::vector<object>>().size(), 0U); |
|||
EXPECT_TRUE(obj.has<std::vector<int>>()); |
|||
EXPECT_EQ(obj.get<std::vector<int>>().size(), 0U); |
|||
EXPECT_FALSE(obj.has<bool>()); |
|||
EXPECT_FALSE(obj.get<bool>()); |
|||
} |
|||
|
|||
TEST(ObjectTest, set_object) { |
|||
object obj1, obj2; |
|||
|
|||
obj1.set(true); |
|||
obj2.set(obj1); |
|||
|
|||
EXPECT_EQ(obj1, obj2); |
|||
} |
@ -0,0 +1,32 @@ |
|||
/**
|
|||
* Copyright (C) 2018 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "util.hpp" |
|||
#include "test.hpp" |
|||
#include "object.hpp" |
|||
|
|||
using namespace jessilib; |
|||
using namespace std::literals; |
|||
|
|||
TEST(UtilTest, filename) { |
|||
constexpr const char* filename = JESSILIB_FILENAME; |
|||
EXPECT_STREQ(filename, "util.cpp"); |
|||
} |
|||
|
|||
// Non-virtual using variant: 48
|
|||
//
|
Loading…
Reference in new issue