Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions include/albatross/src/indexing/apply.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,30 @@ inline auto filter(const std::vector<ValueType> &values,
return output;
}

template <typename ValueType, typename ApplyFunction,
typename ApplyType = typename details::value_only_apply_result<
ApplyFunction, ValueType>::type,
typename std::enable_if<details::is_valid_value_only_apply_function<
ApplyFunction, ValueType>::value &&
std::is_same<void, ApplyType>::value,
int>::type = 0>
void apply(const std::vector<ValueType> &xs, const ApplyFunction &f) {
std::for_each(xs.begin(), xs.end(), f);
}

template <typename ValueType, typename ApplyFunction,
typename ApplyType = typename details::value_only_apply_result<
ApplyFunction, ValueType>::type,
typename std::enable_if<details::is_valid_value_only_apply_function<
ApplyFunction, ValueType>::value &&
!std::is_same<void, ApplyType>::value,
int>::type = 0>
auto apply(const std::vector<ValueType> &xs, const ApplyFunction &f) {
std::vector<ApplyType> output(xs.size());
std::transform(xs.begin(), xs.end(), output.begin(), f);
return output;
}

} // namespace albatross

#endif /* ALBATROSS_INDEXING_APPLY_HPP_ */
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_executable(albatross_unit_tests
test_apply.cc
test_block_utils.cc
test_call_trace.cc
test_callers.cc
Expand Down
136 changes: 136 additions & 0 deletions tests/test_apply.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2019 Swift Navigation Inc.
* Contact: Swift Navigation <[email protected]>
*
* This source is subject to the license found in the file 'LICENSE' which must
* be distributed together with this source. All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <albatross/Indexing>
#include <gtest/gtest.h>

namespace albatross {

std::vector<double> test_double_vector() { return linspace(0., 10., 11); }

double square(double x) { return x * x; }

struct Foo {
Foo() : value(){};
Foo(const double &x) : value(x){};

bool operator==(const Foo &other) const {
return fabs(other.value - value) < std::numeric_limits<double>::epsilon();
}

double value;
};

Foo make_foo(double x) { return Foo(x); }

class Square {
public:
double operator()(double x) const { return square(x); }
};

/*
* Test Cases
*/

struct SquareClassMethodApply {

auto get_parent() const { return test_double_vector(); }

auto get_function() const { return Square(); }
};

struct SquareFunctionPointerApply {

auto get_parent() const { return test_double_vector(); }

auto get_function() const { return &square; }
};

struct SquareFunctionApply {

auto get_parent() const { return test_double_vector(); }

auto get_function() const { return square; }
};

struct SquareLambdaApply {

auto get_parent() const { return test_double_vector(); }

auto get_function() const {
const auto lambda_square = [](double x) { return square(x); };
return lambda_square;
}
};

struct MakeFooFunctionApply {

auto get_parent() const { return test_double_vector(); }

auto get_function() const { return make_foo; }
};

template <typename CaseType> class ApplyTester : public ::testing::Test {
public:
CaseType test_case;
};

typedef ::testing::Types<SquareClassMethodApply, SquareFunctionPointerApply,
SquareFunctionApply, SquareLambdaApply>
ApplyTestCases;

TYPED_TEST_CASE_P(ApplyTester);

TYPED_TEST_P(ApplyTester, test_apply_sanity) {
auto parent = this->test_case.get_parent();
const auto actual = apply(parent, this->test_case.get_function());

typename std::remove_const<decltype(actual)>::type expected;
for (const auto &x : parent) {
expected.emplace_back(this->test_case.get_function()(x));
}

EXPECT_EQ(expected, actual);
}

REGISTER_TYPED_TEST_CASE_P(ApplyTester, test_apply_sanity);

INSTANTIATE_TYPED_TEST_CASE_P(test_apply, ApplyTester, ApplyTestCases);

TEST(test_apply, test_vector_apply_free_function) {

const auto xs = linspace(0., 10., 11);
const auto actual = apply(xs, square);

std::vector<double> expected;
for (const auto &x : xs) {
expected.push_back(x * x);
}

EXPECT_EQ(expected.size(), actual.size());
EXPECT_EQ(expected, actual);
}

TEST(test_apply, test_vector_apply_void) {

const auto xs = linspace(0., 10., 11);

std::size_t call_count = 0;

const auto count_calls = [&](const double &x) { ++call_count; };

apply(xs, count_calls);

EXPECT_EQ(call_count, xs.size());
}

} // namespace albatross