This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
libstdc++/21772 part 2
- From: Benjamin Kosnik <bkoz at redhat dot com>
- To: libstdc++ at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 17 Dec 2009 01:28:15 -0800
- Subject: libstdc++/21772 part 2
- References: <20091215214406.2a2f5348@mcgee.artheist.org>
> First part of this, while waiting on cross results.
Second part of this, docs, test framework and files for std::list,
which seems fine.
tested x86_64/linux
tested x86_64/darwin10.2.0
-benjamin
2009-12-16 Benjamin Kosnik <bkoz@redhat.com>
PR libstdc++/21772 part 2
* doc/xml/manual/test.xml: Add documentation about testing details.
* testsuite/util/exception/safety.h: New. Functor objects for
testing C++0x container classes.
* testsuite/util/testsuite_container_traits.h: Add traits.
* testsuite/23_containers/list/requirements/exception/
basic.cc: New.
generation_prohibited.cc: New.
propagation_consistent.cc: New.
Index: doc/xml/manual/test.xml
===================================================================
--- doc/xml/manual/test.xml (revision 155304)
+++ doc/xml/manual/test.xml (working copy)
@@ -1,6 +1,6 @@
<sect1 id="manual.intro.setup.test" xreflabel="Testing">
<?dbhtml filename="test.html"?>
-
+
<sect1info>
<keywordset>
<keyword>
@@ -48,7 +48,7 @@
that are packaged in a separate testing library.
</para>
-<para>
+<para>
All test cases for functionality required by the runtime components
of the C++ standard (ISO 14882) are files within the following
directories.
@@ -65,6 +65,9 @@
25_algorithms
26_numerics
27_io
+28_regex
+29_atomics
+30_threads
</programlisting>
<para>
@@ -77,9 +80,8 @@
demangle Tests for __cxa_demangle, the IA 64 C++ ABI demangler
ext Tests for extensions.
performance Tests for performance analysis, and performance regressions.
-thread Tests for threads.
</programlisting>
-
+
<para>
Some directories don't have test files, but instead contain
auxiliary information:
@@ -104,7 +106,7 @@
</para>
<programlisting>
21_strings/find.cc
- </programlisting>
+ </programlisting>
<para>
However, that practice soon became a liability as the test cases
became huge and unwieldy, and testing new or extended
@@ -123,11 +125,11 @@
21_strings/basic_string/find/wchar_t/1.cc
21_strings/basic_string/find/wchar_t/2.cc
21_strings/basic_string/find/wchar_t/3.cc
- </programlisting>
+ </programlisting>
<para>
All new tests should be written with the policy of one test
- case, one file in mind.
+ case, one file in mind.
</para>
</sect3>
@@ -140,7 +142,7 @@
used within the testsuite to designate particular kinds of
tests.
</para>
-
+
<itemizedlist>
<listitem>
<para>
@@ -151,10 +153,10 @@
to finish or pass. At the moment, the interactive tests are not
run by default. Instead, they are run by hand, like:
</para>
- <programlisting>
+ <programlisting>
g++ 27_io/objects/char/3_xin.cc
cat 27_io/objects/char/3_xin.in | a.out
- </programlisting>
+ </programlisting>
</listitem>
<listitem>
<para>
@@ -232,7 +234,7 @@
<sect3 id="test.run.basic">
<title>Basic</title>
-
+
<para>
You can check the status of the build without installing it
using the dejagnu harness, much like the rest of the gcc
@@ -254,7 +256,7 @@
the exact command line passed to the compiler, the compiler
output, and the executable output (if any).
</para>
-
+
<para>
Archives of test results for various versions and platforms are
available on the GCC website in the <ulink
@@ -266,7 +268,7 @@
combination of source version, operating system, and host CPU.
</para>
</sect3>
-
+
<sect3 id="test.run.variations">
<title>Variations</title>
<para>
@@ -322,7 +324,7 @@
make check-target-libstdc++-v3 RUNTESTFLAGS="--target_board=arm-sim"
</programlisting>
- <para>
+ <para>
Also, here is an example of how to run the libstdc++ testsuite
for a multilibed build directory with different ABI settings:
</para>
@@ -330,7 +332,7 @@
<programlisting>
make check-target-libstdc++-v3 RUNTESTFLAGS='--target_board \"unix{-mabi=32,,-mabi=64}\"'
</programlisting>
-
+
<para>
You can run the tests with a compiler and library that have
already been installed. Make sure that the compiler (e.g.,
@@ -354,7 +356,7 @@
testsuites in parallel from the same directory.
</para>
- <para>
+ <para>
In addition, there are some testing options that are mostly of
interest to library maintainers and system integrators. As such,
these tests may not work on all cpu and host combinations, and
@@ -378,7 +380,7 @@
<para>
<emphasis>testsuite_files</emphasis>
</para>
- <para>
+ <para>
This is a list of all the test cases that will be run. Each
test case is on a separate line, given with an absolute path
from the <emphasis>libsrcdir/testsuite</emphasis> directory.
@@ -389,7 +391,7 @@
<para>
<emphasis>testsuite_files_interactive</emphasis>
</para>
- <para>
+ <para>
This is a list of all the interactive test cases, using the
same format as the file list above. These tests are not run
by default.
@@ -400,7 +402,7 @@
<para>
<emphasis>testsuite_files_performance</emphasis>
</para>
- <para>
+ <para>
This is a list of all the performance test cases, using the
same format as the file list above. These tests are not run
by default.
@@ -411,7 +413,7 @@
<para>
<emphasis>testsuite_thread</emphasis>
</para>
- <para>
+ <para>
This file indicates that the host system can run tests which
involved multiple threads.
</para>
@@ -421,7 +423,7 @@
<para>
<emphasis>testsuite_wchar_t</emphasis>
</para>
- <para>
+ <para>
This file indicates that the host system can run the wchar_t
tests, and corresponds to the macro definition <code>
_GLIBCXX_USE_WCHAR_T</code> in the file c++config.h.
@@ -432,11 +434,11 @@
<programlisting>
make check-abi
</programlisting>
-
+
<para>
The library ABI can be tested. This involves testing the shared
library against an ABI-defining previous version of symbol
- exports.
+ exports.
</para>
<programlisting>
@@ -507,7 +509,7 @@
<para>
The first step in making a new test case is to choose the correct
directory and file name, given the organization as previously
- described.
+ described.
</para>
<para>
@@ -638,7 +640,7 @@
<sect3 id="test.harness.dejagnu">
<title>Dejagnu Harness Details</title>
- <para>
+ <para>
Underlying details of testing for conformance and regressions are
abstracted via the GNU Dejagnu package. This is similar to the
rest of GCC.
@@ -684,7 +686,7 @@
<sect3 id="test.harness.utils">
<title>Utilities</title>
- <para>
+ <para>
</para>
<para>
The testsuite directory also contains some files that implement
@@ -709,11 +711,11 @@
<emphasis>testsuite_abi_check.cc</emphasis>
</para>
<para>
- Creates the executable <emphasis>abi_check</emphasis>.
- Used to check correctness of symbol versioning, visibility of
- exported symbols, and compatibility on symbols in the shared
- library, for hosts that support this feature. More information
- can be found in the ABI documentation <link linkend="appendix.porting.abi">here</link>
+ Creates the executable <emphasis>abi_check</emphasis>.
+ Used to check correctness of symbol versioning, visibility of
+ exported symbols, and compatibility on symbols in the shared
+ library, for hosts that support this feature. More information
+ can be found in the ABI documentation <link linkend="appendix.porting.abi">here</link>
</para>
</listitem>
<listitem>
@@ -722,11 +724,11 @@
<emphasis>testsuite_allocator.cc</emphasis>
</para>
<para>
- Contains specialized allocators that keep track of construction
- and destruction. Also, support for overriding global new and
- delete operators, including verification that new and delete
- are called during execution, and that allocation over max_size
- fails.
+ Contains specialized allocators that keep track of construction
+ and destruction. Also, support for overriding global new and
+ delete operators, including verification that new and delete
+ are called during execution, and that allocation over max_size
+ fails.
</para>
</listitem>
<listitem>
@@ -734,9 +736,9 @@
<emphasis>testsuite_character.h</emphasis>
</para>
<para>
- Contains <code>std::char_traits</code> and
- <code>std::codecvt</code> specializations for a user-defined
- POD.
+ Contains <code>std::char_traits</code> and
+ <code>std::codecvt</code> specializations for a user-defined
+ POD.
</para>
</listitem>
<listitem>
@@ -748,20 +750,20 @@
A large number of utilities, including:
</para>
<itemizedlist>
- <listitem><para>VERIFY</para></listitem>
- <listitem><para>set_memory_limits</para></listitem>
- <listitem><para>verify_demangle</para></listitem>
- <listitem><para>run_tests_wrapped_locale</para></listitem>
- <listitem><para>run_tests_wrapped_env</para></listitem>
- <listitem><para>try_named_locale</para></listitem>
- <listitem><para>try_mkfifo</para></listitem>
- <listitem><para>func_callback</para></listitem>
- <listitem><para>counter</para></listitem>
- <listitem><para>copy_tracker</para></listitem>
- <listitem><para>copy_constructor</para></listitem>
- <listitem><para>assignment_operator</para></listitem>
- <listitem><para>destructor</para></listitem>
- <listitem>
+ <listitem><para>VERIFY</para></listitem>
+ <listitem><para>set_memory_limits</para></listitem>
+ <listitem><para>verify_demangle</para></listitem>
+ <listitem><para>run_tests_wrapped_locale</para></listitem>
+ <listitem><para>run_tests_wrapped_env</para></listitem>
+ <listitem><para>try_named_locale</para></listitem>
+ <listitem><para>try_mkfifo</para></listitem>
+ <listitem><para>func_callback</para></listitem>
+ <listitem><para>counter</para></listitem>
+ <listitem><para>copy_tracker</para></listitem>
+ <listitem><para>copy_constructor</para></listitem>
+ <listitem><para>assignment_operator</para></listitem>
+ <listitem><para>destructor</para></listitem>
+ <listitem>
<para>pod_char, pod_int and associated char_traits specializations</para>
</listitem>
</itemizedlist>
@@ -792,13 +794,239 @@
reporting functions including:
</para>
<itemizedlist>
- <listitem><para>time_counter</para></listitem>
- <listitem><para>resource_counter</para></listitem>
- <listitem><para>report_performance</para></listitem>
+ <listitem><para>time_counter</para></listitem>
+ <listitem><para>resource_counter</para></listitem>
+ <listitem><para>report_performance</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</sect3>
</sect2>
+
+<sect2 id="test.special">
+<title>Special Topics</title>
+
+<sect3 id="test.exception.safety">
+<title>
+ Qualifying Exception Safety Guarantees
+ <indexterm>
+ <primary>Test</primary>
+ <secondary>Exception Safety</secondary>
+ </indexterm>
+</title>
+
+<sect4 id="test.exception.safety.overview">
+<title>Overview</title>
+
+ <para>
+ Testing is composed of running a particular test sequence,
+ and looking at what happens to the surrounding code when
+ exceptions are thrown. Each test is composed of measuring
+ initial state, executing a particular sequence of code under
+ some instrumented conditions, measuring a final state, and
+ then examining the differences between the two states.
+ </para>
+
+ <para>
+ Test sequences are composed of constructed code sequences
+ that exercise a particular function or member function, and
+ either confirm no exceptions were generated, or confirm the
+ consistency/coherency of the test subject in the event of a
+ thrown exception.
+ </para>
+
+ <para>
+ Random code paths can be constructed using the the basic test
+ sequences and instrumentation as above, only combined in a
+ random or pseudo-random way.
+ </para>
+
+ <para> To compute the code paths that throw, test instruments
+ are used that throw on allocation events
+ (<classname>__gnu_cxx::throw_allocator_random</classname>
+ and <classname>__gnu_cxx::throw_allocator_limit</classname>)
+ and copy, assignment, comparison, increment, swap, and
+ various operators
+ (<classname>__gnu_cxx::throw_type_random</classname>
+ and <classname>__gnu_cxx::throw_type_limit</classname>). Looping
+ through a given test sequence and conditionally throwing in
+ all instrumented places. Then, when the test sequence
+ completes without an exception being thrown, assume all
+ potential error paths have been exercised in a sequential
+ manner.
+ </para>
+</sect4>
+
+
+<sect4 id="test.exception.safety.status">
+<title>
+ Existing tests
+</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Ad Hoc
+ </para>
+ <para>
+ For example,
+ <filename>testsuite/23_containers/list/modifiers/3.cc</filename>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Policy Based Data Structures
+ </para>
+ <para>
+ For example, take the test
+ functor <classname>rand_reg_test</classname> in
+ in <filename>testsuite/ext/pb_ds/regression/tree_no_data_map_rand.cc</filename>. This uses <classname>container_rand_regression_test</classname> in
+<filename>testsuite/util/regression/rand/assoc/container_rand_regression_test.h</filename>.
+
+ </para>
+
+ <para>
+ Which has several tests for container member functions,
+Includes control and test container objects. Configuration includes
+random seed, iterations, number of distinct values, and the
+probability that and exception will be thrown. Assumes instantiating
+container uses an extension
+allocator, <classname>__gnu_cxx::throw_allocator_random</classname>,
+as the allocator type.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ C++0x Container Requirements.
+ </para>
+
+ <para>
+ Coverage is currently limited to testing container
+ requirements for exception safety,
+ although <classname>__gnu_cxx::throw_type</classname> meets
+ the additional type requirements for testing numeric data
+ structures and instantiating algorithms.
+ </para>
+
+ <para>
+ Of particular interest is extending testing to algorithms and
+ then to parallel algorithms. Also io, and locales.
+ </para>
+ </listitem>
+ </itemizedlist>
+</sect4>
+
+
+<sect4 id="test.exception.safety.containers">
+<title>
+C++0x Requirements Test Sequence Descriptions
+</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Basic
+ </para>
+
+ <para>
+ Basic consistency on exception propagation tests. For
+ each container, an object of that container is constructed,
+ a specific member function is exercised in
+ a <literal>try</literal> block, and then any thrown
+ exceptions lead to error checking in the appropriate
+ <literal>catch</literal> block. The container's use of
+ resources is compared to the container's use prior to the
+ test block. Resource monitoring is limited to allocations
+ made through the container's <type>allocator_type</type>,
+ which should be sufficient for container data
+ structures. Included in these tests are member functions
+ are <type>iterator</type> and <type>const_iterator</type>
+ operations, <function>pop_front</function>, <function>pop_back</function>, <function>push_front</function>, <function>push_back</function>, <function>insert</function>, <function>erase</function>, <function>swap</function>, <function>clear</function>,
+ and <function>rehash</function>. The container in question is
+ instantiated with two instrumented template arguments,
+ with <classname>__gnu_cxx::throw_allocator_limit</classname>
+ as the allocator type, and
+ with <classname>__gnu_cxx::throw_type_limit</classname> as
+ the value type. This allows the test to loop through
+ conditional throw points.
+ </para>
+
+ <para>
+ The general form is demonstrated in
+ <filename>testsuite/23_containers/list/requirements/exception/basic.cc
+ </filename>. The instantiating test object is <classname>__gnu_test::basic_safety</classname> and is detailed in <filename>testsuite/util/exception/safety.h</filename>.
+ </para>
+ </listitem>
+
+
+ <listitem>
+ <para>
+ Generation Prohibited
+ </para>
+
+ <para>
+ Exception generation tests. For each container, an object of
+ that container is constructed and all member functions
+ required to not throw exceptions are exercised. Included in
+ these tests are member functions
+ are <type>iterator</type> and <type>const_iterator</type> operations, <function>erase</function>, <function>pop_front</function>, <function>pop_back</function>, <function>swap</function>,
+ and <function>clear</function>. The container in question is
+ instantiated with two instrumented template arguments,
+ with <classname>__gnu_cxx::throw_allocator_random</classname>
+ as the allocator type, and
+ with <classname>__gnu_cxx::throw_type_random</classname> as
+ the value type. This test does not loop, an instead is sudden
+ death: first error fails.
+ </para>
+ <para>
+ The general form is demonstrated in
+ <filename>testsuite/23_containers/list/requirements/exception/generation_prohibited.cc
+ </filename>. The instantiating test object is <classname>__gnu_test::generation_prohibited</classname> and is detailed in <filename>testsuite/util/exception/safety.h</filename>.
+ </para>
+ </listitem>
+
+
+ <listitem>
+ <para>
+ Propagation Consistent
+ </para>
+
+ <para>
+ Container rollback on exception propagation tests. For
+ each container, an object of that container is constructed,
+ a specific member function that requires rollback to a previous
+ known good state is exercised in
+ a <literal>try</literal> block, and then any thrown
+ exceptions lead to error checking in the appropriate
+ <literal>catch</literal> block. The container is compared to
+ the container's last known good state using such parameters
+ as size, contents, and iterator references. Included in these
+ tests are member functions
+ are <function>push_front</function>, <function>push_back</function>, <function>insert</function>,
+ and <function>rehash</function>. The container in question is
+ instantiated with two instrumented template arguments,
+ with <classname>__gnu_cxx::throw_allocator_limit</classname>
+ as the allocator type, and
+ with <classname>__gnu_cxx::throw_type_limit</classname> as
+ the value type. This allows the test to loop through
+ conditional throw points.
+ </para>
+
+ <para>
+ The general form demonstrated in
+ <filename>testsuite/23_containers/list/requirements/exception/propagation_coherent.cc
+ </filename>. The instantiating test object is <classname>__gnu_test::propagation_coherent</classname> and is detailed in <filename>testsuite/util/exception/safety.h</filename>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+</sect4>
+
+</sect3>
+
+</sect2>
+
</sect1>
Index: testsuite/23_containers/list/requirements/exception/propagation_consistent.cc
===================================================================
--- testsuite/23_containers/list/requirements/exception/propagation_consistent.cc (revision 0)
+++ testsuite/23_containers/list/requirements/exception/propagation_consistent.cc (revision 0)
@@ -0,0 +1,34 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-require-cstdint "" }
+
+// 2009-09-09 Benjamin Kosnik <benjamin@redhat.com>
+
+// Copyright (C) 2009 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <list>
+#include <exception/safety.h>
+
+// Container requirement testing, exceptional behavior
+int main()
+{
+ typedef __gnu_cxx::throw_value_limit value_type;
+ typedef __gnu_cxx::throw_allocator_limit<value_type> allocator_type;
+ typedef std::list<value_type, allocator_type> test_type;
+ __gnu_test::propagation_consistent<test_type> test;
+ return 0;
+}
Index: testsuite/23_containers/list/requirements/exception/basic.cc
===================================================================
--- testsuite/23_containers/list/requirements/exception/basic.cc (revision 0)
+++ testsuite/23_containers/list/requirements/exception/basic.cc (revision 0)
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-require-cstdint "" }
+
+// 2009-11-30 Benjamin Kosnik <benjamin@redhat.com>
+
+// Copyright (C) 2009 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <list>
+#include <exception/safety.h>
+
+void
+value()
+{
+ typedef __gnu_cxx::throw_value_limit value_type;
+ typedef __gnu_cxx::throw_allocator_limit<value_type> allocator_type;
+ typedef std::list<value_type, allocator_type> test_type;
+ __gnu_test::basic_safety<test_type> test;
+}
+
+// Container requirement testing, exceptional behavior
+int main()
+{
+ value();
+ return 0;
+}
Index: testsuite/23_containers/list/requirements/exception/generation_prohibited.cc
===================================================================
--- testsuite/23_containers/list/requirements/exception/generation_prohibited.cc (revision 0)
+++ testsuite/23_containers/list/requirements/exception/generation_prohibited.cc (revision 0)
@@ -0,0 +1,34 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-require-cstdint "" }
+
+// 2009-09-09 Benjamin Kosnik <benjamin@redhat.com>
+
+// Copyright (C) 2009 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <list>
+#include <exception/safety.h>
+
+// Container requirement testing, exceptional behavior
+int main()
+{
+ typedef __gnu_cxx::throw_value_random value_type;
+ typedef __gnu_cxx::throw_allocator_random<value_type> allocator_type;
+ typedef std::list<value_type, allocator_type> test_type;
+ __gnu_test::generation_prohibited<test_type> test;
+ return 0;
+}
Index: testsuite/util/exception/safety.h
===================================================================
--- testsuite/util/exception/safety.h (revision 0)
+++ testsuite/util/exception/safety.h (revision 0)
@@ -0,0 +1,1066 @@
+// -*- C++ -*-
+
+// Copyright (C) 2009 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License as published by the Free Software
+// Foundation; either version 3, or (at your option) any later
+// version.
+
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_EXCEPTION_SAFETY_H
+#define _GLIBCXX_EXCEPTION_SAFETY_H
+
+#include <testsuite_container_traits.h>
+#include <ext/throw_allocator.h>
+
+// Container requirement testing.
+namespace __gnu_test
+{
+ // Base class for exception testing, contains utilities.
+ struct setup_base
+ {
+ typedef std::size_t size_type;
+ typedef std::uniform_int_distribution<size_type> distribution_type;
+ typedef std::mt19937 engine_type;
+
+ // Return randomly generated integer on range [0, __max_size].
+ static size_type
+ generate(size_type __max_size)
+ {
+ // Make the generator static...
+ const engine_type engine;
+ const distribution_type distribution;
+ static auto generator = std::bind(distribution, engine,
+ std::placeholders::_1);
+
+ // ... but set the range for this particular invocation here.
+ const typename distribution_type::param_type p(0, __max_size);
+ size_type random = generator(p);
+ if (random < distribution.min() || random > distribution.max())
+ {
+ std::string __s("setup_base::generate");
+ __s += "\n";
+ __s += "random number generated is: ";
+ char buf[40];
+ __builtin_sprintf(buf, "%lu", random);
+ __s += buf;
+ __s += " on range [";
+ __builtin_sprintf(buf, "%lu", distribution.min());
+ __s += buf;
+ __s += ", ";
+ __builtin_sprintf(buf, "%lu", distribution.max());
+ __s += buf;
+ __s += "]\n";
+ std::__throw_out_of_range(__s.c_str());
+ }
+ return random;
+ }
+
+ // Given an instantiating type, return a unique value.
+ template<typename _Tp>
+ struct generate_unique
+ {
+ typedef _Tp value_type;
+
+ operator value_type()
+ {
+ static value_type __ret;
+ ++__ret;
+ return __ret;
+ }
+ };
+
+ // Partial specialization for pair.
+ template<typename _Tp1, typename _Tp2>
+ struct generate_unique<std::pair<const _Tp1, _Tp2>>
+ {
+ typedef _Tp1 first_type;
+ typedef _Tp2 second_type;
+ typedef std::pair<const _Tp1, _Tp2> pair_type;
+
+ operator pair_type()
+ {
+ static first_type _S_1;
+ static second_type _S_2;
+ ++_S_1;
+ ++_S_2;
+ return pair_type(_S_1, _S_2);
+ }
+ };
+
+ // Partial specialization for throw_value
+ template<typename _Cond>
+ struct generate_unique<__gnu_cxx::throw_value_base<_Cond>>
+ {
+ typedef __gnu_cxx::throw_value_base<_Cond> value_type;
+
+ operator value_type()
+ {
+ static size_t _S_i(0);
+ return value_type(_S_i++);
+ }
+ };
+
+
+ // Construct container of size n directly. _Tp == container type.
+ template<typename _Tp>
+ struct make_container_base
+ {
+ _Tp _M_container;
+
+ make_container_base() = default;
+ make_container_base(const size_type n): _M_container(n) { }
+
+ operator _Tp&() { return _M_container; }
+ };
+
+ // Construct container of size n, via multiple insertions. For
+ // associated and unordered types, unique value_type elements are
+ // necessary.
+ template<typename _Tp, bool = traits<_Tp>::is_mapped::value>
+ struct make_insert_container_base
+ : public make_container_base<_Tp>
+ {
+ using make_container_base<_Tp>::_M_container;
+ typedef typename _Tp::value_type value_type;
+
+ make_insert_container_base(const size_type n)
+ {
+ for (size_type i = 0; i < n; ++i)
+ {
+ value_type v = generate_unique<value_type>();
+ _M_container.insert(v);
+ }
+ assert(_M_container.size() == n);
+ }
+ };
+
+ template<typename _Tp>
+ struct make_insert_container_base<_Tp, false>
+ : public make_container_base<_Tp>
+ {
+ using make_container_base<_Tp>::_M_container;
+ typedef typename _Tp::value_type value_type;
+
+ make_insert_container_base(const size_type n)
+ {
+ for (size_type i = 0; i < n; ++i)
+ {
+ value_type v = generate_unique<value_type>();
+ _M_container.insert(_M_container.end(), v);
+ }
+ assert(_M_container.size() == n);
+ }
+ };
+
+ template<typename _Tp, bool = traits<_Tp>::has_size_type_constructor::value>
+ struct make_container_n;
+
+ // Specialization for non-associative types that have a constructor with
+ // a size argument.
+ template<typename _Tp>
+ struct make_container_n<_Tp, true>
+ : public make_container_base<_Tp>
+ {
+ make_container_n(const size_type n) : make_container_base<_Tp>(n) { }
+ };
+
+ template<typename _Tp>
+ struct make_container_n<_Tp, false>
+ : public make_insert_container_base<_Tp>
+ {
+ make_container_n(const size_type n)
+ : make_insert_container_base<_Tp>(n) { }
+ };
+
+
+ // Randomly size and populate a given container reference.
+ // NB: Responsibility for turning off exceptions lies with caller.
+ template<typename _Tp, bool = traits<_Tp>::is_allocator_aware::value>
+ struct populate
+ {
+ typedef _Tp container_type;
+ typedef typename container_type::allocator_type allocator_type;
+ typedef typename container_type::value_type value_type;
+
+ populate(_Tp& __container)
+ {
+ const allocator_type a = __container.get_allocator();
+
+ // Size test container.
+ const size_type max_elements = 100;
+ size_type n = generate(max_elements);
+
+ // Construct new container.
+ make_container_n<container_type> made(n);
+ container_type& tmp = made;
+ std::swap(tmp, __container);
+ }
+ };
+
+ // Partial specialization, empty.
+ template<typename _Tp>
+ struct populate<_Tp, false>
+ {
+ populate(_Tp&) { }
+ };
+
+ // Compare two containers for equivalence.
+ // Right now, that means size.
+ // Returns true if equal, throws if not.
+ template<typename _Tp>
+ static bool
+ compare(const _Tp& __control, const _Tp& __test)
+ {
+ // Make sure test container is in a consistent state, as
+ // compared to the control container.
+ // NB: Should be equivalent to __test != __control, but
+ // computed without equivalence operators
+ const size_type szt = std::distance(__test.begin(), __test.end());
+ const size_type szc = std::distance(__control.begin(),
+ __control.end());
+ bool __equal_size = szt == szc;
+
+ // Should test iterator validity before and after exception.
+ bool __equal_it = std::equal(__test.begin(), __test.end(),
+ __control.begin());
+
+ if (!__equal_size || !__equal_it)
+ throw std::logic_error("setup_base::compare containers not equal");
+
+ return true;
+ }
+ };
+
+
+ // Containing structure holding functors.
+ struct functor_base : public setup_base
+ {
+ // Abstract the erase function.
+ template<typename _Tp>
+ struct erase_base
+ {
+ typedef typename _Tp::iterator iterator;
+
+ iterator (_Tp::* _F_erase_point)(iterator);
+ iterator (_Tp::* _F_erase_range)(iterator, iterator);
+
+ erase_base()
+ : _F_erase_point(&_Tp::erase), _F_erase_range(&_Tp::erase) { }
+ };
+
+ // Specialization, as forward_list has erase_after.
+ template<typename _Tp1, typename _Tp2>
+ struct erase_base<std::forward_list<_Tp1, _Tp2>>
+ {
+ typedef std::forward_list<_Tp1, _Tp2> container_type;
+ typedef typename container_type::iterator iterator;
+ typedef typename container_type::const_iterator const_iterator;
+
+ void (container_type::* _F_erase_point)(const_iterator);
+ void (container_type::* _F_erase_range)(const_iterator, const_iterator);
+
+ erase_base()
+ : _F_erase_point(&container_type::erase_after),
+ _F_erase_range(&container_type::erase_after) { }
+ };
+
+ template<typename _Tp, bool = traits<_Tp>::has_erase::value>
+ struct erase_point : public erase_base<_Tp>
+ {
+ using erase_base<_Tp>::_F_erase_point;
+
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ // NB: Should be equivalent to size() member function, but
+ // computed with begin() and end().
+ const size_type sz = std::distance(__container.begin(),
+ __container.end());
+
+ // NB: Lowest common denominator: use forward iterator operations.
+ auto i = __container.begin();
+ std::advance(i, generate(sz));
+
+ // Makes it easier to think of this as __container.erase(i)
+ (__container.*_F_erase_point)(i);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct erase_point<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::has_erase::value>
+ struct erase_range : public erase_base<_Tp>
+ {
+ using erase_base<_Tp>::_F_erase_range;
+
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ const size_type sz = std::distance(__container.begin(),
+ __container.end());
+ size_type s1 = generate(sz);
+ size_type s2 = generate(sz);
+ auto i1 = __container.begin();
+ auto i2 = __container.begin();
+ std::advance(i1, std::min(s1, s2));
+ std::advance(i2, std::max(s1, s2));
+
+ // Makes it easier to think of this as __container.erase(i1, i2).
+ (__container.*_F_erase_range)(i1, i2);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct erase_range<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
+ struct pop_front
+ {
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ __container.pop_front();
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct pop_front<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
+ && traits<_Tp>::is_reversible::value>
+ struct pop_back
+ {
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ __container.pop_back();
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct pop_back<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
+ struct push_front
+ {
+ typedef _Tp container_type;
+ typedef typename container_type::value_type value_type;
+
+ void
+ operator()(_Tp& __test)
+ {
+ try
+ {
+ const value_type cv = generate_unique<value_type>();
+ __test.push_front(cv);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+
+ // Assumes containers start out equivalent.
+ void
+ operator()(_Tp& __control, _Tp& __test)
+ {
+ try
+ {
+ const value_type cv = generate_unique<value_type>();
+ __test.push_front(cv);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct push_front<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+
+ void
+ operator()(_Tp&, _Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
+ && traits<_Tp>::is_reversible::value>
+ struct push_back
+ {
+ typedef _Tp container_type;
+ typedef typename container_type::value_type value_type;
+
+ void
+ operator()(_Tp& __test)
+ {
+ try
+ {
+ const value_type cv = generate_unique<value_type>();
+ __test.push_back(cv);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+
+ // Assumes containers start out equivalent.
+ void
+ operator()(_Tp& __control, _Tp& __test)
+ {
+ try
+ {
+ const value_type cv = generate_unique<value_type>();
+ __test.push_back(cv);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct push_back<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+
+ void
+ operator()(_Tp&, _Tp&) { }
+ };
+
+
+ // Abstract the insert function into two parts:
+ // 1, insert_base_functions == holds function pointer
+ // 2, insert_base == links function pointer to class insert method
+ template<typename _Tp>
+ struct insert_base
+ {
+ typedef typename _Tp::iterator iterator;
+ typedef typename _Tp::value_type value_type;
+
+ iterator (_Tp::* _F_insert_point)(iterator, const value_type&);
+
+ insert_base() : _F_insert_point(&_Tp::insert) { }
+ };
+
+ // Specialization, as string insertion has a different signature.
+ template<typename _Tp1, typename _Tp2, typename _Tp3>
+ struct insert_base<std::basic_string<_Tp1, _Tp2, _Tp3>>
+ {
+ typedef std::basic_string<_Tp1, _Tp2, _Tp3> container_type;
+ typedef typename container_type::iterator iterator;
+ typedef typename container_type::value_type value_type;
+
+ iterator (container_type::* _F_insert_point)(iterator, value_type);
+
+ insert_base() : _F_insert_point(&container_type::insert) { }
+ };
+
+ template<typename _Tp1, typename _Tp2, typename _Tp3>
+ struct insert_base<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3>>
+ {
+ typedef __gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3> container_type;
+ typedef typename container_type::iterator iterator;
+ typedef typename container_type::value_type value_type;
+
+ iterator (container_type::* _F_insert_point)(iterator, value_type);
+
+ insert_base() : _F_insert_point(&container_type::insert) { }
+ };
+
+ // Specialization, as forward_list insertion has a different signature.
+ template<typename _Tp1, typename _Tp2>
+ struct insert_base<std::forward_list<_Tp1, _Tp2>>
+ {
+ typedef std::forward_list<_Tp1, _Tp2> container_type;
+ typedef typename container_type::iterator iterator;
+ typedef typename container_type::const_iterator const_iterator;
+ typedef typename container_type::value_type value_type;
+
+ iterator (container_type::* _F_insert_point)(const_iterator,
+ const value_type&);
+
+ insert_base() : _F_insert_point(&container_type::insert_after) { }
+ };
+
+ template<typename _Tp, bool = traits<_Tp>::has_insert::value>
+ struct insert_point : public insert_base<_Tp>
+ {
+ typedef _Tp container_type;
+ typedef typename container_type::value_type value_type;
+ using insert_base<_Tp>::_F_insert_point;
+
+ void
+ operator()(_Tp& __test)
+ {
+ try
+ {
+ const value_type cv = generate_unique<value_type>();
+ const size_type sz = std::distance(__test.begin(), __test.end());
+ size_type s = generate(sz);
+ auto i = __test.begin();
+ std::advance(i, s);
+ (__test.*_F_insert_point)(i, cv);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+
+ // Assumes containers start out equivalent.
+ void
+ operator()(_Tp& __control, _Tp& __test)
+ {
+ try
+ {
+ const value_type cv = generate_unique<value_type>();
+ const size_type sz = std::distance(__test.begin(), __test.end());
+ size_type s = generate(sz);
+ auto i = __test.begin();
+ std::advance(i, s);
+ (__test.*_F_insert_point)(i, cv);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct insert_point<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+
+ void
+ operator()(_Tp&, _Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::is_associative::value
+ || traits<_Tp>::is_unordered::value>
+ struct clear
+ {
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ __container.clear();
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct clear<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+ };
+
+
+ template<typename _Tp, bool = traits<_Tp>::is_unordered::value>
+ struct rehash
+ {
+ void
+ operator()(_Tp& __test)
+ {
+ try
+ {
+ size_type s = generate(__test.bucket_count());
+ __test.rehash(s);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+
+ void
+ operator()(_Tp& __control, _Tp& __test)
+ {
+ try
+ {
+ size_type s = generate(__test.bucket_count());
+ __test.rehash(s);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ {
+ // Also check hash status.
+ bool fail(false);
+ if (__control.load_factor() != __test.load_factor())
+ fail = true;
+ if (__control.max_load_factor() != __test.max_load_factor())
+ fail = true;
+ if (__control.bucket_count() != __test.bucket_count())
+ fail = true;
+ if (__control.max_bucket_count() != __test.max_bucket_count())
+ fail = true;
+
+ if (fail)
+ {
+ char buf[40];
+ std::string __s("setup_base::rehash "
+ "containers not equal");
+ __s += "\n";
+ __s += "\n";
+ __s += "\t\t\tcontrol : test";
+ __s += "\n";
+ __s += "load_factor\t\t";
+ __builtin_sprintf(buf, "%lu", __control.load_factor());
+ __s += buf;
+ __s += " : ";
+ __builtin_sprintf(buf, "%lu", __test.load_factor());
+ __s += buf;
+ __s += "\n";
+
+ __s += "max_load_factor\t\t";
+ __builtin_sprintf(buf, "%lu", __control.max_load_factor());
+ __s += buf;
+ __s += " : ";
+ __builtin_sprintf(buf, "%lu", __test.max_load_factor());
+ __s += buf;
+ __s += "\n";
+
+ __s += "bucket_count\t\t";
+ __builtin_sprintf(buf, "%lu", __control.bucket_count());
+ __s += buf;
+ __s += " : ";
+ __builtin_sprintf(buf, "%lu", __test.bucket_count());
+ __s += buf;
+ __s += "\n";
+
+ __s += "max_bucket_count\t";
+ __builtin_sprintf(buf, "%lu", __control.max_bucket_count());
+ __s += buf;
+ __s += " : ";
+ __builtin_sprintf(buf, "%lu", __test.max_bucket_count());
+ __s += buf;
+ __s += "\n";
+
+ std::__throw_logic_error(__s.c_str());
+ }
+ }
+ }
+ };
+
+ // Specialization, empty.
+ template<typename _Tp>
+ struct rehash<_Tp, false>
+ {
+ void
+ operator()(_Tp&) { }
+
+ void
+ operator()(_Tp&, _Tp&) { }
+ };
+
+
+ template<typename _Tp>
+ struct swap
+ {
+ _Tp _M_other;
+
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ __container.swap(_M_other);
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+
+ template<typename _Tp>
+ struct iterator_operations
+ {
+ typedef _Tp container_type;
+ typedef typename container_type::iterator iterator;
+
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ // Any will do.
+ iterator i = __container.begin();
+ iterator __attribute__((unused)) icopy(i);
+ iterator __attribute__((unused)) iassign = i;
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+
+
+ template<typename _Tp>
+ struct const_iterator_operations
+ {
+ typedef _Tp container_type;
+ typedef typename container_type::const_iterator const_iterator;
+
+ void
+ operator()(_Tp& __container)
+ {
+ try
+ {
+ // Any will do.
+ const_iterator i = __container.begin();
+ const_iterator __attribute__((unused)) icopy(i);
+ const_iterator __attribute__((unused)) iassign = i;
+ }
+ catch(const __gnu_cxx::forced_error&)
+ { throw; }
+ }
+ };
+ };
+
+ // Base class for exception tests.
+ template<typename _Tp>
+ struct test_base: public functor_base
+ {
+ typedef _Tp container_type;
+
+ typedef functor_base base_type;
+ typedef populate<container_type> populate;
+ typedef make_container_n<container_type> make_container_n;
+
+ typedef clear<container_type> clear;
+ typedef erase_point<container_type> erase_point;
+ typedef erase_range<container_type> erase_range;
+ typedef insert_point<container_type> insert_point;
+ typedef pop_front<container_type> pop_front;
+ typedef pop_back<container_type> pop_back;
+ typedef push_front<container_type> push_front;
+ typedef push_back<container_type> push_back;
+ typedef rehash<container_type> rehash;
+ typedef swap<container_type> swap;
+ typedef iterator_operations<container_type> iterator_ops;
+ typedef const_iterator_operations<container_type> const_iterator_ops;
+
+ using base_type::compare;
+
+ // Functor objects.
+ clear _M_clear;
+ erase_point _M_erasep;
+ erase_range _M_eraser;
+ insert_point _M_insertp;
+ pop_front _M_popf;
+ pop_back _M_popb;
+ push_front _M_pushf;
+ push_back _M_pushb;
+ rehash _M_rehash;
+ swap _M_swap;
+
+ iterator_ops _M_iops;
+ const_iterator_ops _M_ciops;
+ };
+
+
+ // Run through all member functions for basic exception safety
+ // guarantee: no resource leaks when exceptions are thrown.
+ //
+ // Types of resources checked: memory.
+ //
+ // For each member function, use throw_value and throw_allocator as
+ // value_type and allocator_type to force potential exception safety
+ // errors.
+ //
+ // NB: Assumes
+ // _Tp::value_type is __gnu_cxx::throw_value_*
+ // _Tp::allocator_type is __gnu_cxx::throw_allocator_*
+ // And that the _Cond template parameter for them both is
+ // __gnu_cxx::limit_condition.
+ template<typename _Tp>
+ struct basic_safety : public test_base<_Tp>
+ {
+ typedef _Tp container_type;
+ typedef test_base<container_type> base_type;
+ typedef typename base_type::populate populate;
+ typedef std::function<void(container_type&)> function_type;
+ typedef __gnu_cxx::limit_condition condition_type;
+
+ using base_type::generate;
+
+ container_type _M_container;
+ std::vector<function_type> _M_functions;
+
+ basic_safety() { run(); }
+
+ void
+ run()
+ {
+ // Setup.
+ condition_type::never_adjustor off;
+
+ // Construct containers.
+ populate p1(_M_container);
+ populate p2(base_type::_M_swap._M_other);
+
+ // Construct list of member functions to exercise.
+ _M_functions.push_back(function_type(base_type::_M_iops));
+ _M_functions.push_back(function_type(base_type::_M_ciops));
+
+ _M_functions.push_back(function_type(base_type::_M_erasep));
+ _M_functions.push_back(function_type(base_type::_M_eraser));
+ _M_functions.push_back(function_type(base_type::_M_insertp));
+ _M_functions.push_back(function_type(base_type::_M_popf));
+ _M_functions.push_back(function_type(base_type::_M_popb));
+ _M_functions.push_back(function_type(base_type::_M_pushf));
+ _M_functions.push_back(function_type(base_type::_M_pushb));
+ _M_functions.push_back(function_type(base_type::_M_rehash));
+ _M_functions.push_back(function_type(base_type::_M_swap));
+
+ // Last.
+ _M_functions.push_back(function_type(base_type::_M_clear));
+
+ // Run tests.
+ auto i = _M_functions.begin();
+ for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
+ {
+ function_type& f = *i;
+ run_steps_to_limit(f);
+ }
+ }
+
+ template<typename _Funct>
+ void
+ run_steps_to_limit(const _Funct& __f)
+ {
+ size_t i(1);
+ bool exit(false);
+ auto a = _M_container.get_allocator();
+
+ do
+ {
+ // Use the current step as an allocator label.
+ a.set_label(i);
+
+ try
+ {
+ condition_type::limit_adjustor limit(i);
+ __f(_M_container);
+
+ // If we get here, done.
+ exit = true;
+ }
+ catch(const __gnu_cxx::forced_error&)
+ {
+ // Check this step for allocations.
+ // NB: Will throw std::logic_error if allocations.
+ a.check_allocated(i);
+
+ // Check memory allocated with operator new.
+
+ ++i;
+ }
+ }
+ while (!exit);
+
+ // Log count info.
+ std::cout << __f.target_type().name() << std::endl;
+ std::cout << "end count " << i << std::endl;
+ }
+ };
+
+
+ // Run through all member functions with a no throw requirement, sudden death.
+ // all: member functions erase, pop_back, pop_front, swap
+ // iterator copy ctor, assignment operator
+ // unordered and associative: clear
+ // NB: Assumes _Tp::allocator_type is __gnu_cxx::throw_allocator_random.
+ template<typename _Tp>
+ struct generation_prohibited : public test_base<_Tp>
+ {
+ typedef _Tp container_type;
+ typedef test_base<container_type> base_type;
+ typedef typename base_type::populate populate;
+ typedef __gnu_cxx::random_condition condition_type;
+
+ container_type _M_container;
+
+ generation_prohibited() { run(); }
+
+ void
+ run()
+ {
+ // Furthermore, assumes that the test functor will throw
+ // forced_exception via throw_allocator, that all errors are
+ // propagated and in error. Sudden death!
+
+ // Setup.
+ {
+ condition_type::never_adjustor off;
+ populate p1(_M_container);
+ populate p2(base_type::_M_swap._M_other);
+ }
+
+ // Run tests.
+ {
+ condition_type::always_adjustor on;
+
+ _M_erasep(_M_container);
+ _M_eraser(_M_container);
+
+ _M_popf(_M_container);
+ _M_popb(_M_container);
+
+ _M_iops(_M_container);
+ _M_ciops(_M_container);
+
+ _M_swap(_M_container);
+
+ // Last.
+ _M_clear(_M_container);
+ }
+ }
+ };
+
+
+ // Test strong exception guarantee.
+ // Run through all member functions with a roll-back, consistent
+ // coherent requirement.
+ // all: member functions insert of a single element, push_back, push_front
+ // unordered: rehash
+ template<typename _Tp>
+ struct propagation_consistent : public test_base<_Tp>
+ {
+ typedef _Tp container_type;
+ typedef test_base<container_type> base_type;
+ typedef typename base_type::populate populate;
+ typedef std::function<void(container_type&)> function_type;
+ typedef __gnu_cxx::limit_condition condition_type;
+
+ using base_type::compare;
+
+ container_type _M_container_test;
+ container_type _M_container_control;
+ std::vector<function_type> _M_functions;
+
+ propagation_consistent() { run(); }
+
+ void
+ sync()
+ { _M_container_test = _M_container_control; }
+
+ // Run test.
+ void
+ run()
+ {
+ // Setup.
+ condition_type::never_adjustor off;
+
+ // Construct containers.
+ populate p(_M_container_control);
+ sync();
+
+ // Construct list of member functions to exercise.
+ _M_functions.push_back(function_type(base_type::_M_pushf));
+ _M_functions.push_back(function_type(base_type::_M_pushb));
+ _M_functions.push_back(function_type(base_type::_M_insertp));
+ _M_functions.push_back(function_type(base_type::_M_rehash));
+
+ // Run tests.
+ auto i = _M_functions.begin();
+ for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
+ {
+ function_type& f = *i;
+ run_steps_to_limit(f);
+ }
+ }
+
+ template<typename _Funct>
+ void
+ run_steps_to_limit(const _Funct& __f)
+ {
+ size_t i(1);
+ bool exit(false);
+
+ do
+ {
+ sync();
+
+ try
+ {
+ condition_type::limit_adjustor limit(i);
+ __f(_M_container_test);
+
+ // If we get here, done.
+ exit = true;
+ }
+ catch(const __gnu_cxx::forced_error&)
+ {
+ compare(_M_container_control, _M_container_test);
+ ++i;
+ }
+ }
+ while (!exit);
+
+ // Log count info.
+ std::cout << __f.target_type().name() << std::endl;
+ std::cout << "end count " << i << std::endl;
+ }
+ };
+
+} // namespace __gnu_test
+
+#endif
Index: testsuite/util/testsuite_container_traits.h
===================================================================
--- testsuite/util/testsuite_container_traits.h (revision 155304)
+++ testsuite/util/testsuite_container_traits.h (working copy)
@@ -24,8 +24,9 @@
#include <ext/vstring.h>
namespace __gnu_test
-{
+{
// Container traits.
+ // Base class with default false values for all traits.
struct traits_base
{
// Type, nested type, and typedef related traits.
@@ -37,6 +38,11 @@
typedef std::false_type is_associative;
typedef std::false_type is_unordered;
typedef std::false_type is_mapped;
+
+ typedef std::false_type has_erase;
+ typedef std::false_type has_insert;
+ typedef std::false_type has_push_pop;
+ typedef std::false_type has_size_type_constructor;
};
// Primary template does nothing. Specialize on each type under
@@ -46,40 +52,55 @@
// Specialize for each container.
template<typename _Tp, size_t _Np>
- struct traits<std::array<_Tp, _Np> > : public traits_base
+ struct traits<std::array<_Tp, _Np>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
};
- template<typename _Tp>
- struct traits<std::deque<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::deque<_Tp1, _Tp2>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
+
+ typedef std::true_type has_erase;
+ typedef std::true_type has_insert;
+ typedef std::true_type has_push_pop;
+ typedef std::true_type has_size_type_constructor;
};
- template<typename _Tp>
- struct traits<std::forward_list<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::forward_list<_Tp1, _Tp2>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
+
+ typedef std::true_type has_erase;
+ typedef std::true_type has_insert;
+ typedef std::true_type has_push_pop;
+ typedef std::true_type has_size_type_constructor;
};
- template<typename _Tp>
- struct traits<std::list<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::list<_Tp1, _Tp2>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
+
+ typedef std::true_type has_erase;
+ typedef std::true_type has_insert;
+ typedef std::true_type has_push_pop;
+ typedef std::true_type has_size_type_constructor;
};
- template<typename _Kp, typename _Tp>
- struct traits<std::map<_Kp, _Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3, typename _Tp4>
+ struct traits<std::map<_Tp1, _Tp2, _Tp3, _Tp4>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
@@ -87,10 +108,12 @@
typedef std::true_type is_pointer_aware;
typedef std::true_type is_associative;
typedef std::true_type is_mapped;
+
+ typedef std::true_type has_insert;
};
- template<typename _Kp, typename _Tp>
- struct traits<std::multimap<_Kp, _Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3, typename _Tp4>
+ struct traits<std::multimap<_Tp1, _Tp2, _Tp3, _Tp4>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
@@ -100,108 +123,142 @@
typedef std::true_type is_mapped;
};
- template<typename _Tp>
- struct traits<std::multiset<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3>
+ struct traits<std::multiset<_Tp1, _Tp2, _Tp3>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
typedef std::true_type is_associative;
+
+ typedef std::true_type has_insert;
};
- template<typename _Tp>
- struct traits<std::priority_queue<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::priority_queue<_Tp1, _Tp2>> : public traits_base
{
typedef std::true_type is_adaptor;
};
- template<typename _Tp>
- struct traits<std::queue<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::queue<_Tp1, _Tp2>> : public traits_base
{
typedef std::true_type is_adaptor;
};
- template<typename _Tp>
- struct traits<std::set<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3>
+ struct traits<std::set<_Tp1, _Tp2, _Tp3>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
typedef std::true_type is_associative;
+
+ typedef std::true_type has_insert;
};
- template<typename _Tp>
- struct traits<std::stack<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::stack<_Tp1, _Tp2> > : public traits_base
{
typedef std::true_type is_adaptor;
};
- template<typename _Kp, typename _Tp>
- struct traits<std::unordered_map<_Kp, _Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3,
+ typename _Tp4, typename _Tp5>
+ struct traits<std::unordered_map<_Tp1, _Tp2, _Tp3, _Tp4, _Tp5>>
+ : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
typedef std::true_type is_unordered;
typedef std::true_type is_mapped;
+
+ typedef std::true_type has_size_type_constructor;
+ typedef std::true_type has_insert;
};
- template<typename _Kp, typename _Tp>
- struct traits<std::unordered_multimap<_Kp, _Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3,
+ typename _Tp4, typename _Tp5>
+ struct traits<std::unordered_multimap<_Tp1, _Tp2, _Tp3, _Tp4, _Tp5>>
+ : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
typedef std::true_type is_unordered;
typedef std::true_type is_mapped;
+
+ typedef std::true_type has_size_type_constructor;
};
- template<typename _Tp>
- struct traits<std::unordered_multiset<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3, typename _Tp4>
+ struct traits<std::unordered_multiset<_Tp1, _Tp2, _Tp3, _Tp4>>
+ : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
typedef std::true_type is_unordered;
+
+ typedef std::true_type has_insert;
};
- template<typename _Tp>
- struct traits<std::unordered_set<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3, typename _Tp4>
+ struct traits<std::unordered_set<_Tp1, _Tp2, _Tp3, _Tp4>>
+ : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
typedef std::true_type is_unordered;
+
+ typedef std::true_type has_size_type_constructor;
+ typedef std::true_type has_insert;
};
- template<typename _Tp>
- struct traits<std::vector<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2>
+ struct traits<std::vector<_Tp1, _Tp2>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
+
+ typedef std::true_type has_erase;
+ typedef std::true_type has_insert;
+ typedef std::true_type has_size_type_constructor;
};
- template<typename _Tp>
- struct traits<std::basic_string<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3>
+ struct traits<std::basic_string<_Tp1, _Tp2, _Tp3>> : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
+
+ typedef std::true_type has_erase;
+ typedef std::true_type has_insert;
};
- template<typename _Tp>
- struct traits<__gnu_cxx::__versa_string<_Tp> > : public traits_base
+ template<typename _Tp1, typename _Tp2, typename _Tp3,
+ template <typename, typename, typename> class _Tp4>
+ struct traits<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>
+ : public traits_base
{
typedef std::true_type is_container;
typedef std::true_type is_reversible;
typedef std::true_type is_allocator_aware;
typedef std::true_type is_pointer_aware;
+
+ typedef std::true_type has_erase;
+
+ // XXX no vstring<rc>::insert
+ // typedef std::true_type has_insert;
};
} // namespace __gnu_test
-#endif
+#endif