proxygen
StlVectorTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-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 
17 // @author Nicholas Ormrod <njormrod@fb.com>
18 
19 /*
20 
21 This file contains an extensive STL compliance test suite for an STL vector
22 implementation (such as FBVector).
23 
24 GCC 4.7 is required.
25 
26 */
27 
28 #if 0
29 #define USING_STD_VECTOR
30 #endif
31 
32 /*
33 
34 The insanity of this file deserves a superficial explanation.
35 
36 This file tests an implementation of STL vector. It is extremely comprehensive.
37 If it compiles (more on that later) it generates a binary which, when run,
38 exhaustively tests its vector for standard compliance.
39 
40 Limitations:
41 -If it doesn't compile, the compiler errors are mind-boggling.
42 -Not everything is testable. There are a few comments in the code where
43  the implementation must be inspected, as opposed to tested. These are very
44  simple inspections. Search for 'whitebox'.
45 -It does not test boolean specialization.
46 
47 ==========================
48 How this file is organized
49 
50 --------------
51 Data and Alloc
52 
53 Data is a class designed to provide diagnostics when stored in a vector. It
54 counts the number of operations performed on it, can have any function
55 disabled or labeled as noexcept, throws errors from anywhere that is not
56 noexcept, tracks its supposed location in memory (optional), tracks
57 aggregate information, and can print a trace of its action.
58 
59 Alloc, like Data, is a full-blown diagnostic allocator. It keeps track of
60 all space it has allocated, keeps counters, throws exceptions, and can easily
61 compare equal or not equal with other Allocs.
62 
63 These two classes have a few useful helper functions:
64 isSane - checks that all the tracked variables make sense
65 softReset - simplifies the variables before a test
66 hardReset - brutally resets all variables to the default state
67 
68 --------
69 STL_TEST
70 
71 Google test is not quite good enough for this test file, because we need to
72 run tests across different input values and different types.
73 
74 The STL_TEST macro takes a few arguments:
75 string - what is being tested
76 id - unique id, passed to TEST
77 restriction - requirements for test types
78 parameters - which variables to range over
79 
80 Eg: STL_TEST("23.2.3", isCopyable, is_copy_constructible, a) { ... }
81 
82 The restriction is used to select which types get tested. Copy construction,
83 for example, requires a data type which is copy constructible, whereas to test
84 the clear operation, the data only needs to be destructible. If the type does
85 not pass the restriction, then the test is not instantiated with that type (if
86 it were, then there would be a compiler error).
87 
88 The variable names in the standard have very specific meaning. For example,
89 a and b are always vectors, i and j are always external iterators, etc. These
90 bindings are used in the STL_TEST - if you need a vector and an int, have
91 parameters a and n.
92 
93 There is a list (BOOST_PP_SEQ) of test types and interface types. If the
94 type passes the restriction, then the test body is instantiated with that
95 type as its template parameter. Instantiation ensures that the contractual
96 elements of the standard are satisfied. Only the test types, however, and
97 not the interfact types, are actually tested.
98 
99 If a test type passes the restriction, then it is run with a variety of
100 arguments. Each variable (e.g. a and b) have a generator, which generates
101 a range of values for that variable before each test. Generated values are not
102 reused - they are remade for every run. This causes long runtimes, but ensures
103 that corner cases are not missed.
104 
105 There are two implicit extra parameters, z and ticks. Ignore z. Ticks, on the
106 other hand, is very important. Each is test is run multiple times with the
107 same arguments; the first time with no ticks (and hence no Data or Alloc
108 exceptions), and then once again for each and every location that an
109 exception can be thrown. This ensures that exception corner cases are alse
110 thoroughly tested.
111 
112 At the end of each test, a set of verification functions is run to ensure
113 that nothing was corrupted.
114 
115 ---------
116 The tests
117 
118 All specifications from N3337 Chapter 23 (Containers) that pertains to
119 vector is tested (if possible). Each aspect has a dedicated STL_TEST, so that
120 there are no compounding errors. The tests are organized as they appear in
121 N3337.
122 
123 The backbone of the testing framework is based on a small set of vector
124 operations:
125 -empty construction
126 -copy construction (a little bit)
127 -size
128 -capacity
129 -data
130 -emplace_back
131 
132 These functions are used to generate and verify the tests. If they fail, then
133 the cascade of errors will be enormous. They are, therefore, tested first.
134 
135 */
136 /*
137 
138 THOUGHTS:
139 
140 -Not all complexity checks are verified. These will be relentlessly hunted down
141  in the benchmarking phase.
142 
143 -It seems that initializer lists with implicit arguments are constructed before
144  being passed into the vector. When one of the constructors fails, it fails in
145  the initializer list, before it even gets to the vector. The IL, however,
146  doesn't clean up properly, and already-constructed elements are not
147  destroyed. This causes a memory leak, and the tests break, but it is not the
148  fault of the vector itself. Further, since the implementation for the
149  initializer lists is specified in the standard as calling an associated
150  function with (il.begin(), il.end()), we really just have to check the throws
151  cases for the associated functions (which all work fine). Initializer lists
152  also do not work with explicit constructors.
153 
154 -The implementation of std::copy from iterators prevents Data(int) from being
155  explicit. Explicitness is, perhaps, a desirable quality, but with fundamental
156  std library code like copy not supporting it, it seems impractical.
157 
158 */
159 
160 // include the vector first, to ensure its header is self-sufficient
161 #ifdef USING_STD_VECTOR
162 #include <vector>
163 #define VECTOR_ std::vector
164 #else
165 #include <folly/FBVector.h>
166 #define VECTOR_ folly::fbvector
167 #endif
168 
169 //#define USING_STD_VECTOR
170 
171 #include <climits>
172 #include <cstddef>
173 #include <exception>
174 #include <iomanip>
175 #include <iostream>
176 #include <map>
177 #include <set>
178 #include <sstream>
179 #include <stdexcept>
180 #include <string>
181 #include <type_traits>
182 #include <typeinfo>
183 
184 #include <boost/iterator/iterator_adaptor.hpp>
185 #include <boost/preprocessor.hpp>
186 
187 #include <folly/Conv.h>
188 #include <folly/Portability.h>
189 #include <folly/ScopeGuard.h>
191 #include <folly/portability/GTest.h>
192 
193 // We use some pre-processor magic to auto-generate setup and destruct code,
194 // but it also means we have some parameters that may not be used.
196 FOLLY_GNU_DISABLE_WARNING("-Wunused-parameter")
197 FOLLY_GNU_DISABLE_WARNING("-Wunused-variable")
198 // Using SCOPED_TRACE repeatedly from within a macro violates -Wshadow
199 FOLLY_GNU_DISABLE_WARNING("-Wshadow")
200 
201 using namespace std;
202 using namespace folly;
203 
204 //=============================================================================
205 //=============================================================================
206 // Data type
207 
208 //-----------------------------------------------------------------------------
209 // Flags
210 
211 typedef uint32_t Flags;
212 
213 // each method has 3 options: normal, noexcept, throw, and deleted
214 // normal is the default
215 // throw is mutually exclusive with noexcept
216 //
217 // DC - default constructor
218 // CC - copy constructor
219 // MC - move constructor
220 // OC - other constructor
221 // CA - copy assignment
222 // MA - move assignment
223 enum FlagVals : Flags {
224  DC_NOEXCEPT = 0x1,
225  DC_THROW = 0x2,
226  DC_DELETE = 0x8000,
227  CC_NOEXCEPT = 0x4,
228  CC_THROW = 0x8,
229  CC_DELETE = 0x10000,
230  MC_NOEXCEPT = 0x10,
231  MC_THROW = 0x20,
232  MC_DELETE = 0x20000,
233  OC_NOEXCEPT = 0x40,
234  OC_THROW = 0x80,
235  // OC_DELETE - DNE
236 
237  CA_NOEXCEPT = 0x100,
238  CA_THROW = 0x200,
239  CA_DELETE = 0x40000,
240  MA_NOEXCEPT = 0x400,
241  MA_THROW = 0x800,
242  MA_DELETE = 0x80000,
243 
245 
246  IS_RELOCATABLE = 0x2000,
247 
248  // for the allocator
249  PROP_COPY = 0x100000,
250  PROP_MOVE = 0x200000,
251  PROP_SWAP = 0x400000,
252 };
253 
254 //-----------------------------------------------------------------------------
255 // Deletors
256 
257 template <bool b>
258 struct D0 {
259  D0() = default;
260  D0(const D0&) = default;
261  D0(D0&&) = default;
262  explicit D0(std::nullptr_t) {}
263  D0& operator=(const D0&) = default;
264  D0& operator=(D0&&) = default;
265 };
266 template <>
267 struct D0<true> {
268  D0() = delete;
269  D0(const D0&) = default;
270  D0(D0&&) = default;
271  explicit D0(std::nullptr_t) {}
272  D0& operator=(const D0&) = default;
273  D0& operator=(D0&&) = default;
274 };
275 
276 template <bool b>
277 struct D1 {
278  D1() = default;
279  D1(const D1&) = default;
280  D1(D1&&) = default;
281  explicit D1(std::nullptr_t) {}
282  D1& operator=(const D1&) = default;
283  D1& operator=(D1&&) = default;
284 };
285 template <>
286 struct D1<true> {
287  D1() = default;
288  D1(const D1&) = delete;
289  D1(D1&&) = default;
290  explicit D1(std::nullptr_t) {}
291  D1& operator=(const D1&) = default;
292  D1& operator=(D1&&) = default;
293 };
294 
295 template <bool b>
296 struct D2 {
297  D2() = default;
298  D2(const D2&) = default;
299  D2(D2&&) = default;
300  explicit D2(std::nullptr_t) {}
301  D2& operator=(const D2&) = default;
302  D2& operator=(D2&&) = default;
303 };
304 template <>
305 struct D2<true> {
306  D2() = default;
307  D2(const D2&) = default;
308  D2(D2&&) = delete;
309  explicit D2(std::nullptr_t) {}
310  D2& operator=(const D2&) = default;
311  D2& operator=(D2&&) = default;
312 };
313 
314 template <bool b>
315 struct D3 {
316  D3() = default;
317  D3(const D3&) = default;
318  D3(D3&&) = default;
319  explicit D3(std::nullptr_t) {}
320  D3& operator=(const D3&) = default;
321  D3& operator=(D3&&) = default;
322 };
323 template <>
324 struct D3<true> {
325  D3() = default;
326  D3(const D3&) = default;
327  D3(D3&&) = default;
328  explicit D3(std::nullptr_t) {}
329  D3& operator=(const D3&) = delete;
330  D3& operator=(D3&&) = default;
331 };
332 
333 template <bool b>
334 struct D4 {
335  D4() = default;
336  D4(const D4&) = default;
337  D4(D4&&) = default;
338  explicit D4(std::nullptr_t) {}
339  D4& operator=(const D4&) = default;
340  D4& operator=(D4&&) = default;
341 };
342 template <>
343 struct D4<true> {
344  D4() = default;
345  D4(const D4&) = default;
346  D4(D4&&) = default;
347  explicit D4(std::nullptr_t) {}
348  D4& operator=(const D4&) = default;
349  D4& operator=(D4&&) = delete;
350 };
351 
352 template <Flags f>
353 struct Delete : D0<(f & DC_DELETE) != 0>,
354  D1<(f & CC_DELETE) != 0>,
355  D2<(f & MC_DELETE) != 0>,
356  D3<(f & CA_DELETE) != 0>,
357  D4<(f & MA_DELETE) != 0> {
358  Delete() = default;
359  Delete(const Delete&) = default;
360  Delete(Delete&&) = default;
361  Delete& operator=(const Delete&) = default;
362  Delete& operator=(Delete&&) = default;
363 
364  explicit Delete(std::nullptr_t)
365  : D0<(f & DC_DELETE) != 0>(nullptr),
366  D1<(f & CC_DELETE) != 0>(nullptr),
367  D2<(f & MC_DELETE) != 0>(nullptr),
368  D3<(f & CA_DELETE) != 0>(nullptr),
369  D4<(f & MA_DELETE) != 0>(nullptr) {}
370 };
371 
372 //-----------------------------------------------------------------------------
373 // Ticker
374 
375 struct TickException : std::runtime_error {
376  explicit TickException(const std::string& s)
377  : std::runtime_error("tick: " + s) {}
378 };
379 
380 struct Ticker {
381  static int CountTicks;
382  static int TicksLeft;
383  static void Tick(const std::string& s) {
384  if (TicksLeft == 0) {
385  throw TickException(s);
386  }
387  CountTicks++;
388  TicksLeft--;
389  }
390 };
391 
392 int Ticker::CountTicks = 0;
393 int Ticker::TicksLeft = -1;
394 
395 template <Flags f>
396 struct DataTicker : Ticker {
398  if (!(f & DC_NOEXCEPT)) {
399  Tick("Data()");
400  }
401  }
403  if (!(f & CC_NOEXCEPT)) {
404  Tick("Data(const Data&)");
405  }
406  }
408  if (!(f & MC_NOEXCEPT)) {
409  Tick("Data(Data&&)");
410  }
411  }
412  explicit DataTicker(std::nullptr_t) noexcept((f & OC_NOEXCEPT) != 0) {
413  if (!(f & OC_NOEXCEPT)) {
414  Tick("Data(int)");
415  }
416  }
418  void operator=(const DataTicker&) noexcept((f & CA_NOEXCEPT) != 0) {
419  if (!(f & CA_NOEXCEPT)) {
420  Tick("op=(const Data&)");
421  }
422  }
424  if (!(f & MA_NOEXCEPT)) {
425  Tick("op=(Data&&)");
426  }
427  }
428 };
429 
430 //-----------------------------------------------------------------------------
431 // Operation counter
432 
433 struct Counter {
434  static int CountDC;
435  static int CountCC;
436  static int CountMC;
437  static int CountOC;
438  static int CountCA;
439  static int CountMA;
440  static int CountDestroy;
441  static int CountTotalOps;
443 
445  CountTotalOps++;
446  CountDC++;
447  }
449  CountTotalOps++;
450  CountCC++;
451  }
453  CountTotalOps++;
454  CountMC++;
455  }
456  explicit Counter(std::nullptr_t) noexcept {
457  CountTotalOps++;
458  CountOC++;
459  }
460  void operator=(const Counter&) noexcept {
461  CountTotalOps++;
462  CountCA++;
463  }
465  CountTotalOps++;
466  CountMA++;
467  }
469  CountTotalOps++;
470  CountDestroy++;
471  }
472 };
473 
474 int Counter::CountDC = 0;
475 int Counter::CountCC = 0;
476 int Counter::CountMC = 0;
477 int Counter::CountOC = 0;
478 int Counter::CountCA = 0;
479 int Counter::CountMA = 0;
480 int Counter::CountDestroy = 0;
481 int Counter::CountTotalOps = 0;
483 
484 //-----------------------------------------------------------------------------
485 // Tracker
486 
487 struct Tracker {
488  static int UID;
489  static std::map<int, int> UIDCount;
490  static int UIDTotal;
491  static std::map<const Tracker*, int> Locations;
492  static bool Print;
493 
494  Tracker* self;
495  int uid;
496 
497  Tracker(Tracker* self, int uid) : self(self), uid(uid) {}
498 };
499 
500 template <bool isRelocatable>
502  DataTracker() noexcept : Tracker(this, UID++) {
503  UIDCount[uid]++;
504  UIDTotal++;
505  if (!isRelocatable) {
506  Locations[self] = uid;
507  }
508  print("Data()");
509  }
510  DataTracker(const DataTracker& o) noexcept : Tracker(this, o.uid) {
511  UIDCount[uid]++;
512  UIDTotal++;
513  if (!isRelocatable) {
514  Locations[self] = uid;
515  }
516  print("Data(const Data&)");
517  }
518  DataTracker(DataTracker&& o) noexcept : Tracker(this, o.uid) {
519  UIDCount[uid]++;
520  UIDTotal++;
521  if (!isRelocatable) {
522  Locations[self] = uid;
523  }
524  print("Data(Data&&)");
525  }
526 
527  explicit DataTracker(int uid) noexcept : Tracker(this, uid) {
528  UIDCount[uid]++;
529  UIDTotal++;
530  if (!isRelocatable) {
531  Locations[self] = uid;
532  }
533  print("Data(int)");
534  }
535 
537  UIDCount[uid]--;
538  UIDTotal--;
539  if (!isRelocatable) {
540  Locations.erase(self);
541  }
542  print("~Data()");
543  uid = 0xdeadbeef;
544  self = (DataTracker*)0xfeebdaed;
545  }
546 
548  UIDCount[uid]--;
549  uid = o.uid;
550  UIDCount[uid]++;
551  if (!isRelocatable) {
552  Locations[self] = uid;
553  }
554  print("op=(const Data&)");
555  return *this;
556  }
558  UIDCount[uid]--;
559  uid = o.uid;
560  UIDCount[uid]++;
561  if (!isRelocatable) {
562  Locations[self] = uid;
563  }
564  print("op=(Data&&)");
565  return *this;
566  }
567 
568  void print(const std::string& fun) {
569  if (Print) {
570  std::cerr << std::setw(20) << fun << ": uid = " << std::setw(3) << uid;
571  if (!isRelocatable) {
572  std::cerr << ", self = " << self;
573  }
574  std::cerr << std::endl;
575  }
576  }
577 };
578 
579 int Tracker::UID = 1234;
580 std::map<int, int> Tracker::UIDCount;
581 int Tracker::UIDTotal = 0;
582 std::map<const Tracker*, int> Tracker::Locations;
583 bool Tracker::Print = false;
584 
585 //-----------------------------------------------------------------------------
586 //-----------------------------------------------------------------------------
587 // Data
588 
589 template <Flags f = 0, size_t pad = 0>
590 struct Data : DataTracker<(f & IS_RELOCATABLE) != 0>,
591  Counter,
592  DataTicker<f>,
593  Delete<f> {
594  static const Flags flags = f;
595  char spacehog[pad ? pad : 1];
596 
597  Data() = default;
598  Data(const Data&) = default;
599  Data(Data&&) = default;
600  /* implicit */ Data(int i)
601  : DataTracker<(f & IS_RELOCATABLE) != 0>(i),
602  Counter(),
603  DataTicker<f>(nullptr),
604  Delete<f>(nullptr) {}
605  ~Data() = default;
606  Data& operator=(const Data&) = default;
607  Data& operator=(Data&&) = default;
608 
609  private:
610  int operator&() const;
611 };
612 
613 namespace folly {
614 template <Flags f, size_t pad>
615 struct IsRelocatable<Data<f, pad>> : bool_constant<(f & IS_RELOCATABLE) != 0> {
616 };
617 } // namespace folly
618 
619 //-----------------------------------------------------------------------------
620 //-----------------------------------------------------------------------------
621 // Allocator
622 
623 template <typename T>
624 struct isPropCopy : true_type {};
625 template <Flags f, size_t pad>
626 struct isPropCopy<Data<f, pad>> : bool_constant<(f & PROP_COPY) != 0> {};
627 
628 template <typename T>
629 struct isPropMove : true_type {};
630 template <Flags f, size_t pad>
631 struct isPropMove<Data<f, pad>> : bool_constant<(f & PROP_MOVE) != 0> {};
632 
633 template <typename T>
634 struct isPropSwap : true_type {};
635 template <Flags f, size_t pad>
636 struct isPropSwap<Data<f, pad>> : bool_constant<(f & PROP_SWAP) != 0> {};
637 
638 struct AllocTracker {
639  static int Constructed;
640  static int Destroyed;
641  static map<void*, size_t> Allocated;
642  static map<void*, int> Owner;
643 };
646 map<void*, size_t> AllocTracker::Allocated;
647 map<void*, int> AllocTracker::Owner;
648 
649 template <class T>
651  typedef typename std::allocator<T>::pointer pointer;
652  typedef typename std::allocator<T>::const_pointer const_pointer;
653  typedef typename std::allocator<T>::difference_type difference_type;
654  typedef typename std::allocator<T>::size_type size_type;
655  typedef typename std::allocator<T>::value_type value_type;
656 
657  //-----
658  // impl
659 
660  std::allocator<T> a;
661  int id;
662  explicit Alloc(int i = 8) : a(), id(i) {}
663  Alloc(const Alloc& o) : a(o.a), id(o.id) {}
664  Alloc(Alloc&& o) noexcept : a(move(o.a)), id(o.id) {}
665  Alloc& operator=(const Alloc&) = default;
666  Alloc& operator=(Alloc&&) noexcept = default;
667  bool operator==(const Alloc& o) const {
668  return a == o.a && id == o.id;
669  }
670  bool operator!=(const Alloc& o) const {
671  return !(*this == o);
672  }
673 
674  //---------
675  // tracking
676 
677  pointer allocate(size_type n) {
678  if (n == 0) {
679  cerr << "called allocate(0)" << endl;
680  throw runtime_error("allocate fail");
681  }
682  Tick("allocate");
683  auto p = a.allocate(n);
684  Allocated[p] = n;
685  Owner[p] = id;
686  return p;
687  }
688 
689  void deallocate(pointer p, size_type n) {
690  if (p == nullptr) {
691  cerr << "deallocate(nullptr, " << n << ")" << endl;
692  FAIL() << "deallocate failed";
693  }
694  if (Allocated[p] != n) {
695  cerr << "deallocate(" << p << ", " << n << ") invalid: ";
696  if (Allocated[p] == 0) {
697  cerr << "never allocated";
698  } else if (Allocated[p] == size_t(-1)) {
699  cerr << "already deallocated";
700  } else {
701  cerr << "wrong number (want " << Allocated[p] << ")";
702  }
703  cerr << endl;
704  FAIL() << "deallocate failed";
705  }
706  if (Owner[p] != id) {
707  cerr << "deallocate(" << p << "), where pointer is owned by " << Owner[p]
708  << ", instead of self - " << id << endl;
709  FAIL() << "deallocate failed";
710  }
711  Allocated[p] = -1;
712  a.deallocate(p, n);
713  }
714 
715  template <class U, class... Args>
716  void construct(U* p, Args&&... args) {
717  Tick("construct");
718  a.construct(p, std::forward<Args>(args)...);
719  Constructed++;
720  }
721 
722  template <class U>
723  void destroy(U* p) {
724  Destroyed++;
725  a.destroy(p);
726  }
727 
728  //--------------
729  // container ops
730 
732  Tick("select allocator for copy");
733  return Alloc(id + 1);
734  }
735 
739 };
740 
741 //=============================================================================
742 //=============================================================================
743 // Verification and resetting
744 
745 void softReset(int ticks = -1) {
750  Counter::CountDestroy = Counter::CountTotalOps = 0;
751  Ticker::CountTicks = 0;
752  Ticker::TicksLeft = ticks;
753 }
754 
755 void hardReset() {
756  Tracker::UIDCount.clear();
757  Tracker::UIDTotal = 0;
758  Tracker::Locations.clear();
759  softReset();
761 
764  AllocTracker::Allocated.clear();
765  AllocTracker::Owner.clear();
766 }
767 
768 int getTotal() {
771  int del = Counter::CountDestroy;
772  return con - del;
773 }
774 
775 void isSane() {
776  int tot = getTotal();
777  ASSERT_GE(tot, 0) << "more objects deleted than constructed";
778 
780  << "UIDTotal has incorrect number of objects";
781 
782  int altTot = 0;
783  for (const auto& kv : Tracker::UIDCount) {
784  ASSERT_TRUE(kv.second >= 0) << "there exists " << kv.second
785  << " Data "
786  "with uid "
787  << kv.first;
788  altTot += kv.second;
789  }
790  ASSERT_EQ(tot, altTot) << "UIDCount corrupted";
791 
792  if (!Tracker::Locations.empty()) { // implied by IsRelocatable
793  ASSERT_EQ(tot, Tracker::Locations.size())
794  << "Locations has incorrect number of objects";
795  for (const auto& du : Tracker::Locations) {
796  ASSERT_EQ(du.second, du.first->uid) << "Locations contains wrong uid";
797  ASSERT_EQ(du.first, du.first->self) << "Data.self is corrupted";
798  }
799  }
800 }
801 
802 //-----------------------------------------------------------------------------
803 // Traits
804 
805 template <typename T>
807  : bool_constant<
808  std::is_copy_constructible<T>::value &&
809  std::is_copy_assignable<T>::value> {};
810 
811 template <typename T>
813  : bool_constant<
814  std::is_move_constructible<T>::value &&
815  std::is_move_assignable<T>::value> {};
816 
817 template <class Vector>
819  : bool_constant<!is_same<
820  typename Vector::allocator_type,
821  std::allocator<typename Vector::value_type>>::value> {};
822 
823 template <typename T>
825 template <Flags f, size_t pad>
827  : bool_constant<
828  is_move_constructibleAndAssignable<Data<f, pad>>::value ||
829  f & PROP_MOVE> {};
830 
831 //=============================================================================
832 //=============================================================================
833 // Framework
834 
835 //-----------------------------------------------------------------------------
836 // Timing
837 
839 #ifdef _MSC_VER
840  return __rdtsc();
841 #else
842  unsigned reslo, reshi;
843 
844  __asm__ __volatile__("xorl %%eax,%%eax \n cpuid \n" ::
845  : "%eax", "%ebx", "%ecx", "%edx");
846  __asm__ __volatile__("rdtsc\n" : "=a"(reslo), "=d"(reshi));
847  __asm__ __volatile__("xorl %%eax,%%eax \n cpuid \n" ::
848  : "%eax", "%ebx", "%ecx", "%edx");
849 
850  return ((uint64_t)reshi << 32) | reslo;
851 #endif
852 }
853 
854 //-----------------------------------------------------------------------------
855 // New Boost
856 
857 // clang-format off
858 #define IBOOST_PP_VARIADIC_SIZE(...) IBOOST_PP_VARIADIC_SIZE_I(__VA_ARGS__, \
859  64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, \
860  45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, \
861  26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, \
862  7, 6, 5, 4, 3, 2, 1,)
863 #define IBOOST_PP_VARIADIC_SIZE_I(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, \
864  e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, \
865  e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, \
866  e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, e50, e51, e52, e53, e54, \
867  e55, e56, e57, e58, e59, e60, e61, e62, e63, size, ...) size
868 // clang-format on
869 #define IBOOST_PP_VARIADIC_TO_SEQ(...) \
870  BOOST_PP_TUPLE_TO_SEQ(IBOOST_PP_VARIADIC_SIZE(__VA_ARGS__), (__VA_ARGS__))
871 
872 //-----------------------------------------------------------------------------
873 // STL_TEST
874 
875 #define GEN_TEST(r, name, type) \
876  { \
877  string atype = PrettyType<typename type::allocator_type>()(); \
878  string ptype = PrettyType<typename type::value_type>()(); \
879  SCOPED_TRACE("allocator: " + atype); \
880  { \
881  SCOPED_TRACE("datatype: " + ptype); \
882  { \
883  test_##name##3 < type > (); \
884  if (::testing::Test::HasFatalFailure()) \
885  return; \
886  } \
887  } \
888  }
889 #define GEN_TYPE_TEST(r, name, type) \
890  if (0) \
891  test_I_##name##3 < type > ();
892 #define GEN_RUNNABLE_TEST(r, name, type) \
893  one = test_I_##name##3 < type > () || one;
894 
895 #define GEN_LOOPER(r, d, arg) BOOST_PP_CAT(LOOPER_, arg)
896 #define GEN_VMAKER(r, d, arg) \
897  { \
898  BOOST_PP_CAT(VMAKER_, arg) {
899 #define GEN_UMAKER(r, d, arg) \
900  } \
901  BOOST_PP_CAT(UMAKER_, arg) \
902  }
903 #define GEN_CLOSER(r, d, arg) BOOST_PP_CAT(CLOSER_, arg)
904 
905 #define TYPIFY(r, d, name) BOOST_PP_CAT(TYPIFY_, name)
906 #define ARGIFY(r, d, name) TYPIFY(r, d, name) name
907 
908 // clang-format off
909 #define MAKE_TEST(ref, name, types, restriction, argseq, ...) \
910  template <class Vector> void test_ ## name ## 2 (std::false_type) {} \
911  template <class Vector> void test_ ## name ## 2 (std::true_type) { \
912  BOOST_PP_SEQ_FOR_EACH(GEN_LOOPER, _, argseq) \
913  { \
914  SETUP \
915  { \
916  BOOST_PP_SEQ_FOR_EACH(GEN_VMAKER, _, argseq) \
917  { \
918  test_ ## name <Vector, typename Vector::value_type, \
919  typename Vector::allocator_type> ( __VA_ARGS__ ); \
920  if (::testing::Test::HasFatalFailure()) { \
921  return; \
922  } \
923  } \
924  BOOST_PP_SEQ_FOR_EACH(GEN_UMAKER, _, BOOST_PP_SEQ_REVERSE(argseq)) \
925  } \
926  TEARDOWN \
927  } \
928  BOOST_PP_SEQ_FOR_EACH(GEN_CLOSER, _, BOOST_PP_SEQ_REVERSE(argseq)) \
929  } \
930  template <class Vector> void test_ ## name ## 3 () { \
931  test_ ## name ## 2 <Vector> (bool_constant< \
932  restriction<typename Vector::value_type>::value && \
933  is_copy_constructible<typename Vector::value_type>::value \
934  >()); \
935  } \
936  \
937  template <class Vector> bool test_I_ ## name ## 2 (std::false_type) \
938  { return false; } \
939  template <class Vector> bool test_I_ ## name ## 2 (std::true_type) { \
940  return true; \
941  auto f = test_ ## name <Vector, \
942  typename Vector::value_type, typename Vector::allocator_type>; \
943  (void)f; \
944  return true; \
945  } \
946  template <class Vector> bool test_I_ ## name ## 3 () { \
947  return test_I_ ## name ## 2 <Vector> (bool_constant< \
948  restriction<typename Vector::value_type>::value>()); \
949  return false; \
950  } \
951  \
952  TEST(FBVector, name) { \
953  SCOPED_TRACE("N3337 reference: " ref); \
954  BOOST_PP_SEQ_FOR_EACH(GEN_TEST, name, types) \
955  BOOST_PP_SEQ_FOR_EACH(GEN_TYPE_TEST, name, INTERFACE_TYPES) \
956  bool one = false; \
957  BOOST_PP_SEQ_FOR_EACH(GEN_RUNNABLE_TEST, name, types) \
958  if (!one) { \
959  FAIL() << "No tests qualified to run"; \
960  } \
961  }
962 // clang-format on
963 
964 #define DECL(name, ...) \
965  template <class Vector, typename T, typename Allocator> \
966  void test_##name(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \
967  ARGIFY, _, IBOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))))
968 
969 #define STL_TEST_I(ref, name, restriction, ...) \
970  DECL(name, __VA_ARGS__); \
971  MAKE_TEST( \
972  ref, \
973  name, \
974  TEST_TYPES, \
975  restriction, \
976  IBOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__), \
977  __VA_ARGS__) \
978  DECL(name, __VA_ARGS__)
979 
980 #define STL_TEST(ref, name, restriction, ...) \
981  STL_TEST_I(ref, name, restriction, z, ##__VA_ARGS__, ticks)
982 
983 //-----------------------------------------------------------------------------
984 // Test Types
985 
986 typedef Data<> ED1;
991 
992 typedef VECTOR_<int, std::allocator<int>> _TVIS;
993 typedef VECTOR_<int, Alloc<int>> _TVI;
994 typedef VECTOR_<ED1, std::allocator<ED1>> _TV1;
995 typedef VECTOR_<ED2, std::allocator<ED2>> _TV2;
996 typedef VECTOR_<ED3, std::allocator<ED3>> _TV3;
997 typedef VECTOR_<ED4, std::allocator<ED4>> _TV4;
998 typedef VECTOR_<ED5, std::allocator<ED5>> _TV5v1;
999 typedef VECTOR_<ED5, Alloc<ED5>> _TV5;
1000 
1004 
1005 typedef VECTOR_<EP1, Alloc<EP1>> _TP1;
1006 typedef VECTOR_<EP2, Alloc<EP2>> _TP2;
1007 typedef VECTOR_<EP3, Alloc<EP3>> _TP3;
1008 
1009 #define TEST_TYPES \
1010  (_TVIS)(_TVI)(_TV1)(_TV2)(_TV3)(_TV4)(_TV5v1)(_TV5)(_TP1)(_TP2)(_TP3)
1011 
1012 typedef Data<ALL_DELETE> DD1; // unoperable
1014 typedef Data<CA_DELETE | MA_DELETE> DD3; // unassignable
1015 typedef Data<CC_DELETE | MC_DELETE> DD4; // uncopyable
1016 typedef Data<ALL_DELETE & ~DC_DELETE> DD5; // only default constructible
1017 typedef Data<CC_DELETE> DD6; // move-only copy construction
1018 typedef Data<CA_DELETE> DD7; // move-only assignment
1019 
1021 typedef VECTOR_<DDSMA, Alloc<DDSMA>> _TSpecialMA;
1022 
1023 // clang-format off
1024 #define INTERFACE_TYPES \
1025  (_TVI)(VECTOR_<DD1>)(VECTOR_<DD2>)(VECTOR_<DD3>) \
1026  (VECTOR_<DD4>)(VECTOR_<DD5>)(VECTOR_<DD6>) \
1027  (VECTOR_<DD7>)(_TSpecialMA)
1028 // clang-format on
1029 
1030 //-----------------------------------------------------------------------------
1031 // Pretty printers
1032 
1033 template <typename T>
1034 struct PrettyType {
1035  string operator()() {
1036  if (is_same<T, int>::value) {
1037  return "int";
1038  }
1040  return "char";
1041  }
1043  return "uint64_t";
1044  }
1045  return typeid(T).name();
1046  }
1047 };
1048 
1049 template <Flags f, size_t pad>
1050 struct PrettyType<Data<f, pad>> {
1051  string operator()() {
1052  stringstream tpe;
1053  tpe << "Data";
1054 
1055  if ((f & DC_DELETE) || (f & CC_DELETE) || (f & MC_DELETE) ||
1056  (f & CA_DELETE) || (f & MA_DELETE)) {
1057  tpe << "[^";
1058  if (f & DC_DELETE) {
1059  tpe << " DC,";
1060  }
1061  if (f & CC_DELETE) {
1062  tpe << " CC,";
1063  }
1064  if (f & MC_DELETE) {
1065  tpe << " MC,";
1066  }
1067  if (f & CA_DELETE) {
1068  tpe << " CA,";
1069  }
1070  if (f & MA_DELETE) {
1071  tpe << " MA,";
1072  }
1073  tpe << "]";
1074  }
1075 
1076  if ((f & DC_NOEXCEPT) || (f & CC_NOEXCEPT) || (f & MC_NOEXCEPT) ||
1077  (f & CA_NOEXCEPT) || (f & MA_NOEXCEPT)) {
1078  tpe << "[safe";
1079  if (f & DC_NOEXCEPT) {
1080  tpe << " DC,";
1081  }
1082  if (f & CC_NOEXCEPT) {
1083  tpe << " CC,";
1084  }
1085  if (f & MC_NOEXCEPT) {
1086  tpe << " MC,";
1087  }
1088  if (f & CA_NOEXCEPT) {
1089  tpe << " CA,";
1090  }
1091  if (f & MA_NOEXCEPT) {
1092  tpe << " MA,";
1093  }
1094  tpe << "]";
1095  }
1096 
1097  if (f & IS_RELOCATABLE) {
1098  tpe << "(relocatable)";
1099  }
1100 
1101  if (pad != 0) {
1102  tpe << "{pad " << pad << "}";
1103  }
1104 
1105  return tpe.str();
1106  }
1107 };
1108 
1109 template <typename T>
1110 struct PrettyType<std::allocator<T>> {
1111  string operator()() {
1112  return "std::allocator<" + PrettyType<T>()() + ">";
1113  }
1114 };
1115 
1116 template <typename T>
1117 struct PrettyType<Alloc<T>> {
1118  string operator()() {
1119  return "Alloc<" + PrettyType<T>()() + ">";
1120  }
1121 };
1122 
1123 //-----------------------------------------------------------------------------
1124 // Setup, teardown, runup, rundown
1125 
1126 // These four macros are run once per test. Setup and runup occur before the
1127 // test, teardown and rundown after. Setup and runup straddle the
1128 // initialization sequence, whereas rundown and teardown straddle the
1129 // cleanup.
1130 
1131 #define SETUP hardReset();
1132 #define TEARDOWN
1133 
1134 //-----------------------------------------------------------------------------
1135 // Types and typegens
1136 
1137 //------
1138 // dummy
1139 
1140 #define TYPIFY_z std::nullptr_t
1141 #define LOOPER_z \
1142  Vector* a_p = nullptr; \
1143  Vector* b_p = nullptr; \
1144  typename Vector::value_type* t_p = nullptr;
1145 #define VMAKER_z std::nullptr_t z = nullptr;
1146 #define UMAKER_z \
1147  verify<Vector>(0); \
1148  if (::testing::Test::HasFatalFailure()) { \
1149  return; \
1150  }
1151 #define CLOSER_z
1152 
1153 //------
1154 // ticks
1155 
1156 #define VERIFICATION \
1157  if (b_p != nullptr) \
1158  verify(t_p != nullptr, *a_p, *b_p); \
1159  else if (a_p != nullptr) \
1160  verify(t_p != nullptr, *a_p); \
1161  else \
1162  verify<Vector>(t_p != nullptr); \
1163  if (::testing::Test::HasFatalFailure()) \
1164  return;
1165 
1166 #define TYPIFY_ticks int
1167 #define LOOPER_ticks \
1168  int _maxTicks_ = 0; \
1169  bool ticks_thrown = false; \
1170  for (int ticks = -1; ticks < _maxTicks_; ++ticks) {
1171 #define VMAKER_ticks \
1172  string ticks_st = folly::to<string>("ticks = ", ticks); \
1173  SCOPED_TRACE(ticks_st); \
1174  { \
1175  SCOPED_TRACE("pre-run verification"); \
1176  VERIFICATION \
1177  } \
1178  try { \
1179  softReset(ticks);
1180 #define UMAKER_ticks \
1181  _maxTicks_ = Ticker::CountTicks; \
1182  } \
1183  catch (const TickException&) { \
1184  ticks_thrown = true; \
1185  } \
1186  catch (const std::exception& e) { \
1187  FAIL() << "EXCEPTION: " << e.what(); \
1188  } \
1189  catch (...) { \
1190  FAIL() << "UNKNOWN EXCEPTION"; \
1191  } \
1192  if (ticks >= 0 && Ticker::CountTicks > ticks && !ticks_thrown) \
1193  FAIL() << "CountTicks = " << Ticker::CountTicks << " > " << ticks \
1194  << " = ticks" \
1195  << ", but no tick error was observed"; \
1196  VERIFICATION
1197 #define CLOSER_ticks }
1198 
1199 //--------------------------------------------------
1200 // vectors (second could be .equal, ==, or distinct)
1201 
1202 static const vector<pair<int, int>> VectorSizes = {
1203  {0, -1},
1204  {1, -1},
1205  {2, -1},
1206  {10, -1},
1207  {10, 1},
1208  {10, 0},
1209 #if !FOLLY_SANITIZE_ADDRESS
1210  {100, -1},
1211  {100, 1},
1212 #endif
1213 
1214 #if 0
1215  {10, -1},
1216  {10, 0},
1217  {10, 1},
1218  {10, 2},
1219  {10, 10},
1220  {100, -1},
1221  {100, 0},
1222  {100, 1},
1223  {100, 2},
1224  {100, 10},
1225  {100, 100},
1226  {1000, -1},
1227  {1000, 0},
1228  {1000, 1},
1229  {1000, 2},
1230  {1000, 10},
1231  {1000, 100},
1232  {1000, 1000},
1233 #endif
1234 };
1235 
1236 int populateIndex = 1426;
1237 template <class Vector>
1238 void populate(Vector& v, const pair<int, int>& ss) {
1239  int i = 0;
1240  for (; i < ss.first; ++i) {
1241  v.emplace_back(populateIndex++);
1242  }
1243  if (ss.second >= 0) {
1244  while (v.capacity() - v.size() != size_t(ss.second)) {
1245  v.emplace_back(populateIndex++);
1246  }
1247  }
1248 }
1249 
1250 template <typename A>
1251 struct allocGen {
1252  static A get() {
1253  return A();
1254  }
1255 };
1256 template <typename T>
1257 struct allocGen<Alloc<T>> {
1258  static Alloc<T> get() {
1259  static int c = 0;
1260  c += 854;
1261  return Alloc<T>(c);
1262  }
1263 };
1264 
1265 #define TYPIFY_a Vector&
1266 #define LOOPER_a for (const auto& a_ss : VectorSizes) {
1267 #define VMAKER_a \
1268  Vector a(allocGen<typename Vector::allocator_type>::get()); \
1269  a_p = &a; \
1270  populate(*a_p, a_ss); \
1271  string a_st = folly::to<string>("a (", a.size(), "/", a.capacity(), ")"); \
1272  SCOPED_TRACE(a_st);
1273 #define UMAKER_a \
1274  verify(0, a); \
1275  if (::testing::Test::HasFatalFailure()) \
1276  return;
1277 #define CLOSER_a }
1278 
1279 #define TYPIFY_b Vector&
1280 #define LOOPER_b for (int b_i = -2; b_i < (int)VectorSizes.size(); ++b_i) {
1281 #define VMAKER_b \
1282  Vector b_s(allocGen<typename Vector::allocator_type>::get()); \
1283  b_p = &b_s; \
1284  string b_st; \
1285  if (b_i == -2) { \
1286  b_p = &a; \
1287  b_st = "b is an alias of a"; \
1288  } else if (b_i == -1) { \
1289  b_s.~Vector(); \
1290  new (&b_s) Vector(a); \
1291  b_st = "b is a deep copy of a"; \
1292  } else { \
1293  populate(b_s, VectorSizes[b_i]); \
1294  b_st = folly::to<string>("b (", b_s.size(), "/", b_s.capacity(), ")"); \
1295  } \
1296  Vector& b = *b_p; \
1297  SCOPED_TRACE(b_st);
1298 #define UMAKER_b \
1299  verify(0, a, b); \
1300  if (::testing::Test::HasFatalFailure()) \
1301  return;
1302 #define CLOSER_b }
1303 
1304 //----
1305 // int
1306 
1307 static const vector<int> nSizes = {0, 1, 2, 9, 10, 11};
1308 
1309 #define TYPIFY_n int
1310 #define LOOPER_n for (int n : nSizes) {
1311 #define VMAKER_n \
1312  string n_st = folly::to<string>("n = ", n); \
1313  SCOPED_TRACE(n_st);
1314 #define UMAKER_n
1315 #define CLOSER_n }
1316 
1317 //-----------------------
1318 // non-internal iterators
1319 
1320 static int ijarr[12] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89};
1321 static int ijarC[12] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89};
1322 
1323 #define TYPIFY_i int*
1324 #define LOOPER_i
1325 #define VMAKER_i \
1326  int* i = ijarr; \
1327  SCOPED_TRACE("i = fib[0]");
1328 #define UMAKER_i
1329 #define CLOSER_i
1330 
1331 #define TYPIFY_j int*
1332 #define LOOPER_j for (int j_i = 0; j_i < 12; ++j_i) {
1333 #define VMAKER_j \
1334  int* j = ijarr + j_i; \
1335  string j_st = folly::to<string>("j = fib[", j_i, "]"); \
1336  SCOPED_TRACE(j_st);
1337 #define UMAKER_j \
1338  for (int j_c = 0; j_c < 12; ++j_c) \
1339  ASSERT_EQ(ijarC[j_c], ijarr[j_c]);
1340 #define CLOSER_j }
1341 
1342 //-------------------
1343 // internal iterators
1344 
1345 template <class Vector>
1346 std::pair<typename Vector::iterator, string> iterSpotter(Vector& v, int i) {
1347  typename Vector::iterator it;
1348  string msg;
1349 
1350  switch (i) {
1351  case 1:
1352  if (!v.empty()) {
1353  it = v.begin();
1354  ++it;
1355  msg = "a[1]";
1356  break;
1357  }
1359  case 0:
1360  it = v.begin();
1361  msg = "a.begin";
1362  break;
1363 
1364  case 2:
1365  if (!v.empty()) {
1366  it = v.end();
1367  --it;
1368  msg = "a[-1]";
1369  break;
1370  }
1372  case 3:
1373  it = v.end();
1374  msg = "a.end";
1375  break;
1376 
1377  default:
1378  cerr << "internal error" << endl;
1379  exit(1);
1380  }
1381 
1382  return make_pair(it, msg);
1383 }
1384 
1385 #define TYPIFY_p typename Vector::iterator
1386 #define LOOPER_p for (int p_i = 0; p_i < 4; ++p_i) {
1387 #define VMAKER_p \
1388  auto p_im = iterSpotter(a, p_i); \
1389  auto& p = p_im.first; \
1390  auto& p_m = p_im.second; \
1391  SCOPED_TRACE("p = " + p_m);
1392 #define UMAKER_p
1393 #define CLOSER_p }
1394 
1395 #define TYPIFY_q typename Vector::iterator
1396 #define LOOPER_q for (int q_i = p_i; q_i < 4; ++q_i) {
1397 #define VMAKER_q \
1398  auto q_im = iterSpotter(a, q_i); \
1399  auto& q = q_im.first; \
1400  auto& q_m = q_im.second; \
1401  SCOPED_TRACE("q = " + q_m);
1402 #define UMAKER_q
1403 #define CLOSER_q }
1404 
1405 //---------
1406 // datatype
1407 
1408 static const vector<int> tVals = {0, 1, 2, 3, 17, 66, 521};
1409 
1410 #define TYPIFY_t typename Vector::value_type&
1411 #define LOOPER_t for (int t_v : tVals) {
1412 #define VMAKER_t \
1413  typename Vector::value_type t_s(t_v); \
1414  t_p = addressof(t_s); \
1415  string t_st = folly::to<string>("t(", t_v, ")"); \
1416  if (t_v < 4 && a_p != nullptr) { \
1417  auto t_im = iterSpotter(*a_p, t_v); \
1418  if (t_im.first != a_p->end()) { \
1419  t_p = addressof(*t_im.first); \
1420  t_st = "t is " + t_im.second; \
1421  } \
1422  } \
1423  typename Vector::value_type& t = *t_p; \
1424  SCOPED_TRACE(t_st);
1425 #define UMAKER_t
1426 #define CLOSER_t }
1427 
1428 //----------
1429 // allocator
1430 
1431 #define TYPIFY_m typename Vector::allocator_type
1432 #define LOOPER_m \
1433  int m_max = 1 + (a_p != nullptr); \
1434  for (int m_i = 0; m_i < m_max; ++m_i) {
1435 #define VMAKER_m \
1436  typename Vector::allocator_type m = \
1437  m_i == 0 ? typename Vector::allocator_type() : a_p->get_allocator();
1438 #define UMAKER_m
1439 #define CLOSER_m }
1440 
1441 //-----------------------------------------------------------------------------
1442 // Verifiers
1443 
1444 // verify a vector
1445 template <class Vector>
1446 void verifyVector(const Vector& v) {
1447  ASSERT_TRUE(v.begin() <= v.end()) << "end is before begin";
1448  ASSERT_TRUE(v.empty() == (v.begin() == v.end())) << "empty != (begin == end)";
1449  ASSERT_TRUE(v.size() == size_t(distance(v.begin(), v.end())))
1450  << "size != end - begin";
1451  ASSERT_TRUE(v.size() <= v.capacity()) << "size > capacity";
1452  ASSERT_TRUE(v.capacity() <= v.max_size()) << "capacity > max_size";
1453  ASSERT_TRUE(v.data() || true); // message won't print - it will just crash
1454  ASSERT_TRUE(v.size() == 0 || v.data() != nullptr)
1455  << "nullptr data points to at least one element";
1456 }
1457 
1458 void verifyAllocator(int ele, int cap) {
1460 
1461  int tot = 0;
1462  for (auto kv : AllocTracker::Allocated) {
1463  if (kv.second != size_t(-1)) {
1464  tot += kv.second;
1465  }
1466  }
1467  ASSERT_EQ(cap, tot) << "the allocator counts " << tot
1468  << " space, "
1469  "but the vector(s) have (combined) capacity "
1470  << cap;
1471 }
1472 
1473 // Master verifier
1474 template <class Vector>
1475 void verify(int extras) {
1477  ASSERT_EQ(0 + extras, getTotal()) << "there exist Data but no vectors";
1478  }
1479  isSane();
1481  return;
1482  }
1484  verifyAllocator(0, 0);
1485  }
1486 }
1487 template <class Vector>
1488 void verify(int extras, const Vector& v) {
1489  verifyVector(v);
1491  ASSERT_EQ(v.size() + extras, getTotal())
1492  << "not all Data are in the vector";
1493  }
1494  isSane();
1496  return;
1497  }
1499  verifyAllocator(v.size(), v.capacity());
1500  }
1501 }
1502 template <class Vector>
1503 void verify(int extras, const Vector& v1, const Vector& v2) {
1504  verifyVector(v1);
1505  verifyVector(v2);
1506  auto size = v1.size();
1507  auto cap = v1.capacity();
1508  if (&v1 != &v2) {
1509  size += v2.size();
1510  cap += v2.capacity();
1511  }
1513  ASSERT_EQ(size + extras, getTotal()) << "not all Data are in the vector(s)";
1514  }
1515  isSane();
1517  return;
1518  }
1520  verifyAllocator(size, cap);
1521  }
1522 }
1523 
1524 //=============================================================================
1525 // Helpers
1526 
1527 // save the state of a vector
1528 int convertToInt(int t) {
1529  return t;
1530 }
1531 template <Flags f, size_t pad>
1533  return t.uid;
1534 }
1535 template <typename T>
1536 int convertToInt(const std::allocator<T>&) {
1537  return -1;
1538 }
1539 template <typename T>
1540 int convertToInt(const Alloc<T>& a) {
1541  return a.id;
1542 }
1543 
1544 template <class Vector>
1545 class DataState {
1546  typedef typename Vector::size_type size_type;
1547  size_type size_;
1548  int* data_;
1549 
1550  public:
1551  /* implicit */ DataState(const Vector& v) {
1552  size_ = v.size();
1553  if (size_ != 0) {
1554  data_ = new int[size_];
1555  for (size_type i = 0; i < size_; ++i) {
1556  data_[i] = convertToInt(v.data()[i]);
1557  }
1558  } else {
1559  data_ = nullptr;
1560  }
1561  }
1563  delete[] data_;
1564  }
1565 
1566  bool operator==(const DataState& o) const {
1567  if (size_ != o.size_) {
1568  return false;
1569  }
1570  for (size_type i = 0; i < size_; ++i) {
1571  if (data_[i] != o.data_[i]) {
1572  return false;
1573  }
1574  }
1575  return true;
1576  }
1577 
1578  int operator[](size_type i) {
1579  if (i >= size_) {
1580  cerr << "trying to access DataState out of bounds" << endl;
1581  exit(1);
1582  }
1583  return data_[i];
1584  }
1585 
1586  size_type size() {
1587  return size_;
1588  }
1589 };
1590 
1591 // downgrade iterators
1592 template <typename It, class tag>
1593 class Transformer : public boost::iterator_adaptor<
1594  Transformer<It, tag>,
1595  It,
1596  typename iterator_traits<It>::value_type,
1597  tag> {
1598  friend class boost::iterator_core_access;
1599  shared_ptr<set<It>> dereferenced;
1600 
1601  public:
1602  explicit Transformer(const It& it)
1603  : Transformer::iterator_adaptor_(it), dereferenced(new set<It>()) {}
1604 
1605  typename iterator_traits<It>::value_type& dereference() const {
1606  if (dereferenced->find(this->base_reference()) != dereferenced->end()) {
1607  cerr << "iterator dereferenced more than once" << endl;
1608  exit(1);
1609  }
1610  dereferenced->insert(this->base_reference());
1611  return *this->base_reference();
1612  }
1613 };
1614 
1615 template <typename It>
1618 }
1619 template <typename It>
1622 }
1623 
1624 // mutate a value (in contract only)
1625 void mutate(int& i) {
1626  if ((false)) {
1627  i = 0;
1628  }
1629 }
1631  if ((false)) {
1632  i = 0;
1633  }
1634 }
1635 template <Flags f, size_t pad>
1637  if ((false)) {
1638  ds.uid = 0;
1639  }
1640 }
1641 
1642 //=============================================================================
1643 // Tests
1644 
1645 // #if 0
1646 
1647 // #else
1648 
1649 //-----------------------------------------------------------------------------
1650 // Container
1651 
1652 STL_TEST("23.2.1 Table 96.1-7", containerTypedefs, is_destructible) {
1653  static_assert(
1655  "T != Vector::value_type");
1656  static_assert(
1658  "T& != Vector::reference");
1659  static_assert(
1661  "const T& != Vector::const_reference");
1662  static_assert(
1663  is_convertible<
1664  typename iterator_traits<
1665  typename Vector::iterator>::iterator_category,
1666  forward_iterator_tag>::value,
1667  "Vector::iterator is not a forward iterator");
1668  static_assert(
1669  is_same<
1670  T,
1671  typename iterator_traits<typename Vector::iterator>::value_type>::
1672  value,
1673  "Vector::iterator does not iterate over type T");
1674  static_assert(
1675  is_convertible<
1676  typename iterator_traits<
1677  typename Vector::const_iterator>::iterator_category,
1678  forward_iterator_tag>::value,
1679  "Vector::const_iterator is not a forward iterator");
1680  static_assert(
1681  is_same<
1682  T,
1683  typename iterator_traits<
1684  typename Vector::const_iterator>::value_type>::value,
1685  "Vector::const_iterator does not iterate over type T");
1686  static_assert(
1687  is_convertible<
1688  typename Vector::iterator,
1689  typename Vector::const_iterator>::value,
1690  "Vector::iterator is not convertible to Vector::const_iterator");
1691  static_assert(
1693  "Vector::difference_type is not signed");
1694  static_assert(
1695  is_same<
1696  typename Vector::difference_type,
1697  typename iterator_traits<
1698  typename Vector::iterator>::difference_type>::value,
1699  "Vector::difference_type != Vector::iterator::difference_type");
1700  static_assert(
1701  is_same<
1702  typename Vector::difference_type,
1703  typename iterator_traits<
1704  typename Vector::const_iterator>::difference_type>::value,
1705  "Vector::difference_type != Vector::const_iterator::difference_type");
1706  static_assert(
1708  "Vector::size_type is not unsigned");
1709  static_assert(
1710  sizeof(typename Vector::size_type) >=
1711  sizeof(typename Vector::difference_type),
1712  "Vector::size_type is smaller than Vector::difference_type");
1713 }
1714 
1715 STL_TEST("23.2.1 Table 96.8-9", emptyConstruction, is_destructible) {
1716  Vector u;
1717 
1718  ASSERT_TRUE(u.get_allocator() == Allocator());
1720 
1721  ASSERT_TRUE(u.empty()) << u.size();
1722  ASSERT_EQ(0, u.capacity());
1723 
1724  if (false) {
1725  Vector();
1726  }
1727 }
1728 
1729 STL_TEST("framework", populate, is_copy_constructible) {
1730  // We use emplace_back to construct vectors for testing, as well as size,
1731  // data, and capacity. We make sure these work before proceeding with tests.
1732 
1733  Vector u;
1734  ASSERT_EQ(0, u.size());
1735  ASSERT_EQ(nullptr, u.data());
1736 
1737  u.emplace_back(17);
1738  ASSERT_EQ(1, u.size());
1739  ASSERT_LT(u.capacity(), 100)
1740  << "single push_back increased capacity to " << u.capacity();
1741  ASSERT_NE(nullptr, u.data());
1742  ASSERT_EQ(17, convertToInt(u.data()[0]))
1743  << "first object did not get emplaced correctly";
1744 
1745  for (int i = 0; i < 3; ++i) {
1746  auto cap = u.capacity();
1747  while (u.size() < cap) {
1748  u.emplace_back(22);
1749  ASSERT_EQ(cap, u.capacity()) << "Vector grew when it did not need to";
1750  ASSERT_EQ(22, convertToInt(u.data()[u.size() - 1]))
1751  << "push_back with excess capacity failed";
1752  }
1753 
1754  ASSERT_EQ(cap, u.size());
1755 
1756  u.emplace_back(4);
1757  ASSERT_GT(u.capacity(), cap) << "capacity did not grow on overflow";
1758  ASSERT_EQ(cap + 1, u.size());
1759  ASSERT_EQ(4, convertToInt(u.data()[u.size() - 1]))
1760  << "grow object did not get emplaced correctly";
1761  }
1762 }
1763 
1764 STL_TEST("23.2.1 Table 96.10-11", copyConstruction, is_copy_constructible, a) {
1765  const auto& ca = a;
1766  DataState<Vector> dsa(ca);
1767  auto am = a.get_allocator();
1768 
1769  Vector u(ca);
1770 
1771  ASSERT_TRUE(
1772  std::allocator_traits<Allocator>::select_on_container_copy_construction(
1773  am) == u.get_allocator());
1774  ASSERT_TRUE(dsa == u);
1775  ASSERT_TRUE(
1776  (ca.data() == nullptr && u.data() == nullptr) || (ca.data() != u.data()))
1777  << "only a shallow copy was made";
1778 
1779  if (false) {
1780  Vector(ca2);
1781  Vector u2 = ca2;
1782  }
1783 }
1784 
1785 STL_TEST("23.2.1 Table 96.12", moveConstruction, is_destructible, a) {
1786  DataState<Vector> dsa(a);
1787  auto m = a.get_allocator();
1788 
1789  Vector u(move(a));
1790 
1791  ASSERT_TRUE(m == u.get_allocator());
1793 
1794  ASSERT_TRUE(dsa == u);
1795 
1796  if (false) {
1797  Vector u2 = move(a);
1798  }
1799 }
1800 
1801 STL_TEST("23.2.1 Table 96.13", moveAssignment, special_move_assignable, a, b) {
1802  DataState<Vector> dsb(b);
1803  auto am = a.get_allocator();
1804  auto bm = b.get_allocator();
1805 
1806  Vector& ret = a = std::move(b);
1807 
1808  if (std::allocator_traits<
1810  ASSERT_TRUE(bm == a.get_allocator());
1811  } else {
1812  ASSERT_TRUE(am == a.get_allocator());
1813  }
1814  ASSERT_TRUE(&ret == &a);
1815  ASSERT_TRUE(&a == &b || dsb == a) << "move assignment did not create a copy";
1816  // The source of the move may be left in any (albeit valid) state.
1817 }
1818 
1819 STL_TEST("23.2.1 Table 96.14", destructible, is_destructible) {
1820  // The test generators check this clause already.
1821 }
1822 
1823 STL_TEST("23.2.1 Table 96.15-18", iterators, is_destructible, a) {
1824  DataState<Vector> dsa(a);
1825  const auto& ca = a;
1826 
1827  auto itb = a.begin();
1828  auto citb = ca.begin();
1829  auto Citb = a.cbegin();
1830  auto ite = a.end();
1831  auto cite = ca.end();
1832  auto Cite = a.cend();
1833 
1835 
1836  ASSERT_TRUE(dsa == a) << "call to begin or end modified internal data";
1837 
1838  ASSERT_TRUE(citb == Citb) << "cv.begin != v.cbegin";
1839  ASSERT_TRUE(cite == Cite) << "cv.end != v.cend";
1840 
1841  if (ca.size() == 0) {
1842  ASSERT_TRUE(itb == ite) << "begin != end when empty";
1843  ASSERT_TRUE(Citb == Cite) << "cbegin != cend when empty";
1844  } else {
1845  ASSERT_TRUE(itb != ite) << "begin == end when non-empty";
1846  ASSERT_TRUE(Citb != Cite) << "cbegin == cend when non-empty";
1847  }
1848 
1849  auto dist = size_t(std::distance(itb, ite));
1850  auto Cdist = size_t(std::distance(Citb, Cite));
1851  ASSERT_TRUE(dist == ca.size()) << "distance(begin, end) != size";
1852  ASSERT_TRUE(Cdist == ca.size()) << "distance(cbegin, cend) != size";
1853 }
1854 
1855 STL_TEST("23.2.1 Table 96.19-20", equitable, is_arithmetic, a, b) {
1856  const auto& ca = a;
1857  const auto& cb = b;
1858  DataState<Vector> dsa(a);
1859  DataState<Vector> dsb(b);
1860 
1861  ASSERT_TRUE((bool)(ca == cb) == (bool)(dsa == dsb))
1862  << "== does not return equality";
1863  ASSERT_TRUE((bool)(ca == cb) != (bool)(ca != cb))
1864  << "!= is not the opposite of ==";
1865 
1866  // Data is uncomparable, by design; therefore this test's restriction
1867  // is 'is_arithmetic'
1868 }
1869 
1870 STL_TEST("23.2.1 Table 96.21", memberSwappable, is_destructible, a, b) {
1872  convertToInt(a.get_allocator()) != convertToInt(b.get_allocator())) {
1873  // undefined behaviour
1874  return;
1875  }
1876 
1877  DataState<Vector> dsa(a);
1878  DataState<Vector> dsb(b);
1879  auto adata = a.data();
1880  auto bdata = b.data();
1881  auto am = a.get_allocator();
1882  auto bm = b.get_allocator();
1883 
1884  try {
1885  a.swap(b);
1886  } catch (...) {
1887  FAIL() << "swap is noexcept";
1888  }
1889 
1891  ASSERT_TRUE(bm == a.get_allocator());
1892  ASSERT_TRUE(am == b.get_allocator());
1893  } else {
1894  ASSERT_TRUE(am == a.get_allocator());
1895  ASSERT_TRUE(bm == b.get_allocator());
1896  }
1898 
1899  ASSERT_TRUE(adata == b.data() && bdata == a.data());
1900  ASSERT_TRUE(dsa == b && dsb == a) << "swap did not swap";
1901 }
1902 
1903 STL_TEST("23.2.1 Table 96.22", nonmemberSwappable, is_destructible, a, b) {
1905  convertToInt(a.get_allocator()) != convertToInt(b.get_allocator())) {
1906  // undefined behaviour
1907  return;
1908  }
1909 
1910  DataState<Vector> dsa(a);
1911  DataState<Vector> dsb(b);
1912  auto adata = a.data();
1913  auto bdata = b.data();
1914  auto am = a.get_allocator();
1915  auto bm = b.get_allocator();
1916 
1917  try {
1918  swap(a, b);
1919  } catch (...) {
1920  FAIL() << "swap is noexcept";
1921  }
1922 
1924  ASSERT_TRUE(bm == a.get_allocator());
1925  ASSERT_TRUE(am == b.get_allocator());
1926  } else {
1927  ASSERT_TRUE(am == a.get_allocator());
1928  ASSERT_TRUE(bm == b.get_allocator());
1929  }
1931 
1932  ASSERT_TRUE(adata == b.data() && bdata == a.data());
1933  ASSERT_TRUE(dsa == b && dsb == a) << "swap did not swap";
1934 }
1935 
1936 STL_TEST(
1937  "23.2.1 Table 96.23",
1938  copyAssign,
1940  a,
1941  b) {
1942  // it is possible to make use of just the copy constructor.
1943 
1944 #ifdef USING_STD_VECTOR
1945  if (std::allocator_traits<
1947  convertToInt(a.get_allocator()) != convertToInt(b.get_allocator())) {
1948  // Bug. By the looks of things, in the above case, their bez is being
1949  // cleared and deallocated, but then the garbage pointers are being used.
1950  return;
1951  }
1952 #endif
1953 
1954  const auto& cb = b;
1955  DataState<Vector> dsb(cb);
1956  auto am = a.get_allocator();
1957  auto bm = b.get_allocator();
1958 
1959  Vector& ret = a = cb;
1960 
1961  if (std::allocator_traits<
1963  ASSERT_TRUE(bm == a.get_allocator());
1964  } else {
1965  ASSERT_TRUE(am == a.get_allocator());
1966  }
1967  ASSERT_TRUE(&ret == &a);
1968  ASSERT_TRUE(dsb == a) << "copy-assign not equal to original";
1969 }
1970 
1971 STL_TEST("23.2.1 Table 96.24-26", sizeops, is_destructible) {
1972  // This check generators check this clause already.
1973 }
1974 
1975 //-----------------------------------------------------------------------------
1976 // Reversible container
1977 
1978 STL_TEST("23.2.1 Table 97.1-2", reversibleContainerTypedefs, is_destructible) {
1979  static_assert(
1980  is_same<
1981  typename Vector::reverse_iterator,
1982  std::reverse_iterator<typename Vector::iterator>>::value,
1983  "Vector::reverse_iterator != reverse_iterator<Vector:iterator");
1984  static_assert(
1985  is_same<
1986  typename Vector::const_reverse_iterator,
1987  std::reverse_iterator<typename Vector::const_iterator>>::value,
1988  "Vector::const_reverse_iterator != "
1989  "const_reverse_iterator<Vector::iterator");
1990 }
1991 
1992 STL_TEST("23.2.1 Table 97.3-5", reversibleIterators, is_destructible, a) {
1993  const auto& ca = a;
1994  DataState<Vector> ds(a);
1995 
1996  auto ritb = a.rbegin();
1997  auto critb = ca.rbegin();
1998  auto Critb = a.crbegin();
1999  auto rite = a.rend();
2000  auto crite = ca.rend();
2001  auto Crite = a.crend();
2002 
2004 
2005  ASSERT_TRUE(ds == a) << "call to rbegin or rend modified internal data";
2006 
2007  ASSERT_TRUE(critb == Critb) << "cv.rbegin != v.crbegin";
2008  ASSERT_TRUE(crite == Crite) << "cv.rend != v.crend";
2009 
2010  if (ca.size() == 0) {
2011  ASSERT_TRUE(ritb == rite) << "rbegin != rend when empty";
2012  ASSERT_TRUE(Critb == Crite) << "crbegin != crend when empty";
2013  } else {
2014  ASSERT_TRUE(ritb != rite) << "rbegin == rend when non-empty";
2015  ASSERT_TRUE(Critb != Crite) << "crbegin == crend when non-empty";
2016  }
2017 
2018  auto dist = size_t(std::distance(ritb, rite));
2019  auto Cdist = size_t(std::distance(Critb, Crite));
2020  ASSERT_TRUE(dist == ca.size()) << "distance(rbegin, rend) != size";
2021  ASSERT_TRUE(Cdist == ca.size()) << "distance(crbegin, crend) != size";
2022 }
2023 
2024 //-----------------------------------------------------------------------------
2025 // Lexicographical functions
2026 
2027 STL_TEST("23.2.1 Table 98", comparable, is_arithmetic) {
2028  const Vector v1 = {1, 2, 3, 4};
2029  const Vector v2 = {1, 2, 3, 4, 5};
2030  const Vector v3 = {1, 2, 2};
2031  const Vector v4 = {1, 2, 2, 4, 5};
2032  const Vector v5 = {};
2033  const Vector v6 = {1, 2, 3, 4};
2034 
2035  ASSERT_TRUE(v1 < v2);
2036  ASSERT_TRUE(v1 > v3);
2037  ASSERT_TRUE(v1 > v4);
2038  ASSERT_TRUE(v1 > v5);
2039  ASSERT_TRUE(v1 <= v6);
2040  ASSERT_TRUE(v1 >= v6);
2041 }
2042 
2043 //-----------------------------------------------------------------------------
2044 // Allocator-aware requirements (AA)
2045 
2046 STL_TEST("23.2.1 Table 99.1", allocatorTypedefs, is_destructible) {
2047  static_assert(
2049  "Vector and vector's allocator value_type mismatch");
2050 }
2051 
2052 STL_TEST("23.2.1 Table 99.2", getAllocator, is_destructible) {
2053  // whitebox: ensure that a.get_allocator() returns a copy of its allocator
2054 }
2055 
2056 STL_TEST("23.2.1 Table 99.3", defaultAllocator, is_destructible) {
2057  // there is nothing new to test here
2058 }
2059 
2060 STL_TEST("23.2.1 Table 99.4", customAllocator, is_destructible, m) {
2061  const auto& cm = m;
2062 
2063  Vector u(cm);
2064 
2065  ASSERT_TRUE(u.get_allocator() == m);
2066 
2067  if (false) {
2068  Vector t(m);
2069  }
2070 }
2071 
2072 STL_TEST("23.2.1 Table 99.5", copyWithAllocator, is_copy_constructible, a, m) {
2073  DataState<Vector> dsa(a);
2074  const auto& ca = a;
2075  const auto& cm = m;
2076 
2077  Vector u(ca, cm);
2078 
2079  ASSERT_TRUE(u.get_allocator() == m);
2080  ASSERT_TRUE(dsa == u);
2081  ASSERT_TRUE(
2082  (ca.data() == nullptr && u.data() == nullptr) || (ca.data() != u.data()))
2083  << "only a shallow copy was made";
2084 }
2085 
2086 STL_TEST(
2087  "23.2.1 Table 99.6",
2088  moveConstructionWithAllocator,
2089  is_destructible,
2090  a) {
2091  (void)a;
2092  // there is nothing new to test here
2093 }
2094 
2095 STL_TEST(
2096  "23.2.1 Table 99.6",
2097  moveConstructionWithAllocatorSupplied,
2098  is_move_constructible,
2099  a,
2100  m) {
2101  bool deep = m != a.get_allocator();
2102  auto osize = a.size();
2103  auto oalloc = AllocTracker::Constructed;
2104  const auto& cm = m;
2105 
2106  Vector u(std::move(a), cm);
2107 
2108  ASSERT_TRUE(u.get_allocator() == m);
2109 
2110  if (deep) {
2111  if (!AllocTracker::Allocated.empty()) {
2112  ASSERT_EQ(osize, AllocTracker::Constructed - oalloc);
2113  }
2114  } else {
2116  }
2117 }
2118 
2119 STL_TEST("23.2.1 Table 99.7-9", allocAssign, is_destructible) {
2120  // there is nothing new to test here
2121 }
2122 
2123 STL_TEST("23.2.1-7", nAllocConstruction, is_copy_constructible, n, m) {
2124 #ifndef USING_STD_VECTOR
2125  const auto& cm = m;
2126 
2127  Vector u(n, cm);
2128 
2129  ASSERT_TRUE(m == u.get_allocator());
2130 #endif
2131 }
2132 
2133 STL_TEST("23.2.1-7", nCopyAllocConstruction, is_copy_constructible, n, t, m) {
2134  const auto& cm = m;
2135  const auto& ct = t;
2136 
2137  Vector u(n, ct, cm);
2138 
2139  ASSERT_TRUE(m == u.get_allocator());
2140 }
2141 
2142 STL_TEST(
2143  "23.2.1-7",
2144  forwardIteratorAllocConstruction,
2145  is_destructible,
2146  i,
2147  j,
2148  m) {
2149  auto fi = makeForwardIterator(i);
2150  auto fj = makeForwardIterator(j);
2151  const auto& cfi = fi;
2152  const auto& cfj = fj;
2153  const auto& cm = m;
2154 
2155  Vector u(cfi, cfj, cm);
2156 
2157  ASSERT_TRUE(m == u.get_allocator());
2158 }
2159 
2160 STL_TEST(
2161  "23.2.1-7",
2162  inputIteratorAllocConstruction,
2163  is_move_constructible,
2164  i,
2165  j,
2166  m) {
2167 #ifdef USING_STD_VECTOR
2168  if (Ticker::TicksLeft >= 0)
2169  return;
2170 #endif
2171 
2172  auto ii = makeInputIterator(i);
2173  auto ij = makeInputIterator(j);
2174  const auto& cii = ii;
2175  const auto& cij = ij;
2176  const auto& cm = m;
2177 
2178  Vector u(cii, cij, cm);
2179 
2180  ASSERT_TRUE(m == u.get_allocator());
2181 }
2182 
2183 STL_TEST("23.2.1-7", ilAllocConstruction, is_arithmetic, m) {
2184  // gcc fail
2185  if (Ticker::TicksLeft >= 0) {
2186  return;
2187  }
2188 
2189  const auto& cm = m;
2190 
2191  Vector u({1, 4, 7}, cm);
2192 
2193  ASSERT_TRUE(m == u.get_allocator());
2194 }
2195 
2196 //-----------------------------------------------------------------------------
2197 // Data races
2198 
2199 STL_TEST("23.2.2", dataRaces, is_destructible) {
2200  if (false) {
2201  const Vector* cv = nullptr;
2202  typename Vector::size_type* s = nullptr;
2203 
2204  cv->begin();
2205  cv->end();
2206  cv->rbegin();
2207  cv->rend();
2208  cv->front();
2209  cv->back();
2210  cv->data();
2211 
2212  (*cv).at(*s);
2213  (*cv)[*s];
2214  }
2215 
2216  // White-box: check that the non-const versions of each of the above
2217  // functions is implemented in terms of (or the same as) the const version
2218 }
2219 
2220 //-----------------------------------------------------------------------------
2221 // Sequence container
2222 
2223 STL_TEST("23.2.3 Table 100.1, alt", nConstruction, is_constructible, n) {
2224  Vector u(n);
2225 
2226  ASSERT_TRUE(Allocator() == u.get_allocator());
2227  ASSERT_EQ(n, u.size());
2229 }
2230 
2231 STL_TEST("23.2.3 Table 100.1", nCopyConstruction, is_copy_constructible, n, t) {
2232  const auto& ct = t;
2233 
2234  Vector u(n, ct);
2235 
2236  ASSERT_TRUE(Allocator() == u.get_allocator());
2237  ASSERT_EQ(n, u.size()) << "Vector(n, t).size() != n" << endl;
2238  for (const auto& val : u) {
2240  << "not all elements of Vector(n, t) are equal to t";
2241  }
2242 }
2243 
2244 STL_TEST(
2245  "23.2.3 Table 100.2",
2246  forwardIteratorConstruction,
2247  is_destructible,
2248  i,
2249  j) {
2250  // All data is emplace-constructible from int, so we restrict to
2251  // is_destructible
2252 
2253  auto fi = makeForwardIterator(i);
2254  auto fj = makeForwardIterator(j);
2255  const auto& cfi = fi;
2256  const auto& cfj = fj;
2257 
2258  Vector u(cfi, cfj);
2259 
2260  ASSERT_TRUE(Allocator() == u.get_allocator());
2262 
2263  ASSERT_EQ(j - i, u.size()) << "u(i,j).size() != j-i";
2264  for (auto it = u.begin(); it != u.end(); ++it, ++i) {
2265  ASSERT_EQ(*i, convertToInt(*it)) << "u(i,j) constructed incorrectly";
2266  }
2267 }
2268 
2269 STL_TEST(
2270  "23.2.3 Table 100.2",
2271  inputIteratorConstruction,
2272  is_move_constructible,
2273  i,
2274  j) {
2275 #ifdef USING_STD_VECTOR
2276  if (Ticker::TicksLeft >= 0)
2277  return;
2278 #endif
2279 
2280  auto ii = makeInputIterator(i);
2281  auto ij = makeInputIterator(j);
2282  const auto& cii = ii;
2283  const auto& cij = ij;
2284 
2285  Vector u(cii, cij);
2286 
2287  ASSERT_TRUE(Allocator() == u.get_allocator());
2288  ASSERT_EQ(j - i, u.size()) << "u(i,j).size() != j-i";
2289  for (auto it = u.begin(); it != u.end(); ++it, ++i) {
2290  ASSERT_EQ(*i, convertToInt(*it)) << "u(i,j) constructed incorrectly";
2291  }
2292 }
2293 
2294 STL_TEST("23.2.3 Table 100.3", ilConstruction, is_arithmetic) {
2295  // whitebox: ensure that Vector(il) is implemented in terms of
2296  // Vector(il.begin(), il.end())
2297 
2298  // gcc fail
2299  if (Ticker::TicksLeft >= 0) {
2300  return;
2301  }
2302 
2303  Vector u = {1, 4, 7};
2304 
2305  ASSERT_TRUE(Allocator() == u.get_allocator());
2306  ASSERT_EQ(3, u.size()) << "u(il).size() fail";
2307  int i = 1;
2308  auto it = u.begin();
2309  for (; it != u.end(); ++it, i += 3) {
2310  ASSERT_EQ(i, convertToInt(*it)) << "u(il) constructed incorrectly";
2311  }
2312 }
2313 
2314 STL_TEST("23.2.3 Table 100.4", ilAssignment, is_arithmetic, a) {
2315  // whitebox: ensure that assign(il) is implemented in terms of
2316  // assign(il.begin(), il.end())
2317 
2318  // gcc fail
2319  if (Ticker::TicksLeft >= 0) {
2320  return;
2321  }
2322 
2323  auto am = a.get_allocator();
2324 
2325  Vector& b = a = {1, 4, 7};
2326 
2327  ASSERT_TRUE(am == a.get_allocator());
2328  ASSERT_TRUE(&b == &a) << "'a = ...' did not return *this";
2329 
2330  ASSERT_EQ(3, a.size()) << "u(il).size() fail";
2331  int i = 1;
2332  auto it = a.begin();
2333  for (; it != a.end(); ++it, i += 3) {
2334  ASSERT_EQ(i, convertToInt(*it)) << "u(il) constructed incorrectly";
2335  }
2336 }
2337 
2338 //----------------------------
2339 // insert-and-erase subsection
2340 
2341 template <class Vector>
2343  const Vector& a,
2344  DataState<Vector>& dsa,
2345  int idx,
2346  int n,
2347  int val) {
2348  ASSERT_EQ(dsa.size() + n, a.size());
2349  int i = 0;
2350  for (; i < idx; ++i) {
2351  ASSERT_EQ(dsa[i], convertToInt(a.data()[i])) << i;
2352  }
2353  for (; i < idx + n; ++i) {
2354  ASSERT_EQ(val, convertToInt(a.data()[i])) << i;
2355  }
2356  for (; size_t(i) < a.size(); ++i) {
2357  ASSERT_EQ(dsa[i - n], convertToInt(a.data()[i])) << i;
2358  }
2359 }
2360 
2361 STL_TEST(
2362  "23.2.3 Table 100.5",
2363  iteratorEmplacement,
2365  a,
2366  p) {
2367  DataState<Vector> dsa(a);
2368  int idx = distance(a.begin(), p);
2369  auto am = a.get_allocator();
2370 
2371  auto q = a.emplace(p, 44);
2372 
2373  ASSERT_TRUE(am == a.get_allocator());
2374  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2375  insertNTCheck(a, dsa, idx, 1, 44);
2376 }
2377 
2378 STL_TEST(
2379  "23.2.3 Table 100.6",
2380  iteratorInsertion,
2382  a,
2383  p,
2384  t) {
2385  DataState<Vector> dsa(a);
2386  int idx = distance(a.begin(), p);
2387  int tval = convertToInt(t);
2388  auto am = a.get_allocator();
2389  const auto& ct = t;
2390 
2391  auto q = a.insert(p, ct);
2392 
2393  ASSERT_TRUE(am == a.get_allocator());
2394  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2395  insertNTCheck(a, dsa, idx, 1, tval);
2396 }
2397 
2398 STL_TEST(
2399  "23.2.3 Table 100.7",
2400  iteratorInsertionRV,
2402  a,
2403  p,
2404  t) {
2405  // rvalue-references cannot have their address checked for aliased inserts
2406  if (a.data() <= addressof(t) && addressof(t) < a.data() + a.size()) {
2407  return;
2408  }
2409 
2410  DataState<Vector> dsa(a);
2411  int idx = distance(a.begin(), p);
2412  int tval = convertToInt(t);
2413  auto am = a.get_allocator();
2414 
2415  auto q = a.insert(p, std::move(t));
2416 
2417  ASSERT_TRUE(am == a.get_allocator());
2418  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2419  insertNTCheck(a, dsa, idx, 1, tval);
2420 }
2421 
2422 STL_TEST(
2423  "23.2.3 Table 100.8",
2424  iteratorInsertionN,
2426  a,
2427  p,
2428  n,
2429  t) {
2430  DataState<Vector> dsa(a);
2431  int idx = distance(a.begin(), p);
2432  int tval = convertToInt(t);
2433  auto am = a.get_allocator();
2434  const auto& ct = t;
2435 
2436 #ifndef USING_STD_VECTOR
2437  auto q =
2438 #endif
2439 
2440  a.insert(p, n, ct);
2441 
2442  ASSERT_TRUE(am == a.get_allocator());
2443 #ifndef USING_STD_VECTOR
2444  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2445 #endif
2446 
2447  insertNTCheck(a, dsa, idx, n, tval);
2448 }
2449 
2450 template <class Vector>
2452  const Vector& a,
2453  DataState<Vector>& dsa,
2454  int idx,
2455  int* b,
2456  int* e) {
2457  ASSERT_EQ(dsa.size() + (e - b), a.size());
2458  int i = 0;
2459  for (; i < idx; ++i) {
2460  ASSERT_EQ(dsa[i], convertToInt(a.data()[i]));
2461  }
2462  for (; i < idx + (e - b); ++i) {
2463  ASSERT_EQ(*(b + i - idx), convertToInt(a.data()[i]));
2464  }
2465  for (; size_t(i) < a.size(); ++i) {
2466  ASSERT_EQ(dsa[i - (e - b)], convertToInt(a.data()[i]));
2467  }
2468 }
2469 
2470 STL_TEST(
2471  "23.2.3 Table 100.9",
2472  iteratorInsertionIterator,
2474  a,
2475  p,
2476  i,
2477  j) {
2478  DataState<Vector> dsa(a);
2479  int idx = distance(a.begin(), p);
2480 
2481  auto fi = makeForwardIterator(i);
2482  auto fj = makeForwardIterator(j);
2483  auto am = a.get_allocator();
2484  const auto& cfi = fi;
2485  const auto& cfj = fj;
2486 
2487 #ifndef USING_STD_VECTOR
2488  auto q =
2489 #endif
2490 
2491  a.insert(p, cfi, cfj);
2492 
2493  ASSERT_TRUE(am == a.get_allocator());
2494 #ifndef USING_STD_VECTOR
2495  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2496 #endif
2497 
2498  insertItCheck(a, dsa, idx, i, j);
2499 }
2500 
2501 STL_TEST(
2502  "23.2.3 Table 100.9",
2503  iteratorInsertionInputIterator,
2505  a,
2506  p,
2507  i,
2508  j) {
2509  DataState<Vector> dsa(a);
2510  int idx = distance(a.begin(), p);
2511 
2512  auto ii = makeInputIterator(i);
2513  auto ij = makeInputIterator(j);
2514  auto am = a.get_allocator();
2515  const auto& cii = ii;
2516  const auto& cij = ij;
2517 
2518 #ifndef USING_STD_VECTOR
2519  auto q =
2520 #endif
2521 
2522  a.insert(p, cii, cij);
2523 
2524  ASSERT_TRUE(am == a.get_allocator());
2525 #ifndef USING_STD_VECTOR
2526  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2527 #endif
2528 
2529  insertItCheck(a, dsa, idx, i, j);
2530 }
2531 
2532 STL_TEST("23.2.3 Table 100.10", iteratorInsertIL, is_arithmetic, a, p) {
2533  // gcc fail
2534  if (Ticker::TicksLeft >= 0) {
2535  return;
2536  }
2537 
2538  // whitebox: ensure that insert(p, il) is implemented in terms of
2539  // insert(p, il.begin(), il.end())
2540 
2541  DataState<Vector> dsa(a);
2542  int idx = distance(a.begin(), p);
2543  auto am = a.get_allocator();
2544 
2545 #ifndef USING_STD_VECTOR
2546  auto q =
2547 #endif
2548 
2549  a.insert(p, {1, 4, 7});
2550 
2551  ASSERT_TRUE(am == a.get_allocator());
2552 #ifndef USING_STD_VECTOR
2553  ASSERT_EQ(idx, distance(a.begin(), q)) << "incorrect iterator returned";
2554 #endif
2555 
2556  int ila[] = {1, 4, 7};
2557  int* i = ila;
2558  int* j = ila + 3;
2559  insertItCheck(a, dsa, idx, i, j);
2560 }
2561 
2562 template <class Vector>
2563 void eraseCheck(Vector& a, DataState<Vector>& dsa, int idx, int n) {
2564  ASSERT_EQ(dsa.size() - n, a.size());
2565  int i = 0;
2566  auto it = a.begin();
2567  for (; it != a.end(); ++it, ++i) {
2568  if (i == idx) {
2569  i += n;
2570  }
2571  ASSERT_EQ(dsa[i], convertToInt(*it));
2572  }
2573 }
2574 
2575 STL_TEST("23.2.3 Table 100.11", iteratorErase, is_move_assignable, a, p) {
2576  if (p == a.end()) {
2577  return;
2578  }
2579 
2580  DataState<Vector> dsa(a);
2581  int idx = distance(a.begin(), p);
2582  auto am = a.get_allocator();
2583 
2584  auto rit = a.erase(p);
2585 
2586  ASSERT_TRUE(am == a.get_allocator());
2587  ASSERT_EQ(idx, distance(a.begin(), rit)) << "wrong iterator returned";
2588  eraseCheck(a, dsa, idx, 1);
2589 }
2590 
2591 STL_TEST(
2592  "23.2.3 Table 100.12",
2593  iteratorEraseRange,
2594  is_move_assignable,
2595  a,
2596  p,
2597  q) {
2598  if (p == a.end()) {
2599  return;
2600  }
2601 
2602  DataState<Vector> dsa(a);
2603  int idx = distance(a.begin(), p);
2604  auto am = a.get_allocator();
2605 
2606  auto rit = a.erase(p, q);
2607 
2608  ASSERT_TRUE(am == a.get_allocator());
2609  ASSERT_EQ(idx, distance(a.begin(), rit)) << "wrong iterator returned";
2610  eraseCheck(a, dsa, idx, distance(p, q));
2611 }
2612 
2613 //--------------------------------
2614 // end insert-and-erase subsection
2615 
2616 STL_TEST("23.2.3 Table 100.13", clear, is_destructible, a) {
2617  auto am = a.get_allocator();
2618 
2619  try {
2620  a.clear();
2621  } catch (...) {
2622  FAIL() << "clear must be noexcept";
2623  }
2624 
2625  ASSERT_TRUE(am == a.get_allocator());
2626  ASSERT_TRUE(a.empty());
2627 }
2628 
2629 STL_TEST("23.2.3 Table 100.14", assignRange, is_move_assignable, a, i, j) {
2630  auto fi = makeForwardIterator(i);
2631  auto fj = makeForwardIterator(j);
2632  const auto& cfi = fi;
2633  const auto& cfj = fj;
2634  auto am = a.get_allocator();
2635 
2636  a.assign(cfi, cfj);
2637 
2638  ASSERT_TRUE(am == a.get_allocator());
2639  ASSERT_EQ(distance(i, j), a.size());
2640  for (auto it = a.begin(); it != a.end(); ++it, ++i) {
2641  ASSERT_EQ(*i, convertToInt(*it));
2642  }
2643 }
2644 
2645 STL_TEST(
2646  "23.2.3 Table 100.14",
2647  assignInputRange,
2649  a,
2650  i,
2651  j) {
2652  auto ii = makeInputIterator(i);
2653  auto ij = makeInputIterator(j);
2654  const auto& cii = ii;
2655  const auto& cij = ij;
2656  auto am = a.get_allocator();
2657 
2658  a.assign(cii, cij);
2659 
2660  ASSERT_TRUE(am == a.get_allocator());
2661  ASSERT_EQ(distance(i, j), a.size());
2662  for (auto it = a.begin(); it != a.end(); ++it, ++i) {
2663  ASSERT_EQ(*i, convertToInt(*it));
2664  }
2665 }
2666 
2667 STL_TEST("23.2.3 Table 100.15", assignIL, is_arithmetic, a) {
2668  // whitebox: ensure that assign(il) is implemented in terms of
2669  // assign(il.begin(), il.end())
2670 
2671  // gcc fail
2672  if (Ticker::TicksLeft >= 0) {
2673  return;
2674  }
2675 
2676  auto am = a.get_allocator();
2677 
2678  a.assign({1, 4, 7});
2679 
2680  ASSERT_TRUE(am == a.get_allocator());
2681  int ila[] = {1, 4, 7};
2682  int* i = ila;
2683 
2684  ASSERT_EQ(3, a.size());
2685  for (auto it = a.begin(); it != a.end(); ++it, ++i) {
2686  ASSERT_EQ(*i, convertToInt(*it));
2687  }
2688 }
2689 
2690 STL_TEST(
2691  "23.2.3 Table 100.16",
2692  assignN,
2694  a,
2695  n,
2696  t) {
2697  auto am = a.get_allocator();
2698  auto const& ct = t;
2699  auto tval = convertToInt(t);
2700 
2701  a.assign(n, ct);
2702 
2703  ASSERT_TRUE(am == a.get_allocator());
2704  ASSERT_EQ(n, a.size());
2705  for (auto it = a.begin(); it != a.end(); ++it) {
2706  ASSERT_EQ(tval, convertToInt(*it));
2707  }
2708 }
2709 
2710 STL_TEST("23.2.3 Table 101.1", front, is_destructible, a) {
2711  if (a.empty()) {
2712  return;
2713  }
2714 
2715  ASSERT_TRUE(addressof(a.front()) == a.data());
2716 
2718 
2719  if (false) {
2720  mutate(a.front());
2721  const Vector& ca = a;
2722  ca.front();
2723  }
2724 }
2725 
2726 STL_TEST("23.2.3 Table 101.2", back, is_destructible, a) {
2727  if (a.empty()) {
2728  return;
2729  }
2730 
2731  ASSERT_TRUE(addressof(a.back()) == a.data() + a.size() - 1);
2732 
2734 
2735  if (false) {
2736  mutate(a.back());
2737  const Vector& ca = a;
2738  ca.back();
2739  }
2740 }
2741 
2742 STL_TEST("23.2.3 Table 101.4", emplaceBack, is_move_constructible, a) {
2743  DataState<Vector> dsa(a);
2744  auto adata = a.data();
2745  int excess = a.capacity() - a.size();
2746  auto am = a.get_allocator();
2747 
2748  try {
2749  a.emplace_back(44);
2750  } catch (...) {
2751  ASSERT_TRUE(dsa == a) << "failed strong exception guarantee";
2752  throw;
2753  }
2754 
2755  ASSERT_TRUE(am == a.get_allocator());
2756  if (excess > 0) {
2757  ASSERT_TRUE(a.data() == adata) << "unnecessary relocation";
2758  }
2759  ASSERT_EQ(dsa.size() + 1, a.size());
2760  size_t i = 0;
2761  auto it = a.begin();
2762  for (; i < dsa.size(); ++i, ++it) {
2763  ASSERT_EQ(dsa[i], convertToInt(*it));
2764  }
2765  ASSERT_EQ(44, convertToInt(a.back()));
2766 }
2767 
2768 STL_TEST("23.2.3 Table 101.7", pushBack, is_copy_constructible, a, t) {
2769  DataState<Vector> dsa(a);
2770  int tval = convertToInt(t);
2771  auto adata = a.data();
2772  int excess = a.capacity() - a.size();
2773  auto am = a.get_allocator();
2774  const auto& ct = t;
2775 
2776  try {
2777  a.push_back(ct);
2778  } catch (...) {
2779  ASSERT_TRUE(dsa == a) << "failed strong exception guarantee";
2780  throw;
2781  }
2782 
2783  ASSERT_TRUE(am == a.get_allocator());
2784  if (excess > 0) {
2785  ASSERT_TRUE(a.data() == adata) << "unnecessary relocation";
2786  }
2787  ASSERT_EQ(dsa.size() + 1, a.size());
2788  size_t i = 0;
2789  auto it = a.begin();
2790  for (; i < dsa.size(); ++i, ++it) {
2791  ASSERT_EQ(dsa[i], convertToInt(*it));
2792  }
2793  ASSERT_EQ(tval, convertToInt(a.back()));
2794 }
2795 
2796 STL_TEST("23.2.3 Table 101.8", pushBackRV, is_move_constructible, a, t) {
2797  DataState<Vector> dsa(a);
2798  int tval = convertToInt(t);
2799  auto adata = a.data();
2800  int excess = a.capacity() - a.size();
2801  auto am = a.get_allocator();
2802 
2803  try {
2804  a.push_back(move(t));
2805  } catch (...) {
2806  ASSERT_TRUE(dsa == a) << "failed strong exception guarantee";
2807  throw;
2808  }
2809 
2810  ASSERT_TRUE(am == a.get_allocator());
2811  if (excess > 0) {
2812  ASSERT_TRUE(a.data() == adata) << "unnecessary relocation";
2813  }
2814  ASSERT_EQ(dsa.size() + 1, a.size());
2815  size_t i = 0;
2816  auto it = a.begin();
2817  for (; i < dsa.size(); ++i, ++it) {
2818  ASSERT_EQ(dsa[i], convertToInt(*it));
2819  }
2820  ASSERT_EQ(tval, convertToInt(a.back()));
2821 }
2822 
2823 STL_TEST("23.2.3 Table 100.10", popBack, is_destructible, a) {
2824  if (a.empty()) {
2825  return;
2826  }
2827 
2828  DataState<Vector> dsa(a);
2829  auto am = a.get_allocator();
2830 
2831  a.pop_back();
2832 
2833  ASSERT_TRUE(am == a.get_allocator());
2834  ASSERT_EQ(dsa.size() - 1, a.size());
2835  size_t i = 0;
2836  auto it = a.begin();
2837  for (; it != a.end(); ++it, ++i) {
2838  ASSERT_EQ(dsa[i], convertToInt(*it));
2839  }
2840 }
2841 
2842 STL_TEST("23.2.3 Table 100.11", operatorBrace, is_destructible, a) {
2843  const auto& ca = a;
2844  for (size_t i = 0; i < ca.size(); ++i) {
2845  ASSERT_TRUE(addressof(ca[i]) == ca.data() + i);
2846  }
2847 
2849 
2850  if (false) {
2851  mutate(a[0]);
2852  }
2853 }
2854 
2855 STL_TEST("23.2.3 Table 100.12", at, is_destructible, a) {
2856  const auto& ca = a;
2857  for (size_t i = 0; i < ca.size(); ++i) {
2858  ASSERT_TRUE(addressof(ca.at(i)) == ca.data() + i);
2859  }
2860 
2862 
2863  try {
2864  ca.at(ca.size());
2865  FAIL() << "at(size) should have thrown an error";
2866  } catch (const std::out_of_range& e) {
2867  } catch (...) {
2868  FAIL() << "at(size) threw error other than out_of_range";
2869  }
2870 
2871  if (false) {
2872  mutate(a.at(0));
2873  }
2874 }
2875 
2876 STL_TEST("move iterators", moveIterators, is_copy_constructibleAndAssignable) {
2877  if (false) {
2878  int* i = nullptr;
2879  int* j = nullptr;
2880 
2881  auto mfi = make_move_iterator(makeForwardIterator(i));
2882  auto mfj = make_move_iterator(makeForwardIterator(j));
2883  auto mii = make_move_iterator(makeInputIterator(i));
2884  auto mij = make_move_iterator(makeInputIterator(j));
2885 
2886  Vector u1(mfi, mfj);
2887  Vector u2(mii, mij);
2888 
2889  u1.insert(u1.begin(), mfi, mfj);
2890  u1.insert(u1.begin(), mii, mij);
2891 
2892  u1.assign(mfi, mfj);
2893  u1.assign(mii, mij);
2894  }
2895 }
2896 
2897 //-----------------------------------------------------------------------------
2898 // Vector-specifics
2899 
2900 STL_TEST("23.3.6.4", dataAndCapacity, is_destructible) {
2901  // there isn't anything new to test here - data and capacity are used as the
2902  // backbone of DataState. The minimal testing we might want to do is already
2903  // done in the populate test
2904 }
2905 
2906 STL_TEST("23.3.6.3", reserve, is_move_constructible, a, n) {
2907  auto adata = a.data();
2908  auto ocap = a.capacity();
2909  auto am = a.get_allocator();
2910 
2911  a.reserve(n);
2912 
2913  ASSERT_TRUE(am == a.get_allocator());
2914  if (size_t(n) <= ocap) {
2916  ASSERT_TRUE(adata == a.data());
2917  } else {
2918  ASSERT_TRUE(a.capacity() >= size_t(n));
2919  ASSERT_LE(Counter::CountTotalOps, 2 * a.size()); // move and delete
2920  }
2921 }
2922 
2923 STL_TEST("23.3.6.3", lengthError, is_move_constructible) {
2924  auto mx = Vector().max_size();
2925  auto big = mx + 1;
2926  if (mx >= big) {
2927  return; // max_size is the biggest size_type; overflowed
2928  }
2929 
2930  Vector u;
2931  try {
2932  u.reserve(big);
2933  FAIL() << "reserve(big) should have thrown an error";
2934  } catch (const std::length_error& e) {
2935  } catch (...) {
2936  FAIL() << "reserve(big) threw error other than length_error";
2937  }
2938 }
2939 
2940 STL_TEST("23.3.6.3", resize, is_copy_constructible, a, n) {
2941  DataState<Vector> dsa(a);
2942  int sz = a.size();
2943  auto am = a.get_allocator();
2944 
2945  a.resize(n);
2946 
2947  ASSERT_TRUE(am == a.get_allocator());
2948  ASSERT_EQ(n, a.size());
2949 
2950  if (n <= sz) {
2951  for (int i = 0; i < n; ++i) {
2952  ASSERT_EQ(dsa[i], convertToInt(a[i]));
2953  }
2954  } else {
2955  for (int i = 0; i < sz; ++i) {
2956  ASSERT_EQ(dsa[i], convertToInt(a[i]));
2957  }
2958  }
2959 }
2960 
2961 STL_TEST("23.3.6.3", resizeT, is_copy_constructibleAndAssignable, a, n, t) {
2962 #ifdef USING_STD_VECTOR
2963  if (a.data() <= addressof(t) && addressof(t) < a.data() + a.size())
2964  return;
2965 #endif
2966 
2967  DataState<Vector> dsa(a);
2968  int sz = a.size();
2969  auto am = a.get_allocator();
2970  const auto& ct = t;
2971  int val = convertToInt(t);
2972 
2973  a.resize(n, ct);
2974 
2975  ASSERT_TRUE(am == a.get_allocator());
2976  ASSERT_EQ(n, a.size());
2977 
2978  if (n <= sz) {
2979  for (int i = 0; i < n; ++i) {
2980  ASSERT_EQ(dsa[i], convertToInt(a[i]));
2981  }
2982  } else {
2983  int i = 0;
2984  for (; i < sz; ++i) {
2985  ASSERT_EQ(dsa[i], convertToInt(a[i]));
2986  }
2987  for (; i < n; ++i) {
2988  ASSERT_EQ(val, convertToInt(a[i]));
2989  }
2990  }
2991 }
2992 
2993 STL_TEST("23.3.6.3", shrinkToFit, is_move_constructible, a) {
2994  bool willThrow = Ticker::TicksLeft >= 0;
2995 
2996  a.reserve(a.capacity() * 11);
2997 
2998  auto ocap = a.capacity();
2999  DataState<Vector> dsa(a);
3000 
3001  auto am = a.get_allocator();
3002 
3003  try {
3004  a.shrink_to_fit();
3005  } catch (...) {
3006  FAIL() << "shrink_to_fit should swallow errors";
3007  }
3008 
3009  ASSERT_TRUE(am == a.get_allocator());
3010  ASSERT_TRUE(dsa == a);
3011  if (willThrow) {
3012  // ASSERT_EQ(ocap, a.capacity()); might shrink in place
3013  throw TickException("I swallowed the error");
3014  } else {
3015  ASSERT_TRUE(a.capacity() == 0 || a.capacity() < ocap) << "Look into this";
3016  }
3017 }
3018 
3019 #ifndef USING_STD_VECTOR
3020 STL_TEST("EBO", ebo, is_destructible) {
3021  static_assert(
3022  !is_same<Allocator, std::allocator<T>>::value ||
3023  sizeof(Vector) == 3 * sizeof(void*),
3024  "fbvector has default allocator, but has size != 3*sizeof(void*)");
3025 }
3026 
3027 STL_TEST("relinquish", relinquish, is_destructible, a) {
3028  auto sz = a.size();
3029  auto cap = a.capacity();
3030  auto data = a.data();
3031 
3032  auto guts = relinquish(a);
3033 
3034  ASSERT_EQ(data, guts);
3035  ASSERT_TRUE(a.empty());
3036  ASSERT_EQ(0, a.capacity());
3037 
3038  auto alloc = a.get_allocator();
3039  for (size_t i = 0; i < sz; ++i) {
3041  }
3042  if (guts != nullptr) {
3043  if (std::is_same<
3044  decltype(alloc),
3045  std::allocator<typename decltype(alloc)::value_type>>::value) {
3046  free(guts);
3047  } else {
3048  std::allocator_traits<decltype(alloc)>::deallocate(alloc, guts, cap);
3049  }
3050  }
3051 }
3052 
3053 STL_TEST("attach", attach, is_destructible, a) {
3054  DataState<Vector> dsa(a);
3055 
3056  auto sz = a.size();
3057  auto cap = a.capacity();
3058  auto guts = relinquish(a);
3059 
3060  ASSERT_EQ(a.data(), nullptr);
3061  attach(a, guts, sz, cap);
3062 
3063  ASSERT_TRUE(dsa == a);
3064 }
3065 
3066 #endif
3067 
3068 // #endif
3069 
3070 int main(int argc, char** argv) {
3071  testing::InitGoogleTest(&argc, argv);
3072  gflags::ParseCommandLineFlags(&argc, &argv, true);
3073 
3074  return RUN_ALL_TESTS();
3075 }
3076 
static int CountDestroy
~DataTicker() noexcept
#define ASSERT_GE(val1, val2)
Definition: gtest.h:1972
D0(std::nullptr_t)
#define ASSERT_GT(val1, val2)
Definition: gtest.h:1976
Tracker(Tracker *self, int uid)
static map< void *, size_t > Allocated
void BENCHFUN() resize(size_t iters, size_t arg)
#define T(v)
Definition: http_parser.c:233
static int ijarC[12]
void hardReset()
static std::map< const Tracker *, int > Locations
shared_ptr< set< It > > dereferenced
static bool HasFatalFailure()
Definition: gtest.cc:2487
folly::fbvector< EP3, Alloc< EP3 > > _TP3
#define FOLLY_GNU_DISABLE_WARNING(warningName)
Definition: Portability.h:180
void populate(Vector &v, const pair< int, int > &ss)
Data< PROP_SWAP > EP3
TickException(const std::string &s)
iterator_traits< It >::value_type & dereference() const
static int UIDTotal
#define FOLLY_POP_WARNING
Definition: Portability.h:179
auto f
flags
Definition: http_parser.h:127
void verify(int extras)
folly::fbvector< ED3, std::allocator< ED3 > > _TV3
#define FAIL()
Definition: gtest.h:1822
void operator=(Counter &&) noexcept
std::unique_ptr< int > A
folly::fbvector< ED4, std::allocator< ED4 > > _TV4
Data< MC_NOEXCEPT > ED3
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
Counter(std::nullptr_t) noexcept
int operator[](size_type i)
uint32_t Flags
#define FOLLY_PUSH_WARNING
Definition: Portability.h:178
bool operator==(const DataState &o) const
DataTicker(const DataTicker &) noexcept((f &CC_NOEXCEPT)!=0)
char b
#define ASSERT_LT(val1, val2)
Definition: gtest.h:1968
pointer allocate(size_type n)
FlagVals
size_type size_
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: gtest.h:2232
T * relinquish(fbvector< T, A > &v)
Definition: FBVector.h:1744
void softReset(int ticks=-1)
isPropSwap< T > propagate_on_container_swap
Transformer< It, forward_iterator_tag > makeForwardIterator(const It &it)
static bool Print
static std::map< int, int > UIDCount
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static int UID
folly::fbvector< EP2, Alloc< EP2 > > _TP2
DataTracker() noexcept
folly::fbvector< DDSMA, Alloc< DDSMA > > _TSpecialMA
DataTracker(DataTracker &&o) noexcept
static int CountMC
STL namespace.
#define ASSERT_LE(val1, val2)
Definition: gtest.h:1964
static int Destroyed
static int CountCC
double val
Definition: String.cpp:273
folly::fbvector< EP1, Alloc< EP1 > > _TP1
Data< ALL_DELETE &~DC_DELETE > DD5
void print(const std::string &fun)
static map< void *, int > Owner
std::allocator< T >::value_type value_type
static int CountCA
Counter() noexcept
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
int populateIndex
folly::fbvector< int, std::allocator< int > > _TVIS
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static int CountOC
Data< ALL_DELETE|PROP_MOVE > DDSMA
void construct(U *p, Args &&...args)
Data< PROP_COPY > EP1
D0()=default
void verifyAllocator(int ele, int cap)
requires E e noexcept(noexcept(s.error(std::move(e))))
D3(std::nullptr_t)
#define nullptr
Definition: http_parser.c:41
constexpr State operator&(State a, State b)
Definition: Core.h:51
DataTicker(DataTicker &&) noexcept((f &MC_NOEXCEPT)!=0)
int main(int argc, char **argv)
bool_constant< true > true_type
Definition: gtest-port.h:2210
#define STL_TEST(ref, name, restriction,...)
ThreadCachedInt< int64_t > Counter
static const vector< pair< int, int > > VectorSizes
static void destroy()
Data< CA_DELETE|MA_DELETE > DD3
D1(std::nullptr_t)
DataState(const Vector &v)
Data< DC_DELETE|CC_DELETE|MC_DELETE > DD2
static int TicksLeft
void eraseCheck(Vector &a, DataState< Vector > &dsa, int idx, int n)
size_type size()
D2(std::nullptr_t)
const char * name
Definition: http_parser.c:437
std::allocator< T > a
DataTracker(int uid) noexcept
void BENCHFUN() reserve(int iters, int size)
char ** argv
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
Data< MC_NOEXCEPT|CC_DELETE > ED4
DataTracker & operator=(DataTracker &&o) noexcept
static int CountTotalOps
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
Data ED1
std::integral_constant< bool, B > bool_constant
Definition: Traits.h:145
Data(int i)
static int CountTicks
void BENCHFUN() pushBack(int iters, int initialSize)
static const vector< int > nSizes
folly::fbvector< ED5, std::allocator< ED5 > > _TV5v1
Delete(std::nullptr_t)
std::allocator< T >::difference_type difference_type
folly::fbvector< ED2, std::allocator< ED2 > > _TV2
Transformer(const It &it)
int getTotal()
folly::fbvector< int, Alloc< int > > _TVI
string operator()()
~Counter() noexcept
void insertNTCheck(const Vector &a, DataState< Vector > &dsa, int idx, int n, int val)
void verifyVector(const Vector &v)
D0(std::nullptr_t)
static map< string, int > m
DataTicker() noexcept(f &DC_NOEXCEPT)
void operator=(const Counter &) noexcept
std::uniform_int_distribution< milliseconds::rep > dist
char a
bool operator!=(const Alloc &o) const
void attach(fbvector< T, A > &v, T *data, size_t sz, size_t cap)
Definition: FBVector.h:1751
~DataTracker() noexcept
static const char *const value
Definition: Conv.cpp:50
Data< CA_DELETE > DD7
void free()
D1(std::nullptr_t)
static int ijarr[12]
void deallocate(pointer p, size_type n)
std::allocator< T >::const_pointer const_pointer
D4(std::nullptr_t)
folly::fbvector< ED1, std::allocator< ED1 > > _TV1
bool operator==(const Alloc &o) const
DataTracker & operator=(const DataTracker &o) noexcept
uint64_t ReadTSC()
Vector::size_type size_type
DataTicker(std::nullptr_t) noexcept((f &OC_NOEXCEPT)!=0)
D4(std::nullptr_t)
static void Tick(const std::string &s)
Data< ALL_DELETE > DD1
void fun()
const char * string
Definition: Conv.cpp:212
void mutate(int &i)
void destroy(U *p)
int convertToInt(int t)
static set< string > s
isPropMove< T > propagate_on_container_move_assignment
Alloc(int i=8)
Data< IS_RELOCATABLE > ED5
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: gtest.cc:5370
Data< CC_DELETE|MC_DELETE > DD4
Data< PROP_MOVE > EP2
#define ASSERT_NE(val1, val2)
Definition: gtest.h:1960
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
Data< CC_DELETE > DD6
DataTracker(const DataTracker &o) noexcept
std::allocator< T >::size_type size_type
static int CountMA
Data< 0, 4080 > ED2
Counter(const Counter &) noexcept
void insertItCheck(const Vector &a, DataState< Vector > &dsa, int idx, int *b, int *e)
Alloc(const Alloc &o)
void isSane()
Alloc(Alloc &&o) noexcept
static int CountLoggedConstruction
char c
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
std::pair< typename Vector::iterator, string > iterSpotter(Vector &v, int i)
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
D3(std::nullptr_t)
isPropCopy< T > propagate_on_container_copy_assignment
void operator=(DataTicker &&) noexcept((f &MA_NOEXCEPT)!=0)
void operator=(const DataTicker &) noexcept((f &CA_NOEXCEPT)!=0)
StringPiece data_
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
folly::fbvector< ED5, Alloc< ED5 > > _TV5
static int CountDC
static void Delete(T *x)
static int Constructed
Counter(Counter &&) noexcept
static const vector< int > tVals
D2(std::nullptr_t)
D0 & operator=(const D0 &)=default
std::allocator< T >::pointer pointer
Alloc select_on_container_copy_construction() const
Transformer< It, input_iterator_tag > makeInputIterator(const It &it)