Feature/add pair functors (#610)

* Move __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS before `#include <stdint.h>`. (#601)

Macros must be defined before first include of stdint.h. Else they have no effect.

* Replace ETL_COMPILER_ICCAVR by ETL_COMPILER_IAR. (#602)

The current definition mechanism for ETL_COMPILER_ICCAVR does not work. Both IAR compilers, for ARM and AVR define `__IAR_SYSTEMS_ICC__`. Thus `ETL_COMPILER_TYPE_DETECTED` will be defined in line before ETL_COMPILER_ICCAVR is defined. This switch will never be entered.

Currently I see no reason for differentiating both compilers (`__ICCARM__` and `__ICCAVR__`). The condition for the IAR compiler platform (`__IAR_SYSTEMS_ICC__`) is sufficient (combined with <C++11 detection).

At the moment ETL_COMPILER_ICCAVR is used as a switch condition for using `#pragma push_macro`. But actually IAR ARM and IAR AVR have no such macro defined. ETL_COMPILER_IAR is defined for both compilers. Thus the switch condition is replaced with ETL_COMPILER_IAR.

* Fix 'maybe-uninitialized' g++ error on macos (#600)

* Add documentation to the pair class

* Add test directory to the EXAMPLE_PATH

* Update .gitignore

- Remove duplicate entries
- Add doxygen output directories

* Add Select1st and Select2nd functors

* Merge select1st and select2nd into utility.h

Co-authored-by: David Hebbeker <dhebbeker@users.noreply.github.com>
This commit is contained in:
Eric Vantillard 2022-10-01 12:40:18 +02:00 committed by John Wellbelove
parent 92d8739db4
commit b5182dd83e
4 changed files with 190 additions and 33 deletions

23
.gitignore vendored
View File

@ -3,6 +3,8 @@
## Personal ## Personal
################# #################
docs/html docs/html
include/etl/html/
include/etl/latex/
test/vs2013/Debug test/vs2013/Debug
test/vs2013/Release test/vs2013/Release
test/keil/Debug test/keil/Debug
@ -91,14 +93,12 @@ build/
*.tlb *.tlb
*.tli *.tli
*.tlh *.tlh
*.tmp
*.tmp_proj *.tmp_proj
*.log *.log
*.vspscc *.vspscc
*.vssscc *.vssscc
.builds .builds
*.pidb *.pidb
*.log
*.scc *.scc
# Visual C++ cache files # Visual C++ cache files
@ -219,7 +219,6 @@ $RECYCLE.BIN/
*.egg *.egg
*.egg-info *.egg-info
dist/ dist/
build/
eggs/ eggs/
parts/ parts/
var/ var/
@ -241,7 +240,6 @@ pip-log.txt
#Mr Developer #Mr Developer
.mr.developer.cfg .mr.developer.cfg
*.depend *.depend
*.depend
*.layout *.layout
*.session *.session
*.tags *.tags
@ -270,13 +268,9 @@ test/kdevelopbuild/unittest++
test/random_clcg.csv test/random_clcg.csv
test/random_hash.csv test/random_hash.csv
test/random_lcg.csv test/random_lcg.csv
test/random_lcg.csv
test/random_lcg.csv
test/random_lsfr.csv
test/random_lsfr.csv test/random_lsfr.csv
test/random_mwc.csv test/random_mwc.csv
test/random_pcg.csv test/random_pcg.csv
test/random_pcg.csv
test/random_xorshift.csv test/random_xorshift.csv
test/cmake_install.cmake test/cmake_install.cmake
test/Makefile test/Makefile
@ -331,21 +325,16 @@ test/vs2019/Test2
test/vs2019/Debug MSVC - Force C++03 test/vs2019/Debug MSVC - Force C++03
test/vs2019/Debug LLVM - No STL test/vs2019/Debug LLVM - No STL
test/vs2019/Debug - No STL test/vs2019/Debug - No STL
test/meson-info
test/etl_unit_tests.p test/etl_unit_tests.p
test/meson-logs
test/meson-private
test/.ninja_deps test/.ninja_deps
test/.ninja_log test/.ninja_log
test/build.ninja test/build.ninja
test/compile_commands.json test/compile_commands.json
test/etl_unit_tests test/etl_unit_tests
test/build-make test/build-make
test/build-make
test/meson-info test/meson-info
test/meson-logs test/meson-logs
test/meson-private test/meson-private
test/build-make
test/build-ninja test/build-ninja
test/vs2019/Debug MSVC C++20 test/vs2019/Debug MSVC C++20
test/vs2019/Debug MSVC C++20 - No STL test/vs2019/Debug MSVC C++20 - No STL
@ -370,12 +359,4 @@ test/etl_error_handler/build-log_errors-GCC-Debug
test/etl_error_handler/build-exceptions_and_log_errors-GCC-Debug test/etl_error_handler/build-exceptions_and_log_errors-GCC-Debug
test/etl_error_handler/build-exceptions-GCC-Debug test/etl_error_handler/build-exceptions-GCC-Debug
test/etl_error_handler/exceptions_and_log_errors/.vs test/etl_error_handler/exceptions_and_log_errors/.vs
test/etl_error_handler/exceptions/build-make
test/etl_error_handler/log_errors/build-make
test/etl_error_handler/log_errors_and_exceptions/build-make
test/etl_error_handler/log_errors_and_exceptions/.vs
test/etl_error_handler/exceptions/build-make
test/etl_error_handler/log_errors/build-make
test/etl_error_handler/log_errors_and_exceptions/.vs
test/etl_error_handler/log_errors_and_exceptions/build-make
examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvoptx examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvoptx

View File

@ -872,7 +872,7 @@ EXCLUDE_SYMBOLS =
# that contain example code fragments that are included (see the \include # that contain example code fragments that are included (see the \include
# command). # command).
EXAMPLE_PATH = EXAMPLE_PATH = ./test
# If the value of the EXAMPLE_PATH tag contains directories, you can use the # If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and

View File

@ -93,24 +93,36 @@ namespace etl
} }
#endif #endif
//****************************************************************************** /**
* @brief pair holds two objects of arbitrary type
*
* @tparam T1, T2 The types of the elements that the pair stores
*/
template <typename T1, typename T2> template <typename T1, typename T2>
struct pair struct pair
{ {
typedef T1 first_type; typedef T1 first_type; ///< @c first_type is the first bound type
typedef T2 second_type; typedef T2 second_type; ///< @c second_type is the second bound type
T1 first; T1 first; ///< @c first is a copy of the first object
T2 second; T2 second; ///< @c second is a copy of the second object
/// Default constructor /**
* @brief Default constructor
*
* The default constructor creates @c first and @c second using their respective default constructors.
*/
ETL_CONSTEXPR pair() ETL_CONSTEXPR pair()
: first(T1()) : first(T1())
, second(T2()) , second(T2())
{ {
} }
/// Constructor from parameters /**
* @brief Constructor from parameters
*
* Two objects may be passed to a @c pair constructor to be copied.
*/
ETL_CONSTEXPR14 pair(const T1& a, const T2& b) ETL_CONSTEXPR14 pair(const T1& a, const T2& b)
: first(a) : first(a)
, second(b) , second(b)
@ -118,7 +130,9 @@ namespace etl
} }
#if ETL_USING_CPP11 #if ETL_USING_CPP11
/// Move constructor from parameters /**
* @brief Move constructor from parameters.
*/
template <typename U1, typename U2> template <typename U1, typename U2>
ETL_CONSTEXPR14 pair(U1&& a, U2&& b) ETL_CONSTEXPR14 pair(U1&& a, U2&& b)
: first(etl::forward<U1>(a)) : first(etl::forward<U1>(a))
@ -127,7 +141,11 @@ namespace etl
} }
#endif #endif
/// Copy constructor /**
* @brief Copy constructor
*
* There is also a templated copy constructor for the @c pair class itself.
*/
template <typename U1, typename U2> template <typename U1, typename U2>
ETL_CONSTEXPR14 pair(const pair<U1, U2>& other) ETL_CONSTEXPR14 pair(const pair<U1, U2>& other)
: first(other.first) : first(other.first)
@ -224,7 +242,14 @@ namespace etl
#endif #endif
}; };
//****************************************************************************** /**
* @brief A convenience wrapper for creating a @ref pair from two objects.
*
* @param a The first object.
* @param b The second object.
*
* @return A newly-constructed @ref pair object of the appropriate type.
*/
#if ETL_USING_CPP11 #if ETL_USING_CPP11
template <typename T1, typename T2> template <typename T1, typename T2>
inline pair<T1, T2> make_pair(T1&& a, T2&& b) inline pair<T1, T2> make_pair(T1&& a, T2&& b)
@ -246,13 +271,14 @@ namespace etl
a.swap(b); a.swap(b);
} }
//****************************************************************************** /// Two pairs of the same type are equal iff their members are equal.
template <typename T1, typename T2> template <typename T1, typename T2>
inline bool operator ==(const pair<T1, T2>& a, const pair<T1, T2>& b) inline bool operator ==(const pair<T1, T2>& a, const pair<T1, T2>& b)
{ {
return (a.first == b.first) && (a.second == b.second); return (a.first == b.first) && (a.second == b.second);
} }
/// Uses @c operator== to find the result.
template <typename T1, typename T2> template <typename T1, typename T2>
inline bool operator !=(const pair<T1, T2>& a, const pair<T1, T2>& b) inline bool operator !=(const pair<T1, T2>& a, const pair<T1, T2>& b)
{ {
@ -266,24 +292,97 @@ namespace etl
(!(b.first < a.first) && (a.second < b.second)); (!(b.first < a.first) && (a.second < b.second));
} }
/// Uses @c operator< to find the result.
template <typename T1, typename T2> template <typename T1, typename T2>
inline bool operator >(const pair<T1, T2>& a, const pair<T1, T2>& b) inline bool operator >(const pair<T1, T2>& a, const pair<T1, T2>& b)
{ {
return (b < a); return (b < a);
} }
/// Uses @c operator< to find the result.
template <typename T1, typename T2> template <typename T1, typename T2>
inline bool operator <=(const pair<T1, T2>& a, const pair<T1, T2>& b) inline bool operator <=(const pair<T1, T2>& a, const pair<T1, T2>& b)
{ {
return !(b < a); return !(b < a);
} }
/// Uses @c operator< to find the result.
template <typename T1, typename T2> template <typename T1, typename T2>
inline bool operator >=(const pair<T1, T2>& a, const pair<T1, T2>& b) inline bool operator >=(const pair<T1, T2>& a, const pair<T1, T2>& b)
{ {
return !(a < b); return !(a < b);
} }
/**
* @brief Functor to select @ref pair::first
*
* @ref select1st is a functor object that takes a single argument, a @ref pair, and returns the @ref pair::first element.
*
* @b Example
* @snippet test_utility.cpp test_select1st_example
*
* @tparam TPair The function object's argument type.
*
* @see select2nd
*/
template <typename TPair>
struct select1st
{
typedef typename TPair::first_type type; ///< type of member @ref pair::first.
/**
* @brief Function call that return @c p.first.
* @return a reference to member @ref pair::first of the @c pair `p`
*/
type& operator()(TPair& p) const
{
return p.first;
}
/**
* @copydoc operator()(TPair&)const
*/
const type& operator()(const TPair& p) const
{
return p.first;
}
};
/**
* @brief Functor to select @ref pair::second
*
* @ref select2nd is a functor object that takes a single argument, a @ref pair, and returns the @ref pair::second element.
*
* @b Example
* @snippet test_utility.cpp test_select2nd_example
*
* @tparam TPair The function object's argument type.
*
* @see select1st
*/
template <typename TPair>
struct select2nd
{
typedef typename TPair::second_type type; ///< type of member @ref pair::second.
/**
* @brief Function call. The return value is `p.second`.
* @return a reference to member `second` of the pair `p`.
*/
type& operator()(TPair& p) const
{
return p.second;
}
/**
* @copydoc operator()(TPair&)const
*/
const type& operator()(const TPair& p) const
{
return p.second;
}
};
#if ETL_NOT_USING_STL || ETL_CPP14_NOT_SUPPORTED #if ETL_NOT_USING_STL || ETL_CPP14_NOT_SUPPORTED
//*************************************************************************** //***************************************************************************
/// exchange (const) /// exchange (const)

View File

@ -30,6 +30,9 @@ SOFTWARE.
#include "etl/utility.h" #include "etl/utility.h"
#include <map>
#include <vector>
#include "data.h" #include "data.h"
namespace namespace
@ -330,6 +333,80 @@ namespace
CHECK(constCalled); CHECK(constCalled);
} }
//*************************************************************************
TEST(test_select1st)
{
typedef etl::pair<int, std::string> EtlPair;
typedef std::pair<int, std::string> StdPair;
EtlPair ep1(1, "Hello");
StdPair sp2(2, "World");
auto selector = etl::select1st<EtlPair>();
CHECK_EQUAL(1, selector(ep1));
CHECK_EQUAL(2, selector(sp2));
}
//*************************************************************************
TEST(test_select1st_example)
{
//! [test_select1st_example]
using Map = std::map<int, double>;
using Vector = std::vector<int>;
const Map map = {{1, 0.3},
{47, 0.8},
{33, 0.1}};
Vector result{};
// extract the map keys into a vector
std::transform(map.begin(), map.end(), std::back_inserter(result), etl::select1st<Map::value_type>());
//! [test_select1st_example]
CHECK_EQUAL(3, result.size());
const Vector expected{1, 33, 47};
CHECK_ARRAY_EQUAL(expected, result, 3);
}
//*************************************************************************
TEST(test_select2nd)
{
typedef etl::pair<int, std::string> EtlPair;
typedef std::pair<int, std::string> StdPair;
EtlPair ep1(1, "Hello");
StdPair sp2(2, "World");
auto selector = etl::select2nd<EtlPair>();
CHECK_EQUAL(std::string("Hello"), selector(ep1));
CHECK_EQUAL(std::string("World"), selector(sp2));
}
//*************************************************************************
TEST(test_select2nd_example)
{
//! [test_select2nd_example]
using Map = std::map<int, double>;
using Vector = std::vector<double>;
const Map map = {{1, 0.3},
{47, 0.8},
{33, 0.1}};
Vector result{};
// extract the map values into a vector
std::transform(map.begin(), map.end(), std::back_inserter(result), etl::select2nd<Map::value_type>());
//! [test_select2nd_example]
CHECK_EQUAL(3, result.size());
const Vector expected{0.1, 0.3, 0.8};
sort(result.begin(), result.end()); // sort for comparison
CHECK_ARRAY_CLOSE(expected, result, 3, 0.0001);
}
//************************************************************************* //*************************************************************************
TEST(test_functor) TEST(test_functor)
{ {