Skip to content

Commit

Permalink
Helpers for deduction guides implementation
Browse files Browse the repository at this point in the history
Summary: Put helpers in folly/container/Iterator.h to encourage code reuse.

Reviewed By: yfeldblum

Differential Revision: D45865401

fbshipit-source-id: 985f0fa1c777c99e016e64d2ddf5dcff4a21c7ba
  • Loading branch information
ilvokhin authored and facebook-github-bot committed Jun 19, 2023
1 parent c702ade commit 331180d
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
52 changes: 52 additions & 0 deletions folly/container/Iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <type_traits>
#include <utility>

#include <folly/Traits.h>
#include <folly/Utility.h>
#include <folly/container/Access.h>
#include <folly/lang/RValueReferenceWrapper.h>
Expand Down Expand Up @@ -72,6 +73,57 @@ FOLLY_INLINE_VARIABLE constexpr bool range_has_known_distance_v =
invoke_result_t<access::begin_fn, Range>,
invoke_result_t<access::end_fn, Range>>;

// iterator_category_t
//
// Extracts iterator_category from an iterator.
template <typename Iter>
using iterator_category_t =
typename std::iterator_traits<Iter>::iterator_category;

namespace detail {

template <typename Iter, typename Category, typename = void>
FOLLY_INLINE_VARIABLE constexpr bool iterator_category_matches_v_ = false;
template <typename Iter, typename Category>
FOLLY_INLINE_VARIABLE constexpr bool iterator_category_matches_v_<
Iter,
Category,
void_t<iterator_category_t<Iter>>> =
std::is_convertible<iterator_category_t<Iter>, Category>::value;

} // namespace detail

// iterator_category_matches_v
//
// Whether an iterator's category matches Category (std::input_iterator_tag,
// std::output_iterator_tag, etc). Defined for non-iterator types as well.
//
// Useful for containers deduction guides implementation.
template <typename Iter, typename Category>
FOLLY_INLINE_VARIABLE constexpr bool iterator_category_matches_v =
detail::iterator_category_matches_v_<Iter, Category>;

// iterator_value_type_t
//
// Extracts a value type from an iterator.
template <typename Iter>
using iterator_value_type_t = typename std::iterator_traits<Iter>::value_type;

// iterator_key_type_t
//
// Extracts a key type from an iterator, leverages the knowledge that
// key/value containers usually use std::pair<const K, V> as a value_type.
template <typename Iter>
using iterator_key_type_t =
remove_cvref_t<typename iterator_value_type_t<Iter>::first_type>;

// iterator_mapped_type_t
//
// Extracts a mapped type from an iterator.
template <typename Iter>
using iterator_mapped_type_t =
typename iterator_value_type_t<Iter>::second_type;

/**
* Argument tuple for variadic emplace/constructor calls. Stores arguments by
* (decayed) value. Restores original argument types with reference qualifiers
Expand Down
81 changes: 81 additions & 0 deletions folly/container/test/IteratorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <cstddef>
#include <deque>
#include <functional>
#include <iterator>
#include <list>
#include <map>
#include <set>
Expand All @@ -43,6 +44,86 @@ TEST_F(IteratorTest, range_has_known_distance_v) {
EXPECT_TRUE(folly::range_has_known_distance_v<std::vector<int>&>);
}

TEST_F(IteratorTest, iterator_category_t) {
EXPECT_TRUE(( //
std::is_same_v<
folly::iterator_category_t<
std::iterator<std::input_iterator_tag, int>>,
std::input_iterator_tag>));
EXPECT_FALSE(( //
std::is_same_v<
folly::iterator_category_t<
std::iterator<std::input_iterator_tag, int>>,
std::output_iterator_tag>));
}

TEST_F(IteratorTest, iterator_category_matches_v) {
EXPECT_TRUE(( //
folly::iterator_category_matches_v<
std::iterator<std::input_iterator_tag, int>,
std::input_iterator_tag>));
EXPECT_FALSE(( //
folly::iterator_category_matches_v<
std::iterator<std::input_iterator_tag, int>,
std::output_iterator_tag>));
EXPECT_FALSE(( //
folly::iterator_category_matches_v<int, std::input_iterator_tag>));
}

TEST_F(IteratorTest, iterator_value_type_t) {
EXPECT_TRUE(( //
std::is_same_v<
std::map<int, double>::value_type,
folly::iterator_value_type_t<std::map<int, double>::iterator>>));
EXPECT_TRUE(( //
std::is_same_v<
std::map<std::reference_wrapper<int>, double&>::value_type,
folly::iterator_value_type_t<
std::map<std::reference_wrapper<int>, double&>::iterator>>));
EXPECT_FALSE(( //
std::is_same_v<
std::map<int, float>::value_type,
folly::iterator_value_type_t<std::map<int, double>::iterator>>));
}

TEST_F(IteratorTest, iterator_key_type_t) {
EXPECT_TRUE(( //
std::is_same_v<
std::map<int, double>::key_type,
folly::iterator_key_type_t<std::map<int, double>::iterator>>));
EXPECT_TRUE(( //
std::is_same_v<
std::map<std::reference_wrapper<int>, double&>::key_type,
folly::iterator_key_type_t<
std::map<std::reference_wrapper<int>, double&>::iterator>>));
EXPECT_TRUE(( //
std::is_same_v<
int,
folly::iterator_key_type_t<std::iterator<
std::input_iterator_tag,
std::pair<const int&, double>>>>));
EXPECT_FALSE(( //
std::is_same_v<
std::map<char, double>::key_type,
folly::iterator_key_type_t<std::map<int, double>::iterator>>));
}

TEST_F(IteratorTest, iterator_mapped_type_t) {
EXPECT_TRUE(( //
std::is_same_v<
std::map<int, double>::mapped_type,
folly::iterator_mapped_type_t<std::map<int, double>::iterator>>));
EXPECT_TRUE(( //
std::is_same_v<
std::map<std::reference_wrapper<int>, double&>::mapped_type,
folly::iterator_mapped_type_t<
std::map<std::reference_wrapper<int>, double&>::iterator>>));
EXPECT_FALSE(( //
std::is_same_v<
std::map<int, float>::mapped_type,
folly::iterator_mapped_type_t<std::map<int, double>::iterator>>));
}

namespace {
/**
* Container type used for unit tests.
Expand Down

0 comments on commit 331180d

Please sign in to comment.