add Range constructors from std::array
authorAdam Simpkins <simpkins@fb.com>
Sat, 11 Feb 2017 01:11:44 +0000 (17:11 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 11 Feb 2017 01:20:48 +0000 (17:20 -0800)
Summary:
Add explicit constructors to create Range objects referring to the contents of
a std::array.

D4165608 previously added a folly::range() factory function to create Ranges
around const arrays.  However, it did not support non-const arrays.  However,
providing this as a constructor seems better.  This new constructor does not
appear ambiguous with any existing constructors, and a constructor allows for
more natural support of non-const arrays: the caller can explicitly indicate
if they want to construct a Range to const or non-const data in this case.

Reviewed By: yfeldblum

Differential Revision: D4523515

fbshipit-source-id: c1a262f9e8f76907d87d80b03f252576506e70ab

folly/Range.h
folly/test/RangeTest.cpp

index d205a7b3d654c8b839f6346ae740899ad997ac16..bfbb4eb0f609c0547da193f3f0875a36f36219cd 100644 (file)
 #include <folly/portability/Constexpr.h>
 #include <folly/portability/String.h>
 
-#include <algorithm>
 #include <boost/operators.hpp>
+#include <glog/logging.h>
+#include <algorithm>
+#include <array>
 #include <climits>
 #include <cstddef>
 #include <cstring>
-#include <glog/logging.h>
 #include <iosfwd>
 #include <stdexcept>
 #include <string>
@@ -332,6 +333,30 @@ public:
       e_(other.end()) {
   }
 
+  /**
+   * Allow explicit construction of Range() from a std::array of a
+   * convertible type.
+   *
+   * For instance, this allows constructing StringPiece from a
+   * std::array<char, N> or a std::array<const char, N>
+   */
+  template <
+      class T,
+      size_t N,
+      typename = typename std::enable_if<
+          std::is_convertible<const T*, Iter>::value>::type>
+  constexpr explicit Range(const std::array<T, N>& array)
+      : b_{array.empty() ? nullptr : &array.at(0)},
+        e_{array.empty() ? nullptr : &array.at(0) + N} {}
+  template <
+      class T,
+      size_t N,
+      typename =
+          typename std::enable_if<std::is_convertible<T*, Iter>::value>::type>
+  constexpr explicit Range(std::array<T, N>& array)
+      : b_{array.empty() ? nullptr : &array.at(0)},
+        e_{array.empty() ? nullptr : &array.at(0) + N} {}
+
   Range& operator=(const Range& rhs) & = default;
   Range& operator=(Range&& rhs) & = default;
 
@@ -907,8 +932,7 @@ constexpr Range<T*> range(T (&array)[n]) {
 
 template <class T, size_t n>
 constexpr Range<const T*> range(const std::array<T, n>& array) {
-  using r = Range<const T*>;
-  return array.empty() ? r{} : r(&array.at(0), &array.at(0) + n);
+  return Range<const T*>{array};
 }
 
 typedef Range<const char*> StringPiece;
index a7d61f4a3c73c69f4a777e1011133154c2796faf..d4f658653fb340c2dc0b91e4a94e10ab693917bb 100644 (file)
@@ -1298,6 +1298,40 @@ TEST(Range, Constructors) {
   EXPECT_EQ(subpiece1.end(), subpiece2.end());
 }
 
+TEST(Range, ArrayConstructors) {
+  auto charArray = std::array<char, 4>{{'t', 'e', 's', 't'}};
+  auto constCharArray = std::array<char, 6>{{'f', 'o', 'o', 'b', 'a', 'r'}};
+  auto emptyArray = std::array<char, 0>{};
+
+  auto sp1 = StringPiece{charArray};
+  EXPECT_EQ(4, sp1.size());
+  EXPECT_EQ(charArray.data(), sp1.data());
+
+  auto sp2 = StringPiece(constCharArray);
+  EXPECT_EQ(6, sp2.size());
+  EXPECT_EQ(constCharArray.data(), sp2.data());
+
+  auto msp = MutableStringPiece(charArray);
+  EXPECT_EQ(4, msp.size());
+  EXPECT_EQ(charArray.data(), msp.data());
+
+  auto esp = StringPiece(emptyArray);
+  EXPECT_EQ(0, esp.size());
+  EXPECT_EQ(nullptr, esp.data());
+
+  auto emsp = MutableStringPiece(emptyArray);
+  EXPECT_EQ(0, emsp.size());
+  EXPECT_EQ(nullptr, emsp.data());
+
+  static constexpr std::array<int, 4> numArray = {{3, 17, 1, 9}};
+  constexpr auto numRange = Range<const int*>{numArray};
+  EXPECT_EQ(17, numRange[1]);
+
+  static constexpr std::array<int, 0> emptyNumArray{};
+  constexpr auto emptyNumRange = Range<const int*>{emptyNumArray};
+  EXPECT_EQ(0, emptyNumRange.size());
+}
+
 TEST(Range, ConstexprAccessors) {
   constexpr StringPiece piece = range("hello");
   static_assert(piece.size() == 6u, "");