diff options
author | Benjamin Kosnik <bkoz@redhat.com> | 2009-12-17 09:37:16 +0000 |
---|---|---|
committer | Benjamin Kosnik <bkoz@gcc.gnu.org> | 2009-12-17 09:37:16 +0000 |
commit | 5317914406060becef31b5dc1a8bce8bcea932a9 (patch) | |
tree | 0c608f9406158852df879eef2fb019cab3cde860 | |
parent | ccfd729622bed7e213dccdc07bbc60903e1ad65b (diff) | |
download | gcc-5317914406060becef31b5dc1a8bce8bcea932a9.zip gcc-5317914406060becef31b5dc1a8bce8bcea932a9.tar.gz gcc-5317914406060becef31b5dc1a8bce8bcea932a9.tar.bz2 |
PR libstdc++/21772 part 2
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
7 files changed, 1565 insertions, 93 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 21a6978..bf7f50e 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -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 diff --git a/libstdc++-v3/doc/xml/manual/test.xml b/libstdc++-v3/doc/xml/manual/test.xml index 887f403..3da168e 100644 --- a/libstdc++-v3/doc/xml/manual/test.xml +++ b/libstdc++-v3/doc/xml/manual/test.xml @@ -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 index 0000000..33232f9 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/requirements/exception/basic.cc @@ -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 index 0000000..f3d1602 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/requirements/exception/generation_prohibited.cc @@ -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 index 0000000..02d8d0b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/requirements/exception/propagation_consistent.cc @@ -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 index 0000000..ce9dad4 --- /dev/null +++ b/libstdc++-v3/testsuite/util/exception/safety.h @@ -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 diff --git a/libstdc++-v3/testsuite/util/testsuite_container_traits.h b/libstdc++-v3/testsuite/util/testsuite_container_traits.h index 7c4b1a2..85d04c5 100644 --- a/libstdc++-v3/testsuite/util/testsuite_container_traits.h +++ b/libstdc++-v3/testsuite/util/testsuite_container_traits.h @@ -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 |