[#1] First version of bmrshared.
This commit is contained in:
parent
47e64ffa0f
commit
479b1879bb
|
|
@ -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