fbstring::shrink_to_fit
authorAndrei Alexandrescu <aalexandre@fb.com>
Fri, 28 Jun 2013 01:40:35 +0000 (18:40 -0700)
committerSara Golemon <sgolemon@fb.com>
Thu, 18 Jul 2013 18:55:35 +0000 (11:55 -0700)
Summary: Adds the eponymous C++11 capability to fbstring.

Test Plan: fbstring runtests

Reviewed By: tudorb@fb.com

FB internal diff: D867995

folly/FBString.h
folly/test/FBStringTest.cpp

index a410a186187c8f23909dfccb9e7dba4443a5b505..04b90a7c364ffc11a5d4106a5edbb84d579d4291 100644 (file)
@@ -985,7 +985,7 @@ private:
   }
 
 public:
-  // 21.3.1 construct/copy/destroy
+  // C++11 21.4.2 construct/copy/destroy
   explicit basic_fbstring(const A& a = A()) {
   }
 
@@ -1047,6 +1047,11 @@ public:
       : store_(s, n, c, a) {
   }
 
+  // Construction from initialization list
+  basic_fbstring(std::initializer_list<value_type> il) {
+    assign(il.begin(), il.end());
+  }
+
   ~basic_fbstring() {
   }
 
@@ -1076,7 +1081,7 @@ public:
   basic_fbstring& operator=(basic_fbstring&& goner) {
     if (FBSTRING_UNLIKELY(&goner == this)) {
       // Compatibility with std::basic_string<>,
-      // 21.4.2 [string.cons] / 23 requires self-move-assignment support.
+      // C++11 21.4.2 [string.cons] / 23 requires self-move-assignment support.
       return *this;
     }
     // No need of this anymore
@@ -1121,11 +1126,17 @@ public:
     return *this;
   }
 
-  // 21.3.2 iterators:
+  basic_fbstring& operator=(std::initializer_list<value_type> il) {
+    return assign(il.begin(), il.end());
+  }
+
+  // C++11 21.4.3 iterators:
   iterator begin() { return store_.mutable_data(); }
 
   const_iterator begin() const { return store_.data(); }
 
+  const_iterator cbegin() const { return begin(); }
+
   iterator end() {
     return store_.mutable_data() + store_.size();
   }
@@ -1134,6 +1145,8 @@ public:
     return store_.data() + store_.size();
   }
 
+  const_iterator cend() const { return end(); }
+
   reverse_iterator rbegin() {
     return reverse_iterator(end());
   }
@@ -1142,6 +1155,8 @@ public:
     return const_reverse_iterator(end());
   }
 
+  const_reverse_iterator crbegin() const { return rbegin(); }
+
   reverse_iterator rend() {
     return reverse_iterator(begin());
   }
@@ -1150,6 +1165,8 @@ public:
     return const_reverse_iterator(begin());
   }
 
+  const_reverse_iterator crend() const { return rend(); }
+
   // Added by C++11
   // C++11 21.4.5, element access:
   const value_type& front() const { return *begin(); }
@@ -1169,7 +1186,7 @@ public:
     store_.shrink(1);
   }
 
-  // 21.3.3 capacity:
+  // C++11 21.4.4 capacity:
   size_type size() const { return store_.size(); }
 
   size_type length() const { return size(); }
@@ -1213,11 +1230,19 @@ public:
     store_.reserve(res_arg);
   }
 
+  void shrink_to_fit() {
+    // Shrink only if slack memory is sufficiently large
+    if (capacity() < size() * 3 / 2) {
+      return;
+    }
+    basic_fbstring(cbegin(), cend()).swap(*this);
+  }
+
   void clear() { resize(0); }
 
   bool empty() const { return size() == 0; }
 
-  // 21.3.4 element access:
+  // C++11 21.4.5 element access:
   const_reference operator[](size_type pos) const {
     return *(c_str() + pos);
   }
@@ -1240,7 +1265,7 @@ public:
     return (*this)[n];
   }
 
-  // 21.3.5 modifiers:
+  // C++11 21.4.6 modifiers:
   basic_fbstring& operator+=(const basic_fbstring& str) {
     return append(str);
   }
@@ -1254,6 +1279,11 @@ public:
     return *this;
   }
 
+  basic_fbstring& operator+=(std::initializer_list<value_type> il) {
+    append(il);
+    return *this;
+  }
+
   basic_fbstring& append(const basic_fbstring& str) {
 #ifndef NDEBUG
     auto desiredSize = size() + str.size();
@@ -1323,6 +1353,10 @@ public:
     return *this;
   }
 
+  basic_fbstring& append(std::initializer_list<value_type> il) {
+    return append(il.begin(), il.end());
+  }
+
   void push_back(const value_type c) {             // primitive
     store_.push_back(c);
   }
@@ -1332,6 +1366,10 @@ public:
     return assign(str.data(), str.size());
   }
 
+  basic_fbstring& assign(basic_fbstring&& str) {
+    return *this = std::move(str);
+  }
+
   basic_fbstring& assign(const basic_fbstring& str, const size_type pos,
                          size_type n) {
     const size_type sz = str.size();
@@ -1362,6 +1400,10 @@ public:
     return assign(s, traits_type::length(s));
   }
 
+  basic_fbstring& assign(std::initializer_list<value_type> il) {
+    return assign(il.begin(), il.end());
+  }
+
   template <class ItOrLength, class ItOrChar>
   basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) {
     return replace(begin(), end(), first_or_n, last_or_c);
@@ -1394,7 +1436,7 @@ public:
     return *this;
   }
 
-  iterator insert(const iterator p, const value_type c) {
+  iterator insert(const_iterator p, const value_type c) {
     const size_type pos = p - begin();
     insert(p, 1, c);
     return begin() + pos;
@@ -1403,10 +1445,11 @@ public:
 private:
   template <int i> class Selector {};
 
-  basic_fbstring& insertImplDiscr(iterator p,
-                                  size_type n, value_type c, Selector<1>) {
+  iterator insertImplDiscr(const_iterator p,
+                           size_type n, value_type c, Selector<1>) {
     Invariant checker(*this);
     (void) checker;
+    auto const pos = p - begin();
     assert(p >= begin() && p <= end());
     if (capacity() - size() < n) {
       const size_type sz = p - begin();
@@ -1414,33 +1457,33 @@ private:
       p = begin() + sz;
     }
     const iterator oldEnd = end();
-    ifn < size_type(oldEnd - p)) {
+    if (n < size_type(oldEnd - p)) {
       append(oldEnd - n, oldEnd);
       //std::copy(
       //    reverse_iterator(oldEnd - n),
       //    reverse_iterator(p),
       //    reverse_iterator(oldEnd));
-      fbstring_detail::pod_move(&*p, &*oldEnd - n, &*p + n);
-      std::fill(p, p + n, c);
+      fbstring_detail::pod_move(&*p, &*oldEnd - n,
+                                begin() + pos + n);
+      std::fill(begin() + pos, begin() + pos + n, c);
     } else {
       append(n - (end() - p), c);
-      append(p, oldEnd);
-      std::fill(p, oldEnd, c);
+      append(iterator(p), oldEnd);
+      std::fill(iterator(p), oldEnd, c);
     }
     store_.writeTerminator();
-    return *this;
+    return begin() + pos;
   }
 
   template<class InputIter>
-  basic_fbstring& insertImplDiscr(iterator i,
-                                  InputIter b, InputIter e, Selector<0>) {
-    insertImpl(i, b, e,
+  iterator insertImplDiscr(const_iterator i,
+                           InputIter b, InputIter e, Selector<0>) {
+    return insertImpl(i, b, e,
                typename std::iterator_traits<InputIter>::iterator_category());
-    return *this;
   }
 
   template <class FwdIterator>
-  void insertImpl(iterator i,
+  iterator insertImpl(const_iterator i,
                   FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) {
     Invariant checker(*this);
     (void) checker;
@@ -1462,9 +1505,9 @@ private:
       const iterator tailBegin = end() - n2;
       store_.expand_noinit(n2);
       fbstring_detail::pod_copy(tailBegin, tailBegin + n2, end() - n2);
-      std::copy(reverse_iterator(tailBegin), reverse_iterator(i),
+      std::copy(const_reverse_iterator(tailBegin), const_reverse_iterator(i),
                 reverse_iterator(tailBegin + n2));
-      std::copy(s1, s2, i);
+      std::copy(s1, s2, begin() + pos);
     } else {
       FwdIterator t = s1;
       const size_type old_size = size();
@@ -1474,27 +1517,35 @@ private:
       std::copy(t, s2, begin() + old_size);
       fbstring_detail::pod_copy(data() + pos, data() + old_size,
                                  begin() + old_size + newElems);
-      std::copy(s1, t, i);
+      std::copy(s1, t, begin() + pos);
     }
     store_.writeTerminator();
+    return begin() + pos;
   }
 
   template <class InputIterator>
-  void insertImpl(iterator i,
-                  InputIterator b, InputIterator e, std::input_iterator_tag) {
+  iterator insertImpl(const_iterator i,
+                      InputIterator b, InputIterator e,
+                      std::input_iterator_tag) {
+    const auto pos = i - begin();
     basic_fbstring temp(begin(), i);
     for (; b != e; ++b) {
       temp.push_back(*b);
     }
     temp.append(i, end());
     swap(temp);
+    return begin() + pos;
   }
 
 public:
   template <class ItOrLength, class ItOrChar>
-  void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c) {
+  iterator insert(const_iterator p, ItOrLength first_or_n, ItOrChar last_or_c) {
     Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
-    insertImplDiscr(p, first_or_n, last_or_c, sel);
+    return insertImplDiscr(p, first_or_n, last_or_c, sel);
+  }
+
+  iterator insert(const_iterator p, std::initializer_list<value_type> il) {
+    return insert(p, il.begin(), il.end());
   }
 
   basic_fbstring& erase(size_type pos = 0, size_type n = npos) {
@@ -1690,7 +1741,6 @@ public:
     store_.swap(rhs.store_);
   }
 
-  // 21.3.6 string operations:
   const value_type* c_str() const {
     return store_.c_str();
   }
@@ -2165,7 +2215,7 @@ bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs,
  return !(lhs < rhs);
 }
 
-// subclause 21.3.7.8:
+// C++11 21.4.8.8
 template <typename E, class T, class A, class S>
 void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) {
   lhs.swap(rhs);
index bd6def424571cff4b19d849cbb6e9bd11ea1e50b..65fb7ad1711494b4e4c09385e63fc0e6c1e934a4 100644 (file)
@@ -77,17 +77,34 @@ std::list<char> RandomList(unsigned int maxSize) {
 // Tests begin here
 ////////////////////////////////////////////////////////////////////////////////
 
-template <class String> void clause_21_3_1_a(String & test) {
+template <class String> void clause11_21_4_2_a(String & test) {
   test.String::~String();
   new(&test) String();
 }
-template <class String> void clause_21_3_1_b(String & test) {
-  // Copy constructor
+template <class String> void clause11_21_4_2_b(String & test) {
+  String test2(test);
+  assert(test2 == test);
+}
+template <class String> void clause11_21_4_2_c(String & test) {
+  // Test move constructor. There is a more specialized test, see
+  // TEST(FBString, testMoveCtor)
+  String donor(test);
+  String test2(std::move(donor));
+  EXPECT_EQ(test2, test);
+  // Technically not required, but all implementations that actually
+  // support move will move large strings. Make a guess for 128 as the
+  // maximum small string optimization that's reasonable.
+  EXPECT_LE(donor.size(), 128);
+}
+template <class String> void clause11_21_4_2_d(String & test) {
+  // Copy constructor with position and length
   const size_t pos = random(0, test.size());
-  String s(test, pos, random(0, (size_t)(test.size() - pos)));
+  String s(test, pos, random(0, 9)
+           ? random(0, (size_t)(test.size() - pos))
+           : String::npos); // test for npos, too, in 10% of the cases
   test = s;
 }
-template <class String> void clause_21_3_1_c(String & test) {
+template <class String> void clause11_21_4_2_e(String & test) {
   // Constructor from char*, size_t
   const size_t
     pos = random(0, test.size()),
@@ -96,36 +113,58 @@ template <class String> void clause_21_3_1_c(String & test) {
   String s(test.c_str() + pos, n);
   String after(test.data(), test.size());
   EXPECT_EQ(before, after);
-
+  test.swap(s);
+}
+template <class String> void clause11_21_4_2_f(String & test) {
+  // Constructor from char*
+  const size_t
+    pos = random(0, test.size()),
+    n = random(0, test.size() - pos);
+  String before(test.data(), test.size());
+  String s(test.c_str() + pos);
+  String after(test.data(), test.size());
+  EXPECT_EQ(before, after);
+  test.swap(s);
+}
+template <class String> void clause11_21_4_2_g(String & test) {
+  // Constructor from size_t, char
+  const size_t n = random(0, test.size());
+  const auto c = test.front();
+  test = String(n, c);
+}
+template <class String> void clause11_21_4_2_h(String & test) {
+  // Constructors from various iterator pairs
   // Constructor from char*, char*
   String s1(test.begin(), test.end());
   EXPECT_EQ(test, s1);
   String s2(test.data(), test.data() + test.size());
   EXPECT_EQ(test, s2);
-
-  // Constructor from iterators
+  // Constructor from other iterators
   std::list<char> lst;
   for (auto c : test) lst.push_back(c);
   String s3(lst.begin(), lst.end());
   EXPECT_EQ(test, s3);
-
   // Constructor from wchar_t iterators
   std::list<wchar_t> lst1;
   for (auto c : test) lst1.push_back(c);
   String s4(lst1.begin(), lst1.end());
   EXPECT_EQ(test, s4);
-
   // Constructor from wchar_t pointers
   wchar_t t[20];
   t[0] = 'a';
   t[1] = 'b';
   fbstring s5(t, t + 2);;
   EXPECT_EQ("ab", s5);
-
-  test = s;
 }
-template <class String> void clause_21_3_1_d(String & test) {
-  // Assignment
+template <class String> void clause11_21_4_2_i(String & test) {
+  // From initializer_list<char>
+  std::initializer_list<typename String::value_type>
+    il = { 'h', 'e', 'l', 'l', 'o' };
+  String s(il);
+  test.swap(s);
+}
+template <class String> void clause11_21_4_2_j(String & test) {
+  // Assignment from const String&
   auto size = random(0, 2000);
   String s(size, '\0');
   EXPECT_EQ(s.size(), size);
@@ -134,7 +173,20 @@ template <class String> void clause_21_3_1_d(String & test) {
   }
   test = s;
 }
-template <class String> void clause_21_3_1_e(String & test) {
+template <class String> void clause11_21_4_2_k(String & test) {
+  // Assignment from String&&
+  auto size = random(0, 2000);
+  String s(size, '\0');
+  EXPECT_EQ(s.size(), size);
+  FOR_EACH_RANGE (i, 0, s.size()) {
+    s[i] = random('a', 'z');
+  }
+  test = std::move(s);
+  if (typeid(String) == typeid(fbstring)) {
+    EXPECT_LE(s.size(), 128);
+  }
+}
+template <class String> void clause11_21_4_2_l(String & test) {
   // Assignment from char*
   String s(random(0, 1000), '\0');
   size_t i = 0;
@@ -143,7 +195,7 @@ template <class String> void clause_21_3_1_e(String & test) {
   }
   test = s.c_str();
 }
-template <class String> void clause_21_3_1_f(String & test) {
+template <class String> void clause11_21_4_2_lprime(String & test) {
   // Aliased assign
   const size_t pos = random(0, test.size());
   if (avoidAliasing) {
@@ -152,15 +204,23 @@ template <class String> void clause_21_3_1_f(String & test) {
     test = test.c_str() + pos;
   }
 }
-template <class String> void clause_21_3_1_g(String & test) {
+template <class String> void clause11_21_4_2_m(String & test) {
   // Assignment from char
   test = random('a', 'z');
 }
+template <class String> void clause11_21_4_2_n(String & test) {
+  // Assignment from initializer_list<char>
+  initializer_list<typename String::value_type>
+    il = { 'h', 'e', 'l', 'l', 'o' };
+  test = il;
+}
 
-template <class String> void clause_21_3_2(String & test) {
+template <class String> void clause11_21_4_3(String & test) {
   // Iterators. The code below should leave test unchanged
   EXPECT_EQ(test.size(), test.end() - test.begin());
   EXPECT_EQ(test.size(), test.rend() - test.rbegin());
+  EXPECT_EQ(test.size(), test.cend() - test.cbegin());
+  EXPECT_EQ(test.size(), test.crend() - test.crbegin());
 
   auto s = test.size();
   test.resize(test.end() - test.begin());
@@ -169,12 +229,20 @@ template <class String> void clause_21_3_2(String & test) {
   EXPECT_EQ(s, test.size());
 }
 
-template <class String> void clause_21_3_3(String & test) {
+template <class String> void clause11_21_4_4(String & test) {
   // exercise capacity, size, max_size
   EXPECT_EQ(test.size(), test.length());
   EXPECT_LE(test.size(), test.max_size());
   EXPECT_LE(test.capacity(), test.max_size());
   EXPECT_LE(test.size(), test.capacity());
+
+  // exercise shrink_to_fit. Nonbinding request so we can't really do
+  // much beyond calling it.
+  auto copy = test;
+  copy.reserve(copy.capacity() * 3);
+  copy.shrink_to_fit();
+  EXPECT_EQ(copy, test);
+
   // exercise empty
   string empty("empty");
   string notempty("not empty");
@@ -182,16 +250,18 @@ template <class String> void clause_21_3_3(String & test) {
   else test = String(notempty.begin(), notempty.end());
 }
 
-template <class String> void clause_21_3_4(String & test) {
-  // exercise element access 21.3.4
+template <class String> void clause11_21_4_5(String & test) {
+  // exercise element access
   if (!test.empty()) {
+    EXPECT_EQ(test[0], test.front());
+    EXPECT_EQ(test[test.size() - 1], test.back());
     auto const i = random(0, test.size() - 1);
     EXPECT_EQ(test[i], test.at(i));
     test = test[i];
   }
 }
 
-template <class String> void clause_21_3_5_a(String & test) {
+template <class String> void clause11_21_4_6_1(String & test) {
   // 21.3.5 modifiers (+=)
   String test1;
   randomString(&test1);
@@ -240,9 +310,12 @@ template <class String> void clause_21_3_5_a(String & test) {
   len = test.size();
   test += random('a', 'z');
   EXPECT_EQ(test.size(), len + 1);
+  // initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  test += il;
 }
 
-template <class String> void clause_21_3_5_b(String & test) {
+template <class String> void clause11_21_4_6_2(String & test) {
   // 21.3.5 modifiers (append, push_back)
   String s;
 
@@ -267,70 +340,85 @@ template <class String> void clause_21_3_5_b(String & test) {
   c = random('a', 'z');
   test.push_back(c);
   EXPECT_EQ(test[test.size() - 1], c);
+  // initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  test.append(il);
 }
 
-template <class String> void clause_21_3_5_c(String & test) {
+template <class String> void clause11_21_4_6_3_a(String & test) {
   // assign
   String s;
   randomString(&s);
   test.assign(s);
+  EXPECT_EQ(test, s);
+  // move assign
+  test.assign(std::move(s));
+  if (typeid(String) == typeid(fbstring)) {
+    EXPECT_LE(s.size(), 128);
+  }
 }
 
-template <class String> void clause_21_3_5_d(String & test) {
+template <class String> void clause11_21_4_6_3_b(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(s, random(0, s.size()), random(0, maxString));
 }
 
-template <class String> void clause_21_3_5_e(String & test) {
+template <class String> void clause11_21_4_6_3_c(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(s.c_str(), random(0, s.size()));
 }
 
-template <class String> void clause_21_3_5_f(String & test) {
+template <class String> void clause11_21_4_6_3_d(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(s.c_str());
 }
 
-template <class String> void clause_21_3_5_g(String & test) {
+template <class String> void clause11_21_4_6_3_e(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(random(0, maxString), random('a', 'z'));
 }
 
-template <class String> void clause_21_3_5_h(String & test) {
+template <class String> void clause11_21_4_6_3_f(String & test) {
   // assign from bidirectional iterator
   std::list<char> lst(RandomList(maxString));
   test.assign(lst.begin(), lst.end());
 }
 
-template <class String> void clause_21_3_5_i(String & test) {
+template <class String> void clause11_21_4_6_3_g(String & test) {
   // assign from aliased source
   test.assign(test);
 }
 
-template <class String> void clause_21_3_5_j(String & test) {
+template <class String> void clause11_21_4_6_3_h(String & test) {
   // assign from aliased source
   test.assign(test, random(0, test.size()), random(0, maxString));
 }
 
-template <class String> void clause_21_3_5_k(String & test) {
+template <class String> void clause11_21_4_6_3_i(String & test) {
   // assign from aliased source
   test.assign(test.c_str(), random(0, test.size()));
 }
 
-template <class String> void clause_21_3_5_l(String & test) {
+template <class String> void clause11_21_4_6_3_j(String & test) {
   // assign from aliased source
   test.assign(test.c_str());
 }
 
-template <class String> void clause_21_3_5_m(String & test) {
+template <class String> void clause11_21_4_6_3_k(String & test) {
+  // assign from initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  test.assign(il);
+}
+
+template <class String> void clause11_21_4_6_4(String & test) {
   // insert
   String s;
   randomString(&s, maxString);
@@ -346,15 +434,23 @@ template <class String> void clause_21_3_5_m(String & test) {
   test.insert(random(0, test.size()), s.c_str());
   test.insert(random(0, test.size()),
               random(0, maxString), random('a', 'z'));
-  test.insert(test.begin() + random(0, test.size()),
-              random('a', 'z'));
+  typename String::size_type pos = random(0, test.size());
+  typename String::iterator res =
+    test.insert(test.begin() + pos, random('a', 'z'));
+  EXPECT_EQ(res - test.begin(), pos);
   std::list<char> lst(RandomList(maxString));
-  test.insert(test.begin() + random(0, test.size()),
-              lst.begin(), lst.end());
+  pos = random(0, test.size());
+  // Uncomment below to see a bug in gcc
+  /*res = */test.insert(test.begin() + pos, lst.begin(), lst.end());
+  // insert from initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  pos = random(0, test.size());
+  // Uncomment below to see a bug in gcc
+  /*res = */test.insert(test.begin() + pos, il);
 }
 
-template <class String> void clause_21_3_5_n(String & test) {
-  // erase
+template <class String> void clause11_21_4_6_5(String & test) {
+  // erase and pop_back
   if (!test.empty()) {
     test.erase(random(0, test.size()), random(0, maxString));
   }
@@ -368,9 +464,13 @@ template <class String> void clause_21_3_5_n(String & test) {
       test.erase(i, i + random(0, size_t(test.end() - i)));
     }
   }
+  if (!test.empty()) {
+    // Can't test pop_back with std::string, doesn't support it yet.
+    //test.pop_back();
+  }
 }
 
-template <class String> void clause_21_3_5_o(String & test) {
+template <class String> void clause11_21_4_6_6(String & test) {
   auto pos = random(0, test.size());
   if (avoidAliasing) {
     test.replace(pos, random(0, test.size() - pos),
@@ -461,7 +561,7 @@ template <class String> void clause_21_3_5_o(String & test) {
     random(0, maxString), random('a', 'z'));
 }
 
-template <class String> void clause_21_3_5_p(String & test) {
+template <class String> void clause11_21_4_6_7(String & test) {
   std::vector<typename String::value_type>
     vec(random(0, maxString));
   test.copy(
@@ -470,13 +570,13 @@ template <class String> void clause_21_3_5_p(String & test) {
     random(0, test.size()));
 }
 
-template <class String> void clause_21_3_5_q(String & test) {
+template <class String> void clause11_21_4_6_8(String & test) {
   String s;
   randomString(&s, maxString);
   s.swap(test);
 }
 
-template <class String> void clause_21_3_6_a(String & test) {
+template <class String> void clause11_21_4_7_1(String & test) {
   // 21.3.6 string operations
   // exercise c_str() and data()
   assert(test.c_str() == test.data());
@@ -486,14 +586,14 @@ template <class String> void clause_21_3_6_a(String & test) {
   assert(test.get_allocator() == s.get_allocator());
 }
 
-template <class String> void clause_21_3_6_b(String & test) {
+template <class String> void clause11_21_4_7_2_a(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
   Num2String(test, test.find(str, random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_c(String & test) {
+template <class String> void clause11_21_4_7_2_b(String & test) {
   auto from = random(0, test.size());
   auto length = random(0, test.size() - from);
   String str = test.substr(from, length);
@@ -502,7 +602,7 @@ template <class String> void clause_21_3_6_c(String & test) {
                              random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_d(String & test) {
+template <class String> void clause11_21_4_7_2_c(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
@@ -510,20 +610,20 @@ template <class String> void clause_21_3_6_d(String & test) {
                              random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_e(String & test) {
+template <class String> void clause11_21_4_7_2_d(String & test) {
   Num2String(test, test.find(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_f(String & test) {
+template <class String> void clause11_21_4_7_3_a(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
   Num2String(test, test.rfind(str, random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_g(String & test) {
+template <class String> void clause11_21_4_7_3_b(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
@@ -532,7 +632,7 @@ template <class String> void clause_21_3_6_g(String & test) {
                               random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_h(String & test) {
+template <class String> void clause11_21_4_7_3_c(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
@@ -540,20 +640,20 @@ template <class String> void clause_21_3_6_h(String & test) {
                               random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_i(String & test) {
+template <class String> void clause11_21_4_7_3_d(String & test) {
   Num2String(test, test.rfind(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_j(String & test) {
+template <class String> void clause11_21_4_7_4_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_of(str,
                                       random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_k(String & test) {
+template <class String> void clause11_21_4_7_4_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_of(str.c_str(),
@@ -561,27 +661,27 @@ template <class String> void clause_21_3_6_k(String & test) {
                                       random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_l(String & test) {
+template <class String> void clause11_21_4_7_4_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_of(str.c_str(),
                                       random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_m(String & test) {
+template <class String> void clause11_21_4_7_4_d(String & test) {
   Num2String(test, test.find_first_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_n(String & test) {
+template <class String> void clause11_21_4_7_5_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_of(str,
                                      random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_o(String & test) {
+template <class String> void clause11_21_4_7_5_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_of(str.c_str(),
@@ -589,27 +689,27 @@ template <class String> void clause_21_3_6_o(String & test) {
                                      random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_p(String & test) {
+template <class String> void clause11_21_4_7_5_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_of(str.c_str(),
                                      random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_q(String & test) {
+template <class String> void clause11_21_4_7_5_d(String & test) {
   Num2String(test, test.find_last_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_r(String & test) {
+template <class String> void clause11_21_4_7_6_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_not_of(str,
                                           random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_s(String & test) {
+template <class String> void clause11_21_4_7_6_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_not_of(str.c_str(),
@@ -617,27 +717,27 @@ template <class String> void clause_21_3_6_s(String & test) {
                                           random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_t(String & test) {
+template <class String> void clause11_21_4_7_6_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_not_of(str.c_str(),
                                           random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_u(String & test) {
+template <class String> void clause11_21_4_7_6_d(String & test) {
   Num2String(test, test.find_first_not_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_v(String & test) {
+template <class String> void clause11_21_4_7_7_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_not_of(str,
                                          random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_w(String & test) {
+template <class String> void clause11_21_4_7_7_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_not_of(str.c_str(),
@@ -645,24 +745,24 @@ template <class String> void clause_21_3_6_w(String & test) {
                                          random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_x(String & test) {
+template <class String> void clause11_21_4_7_7_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_not_of(str.c_str(),
                                          random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_y(String & test) {
+template <class String> void clause11_21_4_7_7_d(String & test) {
   Num2String(test, test.find_last_not_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_z(String & test) {
+template <class String> void clause11_21_4_7_8(String & test) {
   test = test.substr(random(0, test.size()), random(0, test.size()));
 }
 
-template <class String> void clause_21_3_7_a(String & test) {
+template <class String> void clause11_21_4_7_9_a(String & test) {
   String s;
   randomString(&s, maxString);
   int tristate = test.compare(s);
@@ -671,7 +771,7 @@ template <class String> void clause_21_3_7_a(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_b(String & test) {
+template <class String> void clause11_21_4_7_9_b(String & test) {
   String s;
   randomString(&s, maxString);
   int tristate = test.compare(
@@ -683,7 +783,7 @@ template <class String> void clause_21_3_7_b(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_c(String & test) {
+template <class String> void clause11_21_4_7_9_c(String & test) {
   String str;
   randomString(&str, maxString);
   int tristate = test.compare(
@@ -697,7 +797,7 @@ template <class String> void clause_21_3_7_c(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_d(String & test) {
+template <class String> void clause11_21_4_7_9_d(String & test) {
   String s;
   randomString(&s, maxString);
   int tristate = test.compare(s.c_str());
@@ -706,7 +806,7 @@ template <class String> void clause_21_3_7_d(String & test) {
                 Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_e(String & test) {
+template <class String> void clause11_21_4_7_9_e(String & test) {
   String str;
   randomString(&str, maxString);
   int tristate = test.compare(
@@ -719,7 +819,7 @@ template <class String> void clause_21_3_7_e(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_f(String & test) {
+template <class String> void clause11_21_4_8_1_a(String & test) {
   String s1;
   randomString(&s1, maxString);
   String s2;
@@ -727,7 +827,7 @@ template <class String> void clause_21_3_7_f(String & test) {
   test = s1 + s2;
 }
 
-template <class String> void clause_21_3_7_g(String & test) {
+template <class String> void clause11_21_4_8_1_b(String & test) {
   String s;
   randomString(&s, maxString);
   String s1;
@@ -735,13 +835,13 @@ template <class String> void clause_21_3_7_g(String & test) {
   test = s.c_str() + s1;
 }
 
-template <class String> void clause_21_3_7_h(String & test) {
+template <class String> void clause11_21_4_8_1_c(String & test) {
   String s;
   randomString(&s, maxString);
   test = typename String::value_type(random('a', 'z')) + s;
 }
 
-template <class String> void clause_21_3_7_i(String & test) {
+template <class String> void clause11_21_4_8_1_d(String & test) {
   String s;
   randomString(&s, maxString);
   String s1;
@@ -749,7 +849,7 @@ template <class String> void clause_21_3_7_i(String & test) {
   test = s + s1.c_str();
 }
 
-template <class String> void clause_21_3_7_j(String & test) {
+template <class String> void clause11_21_4_8_1_e(String & test) {
   String s;
   randomString(&s, maxString);
   String s1;
@@ -757,14 +857,14 @@ template <class String> void clause_21_3_7_j(String & test) {
   test = s + s1.c_str();
 }
 
-template <class String> void clause_21_3_7_k(String & test) {
+template <class String> void clause11_21_4_8_1_f(String & test) {
   String s;
   randomString(&s, maxString);
   test = s + typename String::value_type(random('a', 'z'));
 }
 
 // Numbering here is from C++11
-template <class String> void clause_21_4_8_9_a(String & test) {
+template <class String> void clause11_21_4_8_9_a(String & test) {
   basic_stringstream<typename String::value_type> stst(test.c_str());
   String str;
   while (stst) {
@@ -789,15 +889,15 @@ TEST(FBString, testAllClauses) {
       wc = folly::basic_fbstring<wchar_t>(wr.c_str());              \
       auto localSeed = seed + count;                                \
       rng = RandomT(localSeed);                                     \
-      clause_##x(r);                                                \
+      clause11_##x(r);                                                \
       rng = RandomT(localSeed);                                     \
-      clause_##x(c);                                                \
+      clause11_##x(c);                                                \
       EXPECT_EQ(r, c)                                               \
         << "Lengths: " << r.size() << " vs. " << c.size()           \
         << "\nReference: '" << r << "'"                             \
         << "\nActual:    '" << c.data()[0] << "'";                  \
       rng = RandomT(localSeed);                                     \
-      clause_##x(wc);                                               \
+      clause11_##x(wc);                                               \
       int wret = wcslen(wc.c_str());                                \
       char mb[wret+1];                                              \
       int ret = wcstombs(mb, wc.c_str(), sizeof(mb));               \
@@ -809,73 +909,80 @@ TEST(FBString, testAllClauses) {
     } while (++count % 100 != 0)
 
   int count = 0;
-  TEST_CLAUSE(21_3_1_a);
-  TEST_CLAUSE(21_3_1_b);
-  TEST_CLAUSE(21_3_1_c);
-  TEST_CLAUSE(21_3_1_d);
-  TEST_CLAUSE(21_3_1_e);
-  TEST_CLAUSE(21_3_1_f);
-  TEST_CLAUSE(21_3_1_g);
-
-  TEST_CLAUSE(21_3_2);
-  TEST_CLAUSE(21_3_3);
-  TEST_CLAUSE(21_3_4);
-  TEST_CLAUSE(21_3_5_a);
-  TEST_CLAUSE(21_3_5_b);
-  TEST_CLAUSE(21_3_5_c);
-  TEST_CLAUSE(21_3_5_d);
-  TEST_CLAUSE(21_3_5_e);
-  TEST_CLAUSE(21_3_5_f);
-  TEST_CLAUSE(21_3_5_g);
-  TEST_CLAUSE(21_3_5_h);
-  TEST_CLAUSE(21_3_5_i);
-  TEST_CLAUSE(21_3_5_j);
-  TEST_CLAUSE(21_3_5_k);
-  TEST_CLAUSE(21_3_5_l);
-  TEST_CLAUSE(21_3_5_m);
-  TEST_CLAUSE(21_3_5_n);
-  TEST_CLAUSE(21_3_5_o);
-  TEST_CLAUSE(21_3_5_p);
-
-  TEST_CLAUSE(21_3_6_a);
-  TEST_CLAUSE(21_3_6_b);
-  TEST_CLAUSE(21_3_6_c);
-  TEST_CLAUSE(21_3_6_d);
-  TEST_CLAUSE(21_3_6_e);
-  TEST_CLAUSE(21_3_6_f);
-  TEST_CLAUSE(21_3_6_g);
-  TEST_CLAUSE(21_3_6_h);
-  TEST_CLAUSE(21_3_6_i);
-  TEST_CLAUSE(21_3_6_j);
-  TEST_CLAUSE(21_3_6_k);
-  TEST_CLAUSE(21_3_6_l);
-  TEST_CLAUSE(21_3_6_m);
-  TEST_CLAUSE(21_3_6_n);
-  TEST_CLAUSE(21_3_6_o);
-  TEST_CLAUSE(21_3_6_p);
-  TEST_CLAUSE(21_3_6_q);
-  TEST_CLAUSE(21_3_6_r);
-  TEST_CLAUSE(21_3_6_s);
-  TEST_CLAUSE(21_3_6_t);
-  TEST_CLAUSE(21_3_6_u);
-  TEST_CLAUSE(21_3_6_v);
-  TEST_CLAUSE(21_3_6_w);
-  TEST_CLAUSE(21_3_6_x);
-  TEST_CLAUSE(21_3_6_y);
-  TEST_CLAUSE(21_3_6_z);
-
-  TEST_CLAUSE(21_3_7_a);
-  TEST_CLAUSE(21_3_7_b);
-  TEST_CLAUSE(21_3_7_c);
-  TEST_CLAUSE(21_3_7_d);
-  TEST_CLAUSE(21_3_7_e);
-  TEST_CLAUSE(21_3_7_f);
-  TEST_CLAUSE(21_3_7_g);
-  TEST_CLAUSE(21_3_7_h);
-  TEST_CLAUSE(21_3_7_i);
-  TEST_CLAUSE(21_3_7_j);
-  TEST_CLAUSE(21_3_7_k);
-
+  TEST_CLAUSE(21_4_2_a);
+  TEST_CLAUSE(21_4_2_b);
+  TEST_CLAUSE(21_4_2_c);
+  TEST_CLAUSE(21_4_2_d);
+  TEST_CLAUSE(21_4_2_e);
+  TEST_CLAUSE(21_4_2_f);
+  TEST_CLAUSE(21_4_2_g);
+  TEST_CLAUSE(21_4_2_h);
+  TEST_CLAUSE(21_4_2_i);
+  TEST_CLAUSE(21_4_2_j);
+  TEST_CLAUSE(21_4_2_k);
+  TEST_CLAUSE(21_4_2_l);
+  TEST_CLAUSE(21_4_2_lprime);
+  TEST_CLAUSE(21_4_2_m);
+  TEST_CLAUSE(21_4_2_n);
+  TEST_CLAUSE(21_4_3);
+  TEST_CLAUSE(21_4_4);
+  TEST_CLAUSE(21_4_5);
+  TEST_CLAUSE(21_4_6_1);
+  TEST_CLAUSE(21_4_6_2);
+  TEST_CLAUSE(21_4_6_3_a);
+  TEST_CLAUSE(21_4_6_3_b);
+  TEST_CLAUSE(21_4_6_3_c);
+  TEST_CLAUSE(21_4_6_3_d);
+  TEST_CLAUSE(21_4_6_3_e);
+  TEST_CLAUSE(21_4_6_3_f);
+  TEST_CLAUSE(21_4_6_3_g);
+  TEST_CLAUSE(21_4_6_3_h);
+  TEST_CLAUSE(21_4_6_3_i);
+  TEST_CLAUSE(21_4_6_3_j);
+  TEST_CLAUSE(21_4_6_3_k);
+  TEST_CLAUSE(21_4_6_4);
+  TEST_CLAUSE(21_4_6_5);
+  TEST_CLAUSE(21_4_6_6);
+  TEST_CLAUSE(21_4_6_7);
+  TEST_CLAUSE(21_4_6_8);
+  TEST_CLAUSE(21_4_7_1);
+
+  TEST_CLAUSE(21_4_7_2_a);
+  TEST_CLAUSE(21_4_7_2_b);
+  TEST_CLAUSE(21_4_7_2_c);
+  TEST_CLAUSE(21_4_7_2_d);
+  TEST_CLAUSE(21_4_7_3_a);
+  TEST_CLAUSE(21_4_7_3_b);
+  TEST_CLAUSE(21_4_7_3_c);
+  TEST_CLAUSE(21_4_7_3_d);
+  TEST_CLAUSE(21_4_7_4_a);
+  TEST_CLAUSE(21_4_7_4_b);
+  TEST_CLAUSE(21_4_7_4_c);
+  TEST_CLAUSE(21_4_7_4_d);
+  TEST_CLAUSE(21_4_7_5_a);
+  TEST_CLAUSE(21_4_7_5_b);
+  TEST_CLAUSE(21_4_7_5_c);
+  TEST_CLAUSE(21_4_7_5_d);
+  TEST_CLAUSE(21_4_7_6_a);
+  TEST_CLAUSE(21_4_7_6_b);
+  TEST_CLAUSE(21_4_7_6_c);
+  TEST_CLAUSE(21_4_7_6_d);
+  TEST_CLAUSE(21_4_7_7_a);
+  TEST_CLAUSE(21_4_7_7_b);
+  TEST_CLAUSE(21_4_7_7_c);
+  TEST_CLAUSE(21_4_7_7_d);
+  TEST_CLAUSE(21_4_7_8);
+  TEST_CLAUSE(21_4_7_9_a);
+  TEST_CLAUSE(21_4_7_9_b);
+  TEST_CLAUSE(21_4_7_9_c);
+  TEST_CLAUSE(21_4_7_9_d);
+  TEST_CLAUSE(21_4_7_9_e);
+  TEST_CLAUSE(21_4_8_1_a);
+  TEST_CLAUSE(21_4_8_1_b);
+  TEST_CLAUSE(21_4_8_1_c);
+  TEST_CLAUSE(21_4_8_1_d);
+  TEST_CLAUSE(21_4_8_1_e);
+  TEST_CLAUSE(21_4_8_1_f);
   TEST_CLAUSE(21_4_8_9_a);
 }