cmake: build as many source files as possible
[folly.git] / folly / Range.h
index 3bfef1f27d48d638a0f8c2922d3dd4d6667f774e..c4e8b27de1f95e53001a90ae70493cafe1d9c33a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2011-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
 
 #pragma once
 
-#include <folly/FBString.h>
 #include <folly/Portability.h>
 #include <folly/hash/SpookyHashV2.h>
 #include <folly/portability/BitsFunctexcept.h>
@@ -30,6 +29,7 @@
 #include <glog/logging.h>
 #include <algorithm>
 #include <array>
+#include <cassert>
 #include <climits>
 #include <cstddef>
 #include <cstring>
 #include <string>
 #include <type_traits>
 
-// libc++ doesn't provide this header, nor does msvc
-#ifdef FOLLY_HAVE_BITS_CXXCONFIG_H
-// This file appears in two locations: inside fbcode and in the
-// libstdc++ source code (when embedding fbstring as std::string).
-// To aid in this schizophrenic use, two macros are defined in
-// c++config.h:
-//   _LIBSTDCXX_FBSTRING - Set inside libstdc++.  This is useful to
-//      gate use inside fbcode v. libstdc++
-#include <bits/c++config.h>
-#endif
-
 #include <folly/CpuId.h>
 #include <folly/Likely.h>
 #include <folly/Traits.h>
@@ -61,6 +50,15 @@ FOLLY_GCC_DISABLE_WARNING("-Wshadow")
 
 namespace folly {
 
+/**
+ * Ubiquitous helper template for knowing what's a string.
+ */
+template <class T>
+struct IsSomeString : std::false_type {};
+
+template <>
+struct IsSomeString<std::string> : std::true_type {};
+
 template <class Iter>
 class Range;
 
@@ -212,9 +210,12 @@ class Range : private boost::totally_ordered<Range<Iter>> {
   /* implicit */ Range(std::nullptr_t) = delete;
 #endif
 
-  template <class T = Iter, typename detail::IsCharPointer<T>::type = 0>
   constexpr /* implicit */ Range(Iter str)
-      : b_(str), e_(str + constexpr_strlen(str)) {}
+      : b_(str), e_(str + constexpr_strlen(str)) {
+    static_assert(
+        std::is_same<int, typename detail::IsCharPointer<Iter>::type>::value,
+        "This constructor is only available for character ranges");
+  }
 
   template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   /* implicit */ Range(const std::string& str)
@@ -248,30 +249,58 @@ class Range : private boost::totally_ordered<Range<Iter>> {
   Range(const Range& other, size_type first, size_type length = npos)
       : Range(other.subpiece(first, length)) {}
 
-  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
-  /* implicit */ Range(const fbstring& str)
-      : b_(str.data()), e_(b_ + str.size()) {}
+  template <
+      class Container,
+      class = typename std::enable_if<
+          std::is_same<Iter, typename Container::const_pointer>::value>::type,
+      class = decltype(
+          Iter(std::declval<Container const&>().data()),
+          Iter(
+              std::declval<Container const&>().data() +
+              std::declval<Container const&>().size()))>
+  /* implicit */ constexpr Range(Container const& container)
+      : b_(container.data()), e_(b_ + container.size()) {}
 
-  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
-  Range(const fbstring& str, fbstring::size_type startFrom) {
-    if (UNLIKELY(startFrom > str.size())) {
+  template <
+      class Container,
+      class = typename std::enable_if<
+          std::is_same<Iter, typename Container::const_pointer>::value>::type,
+      class = decltype(
+          Iter(std::declval<Container const&>().data()),
+          Iter(
+              std::declval<Container const&>().data() +
+              std::declval<Container const&>().size()))>
+  Range(Container const& container, typename Container::size_type startFrom) {
+    auto const cdata = container.data();
+    auto const csize = container.size();
+    if (UNLIKELY(startFrom > csize)) {
       std::__throw_out_of_range("index out of range");
     }
-    b_ = str.data() + startFrom;
-    e_ = str.data() + str.size();
+    b_ = cdata + startFrom;
+    e_ = cdata + csize;
   }
 
-  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
+  template <
+      class Container,
+      class = typename std::enable_if<
+          std::is_same<Iter, typename Container::const_pointer>::value>::type,
+      class = decltype(
+          Iter(std::declval<Container const&>().data()),
+          Iter(
+              std::declval<Container const&>().data() +
+              std::declval<Container const&>().size()))>
   Range(
-      const fbstring& str,
-      fbstring::size_type startFrom,
-      fbstring::size_type size) {
-    if (UNLIKELY(startFrom > str.size())) {
+      Container const& container,
+      typename Container::size_type startFrom,
+      typename Container::size_type size) {
+    auto const cdata = container.data();
+    auto const csize = container.size();
+    if (UNLIKELY(startFrom > csize)) {
       std::__throw_out_of_range("index out of range");
     }
-    b_ = str.data() + startFrom;
-    if (str.size() - startFrom < size) {
-      e_ = str.data() + str.size();
+    b_ = cdata + startFrom;
+    if (csize - startFrom < size) {
+      e_ = cdata + csize;
     } else {
       e_ = b_ + size;
     }
@@ -445,19 +474,18 @@ class Range : private boost::totally_ordered<Range<Iter>> {
     assert(b_ < e_);
     return detail::value_before(e_);
   }
+
+  template <typename Tgt>
+  auto to() const
+      -> decltype(Tgt(std::declval<Iter const&>(), std::declval<size_type>())) {
+    return Tgt(b_, size());
+  }
   // Works only for Range<const char*> and Range<char*>
   std::string str() const {
-    return std::string(b_, size());
+    return to<std::string>();
   }
   std::string toString() const {
-    return str();
-  }
-  // Works only for Range<const char*> and Range<char*>
-  fbstring fbstr() const {
-    return fbstring(b_, size());
-  }
-  fbstring toFbstring() const {
-    return fbstr();
+    return to<std::string>();
   }
 
   const_range_type castToConst() const {
@@ -984,22 +1012,43 @@ constexpr Range<Iter> range(Iter first, Iter last) {
  * Creates a range to reference the contents of a contiguous-storage container.
  */
 // Use pointers for types with '.data()' member
-template <
-    class Collection,
-    class T = typename std::remove_pointer<
-        decltype(std::declval<Collection>().data())>::type>
-constexpr Range<T*> range(Collection&& v) {
-  return Range<T*>(v.data(), v.data() + v.size());
+template <class Collection>
+constexpr auto range(Collection& v) -> Range<decltype(v.data())> {
+  return Range<decltype(v.data())>(v.data(), v.data() + v.size());
+}
+template <class Collection>
+constexpr auto range(Collection const& v) -> Range<decltype(v.data())> {
+  return Range<decltype(v.data())>(v.data(), v.data() + v.size());
+}
+template <class Collection>
+constexpr auto crange(Collection const& v) -> Range<decltype(v.data())> {
+  return Range<decltype(v.data())>(v.data(), v.data() + v.size());
 }
 
 template <class T, size_t n>
 constexpr Range<T*> range(T (&array)[n]) {
   return Range<T*>(array, array + n);
 }
+template <class T, size_t n>
+constexpr Range<T const*> range(T const (&array)[n]) {
+  return Range<T const*>(array, array + n);
+}
+template <class T, size_t n>
+constexpr Range<T const*> crange(T const (&array)[n]) {
+  return Range<T const*>(array, array + n);
+}
 
 template <class T, size_t n>
-constexpr Range<const T*> range(const std::array<T, n>& array) {
-  return Range<const T*>{array};
+constexpr Range<T*> range(std::array<T, n>& array) {
+  return Range<T*>{array};
+}
+template <class T, size_t n>
+constexpr Range<T const*> range(std::array<T, n> const& array) {
+  return Range<T const*>{array};
+}
+template <class T, size_t n>
+constexpr Range<T const*> crange(std::array<T, n> const& array) {
+  return Range<T const*>{array};
 }
 
 typedef Range<const char*> StringPiece;
@@ -1312,15 +1361,38 @@ struct hasher<
 };
 
 /**
- * Ubiquitous helper template for knowing what's a string
+ * _sp is a user-defined literal suffix to make an appropriate Range
+ * specialization from a literal string.
+ *
+ * Modeled after C++17's `sv` suffix.
  */
-template <class T>
-struct IsSomeString {
-  enum {
-    value =
-        std::is_same<T, std::string>::value || std::is_same<T, fbstring>::value
-  };
-};
+inline namespace literals {
+inline namespace string_piece_literals {
+constexpr Range<char const*> operator"" _sp(
+    char const* str,
+    size_t len) noexcept {
+  return Range<char const*>(str, len);
+}
+
+constexpr Range<char16_t const*> operator"" _sp(
+    char16_t const* str,
+    size_t len) noexcept {
+  return Range<char16_t const*>(str, len);
+}
+
+constexpr Range<char32_t const*> operator"" _sp(
+    char32_t const* str,
+    size_t len) noexcept {
+  return Range<char32_t const*>(str, len);
+}
+
+constexpr Range<wchar_t const*> operator"" _sp(
+    wchar_t const* str,
+    size_t len) noexcept {
+  return Range<wchar_t const*>(str, len);
+}
+} // namespace string_piece_literals
+} // namespace literals
 
 } // namespace folly