Skip to content
Closed
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
12 changes: 12 additions & 0 deletions cpp/src/arrow/util/functional.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,17 @@ class FnOnce<R(A...)> {
std::unique_ptr<Impl> impl_;
};

/// A callable object that simply forwards to T's constructor.
///
/// This allows passing `Constructor<T>()` as a callable argument for applying
/// the T constructor without hand-writing a lambda.
template <typename T>
struct Constructor {
template <typename... Values>
T operator()(Values&&... values) {
return T(std::forward<Values>(values)...);
}
};

} // namespace internal
} // namespace arrow
20 changes: 20 additions & 0 deletions cpp/src/arrow/util/stl_util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "arrow/result.h"
#include "arrow/testing/gtest_util.h"
#include "arrow/util/functional.h"
#include "arrow/util/sort.h"
#include "arrow/util/string.h"
#include "arrow/util/vector.h"
Expand Down Expand Up @@ -92,5 +95,22 @@ TEST(StlUtilTest, ArgSortPermute) {
ExpectSortPermutation({b, c, d, e, a, f}, {4, 0, 1, 2, 3, 5}, 2);
}

TEST(StlUtilTest, MapEmplaceBack) {
auto all_good = EmplacedMappedVector<Result<MoveOnlyDataType>>(
Constructor<MoveOnlyDataType>(), 1, 2, 3);

ASSERT_EQ(all_good[0].ValueUnsafe(), 1);
ASSERT_EQ(all_good[1].ValueUnsafe(), 2);
ASSERT_EQ(all_good[2].ValueUnsafe(), 3);
ASSERT_EQ(all_good.size(), 3);

auto some_bad = EmplacedVector<Result<MoveOnlyDataType>>(
MoveOnlyDataType(1), Status::Invalid("XYZ"), Status::IOError("XYZ"));

ASSERT_EQ(some_bad[0].ValueUnsafe(), 1);
ASSERT_TRUE(some_bad[1].status().IsInvalid());
ASSERT_TRUE(some_bad[2].status().IsIOError());
}

} // namespace internal
} // namespace arrow
38 changes: 38 additions & 0 deletions cpp/src/arrow/util/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,43 @@ std::vector<T> FilterVector(std::vector<T> values, Predicate&& predicate) {
return values;
}

template <typename T, typename Fn>
void MapEmplaceBack(std::vector<T>* out, Fn&& fn) {}

template <typename T, typename Fn, typename Head, typename... Values>
void MapEmplaceBack(std::vector<T>* out, Fn&& fn, Head&& value, Values&&... tail_values) {
out->emplace_back(fn(std::forward<Head>(value)));
MapEmplaceBack(out, std::forward<Fn>(fn), std::forward<Values>(tail_values)...);
}

template <typename T>
void EmplaceBack(std::vector<T>* out) {}

template <typename T, typename Head, typename... Values>
void EmplaceBack(std::vector<T>* out, Head&& value, Values&&... tail_values) {
out->emplace_back(std::forward<Head>(value));
EmplaceBack(out, std::forward<Values>(tail_values)...);
}

// Construct a vector by emplacing with each of the provided values.
// Note this is less flexible than manual calls to emplace_back(), since
// only 1-argument constructors can be invoked.
template <typename T, typename... Values>
std::vector<T> EmplacedVector(Values&&... values) {
std::vector<T> result;
result.reserve(sizeof...(values));
EmplaceBack(&result, std::forward<Values>(values)...);
return result;
}

// Like EmplacedVector, but emplace the result of calling `Fn` on the `values`.
template <typename T, typename Fn, typename... Values>
std::vector<T> EmplacedMappedVector(Fn&& fn, Values&&... values) {
std::vector<T> result;
result.reserve(sizeof...(values));
MapEmplaceBack(&result, std::forward<Fn>(fn), std::forward<Values>(values)...);
return result;
}

} // namespace internal
} // namespace arrow