TupleOps.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright 2015-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <limits>
  18. #include <tuple>
  19. #include <type_traits>
  20. // tupleRange<start, n>(tuple): select n elements starting at index start
  21. // in the given tuple
  22. // tupleRange<start>(tuple): select all elements starting at index start
  23. // until the end of the given tuple
  24. // tuplePrepend(x, tuple): return a tuple obtained by prepending x to the
  25. // given tuple.
  26. //
  27. // In Lisp lingo, std::get<0> is car, tupleRange<1> is cdr, and tuplePrepend
  28. // is cons.
  29. namespace folly {
  30. // TemplateSeq<T, ...> is a type parametrized by sizeof...(Xs) values of type
  31. // T. Used to destructure the values into a template parameter pack;
  32. // see the example in TupleSelect, below.
  33. template <class T, T... xs>
  34. struct TemplateSeq {
  35. template <T x>
  36. using Prepend = TemplateSeq<T, x, xs...>;
  37. };
  38. // TemplateRange<T, start, n>::type is
  39. // TemplateSeq<T, start+1, start+2, ..., start+n-1>
  40. template <class T, T start, T n, class Enable = void>
  41. struct TemplateRange;
  42. template <class T, T start, T n>
  43. struct TemplateRange<T, start, n, typename std::enable_if<(n > 0)>::type> {
  44. using type =
  45. typename TemplateRange<T, start + 1, n - 1>::type::template Prepend<
  46. start>;
  47. };
  48. template <class T, T start, T n>
  49. struct TemplateRange<T, start, n, typename std::enable_if<(n <= 0)>::type> {
  50. using type = TemplateSeq<T>;
  51. };
  52. // Similar to TemplateRange, given a tuple T,
  53. // TemplateTupleRange<T, start, n>::type is
  54. // TemplateSeq<size_t, start, start+1, ..., start+k-1>
  55. // where k = min(tuple_size<T>::value - start, n)
  56. // (that is, it's a TemplateSeq of at most n elements, but won't extend
  57. // past the end of the given tuple)
  58. template <
  59. class T,
  60. std::size_t start = 0,
  61. std::size_t n = std::numeric_limits<std::size_t>::max(),
  62. std::size_t size =
  63. std::tuple_size<typename std::remove_reference<T>::type>::value,
  64. class Enable = typename std::enable_if<(start <= size)>::type>
  65. struct TemplateTupleRange {
  66. using type = typename TemplateRange<
  67. std::size_t,
  68. start,
  69. (n <= size - start ? n : size - start)>::type;
  70. };
  71. namespace detail {
  72. // Helper class to select a subset of a tuple
  73. template <class S>
  74. struct TupleSelect;
  75. template <std::size_t... Ns>
  76. struct TupleSelect<TemplateSeq<std::size_t, Ns...>> {
  77. template <class T>
  78. static auto select(T&& v)
  79. -> decltype(std::make_tuple(std::get<Ns>(std::forward<T>(v))...)) {
  80. return std::make_tuple(std::get<Ns>(std::forward<T>(v))...);
  81. }
  82. };
  83. } // namespace detail
  84. // Return a tuple consisting of the elements at a range of indices.
  85. //
  86. // Use as tupleRange<start, n>(t) to return a tuple of (at most) n
  87. // elements starting at index start in tuple t.
  88. // If only start is specified (tupleRange<start>(t)), returns all elements
  89. // starting at index start until the end of the tuple t.
  90. // Won't compile if start > size of t.
  91. // Will return fewer elements (size - start) if start + n > size of t.
  92. template <
  93. std::size_t start = 0,
  94. std::size_t n = std::numeric_limits<std::size_t>::max(),
  95. class T,
  96. class Seq = typename TemplateTupleRange<T, start, n>::type>
  97. auto tupleRange(T&& v)
  98. -> decltype(detail::TupleSelect<Seq>::select(std::forward<T>(v))) {
  99. return detail::TupleSelect<Seq>::select(std::forward<T>(v));
  100. }
  101. // Return a tuple obtained by prepending car to the tuple cdr.
  102. template <class T, class U>
  103. auto tuplePrepend(T&& car, U&& cdr) -> decltype(std::tuple_cat(
  104. std::make_tuple(std::forward<T>(car)),
  105. std::forward<U>(cdr))) {
  106. return std::tuple_cat(
  107. std::make_tuple(std::forward<T>(car)), std::forward<U>(cdr));
  108. }
  109. } // namespace folly