Merge pull request '[#1] First version of bmrshared.' (#2) from feature/bmrshared-stabilize-release into master
Reviewed-on: https://git.4beumer.nl/bart/network-experiment/pulls/2
This commit is contained in:
commit
5b5d53e49b
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AllowAllArgumentsOnNextLine: 'false'
|
||||||
|
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||||
|
AllowShortBlocksOnASingleLine: 'false'
|
||||||
|
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||||
|
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: None
|
||||||
|
AllowShortLoopsOnASingleLine: 'false'
|
||||||
|
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||||
|
BinPackArguments: 'false'
|
||||||
|
BinPackParameters: 'false'
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
ColumnLimit: '120'
|
||||||
|
Cpp11BracedListStyle: 'true'
|
||||||
|
FixNamespaceComments: 'true'
|
||||||
|
IncludeBlocks: Merge
|
||||||
|
IndentCaseLabels: 'true'
|
||||||
|
IndentWidth: '4'
|
||||||
|
Language: Cpp
|
||||||
|
MaxEmptyLinesToKeep: '2'
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
PointerAlignment: Left
|
||||||
|
SortUsingDeclarations: 'true'
|
||||||
|
SpaceAfterTemplateKeyword: 'false'
|
||||||
|
SpacesInAngles: 'false'
|
||||||
|
SpacesInCStyleCastParentheses: 'false'
|
||||||
|
SpacesInContainerLiterals: 'false'
|
||||||
|
SpacesInSquareBrackets: 'false'
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: '4'
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
...
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type'
|
||||||
|
WarningsAsErrors: true
|
||||||
|
HeaderFileExtensions: ['', 'h','hh','hpp','hxx']
|
||||||
|
ImplementationFileExtensions: ['c','cc','cpp','cxx']
|
||||||
|
HeaderFilterRegex: ''
|
||||||
|
AnalyzeTemporaryDtors: false
|
||||||
|
FormatStyle: google
|
||||||
|
CheckOptions:
|
||||||
|
- key: cert-dcl16-c.NewSuffixes
|
||||||
|
value: 'L;LL;LU;LLU'
|
||||||
|
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||||
|
value: '1'
|
||||||
|
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||||
|
value: '1'
|
||||||
|
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||||
|
value: '1'
|
||||||
|
- key: google-readability-function-size.StatementThreshold
|
||||||
|
value: '800'
|
||||||
|
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||||
|
value: '10'
|
||||||
|
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||||
|
value: '2'
|
||||||
|
- key: modernize-loop-convert.MaxCopySize
|
||||||
|
value: '16'
|
||||||
|
- key: modernize-loop-convert.MinConfidence
|
||||||
|
value: reasonable
|
||||||
|
- key: modernize-loop-convert.NamingStyle
|
||||||
|
value: CamelCase
|
||||||
|
- key: modernize-pass-by-value.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-use-nullptr.NullMacros
|
||||||
|
value: 'NULL'
|
||||||
|
...
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(3rdparty-boost)
|
||||||
|
add_library(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
STATIC
|
||||||
|
empty.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
INTERFACE
|
||||||
|
/home/bart/Development/3rd-party/boost/boost_1_81_0/lib/libboost_url.a
|
||||||
|
/home/bart/Development/3rd-party/boost/boost_1_81_0/lib/libboost_json.a
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PUBLIC /home/bart/Development/3rd-party/boost/boost_1_81_0/include/
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(3rdparty-googletest)
|
||||||
|
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
STATIC
|
||||||
|
empty.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
INTERFACE
|
||||||
|
GTest::gtest
|
||||||
|
GTest::gmock
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
project(3rdparty-googletest-main)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
STATIC
|
||||||
|
empty.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
INTERFACE
|
||||||
|
3rdparty-googletest
|
||||||
|
GTest::gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(all)
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
include(3rdparty-boost.cmake)
|
||||||
|
include(3rdparty-googletest.cmake)
|
||||||
|
add_subdirectory(bmrshared)
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
add_subdirectory(lib)
|
||||||
|
add_subdirectory(tst)
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
class IDataSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IDataSource() = default;
|
||||||
|
virtual void Get(std::string_view id, bool& out) const = 0;
|
||||||
|
virtual void Get(std::string_view id, double& out) const = 0;
|
||||||
|
virtual void Get(std::string_view id, int64_t& out) const = 0;
|
||||||
|
virtual void Get(std::string_view id, uint64_t& out) const = 0;
|
||||||
|
virtual void Get(std::string_view id, std::string& out) const = 0;
|
||||||
|
virtual std::vector<std::string> GetKeys() const = 0;
|
||||||
|
};
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
class ToTupleException : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct ParamError
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string type;
|
||||||
|
};
|
||||||
|
ToTupleException(std::vector<std::string> keysMissing,
|
||||||
|
std::vector<std::string> keysNotUsed,
|
||||||
|
std::vector<ParamError> paramErrors);
|
||||||
|
|
||||||
|
~ToTupleException() override;
|
||||||
|
|
||||||
|
const std::vector<std::string>& GetKeysMissing() const;
|
||||||
|
const std::vector<std::string>& GetKeysNotUsed() const;
|
||||||
|
|
||||||
|
const char* what() const noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string GenerateWhat(const std::vector<std::string>& keysMissing,
|
||||||
|
const std::vector<std::string>& keysNotUsed,
|
||||||
|
const std::vector<ParamError>& paramErrors);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_keysMissing;
|
||||||
|
std::vector<std::string> m_keysNotUsed;
|
||||||
|
std::vector<ParamError> m_paramErrors;
|
||||||
|
std::string m_what;
|
||||||
|
};
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
class flexible_value final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using keyvalue_type = std::map<std::string, flexible_value>;
|
||||||
|
using variant_type = std::variant<bool,
|
||||||
|
double,
|
||||||
|
int64_t,
|
||||||
|
uint64_t,
|
||||||
|
std::string,
|
||||||
|
std::vector<bool>,
|
||||||
|
std::vector<double>,
|
||||||
|
std::vector<int64_t>,
|
||||||
|
std::vector<uint64_t>,
|
||||||
|
std::vector<std::string>,
|
||||||
|
keyvalue_type>;
|
||||||
|
|
||||||
|
flexible_value();
|
||||||
|
flexible_value(const variant_type& value);
|
||||||
|
~flexible_value();
|
||||||
|
|
||||||
|
flexible_value& operator=(const flexible_value& other);
|
||||||
|
flexible_value& operator=(const variant_type& other);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& as() const
|
||||||
|
{
|
||||||
|
return std::get<T>(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T& as()
|
||||||
|
{
|
||||||
|
return std::get<T>(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const std::vector<T>& as_array() const
|
||||||
|
{
|
||||||
|
return as<std::vector<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::vector<T>& as_array()
|
||||||
|
{
|
||||||
|
return as<std::vector<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyvalue_type& as_keyvalue() const;
|
||||||
|
keyvalue_type& as_keyvalue();
|
||||||
|
const variant_type& as_variant() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
variant_type m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <cstddef>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
template<typename TFn>
|
||||||
|
struct function_info;
|
||||||
|
|
||||||
|
template<typename R, typename T, typename... Args>
|
||||||
|
struct function_info<R (T::*)(Args...) const>
|
||||||
|
{
|
||||||
|
using result_type = R;
|
||||||
|
using argument_types = std::tuple<Args...>;
|
||||||
|
static constexpr bool is_const_member = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename R, typename T, typename... Args>
|
||||||
|
struct function_info<R (T::*)(Args...)>
|
||||||
|
{
|
||||||
|
using result_type = R;
|
||||||
|
using argument_types = std::tuple<Args...>;
|
||||||
|
static constexpr bool is_const_member = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "flexible_value.hpp"
|
||||||
|
#include "invoke.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
class IDataSource;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename... TExtraArguments>
|
||||||
|
struct function_wrapper;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename... TExtraArguments>
|
||||||
|
requires(std::is_const<T>::value == true) struct function_wrapper<T, TExtraArguments...>
|
||||||
|
{
|
||||||
|
using wrapper_type = std::function<flexible_value(const T&, const IDataSource&, TExtraArguments...)>;
|
||||||
|
|
||||||
|
template<typename M, typename... TSourceParams>
|
||||||
|
static wrapper_type Wrap(M T::*callableFn, TSourceParams... paramNames)
|
||||||
|
{
|
||||||
|
std::array<std::string, sizeof...(TSourceParams)> names{paramNames...};
|
||||||
|
return [callableFn, names](const T& obj, const IDataSource& source, TExtraArguments... args)
|
||||||
|
{
|
||||||
|
return invoke(obj, callableFn, names, source, args...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename... TExtraArguments>
|
||||||
|
requires(std::is_const<T>::value == false) struct function_wrapper<T, TExtraArguments...>
|
||||||
|
{
|
||||||
|
using wrapper_type = std::function<flexible_value(T&, const IDataSource&, TExtraArguments...)>;
|
||||||
|
|
||||||
|
template<typename M, typename... TSourceParams>
|
||||||
|
static wrapper_type Wrap(M T::*callableFn, TSourceParams... paramNames)
|
||||||
|
{
|
||||||
|
std::array<std::string, sizeof...(TSourceParams)> names{paramNames...};
|
||||||
|
return [callableFn, names](T& obj, const IDataSource& source, TExtraArguments... args)
|
||||||
|
{
|
||||||
|
return invoke(obj, callableFn, names, source, args...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "IDataSource.hpp"
|
||||||
|
#include "flexible_value.hpp"
|
||||||
|
#include "function_info.hpp"
|
||||||
|
#include "to_tuple.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<typename TupleSource, std::size_t NTypesToKeep, typename... TypesToKeep>
|
||||||
|
struct tuple_keepelemsfront;
|
||||||
|
|
||||||
|
template<typename... TupleTypes, typename... TypesToKeep>
|
||||||
|
struct tuple_keepelemsfront<std::tuple<TupleTypes...>, 0, TypesToKeep...>
|
||||||
|
{
|
||||||
|
using tuple = std::tuple<TypesToKeep...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FirstTupleType, typename... TupleTypes, std::size_t NTypesToKeep, typename... TypesToKeep>
|
||||||
|
requires(NTypesToKeep > 0)
|
||||||
|
|
||||||
|
struct tuple_keepelemsfront<std::tuple<FirstTupleType, TupleTypes...>, NTypesToKeep, TypesToKeep...>
|
||||||
|
{
|
||||||
|
using tuple = typename tuple_keepelemsfront<std::tuple<TupleTypes...>,
|
||||||
|
(NTypesToKeep - 1),
|
||||||
|
TypesToKeep...,
|
||||||
|
FirstTupleType>::tuple;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Tuple, std::size_t NTypesToRemove>
|
||||||
|
struct tuple_rmelemsback;
|
||||||
|
|
||||||
|
template<typename... TupleTypes, std::size_t NTypesToRemove>
|
||||||
|
struct tuple_rmelemsback<std::tuple<TupleTypes...>, NTypesToRemove>
|
||||||
|
{
|
||||||
|
using tuple =
|
||||||
|
typename tuple_keepelemsfront<std::tuple<TupleTypes...>, (sizeof...(TupleTypes) - NTypesToRemove)>::tuple;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename M, typename T, std::size_t TParameterCount, typename... TExtraArguments>
|
||||||
|
requires(function_info<M T::*>::is_const_member == false)
|
||||||
|
|
||||||
|
flexible_value invoke(T& callableObj,
|
||||||
|
M T::*callableFn,
|
||||||
|
std::array<std::string, TParameterCount> names,
|
||||||
|
const IDataSource& source,
|
||||||
|
TExtraArguments... arguments)
|
||||||
|
{
|
||||||
|
using CallableInfo = function_info<decltype(callableFn)>;
|
||||||
|
using SourceArgumentsTuple =
|
||||||
|
typename detail::tuple_rmelemsback<typename CallableInfo::argument_types, sizeof...(TExtraArguments)>::tuple;
|
||||||
|
|
||||||
|
SourceArgumentsTuple parameters;
|
||||||
|
to_tuple(source, names, parameters);
|
||||||
|
|
||||||
|
return {std::apply(std::mem_fn<M, T>(callableFn),
|
||||||
|
std::tuple_cat(std::tie(callableObj), parameters, std::tie(arguments...)))};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename M, typename T, std::size_t TParameterCount, typename... TExtraArguments>
|
||||||
|
requires(function_info<M T::*>::is_const_member == true)
|
||||||
|
|
||||||
|
flexible_value invoke(const T& callableObj,
|
||||||
|
M T::*callableFn,
|
||||||
|
std::array<std::string, TParameterCount> names,
|
||||||
|
const IDataSource& source,
|
||||||
|
TExtraArguments... arguments)
|
||||||
|
{
|
||||||
|
using CallableInfo = function_info<decltype(callableFn)>;
|
||||||
|
using SourceArgumentsTuple =
|
||||||
|
typename detail::tuple_rmelemsback<typename CallableInfo::argument_types, sizeof...(TExtraArguments)>::tuple;
|
||||||
|
|
||||||
|
SourceArgumentsTuple parameters;
|
||||||
|
to_tuple(source, names, parameters);
|
||||||
|
|
||||||
|
return {std::apply(std::mem_fn<M, const T>(callableFn),
|
||||||
|
std::tuple_cat(std::tie(callableObj), parameters, std::tie(arguments...)))};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TCallable, std::size_t TParameterCount, typename... TExtraArguments>
|
||||||
|
flexible_value invoke(TCallable& fn,
|
||||||
|
std::array<std::string, TParameterCount> names,
|
||||||
|
const IDataSource& source,
|
||||||
|
TExtraArguments... arguments)
|
||||||
|
{
|
||||||
|
return invoke(fn, &TCallable::operator(), names, source, arguments...);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "IDataSource.hpp"
|
||||||
|
#include "ToTupleException.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
std::vector<std::string>
|
||||||
|
GetKeysMissing(const std::vector<std::string>& allKeys, const std::string* dataBegin, std::size_t arraySize);
|
||||||
|
std::vector<std::string>
|
||||||
|
GetKeysNotUsed(const std::vector<std::string>& allKeys, const std::string* dataBegin, std::size_t arraySize);
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T GetValueFromDataSource(const IDataSource& source,
|
||||||
|
std::string_view id,
|
||||||
|
std::vector<ToTupleException::ParamError>& outErrors)
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
source.Get(id, value);
|
||||||
|
}
|
||||||
|
catch (const std::exception&)
|
||||||
|
{
|
||||||
|
outErrors.push_back(ToTupleException::ParamError{std::string(id), "problem reading"});
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... TParameters, std::size_t... IndexSeq>
|
||||||
|
std::tuple<TParameters...> to_tuple(const IDataSource& source,
|
||||||
|
const std::array<std::string, sizeof...(TParameters)>& names,
|
||||||
|
std::index_sequence<IndexSeq...>)
|
||||||
|
{
|
||||||
|
const auto allKeys = source.GetKeys();
|
||||||
|
const auto keysMissing = GetKeysMissing(allKeys, names.data(), sizeof...(TParameters));
|
||||||
|
const auto keysNotUsed = GetKeysNotUsed(allKeys, names.data(), sizeof...(TParameters));
|
||||||
|
|
||||||
|
// Constructing the tuple by expanding the parameter packs to retrieve each name for the specified type. in
|
||||||
|
// case of errors these are written to errorRecords
|
||||||
|
std::vector<ToTupleException::ParamError> errorRecords;
|
||||||
|
std::tuple<TParameters...> returnValue = {
|
||||||
|
GetValueFromDataSource<TParameters>(source, std::get<IndexSeq>(names), errorRecords)...};
|
||||||
|
|
||||||
|
if (!keysMissing.empty() || !keysNotUsed.empty() || !errorRecords.empty())
|
||||||
|
{
|
||||||
|
throw ToTupleException(keysMissing, keysNotUsed, errorRecords);
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename... Types>
|
||||||
|
std::tuple<Types...> to_tuple(const IDataSource& source, const std::array<std::string, sizeof...(Types)>& names)
|
||||||
|
{
|
||||||
|
return detail::to_tuple<Types...>(source, names, std::make_index_sequence<sizeof...(Types)>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Types>
|
||||||
|
void to_tuple(const IDataSource& source,
|
||||||
|
const std::array<std::string, sizeof...(Types)>& names,
|
||||||
|
std::tuple<Types...>& outParameters)
|
||||||
|
{
|
||||||
|
outParameters = detail::to_tuple<Types...>(source, names, std::make_index_sequence<sizeof...(Types)>());
|
||||||
|
}
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(bmrshared)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
flexible_value.cpp
|
||||||
|
to_tuple.cpp
|
||||||
|
ToTupleException.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#include "bmrshared/ToTupleException.hpp"
|
||||||
|
#include <exception>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
ToTupleException::ToTupleException(std::vector<std::string> keysMissing,
|
||||||
|
std::vector<std::string> keysNotUsed,
|
||||||
|
std::vector<ParamError> paramErrors)
|
||||||
|
: m_keysMissing(std::move(keysMissing))
|
||||||
|
, m_keysNotUsed(std::move(keysNotUsed))
|
||||||
|
, m_paramErrors(std::move(paramErrors))
|
||||||
|
, m_what(GenerateWhat(m_keysMissing, m_keysNotUsed, m_paramErrors))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ToTupleException::~ToTupleException() = default;
|
||||||
|
|
||||||
|
const std::vector<std::string>& ToTupleException::GetKeysMissing() const
|
||||||
|
{
|
||||||
|
return m_keysMissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& ToTupleException::GetKeysNotUsed() const
|
||||||
|
{
|
||||||
|
return m_keysNotUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ToTupleException::what() const noexcept
|
||||||
|
{
|
||||||
|
return m_what.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToTupleException::GenerateWhat(const std::vector<std::string>& keysMissing,
|
||||||
|
const std::vector<std::string>& keysNotUsed,
|
||||||
|
const std::vector<ParamError>& paramErrors)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Errors while converting to tuple.";
|
||||||
|
for (const auto& key : keysMissing)
|
||||||
|
{
|
||||||
|
ss << "\n - missing: " << key;
|
||||||
|
}
|
||||||
|
for (const auto& key : keysNotUsed)
|
||||||
|
{
|
||||||
|
ss << "\n - unused: " << key;
|
||||||
|
}
|
||||||
|
for (const auto& error : paramErrors)
|
||||||
|
{
|
||||||
|
ss << "\n - error: " << error.name << " \"" << error.type << "\"";
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#include "bmrshared/flexible_value.hpp"
|
||||||
|
|
||||||
|
using bmrshared::flexible_value;
|
||||||
|
|
||||||
|
flexible_value::flexible_value() = default;
|
||||||
|
|
||||||
|
flexible_value::flexible_value(const variant_type& value)
|
||||||
|
: m_data(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
flexible_value::~flexible_value() = default;
|
||||||
|
|
||||||
|
flexible_value& flexible_value::operator=(const flexible_value& other) = default;
|
||||||
|
|
||||||
|
flexible_value& flexible_value::operator=(const flexible_value::variant_type& other)
|
||||||
|
{
|
||||||
|
m_data = other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const flexible_value::keyvalue_type& flexible_value::as_keyvalue() const
|
||||||
|
{
|
||||||
|
return as<keyvalue_type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
flexible_value::keyvalue_type& flexible_value::as_keyvalue()
|
||||||
|
{
|
||||||
|
return as<keyvalue_type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const flexible_value::variant_type& flexible_value::as_variant() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#include "bmrshared/to_tuple.hpp"
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
std::vector<std::string> detail::GetKeysMissing(const std::vector<std::string>& allKeys,
|
||||||
|
const std::string* const dataBegin,
|
||||||
|
std::size_t arraySize)
|
||||||
|
{
|
||||||
|
const std::string* const dataEnd = (dataBegin + arraySize);
|
||||||
|
std::vector<std::string> keysMissing;
|
||||||
|
|
||||||
|
for (const std::string* iter = dataBegin; iter != dataEnd; ++iter)
|
||||||
|
{
|
||||||
|
auto iterFound = std::find(allKeys.begin(), allKeys.end(), *iter);
|
||||||
|
if (iterFound == allKeys.end())
|
||||||
|
{
|
||||||
|
keysMissing.push_back(*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysMissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> detail::GetKeysNotUsed(const std::vector<std::string>& allKeys,
|
||||||
|
const std::string* const dataBegin,
|
||||||
|
std::size_t arraySize)
|
||||||
|
{
|
||||||
|
const std::string* const dataEnd = (dataBegin + arraySize);
|
||||||
|
std::vector<std::string> keysNotUsed;
|
||||||
|
|
||||||
|
for (const auto& key : allKeys)
|
||||||
|
{
|
||||||
|
auto iterFound = std::find(dataBegin, dataEnd, key);
|
||||||
|
if (iterFound == dataEnd)
|
||||||
|
{
|
||||||
|
keysNotUsed.push_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysNotUsed;
|
||||||
|
}
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(bmrshared-test)
|
||||||
|
add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
ToTupleTest.cpp
|
||||||
|
InvokeTest.cpp
|
||||||
|
WrapTest.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
TARGET ${PROJECT_NAME}
|
||||||
|
PROPERTY CXX_STANDARD 20
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PUBLIC
|
||||||
|
bmrshared
|
||||||
|
3rdparty-googletest-main
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS ${PROJECT_NAME}
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#include "bmrshared/invoke.hpp"
|
||||||
|
#include "MockDataSource.hpp"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
using ::testing::An;
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::SetArgReferee;
|
||||||
|
using ::testing::TypedEq;
|
||||||
|
|
||||||
|
using bmrshared::flexible_value;
|
||||||
|
using bmrshared::MockDataSource;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Compile-time test of some helper templates.
|
||||||
|
|
||||||
|
static_assert(std::is_same<typename bmrshared::detail::tuple_keepelemsfront<std::tuple<int, char>, 0>::tuple,
|
||||||
|
std::tuple<>>::value);
|
||||||
|
static_assert(std::is_same<typename bmrshared::detail::tuple_keepelemsfront<std::tuple<int, char>, 1>::tuple,
|
||||||
|
std::tuple<int>>::value);
|
||||||
|
static_assert(std::is_same<typename bmrshared::detail::tuple_keepelemsfront<std::tuple<int, char>, 2>::tuple,
|
||||||
|
std::tuple<int, char>>::value);
|
||||||
|
|
||||||
|
static_assert(std::is_same<typename bmrshared::detail::tuple_rmelemsback<std::tuple<int, char>, 0>::tuple,
|
||||||
|
std::tuple<int, char>>::value);
|
||||||
|
static_assert(std::is_same<typename bmrshared::detail::tuple_rmelemsback<std::tuple<int, char>, 1>::tuple,
|
||||||
|
std::tuple<int>>::value);
|
||||||
|
static_assert(
|
||||||
|
std::is_same<typename bmrshared::detail::tuple_rmelemsback<std::tuple<int, char>, 2>::tuple, std::tuple<>>::value);
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint64_t AddNumbers(uint64_t left, uint64_t right) { return left + (right * 2); }
|
||||||
|
uint64_t AddNumbersConst(uint64_t left, uint64_t right) const { return left + (right * 2); }
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
TEST(InvokeTest, Ok_Callable)
|
||||||
|
{
|
||||||
|
auto fn = [](int64_t a, int64_t b)
|
||||||
|
{
|
||||||
|
return (a + (b * 2));
|
||||||
|
};
|
||||||
|
std::array<std::string, 2> names = {"a", "b"};
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(21));
|
||||||
|
|
||||||
|
flexible_value returnValue = bmrshared::invoke(fn, names, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<int64_t>(), 84);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InvokeTest, Ok_Callable_LastArg)
|
||||||
|
{
|
||||||
|
auto fn = [](int64_t a, int64_t b, int64_t lastArg)
|
||||||
|
{
|
||||||
|
return ((lastArg * 4) + a + (b * 2));
|
||||||
|
};
|
||||||
|
std::array<std::string, 2> names = {"a", "b"};
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(21));
|
||||||
|
|
||||||
|
flexible_value returnValue = bmrshared::invoke(fn, names, mockSrc, 1000);
|
||||||
|
EXPECT_EQ(returnValue.as<int64_t>(), 4084);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InvokeTest, Ok_Ptr_Member)
|
||||||
|
{
|
||||||
|
std::array<std::string, 2> names = {"left", "right"};
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"left", "right"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("left", An<uint64_t&>())).WillRepeatedly(SetArgReferee<1>(100));
|
||||||
|
EXPECT_CALL(mockSrc, Get("right", An<uint64_t&>())).WillRepeatedly(SetArgReferee<1>(20));
|
||||||
|
|
||||||
|
TestAddition functor;
|
||||||
|
flexible_value returnValue = bmrshared::invoke(functor, &TestAddition::AddNumbers, names, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<uint64_t>(), 140);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InvokeTest, Ok_Ptr_Const_Member_Const)
|
||||||
|
{
|
||||||
|
std::array<std::string, 2> names = {"left", "right"};
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"left", "right"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("left", An<uint64_t&>())).WillRepeatedly(SetArgReferee<1>(100));
|
||||||
|
EXPECT_CALL(mockSrc, Get("right", An<uint64_t&>())).WillRepeatedly(SetArgReferee<1>(20));
|
||||||
|
|
||||||
|
const TestAddition functor;
|
||||||
|
flexible_value returnValue = bmrshared::invoke(functor, &TestAddition::AddNumbersConst, names, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<uint64_t>(), 140);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InvokeTest, Ok_Ptr_Member_Const)
|
||||||
|
{
|
||||||
|
std::array<std::string, 2> names = {"left", "right"};
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"left", "right"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("left", An<uint64_t&>())).WillRepeatedly(SetArgReferee<1>(100));
|
||||||
|
EXPECT_CALL(mockSrc, Get("right", An<uint64_t&>())).WillRepeatedly(SetArgReferee<1>(20));
|
||||||
|
|
||||||
|
TestAddition functor;
|
||||||
|
flexible_value returnValue = bmrshared::invoke(functor, &TestAddition::AddNumbersConst, names, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<uint64_t>(), 140);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "bmrshared/IDataSource.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bmrshared
|
||||||
|
{
|
||||||
|
class MockDataSource : public IDataSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~MockDataSource() override = default;
|
||||||
|
MOCK_METHOD(void, Get, (std::string_view, bool&), (const, override));
|
||||||
|
MOCK_METHOD(void, Get, (std::string_view, double&), (const, override));
|
||||||
|
MOCK_METHOD(void, Get, (std::string_view, int64_t&), (const, override));
|
||||||
|
MOCK_METHOD(void, Get, (std::string_view, uint64_t&), (const, override));
|
||||||
|
MOCK_METHOD(void, Get, (std::string_view, std::string&), (const, override));
|
||||||
|
MOCK_METHOD(std::vector<std::string>, GetKeys, (), (const, override));
|
||||||
|
};
|
||||||
|
} // namespace bmrshared
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#include "MockDataSource.hpp"
|
||||||
|
#include "bmrshared/IDataSource.hpp"
|
||||||
|
#include "bmrshared/flexible_value.hpp"
|
||||||
|
#include "bmrshared/to_tuple.hpp"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
using ::bmrshared::MockDataSource;
|
||||||
|
using ::testing::An;
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::SetArgReferee;
|
||||||
|
using ::testing::Throw;
|
||||||
|
|
||||||
|
TEST(ToTupleTest, Ok)
|
||||||
|
{
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b", "c"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<double&>())).WillRepeatedly(SetArgReferee<1>(4.2));
|
||||||
|
EXPECT_CALL(mockSrc, Get("c", An<std::string&>())).WillRepeatedly(SetArgReferee<1>("test"));
|
||||||
|
|
||||||
|
using TupleType = std::tuple<int64_t, double, std::string>;
|
||||||
|
const std::array<std::string, 3> names{"a", "b", "c"};
|
||||||
|
const TupleType expected{42, 4.2, "test"};
|
||||||
|
|
||||||
|
TupleType result;
|
||||||
|
bmrshared::to_tuple(mockSrc, names, result);
|
||||||
|
|
||||||
|
EXPECT_EQ(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ToTupleTest, MissingParameter)
|
||||||
|
{
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "c"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<double&>())).WillRepeatedly(Throw(std::runtime_error("")));
|
||||||
|
EXPECT_CALL(mockSrc, Get("c", An<std::string&>())).WillRepeatedly(SetArgReferee<1>("test"));
|
||||||
|
|
||||||
|
using TupleType = std::tuple<int64_t, double, std::string>;
|
||||||
|
const std::array<std::string, 3> names{"a", "b", "c"};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TupleType result;
|
||||||
|
bmrshared::to_tuple(mockSrc, names, result);
|
||||||
|
EXPECT_TRUE(false);
|
||||||
|
}
|
||||||
|
catch (const bmrshared::ToTupleException& e)
|
||||||
|
{
|
||||||
|
EXPECT_THAT(e.GetKeysMissing(), ElementsAre("b"));
|
||||||
|
EXPECT_THAT(e.GetKeysNotUsed(), ElementsAre());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ToTupleTest, NotUsedParameter)
|
||||||
|
{
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b", "c", "d"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<double&>())).WillRepeatedly(SetArgReferee<1>(4.2));
|
||||||
|
EXPECT_CALL(mockSrc, Get("c", An<std::string&>())).WillRepeatedly(SetArgReferee<1>("test"));
|
||||||
|
|
||||||
|
using TupleType = std::tuple<int64_t, double, std::string>;
|
||||||
|
const std::array<std::string, 3> names{"a", "b", "c"};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TupleType result;
|
||||||
|
bmrshared::to_tuple(mockSrc, names, result);
|
||||||
|
EXPECT_TRUE(false);
|
||||||
|
}
|
||||||
|
catch (const bmrshared::ToTupleException& e)
|
||||||
|
{
|
||||||
|
EXPECT_THAT(e.GetKeysMissing(), ElementsAre());
|
||||||
|
EXPECT_THAT(e.GetKeysNotUsed(), ElementsAre("d"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// GNU Lesser General Public License v3.0
|
||||||
|
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
||||||
|
// the Free Software Foundation.
|
||||||
|
//
|
||||||
|
#include "MockDataSource.hpp"
|
||||||
|
#include "bmrshared/function_wrapper.hpp"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
using ::testing::An;
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::SetArgReferee;
|
||||||
|
using ::testing::TypedEq;
|
||||||
|
|
||||||
|
using ::bmrshared::flexible_value;
|
||||||
|
using ::bmrshared::function_wrapper;
|
||||||
|
using ::bmrshared::IDataSource;
|
||||||
|
using ::bmrshared::MockDataSource;
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class TestAddition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int64_t AddNumbers(int64_t left, int64_t right) { return left + (right * 2); }
|
||||||
|
int64_t AddNumbersConst(int64_t left, int64_t right) const { return left + (right * 2); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using TestWrapperType = function_wrapper<TestAddition>;
|
||||||
|
using TestConstWrapperType = function_wrapper<const TestAddition>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(WrapTest, Ptr_to_member)
|
||||||
|
{
|
||||||
|
TestAddition obj;
|
||||||
|
TestWrapperType::wrapper_type wrapped = TestWrapperType::Wrap(&TestAddition::AddNumbers, "a", "b");
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(21));
|
||||||
|
|
||||||
|
flexible_value returnValue = wrapped(obj, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<int64_t>(), 84);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WrapTest, Const_Ptr_to_member)
|
||||||
|
{
|
||||||
|
const TestAddition obj;
|
||||||
|
TestConstWrapperType::wrapper_type wrapped = TestConstWrapperType::Wrap(&TestAddition::AddNumbersConst, "a", "b");
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(21));
|
||||||
|
|
||||||
|
flexible_value returnValue = wrapped(obj, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<int64_t>(), 84);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WrapTest, Const_Ptr_to_member_as_non_const)
|
||||||
|
{
|
||||||
|
const TestAddition obj;
|
||||||
|
TestConstWrapperType::wrapper_type wrapped = TestConstWrapperType::Wrap(&TestAddition::AddNumbersConst, "a", "b");
|
||||||
|
|
||||||
|
MockDataSource mockSrc;
|
||||||
|
EXPECT_CALL(mockSrc, GetKeys()).WillRepeatedly(Return(std::vector<std::string>{"a", "b"}));
|
||||||
|
EXPECT_CALL(mockSrc, Get("a", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(42));
|
||||||
|
EXPECT_CALL(mockSrc, Get("b", An<int64_t&>())).WillRepeatedly(SetArgReferee<1>(21));
|
||||||
|
|
||||||
|
flexible_value returnValue = wrapped(obj, mockSrc);
|
||||||
|
EXPECT_EQ(returnValue.as<int64_t>(), 84);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue