Skip to content

Commit

Permalink
folly/Concepts.h
Browse files Browse the repository at this point in the history
Summary:
We have a need for some common concepts that are used in many places.

This is a proposal, please let me know what you think.

Differential Revision: D59396081
  • Loading branch information
DenisYaroshevskiy authored and facebook-github-bot committed Jul 5, 2024
1 parent 19e4d49 commit 738e046
Show file tree
Hide file tree
Showing 4 changed files with 419 additions and 0 deletions.
5 changes: 5 additions & 0 deletions folly/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ cpp_library(
],
)

cpp_library(
name = "concepts",
headers = ["Concepts.h"],
)

cpp_library(
name = "concurrent_lazy",
headers = ["ConcurrentLazy.h"],
Expand Down
150 changes: 150 additions & 0 deletions folly/Concepts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <concepts>
#include <iterator>
#include <ranges>

namespace folly {

/*
* Concept to restrict perfect forwarding to a specific type.
*
* Example:
* void foo(folly::forwarded<std::vector<int>> auto&& vec);
*
*/
template <typename Fwd, typename To>
concept forwarded = std::same_as<std::remove_cvref_t<Fwd>, To>;

/*
* T is one of the specified types
*
* NOTE: doesn't have subsumption with `std::same_as`
*/
template <typename T, typename... Ts>
concept one_of =
(std::is_same_v<T, Ts> || // using is_same_v because it's is faster to
// compile and doesn't change behaviour
...);

/*
* T implicitly converts to one of the specified types
*
* NOTE: doesn't have subsumption with `one_of`
*/
template <typename From, typename... To>
concept convertible_to_one_of = (std::is_convertible_v<From, To> || ...);

// iterator_of -----------------------------------------------
// iterator for range of exacly one of the listed types

template <typename I, typename... Ts>
concept input_iterator_of =
std::input_iterator<I> && one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept forward_iterator_of =
std::forward_iterator<I> && one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept bidirectional_iterator_of =
std::bidirectional_iterator<I> && one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept random_access_iterator_of =
std::random_access_iterator<I> && one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept contiguous_iterator_of =
std::contiguous_iterator<I> && one_of<std::iter_value_t<I>, Ts...>;

// iterator_of_convertible_to -----------------------------------------------
// iterator for range of smth convertible to one of the listed types

template <typename I, typename... Ts>
concept input_iterator_of_convertible_to = std::input_iterator<I> &&
convertible_to_one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept forward_iterator_of_convertible_to = std::forward_iterator<I> &&
convertible_to_one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept bidirectional_iterator_of_convertible_to =
std::bidirectional_iterator<I> &&
convertible_to_one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept random_access_iterator_of_convertible_to =
std::random_access_iterator<I> &&
convertible_to_one_of<std::iter_value_t<I>, Ts...>;

template <typename I, typename... Ts>
concept contiguous_iterator_of_convertible_to = std::contiguous_iterator<I> &&
convertible_to_one_of<std::iter_value_t<I>, Ts...>;

// range_of -----------------------------------------------
// range of one of the specified types

template <typename R, typename... Ts>
concept input_range_of =
std::ranges::input_range<R> && one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept forward_range_of = std::ranges::forward_range<R> &&
one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept bidirectional_range_of = std::ranges::bidirectional_range<R> &&
one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept random_access_range_of = std::ranges::random_access_range<R> &&
one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept contiguous_range_of = std::ranges::contiguous_range<R> &&
one_of<std::ranges::range_value_t<R>, Ts...>;

// range_of_convertible_to -----------------------------------------------
// range of one of the specified types

template <typename R, typename... Ts>
concept input_range_of_convertible_to = std::ranges::input_range<R> &&
convertible_to_one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept forward_range_of_convertible_to = std::ranges::forward_range<R> &&
convertible_to_one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept bidirectional_range_of_convertible_to =
std::ranges::bidirectional_range<R> &&
convertible_to_one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept random_access_range_of_convertible_to =
std::ranges::random_access_range<R> &&
convertible_to_one_of<std::ranges::range_value_t<R>, Ts...>;

template <typename R, typename... Ts>
concept contiguous_range_of_convertible_to = std::ranges::contiguous_range<R> &&
convertible_to_one_of<std::ranges::range_value_t<R>, Ts...>;

} // namespace folly
10 changes: 10 additions & 0 deletions folly/test/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,16 @@ cpp_unittest(
],
)

cpp_unittest(
name = "concepts_test",
srcs = ["ConceptsTest.cpp"],
headers = [],
deps = [
"//folly:concepts",
"//folly/portability:gtest",
],
)

cpp_benchmark(
name = "concurrent_skip_list_benchmark",
srcs = ["ConcurrentSkipListBenchmark.cpp"],
Expand Down
Loading

0 comments on commit 738e046

Please sign in to comment.