PR libstdc++/21772 part 2
authorBenjamin Kosnik <bkoz@redhat.com>
Thu, 17 Dec 2009 09:37:16 +0000 (09:37 +0000)
committerBenjamin Kosnik <bkoz@gcc.gnu.org>
Thu, 17 Dec 2009 09:37:16 +0000 (09:37 +0000)
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.

From-SVN: r155306

libstdc++-v3/ChangeLog
libstdc++-v3/doc/xml/manual/test.xml
libstdc++-v3/testsuite/23_containers/list/requirements/exception/basic.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/list/requirements/exception/generation_prohibited.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/list/requirements/exception/propagation_consistent.cc [new file with mode: 0644]
libstdc++-v3/testsuite/util/exception/safety.h [new file with mode: 0644]
libstdc++-v3/testsuite/util/testsuite_container_traits.h

index 21a6978dba611baede5c56a8947a07a11b119a07..bf7f50ec99da80d98bbcbdee8ae1481815ae527b 100644 (file)
@@ -1,3 +1,16 @@
+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.
+
 2009-12-15  Benjamin Kosnik  <bkoz@redhat.com>
 
        PR libstdc++/21772 part 1
index 887f4035686325c1da948e629fd46544172c77a8..3da168ec45bf9d7683e518ab24af7cf9ac804bb1 100644 (file)
@@ -1,6 +1,6 @@
 <sect1 id="manual.intro.setup.test" xreflabel="Testing">
 <?dbhtml filename="test.html"?>
+
 <sect1info>
   <keywordset>
     <keyword>
@@ -48,7 +48,7 @@ regressions, ABI, and performance.
   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 @@ regressions, ABI, and performance.
 25_algorithms
 26_numerics
 27_io
+28_regex
+29_atomics
+30_threads
    </programlisting>
 
    <para>
@@ -77,9 +80,8 @@ backward        Tests for backwards compatibility and deprecated features.
 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 @@ util                  Files for libtestc++, utilities and testing routines.
    </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 @@ util                Files for libtestc++, utilities and testing routines.
 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 @@ util                  Files for libtestc++, utilities and testing routines.
       used within the testsuite to designate particular kinds of
       tests.
    </para>
+
 <itemizedlist>
 <listitem>
   <para>
@@ -151,10 +153,10 @@ util                Files for libtestc++, utilities and testing routines.
       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 @@ cat 27_io/objects/char/3_xin.in | a.out
 
   <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 @@ cat 27_io/objects/char/3_xin.in | a.out
        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 @@ cat 27_io/objects/char/3_xin.in | a.out
        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=calmrisc32-sid"
 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 @@ make check-target-libstdc++-v3 RUNTESTFLAGS="--target_board=arm-sim"
  <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
       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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
        <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
        <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
        <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
        <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
        <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
    <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 @@ runtest --tool libstdc++ --srcdir=/path/to/gcc/libstdc++-v3/testsuite
    <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 @@ up in the normal.exp file.
 
 <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 @@ only default variables.
 
 <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 @@ only default variables.
        <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 @@ only default variables.
        <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 @@ only default variables.
        <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 @@ only default variables.
        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 @@ only default variables.
        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>
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/exception/basic.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/exception/basic.cc
new file mode 100644 (file)
index 0000000..33232f9
--- /dev/null
@@ -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;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/exception/generation_prohibited.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/exception/generation_prohibited.cc
new file mode 100644 (file)
index 0000000..f3d1602
--- /dev/null
@@ -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;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/exception/propagation_consistent.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/exception/propagation_consistent.cc
new file mode 100644 (file)
index 0000000..02d8d0b
--- /dev/null
@@ -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;
+}
diff --git a/libstdc++-v3/testsuite/util/exception/safety.h b/libstdc++-v3/testsuite/util/exception/safety.h
new file mode 100644 (file)
index 0000000..ce9dad4
--- /dev/null
@@ -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 7c4b1a27097d7701d4fe513b922599ad0ed8756c..85d04c5728ca12a4c8d6ebc8af360d3ccaff7b9a 100644 (file)
@@ -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 @@ namespace __gnu_test
     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 @@ namespace __gnu_test
 
   // 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 @@ namespace __gnu_test
       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 @@ namespace __gnu_test
       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