From stdcxx-dev-return-1434-apmail-incubator-stdcxx-dev-archive=incubator.apache.org@incubator.apache.org Sat Jun 03 03:24:24 2006 Return-Path: Delivered-To: apmail-incubator-stdcxx-dev-archive@www.apache.org Received: (qmail 21316 invoked from network); 3 Jun 2006 03:24:24 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 3 Jun 2006 03:24:24 -0000 Received: (qmail 93369 invoked by uid 500); 3 Jun 2006 03:24:24 -0000 Delivered-To: apmail-incubator-stdcxx-dev-archive@incubator.apache.org Received: (qmail 93314 invoked by uid 500); 3 Jun 2006 03:24:23 -0000 Mailing-List: contact stdcxx-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stdcxx-dev@incubator.apache.org Delivered-To: mailing list stdcxx-dev@incubator.apache.org Received: (qmail 93303 invoked by uid 99); 3 Jun 2006 03:24:23 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 02 Jun 2006 20:24:23 -0700 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: neutral (asf.osuosl.org: local policy) Received: from [208.30.140.160] (HELO moroha.quovadx.com) (208.30.140.160) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 02 Jun 2006 20:24:21 -0700 Received: from qxvcexch01.ad.quovadx.com ([192.168.170.59]) by moroha.quovadx.com (8.13.4/8.13.4) with ESMTP id k533NNn7032035 for ; Sat, 3 Jun 2006 03:23:24 GMT Received: from [10.70.3.113] ([10.70.3.113]) by qxvcexch01.ad.quovadx.com with Microsoft SMTPSVC(6.0.3790.1830); Fri, 2 Jun 2006 21:24:10 -0600 Message-ID: <4480F4C6.80804@roguewave.com> Date: Fri, 02 Jun 2006 20:32:38 -0600 From: Martin Sebor Organization: Rogue Wave Software User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050920 X-Accept-Language: en-us, en MIME-Version: 1.0 To: stdcxx-dev@incubator.apache.org Subject: testing exception safety of string member templates (was: Re: lib.string.capacity test update) References: <4480628E.7060008@moscow.vdiweb.com> In-Reply-To: <4480628E.7060008@moscow.vdiweb.com> Content-Type: multipart/mixed; boundary="------------010105090205020104050700" X-OriginalArrivalTime: 03 Jun 2006 03:24:10.0150 (UTC) FILETIME=[2DC58C60:01C686BD] X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N --------------010105090205020104050700 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Anton Pevtsov wrote: [...] > I think I caught your idea. Today I modified the replace test (see the > attached file, please) to > exercise the exception safety for the range overload too, Looks great! You should be able to change the type of the ReplaceBase* argument to const ReplaceBase& and avoid the clunky syntax when invoking its operator(). I.e., you should be able to replace ret_ptr = &(*prb)(str, args...); with just ret_ptr = &rb (str, args...); Another simplification to consider (I'm not 100% sure it's a good idea but I can't think of any problems with it either) is to change the templates to take a String argument instead of all of charT, Traits, and Allocator. I guess it doesn't matter which way we go on this one. > but got > strange results. > I found that the allocation for InputIterator occurs several times for > long strings (it is ok, isn't it?). Yes, it's (pretty much) inevitable. > Consider the following test case: > > TEST ("a@1000", 0, 0, "b@1000", 0, -1, "b@1000a@1000", 0), > > Here the allocation takes place two times when we are using UserAlloc. > Suppose that first allocation is ok, but the second one fails: the > bad_alloc is thrown. It will be catched, and we will see that the string > state was changed by the first reallocation. Is this correct from the > exception safety standpoint? That depends :) Strictly speaking it is unspecified. The result of the replace member function template is described by a Returns clause which places a requirement only on the return value of the function but not on its effects (which is what the Effects clause is for). While I don't think that's the intent of the text it is what the standard currently in effect says. The intent, I believe, is as if the Returns clause were an Effects clause, including the exception safety implications. I.e., that an exception have no effects on the state of the object. In my opinion this level of exception safety is appropriate for all specializations of the template *except* for InputIterators. Why? Because there is no way to get back at elements once they've been extracted from an input iterator (consider extracting elements from std::cin, pipe or a socket). I don't believe that data loss is an acceptable tradeoff for strong exception safety. Anyway, the latest version of string (the one that've had checked out for weeks while working on fixing STDCXX-170: http://issues.apache.org/jira/browse/STDCXX-170) behaves as is (intended to be) required by the standard, i.e., it doesn't modify the object. > If so, the test should be corrected. And of course, you might want make > other comments and notes. I've made some of the changes I mentioned above and then some (see the attachment). Specifically, I added another class template to let us more easily exercise (non-template) overloads of the range members. I didn't commit the test because the code that's supposed to exercise reverse_iterators is broken and commented out. Feel free to make changes and improvements and post your version for review. Martin --------------010105090205020104050700 Content-Type: text/plain; name="21.string.replace.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="21.string.replace.cpp" /*************************************************************************** * * 21.string.replace.cpp - string test exercising lib.string.replace * * $Id: 21.string.replace.cpp 410006 2006-05-29 00:01:14Z sebor $ * *************************************************************************** * * Copyright 2006 The Apache Software Foundation or its licensors, * as applicable. * * Copyright 2006 Rogue Wave Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **************************************************************************/ #include // for string #include // for out_of_range, length_error #include // for ptrdiff_t, size_t #include <21.strings.h> #include // for InputIter #include // for rw_enabled() #include // for rw_test() #include // for UserAlloc #include // for bad_alloc, replacement operator new #include // for rw_fprintf() /**************************************************************************/ // for convenience and brevity #define Replace(sig) StringIds::replace_ ## sig static const char* const exceptions[] = { "unknown exception", "out_of_range", "length_error", "bad_alloc", "exception" }; /**************************************************************************/ // exercises: // replace (size_type, size_type, const value_type*) // replace (iterator, iterator, const value_type*) static const StringTestCase iter_iter_cptr_test_cases [] = { // iter_iter_cptr_test_cases serves a double duty #define size_size_cptr_test_cases iter_iter_cptr_test_cases #undef TEST #define TEST(str, off, size, arg, res, bthrow) { \ __LINE__, off, size, -1, -1, -1, \ str, sizeof str - 1, \ arg, sizeof arg - 1, res, sizeof res - 1, bthrow \ } // +------------------------------------------ controlled sequence // | +----------------------------- replace() pos1 argument // | | +-------------------------- replace() n1 argument // | | | +----------------------- sequence to be inserted // | | | | +----------- expected result sequence // | | | | | +-- exception info // | | | | | | -1 - no exceptions // | | | | | | 0 - exception safety // | | | | | | 1,2 - out_of_range // | | | | | | 3 - length_error // | | | | | | // | | | | | +-------+ // | | | | | | // V V V V V V TEST ("ab", 0, 0, "c", "cab", 0), TEST ("", 0, 0, "", "", 0), TEST ("", 0, 0, "abc", "abc", 0), TEST ("ab", 0, 2, "", "", 0), TEST ("ab", 0, 1, "", "b", 0), TEST ("\0", 0, 1, "", "", 0), TEST ("\0", 0, 1, "a", "a", 0), TEST ("\0", 0, 1, "\0\0", "", 0), TEST ("ah", 0, 1, "bcdefg", "bcdefgh", 0), TEST ("ah", 1, 1, "bcdefg", "abcdefg", 0), TEST ("ah", 0, 2, "bcdefg", "bcdefg", 0), TEST ("abc", 0, 2, "cc", "ccc", 0), TEST ("abc", 1, 2, "cc", "acc", 0), TEST ("abc", 0, 3, "defgh", "defgh", 0), TEST ("abc", 2, 1, "defgh", "abdefgh", 0), TEST ("abc", 2, 1, "de\0gh", "abde", 0), TEST ("abc", 2, 1, "", "ab", 0), TEST ("abc", 1, 1, "defgh", "adefghc", 0), TEST ("abc", 0, 0, "ee", "eeabc", 0), TEST ("abc", 0, 0, "\0\0e\0", "abc", 0), TEST ("abc", 2, 0, "ee", "abeec", 0), TEST ("abc", 1, 0, "ee", "aeebc", 0), TEST ("abc", 1, 0, "e\0\0", "aebc", 0), TEST ("a\0b\0\0c", 0, 3, "", "\0\0c", 0), TEST ("a\0b\0\0c", 0, 3, "\0e", "\0\0c", 0), TEST ("\0ab\0\0c", 0, 0, "e\0", "e\0ab\0\0c", 0), TEST ("a\0b\0c\0", 6, 0, "e\0", "a\0b\0c\0e", 0), TEST ("\0ab\0\0c", 5, 0, "e\0", "\0ab\0\0ec", 0), TEST ("x@4096", 0, 4095, "ab", "abx", 0), TEST ("\0@4096", 1, 4094, "abc", "\0abc\0", 0), TEST ("x@4096", 1, 4094, "ab", "xabx", 0), TEST ("x@4096", 0, 4094, "ab", "abxx", 0), TEST ("x@4096", 1, 4093, "", "xxx", 0), TEST ("x@20", 1, 10, "x@118", "x@128", 0), TEST ("x@128", 128, 0, "x@79", "x@207", 0), TEST ("x@207", 0, 0, "x@127", "x@334", 0), TEST ("x@334", 1, 1, "x@207", "x@540", 0), TEST ("x@540", 0, 539, "x@334", "x@335", 0), TEST ("x@539", 539, 0, "x@873", "x@1412", 0), TEST ("x@3695", 0, 2283, "", "x@1412", 0), TEST ("x@1412", 207, 1, "x@2284", "x@3695", 0), TEST ("x@207", 0, 207, "x@2284", "x@2284", 0), TEST ("", 0, 0, "x@4096", "x@4096", 0), TEST ("a", 0, 1, "x@4096", "x@4096", 0), TEST ("x@4096", 0, 4095, "x@4096", "x@4097", 0), TEST ("\0ab\0\0c", 0, 6, "x@4096", "x@4096", 0), TEST ("\0", 2, 0, "", "\0", 1), TEST ("a", 10, 0, "", "a", 1), TEST ("x@4096", 4106, 0, "", "x@4096", 1), TEST ("", 0, 0, "x@4096", "x@4096", 0), // self-referential replacement TEST ("", 0, 0, 0, "", 0), TEST ("abc", 0, 3, 0, "abc", 0), TEST ("abc", 1, 1, 0, "aabcc", 0), TEST ("a\0b\0c\0", 2, 3, 0, "a\0a\0", 0), TEST ("a\0b\0c\0", 0, 0, 0, "aa\0b\0c\0", 0), TEST ("a\0b\0c\0", 6, 0, 0, "a\0b\0c\0a", 0), TEST ("\0ab\0c\0", 3, 3, 0, "\0ab", 0), TEST ("x@4096", 0, 4095, 0, "x@4097", 0), TEST ("last", 4, 0, "test", "lasttest", 0) }; /**************************************************************************/ // exercises: // replace (size_type, size_type, const basic_string&) // replace (iterator, iterator, const basic_string&) static const StringTestCase iter_iter_cstr_test_cases [] = { // iter_iter_cstr_test_cases serves a double duty #define size_size_cstr_test_cases iter_iter_cstr_test_cases #undef TEST #define TEST(s, off, size, arg, res, bthrow) { \ __LINE__, off, size, -1, -1, -1, \ s, sizeof s - 1, \ arg, sizeof arg - 1, res, sizeof res - 1, bthrow \ } // +------------------------------------------- controlled sequence // | +----------------------------- replace() pos1 argument // | | +-------------------------- replace() n1 argument // | | | +----------------------- sequence to be inserted // | | | | +----------- expected result sequence // | | | | | +-- exception info // | | | | | | -1 - no exceptions // | | | | | | 0 - exception safety // | | | | | | 1,2 - out_of_range // | | | | | | 3 - length_error // | | | | | | // | | | | | +-----------+ // | | | | | | // V V V V V V TEST ("ab", 0, 0, "c", "cab", 0), TEST ("", 0, 0, "", "", 0), TEST ("", 0, 0, "\0", "\0", 0), TEST ("", 0, 0, "abc", "abc", 0), TEST ("ab", 0, 2, "", "", 0), TEST ("ab", 0, 1, "", "b", 0), TEST ("ab", 1, 1, "\0", "a\0", 0), TEST ("\0", 0, 1, "", "", 0), TEST ("\0", 0, 1, "a", "a", 0), TEST ("\0", 0, 1, "\0\0", "\0\0", 0), TEST ("ah", 0, 1, "bcdefg", "bcdefgh", 0), TEST ("ah", 1, 1, "bcdefg", "abcdefg", 0), TEST ("ah", 0, 2, "bcdefg", "bcdefg", 0), TEST ("abc", 0, 2, "cc", "ccc", 0), TEST ("abc", 1, 2, "cc", "acc", 0), TEST ("abc", 0, 3, "defgh", "defgh", 0), TEST ("abc", 2, 1, "defgh", "abdefgh", 0), TEST ("abc", 2, 1, "de\0gh", "abde\0gh", 0), TEST ("abc", 2, 1, "", "ab", 0), TEST ("abc", 1, 1, "defgh", "adefghc", 0), TEST ("abc", 0, 0, "ee", "eeabc", 0), TEST ("abc", 0, 0, "\0\0e\0", "\0\0e\0abc", 0), TEST ("abc", 2, 0, "ee", "abeec", 0), TEST ("abc", 1, 0, "ee", "aeebc", 0), TEST ("abc", 1, 0, "e\0\0", "ae\0\0bc", 0), TEST ("a\0b\0\0c", 0, 3, "", "\0\0c", 0), TEST ("a\0b\0\0c", 0, 3, "\0e", "\0e\0\0c", 0), TEST ("a\0b\0\0c", 2, 3, "\0e", "a\0\0ec", 0), TEST ("a\0b\0\0c", 0, 3, "\0\0e\0", "\0\0e\0\0\0c", 0), TEST ("\0ab\0\0c", 1, 2, "\0e\0\0", "\0\0e\0\0\0\0c", 0), TEST ("\0ab\0\0c", 0, 0, "\0e", "\0e\0ab\0\0c", 0), TEST ("a\0b\0c\0", 6, 0, "e\0", "a\0b\0c\0e\0", 0), TEST ("\0ab\0\0c", 5, 0, "\0e", "\0ab\0\0\0ec", 0), TEST ("x@4096", 0, 4095, "ab", "abx", 0), TEST ("x@4096", 1, 4094, "ab", "xabx", 0), TEST ("x@4096", 0, 4094, "ab", "abxx", 0), TEST ("x@4096", 1, 4093, "", "xxx", 0), TEST ("x@4096", 1, 4092, "\0\0", "x\0\0xxx", 0), TEST ("x@20", 1, 10, "x@118", "x@128", 0), TEST ("x@128", 128, 0, "x@79", "x@207", 0), TEST ("x@207", 0, 0, "x@127", "x@334", 0), TEST ("x@334", 1, 1, "x@207", "x@540", 0), TEST ("x@540", 0, 539, "x@334", "x@335", 0), TEST ("x@539", 539, 0, "x@873", "x@1412", 0), TEST ("x@3695", 0, 2283, "", "x@1412", 0), TEST ("x@1412", 207, 1, "x@2284", "x@3695", 0), TEST ("x@207", 0, 207, "x@2284", "x@2284", 0), TEST ("", 0, 0, "x@4096", "x@4096", 0), TEST ("a", 0, 1, "x@4096", "x@4096", 0), TEST ("x@4096", 0, 4095, "x@4096", "x@4097", 0), TEST ("\0ab\0\0c", 0, 6, "x@4096", "x@4096", 0), TEST ("\0", 2, 0, "", "\0", 1), TEST ("a", 10, 0, "", "a", 1), TEST ("x@4096", 4106, 0, "", "x@4096", 1), TEST ("", 0, 0, "x@4096", "x@4096", 0), // self-referential replacement TEST ("abc", 0, 3, 0, "abc", 0), TEST ("abc", 1, 1, 0, "aabcc", 0), TEST ("a\0b\0c\0", 2, 3, 0, "a\0a\0b\0c\0\0", 0), TEST ("a\0b\0c\0", 0, 0, 0, "a\0b\0c\0a\0b\0c\0", 0), TEST ("a\0b\0c\0", 6, 0, 0, "a\0b\0c\0a\0b\0c\0", 0), TEST ("\0ab\0c\0", 3, 3, 0, "\0ab\0ab\0c\0", 0), TEST ("x@4096", 0, 4095, 0, "x@4097", 0), TEST ("last", 4, 0, "test", "lasttest", 0) }; /**************************************************************************/ // exercises: // replace (size_type, size_type, const value_type*, size_type) // replace (iterator, iterator, const value_type*, size_type) static const StringTestCase iter_iter_cptr_size_test_cases [] = { // iter_iter_cptr_size_test_cases serves a double duty #define size_size_cptr_size_test_cases iter_iter_cptr_size_test_cases #undef TEST #define TEST(str, off, size, arg, count, res, bthrow) { \ __LINE__, off, size, -1, count, -1, \ str, sizeof str - 1, \ arg, sizeof arg - 1, res, sizeof res - 1, bthrow \ } // +------------------------------------------ controlled sequence // | +----------------------------- replace() pos1 argument // | | +-------------------------- replace() n1 argument // | | | +----------------------- sequence to be inserted // | | | | +---------- replace() n2 argument // | | | | | +------- expected result sequence // | | | | | | +- exception info // | | | | | | | -1 - no exceptions // | | | | | | | 0 - exception safety // | | | | | | | 1,2 - out_of_range // | | | | | | | 3 - length_error // | | | | | | | // | | | | | | +------------+ // | | | | | | | // V V V V V V V TEST ("ab", 0, 0, "c", 1, "cab", 0), TEST ("", 0, 0, "", 0, "", 0), TEST ("", 0, 0, "abc", 3, "abc", 0), TEST ("ab", 0, 2, "", 0, "", 0), TEST ("ab", 0, 1, "", 0, "b", 0), TEST ("\0", 0, 1, "", 0, "", 0), TEST ("\0", 0, 1, "a", 1, "a", 0), TEST ("\0", 0, 1, "\0\0", 2, "\0\0", 0), TEST ("ah", 0, 1, "bcdefg", 3, "bcdh", 0), TEST ("ah", 1, 1, "bcdefg", 3, "abcd", 0), TEST ("ah", 0, 2, "bcdefg", 5, "bcdef", 0), TEST ("abc", 0, 2, "cc", 2, "ccc", 0), TEST ("abc", 1, 2, "cc", 2, "acc", 0), TEST ("abc", 2, 1, "defgh", 1, "abd", 0), TEST ("abc", 2, 1, "de\0gh", 3, "abde\0", 0), TEST ("abc", 2, 1, "", 0, "ab", 0), TEST ("abc", 0, 0, "ee", 2, "eeabc", 0), TEST ("abc", 0, 0, "\0\0e\0", 4, "\0\0e\0abc", 0), TEST ("abc", 2, 0, "ee", 2, "abeec", 0), TEST ("abc", 1, 0, "ee", 1, "aebc", 0), TEST ("a\0b\0\0c", 0, 3, "", 0, "\0\0c", 0), TEST ("a\0b\0\0c", 0, 3, "e\0", 2, "e\0\0\0c", 0), TEST ("a\0b\0\0c", 2, 3, "e\0", 1, "a\0ec", 0), TEST ("a\0b\0\0c", 2, 3, "\0e", 2, "a\0\0ec", 0), TEST ("\0ab\0\0c", 2, 3, "\0e", 2, "\0a\0ec", 0), TEST ("a\0b\0\0c", 0, 6, "e\0", 2, "e\0", 0), TEST ("x@4096", 1, 4095, "\0", 1, "x\0", 0), TEST ("x@4096", 0, 4095, "ab", 2, "abx", 0), TEST ("x@4096", 1, 4094, "ab", 1, "xax", 0), TEST ("x@4096", 0, 4094, "ab", 2, "abxx", 0), TEST ("x@4096", 1, 4093, "", 0, "xxx", 0), TEST ("x@4096", 1, 4092, "\0\0", 2, "x\0\0xxx", 0), TEST ("", 0, 0, "x@873", 540, "x@540", 0), TEST ("x@20", 1, 10, "x@118", 118, "x@128", 0), TEST ("x@128", 128, 0, "x@79", 79, "x@207", 0), TEST ("x@207", 0, 0, "x@127", 127, "x@334", 0), TEST ("x@207", 207, 207, "x@207", 127, "x@334", 0), TEST ("x@334", 0, 207, "x@545", 540, "x@667", 0), TEST ("x@539", 0, 539, "x@873", 873, "x@873", 0), TEST ("x@878", 5, 5, "x@540", 539, "x@1412", 0), TEST ("x@872", 0, 0, "x@1412", 1412, "x@2284", 0), TEST ("x@1411", 1411, 0, "x@2284", 2284, "x@3695", 0), TEST ("x@1411", 873, 538, "x@3695", 2822, "x@3695", 0), TEST ("x@1412", 0, 0, "x@2284", 2284, "x@3696", 0), TEST ("", 0, 0, "x@3696", 3696, "x@3696", 0), TEST ("a", 0, 1, "x@4096", 4095, "x@4095", 0), TEST ("x@4096", 0, 4095, "y@4096", 4095, "y@4095x", 0), TEST ("x@4096", 0, 2047, "x@4096", 2047, "x@4096", 0), TEST ("x@4096", 2047, 2048, "x@4096", 2048, "x@4096", 0), TEST ("\0", 2, 0, "", 0, "\0", 1), TEST ("a", 10, 0, "", 0, "a", 1), TEST ("x@4096", 4106, 0, "", 0, "x@4096", 1), TEST ("a", 0, 1, "x@4096", 4095, "x@4095", 0), // self-referential replacement TEST ("a", 0, 0, 0 /* self */, 1, "aa", 0), TEST ("a", 0, 1, 0 /* self */, 1, "a", 0), TEST ("a", 1, 0, 0 /* self */, 1, "aa", 0), TEST ("abc", 0, 3, 0 /* self */, 2, "ab", 0), TEST ("abc", 1, 1, 0 /* self */, 3, "aabcc", 0), TEST ("a\0b\0c\0", 2, 3, 0 /* self */, 6, "a\0a\0b\0c\0\0", 0), TEST ("a\0b\0c\0", 0, 0, 0 /* self */, 4, "a\0b\0a\0b\0c\0", 0), TEST ("\0ab\0c\0", 6, 0, 0 /* self */, 1, "\0ab\0c\0\0", 0), TEST ("\0ab\0c\0", 3, 3, 0 /* self */, 2, "\0ab\0a", 0), TEST ("a@4096", 0, 1, 0 /* self */, 1111, "a@5206", 0), TEST ("b@4096", 1, 2, 0 /* self */, 2222, "b@6316", 0), TEST ("x@4096", 0, 4095, 0 /* self */, 4095, "x@4096", 0), TEST ("x@4096", 0, 4095, 0 /* self */, 1, "xx", 0), TEST ("last", 4, 0, "test", 4, "lasttest", 0) }; /**************************************************************************/ // exercises: // replace (size_type, size_type, basic_string&, size_type, size_type) // replace (iterator, Iterator, InputIterator, InputIterator) static const StringTestCase iter_iter_range_test_cases [] = { // iter_iter_range_test_cases serves a double duty #define size_size_cstr_size_size_test_cases iter_iter_range_test_cases #undef TEST #define TEST(str, off, size, arg, off2, size2, res, bthrow) { \ __LINE__, off, size, off2, size2, -1, \ str, sizeof str - 1, \ arg, sizeof arg - 1, res, sizeof res - 1, bthrow \ } // +------------------------------------------- controlled sequence // | +------------------------------ replace() pos argument // | | +-------------------------- replace() n1 argument // | | | +----------------------- sequence to be inserted // | | | | +----------- replace() pos2 argument // | | | | | +------- replace() n2 argument // | | | | | | +---- expected result sequence // | | | | | | | +-- exception info: // | | | | | | | | -1 - no exceptions // | | | | | | | | 0 - exception safety // | | | | | | | | 1, 2 - out_of_range // | | | | | | | | 3 - length_error // | | | | | | | | // | | | | | | | +-----------------+ // | | | | | | | | // V V V V V V V V TEST ("", 0, 0, "", 0, 0, "", 0), TEST ("", 0, 0, "", 0, -1, "", 0), TEST ("", 0, 0, "", 0, 1, "", 0), TEST ("", 0, 1, "", 0, 0, "", 0), TEST ("", 0, 1, "", 0, 1, "", 0), TEST ("", 0, 1, "", 0, -1, "", 0), TEST ("", 0, -1, "", 0, 0, "", 0), TEST ("", 0, -1, "", 0, 1, "", 0), TEST ("", 0, -1, "", 0, -1, "", 0), TEST ("1", 0, 0, "", 0, 0, "1", 0), TEST ("2", 0, 0, "", 0, -1, "2", 0), TEST ("3", 0, 0, "", 0, 1, "3", 0), TEST ("4", 0, 1, "", 0, 0, "", 0), TEST ("5", 0, 1, "", 0, 1, "", 0), TEST ("6", 0, 1, "", 0, -1, "", 0), TEST ("7", 0, -1, "", 0, 0, "", 0), TEST ("8", 0, -1, "", 0, 1, "", 0), TEST ("9", 0, -1, "", 0, -1, "", 0), TEST ("1", 0, 0, "9", 0, 0, "1", 0), TEST ("2", 0, 0, "8", 0, -1, "82", 0), TEST ("3", 0, 0, "7", 0, 1, "73", 0), TEST ("4", 0, 1, "6", 0, 0, "", 0), TEST ("5", 0, 1, "5", 0, 1, "5", 0), TEST ("6", 0, 1, "4", 0, -1, "4", 0), TEST ("7", 0, -1, "3", 0, 0, "", 0), TEST ("8", 0, -1, "2", 0, 1, "2", 0), TEST ("9", 0, -1, "1", 0, -1, "1", 0), TEST ("", 0, 0, "abc", 0, 3, "abc", 0), TEST ("ab", 0, 0, "c", 0, 1, "cab", 0), TEST ("ab", 0, 2, "", 0, 0, "", 0), TEST ("ab", 0, 1, "", 0, 0, "b", 0), TEST ("\0", 0, 1, "", 0, 0, "", 0), TEST ("\0", 0, 1, "a", 0, 1, "a", 0), TEST ("\0", 0, 1, "\0\0", 1, 1, "\0", 0), TEST ("\0", 0, 1, "\0\0", 0, 2, "\0\0", 0), TEST ("ah", 0, 1, "bcdefg", 0, 3, "bcdh", 0), TEST ("ah", 1, 1, "bcdefg", 0, 3, "abcd", 0), TEST ("ah", 0, 1, "bcdefg", 1, 3, "cdeh", 0), TEST ("ah", 1, 1, "bcdefg", 1, 3, "acde", 0), TEST ("ah", 0, 1, "bcdefg", 0, 6, "bcdefgh", 0), TEST ("ah", 1, 1, "bcdefg", 0, 6, "abcdefg", 0), TEST ("abc", 0, 2, "cc", 0, 2, "ccc", 0), TEST ("abc", 1, 2, "cc", 0, 2, "acc", 0), TEST ("abc", 0, 3, "d", 0, 1, "d", 0), TEST ("abc", 0, 3, "def", 0, 3, "def", 0), TEST ("abc", 0, 3, "defgh", 0, 5, "defgh", 0), TEST ("abc", 2, 1, "defgh", 4, 1, "abh", 0), TEST ("abc", 2, 1, "de\0gh", 2, 1, "ab\0", 0), TEST ("abc", 2, 1, "", 0, 0, "ab", 0), TEST ("abc", 1, 1, "defgh", 1, 2, "aefc", 0), TEST ("abc", 0, 0, "ee", 0, 2, "eeabc", 0), TEST ("abc", 0, 0, "\0\0e\0", 0, 4, "\0\0e\0abc", 0), TEST ("abc", 2, 0, "ee", 0, 2, "abeec", 0), TEST ("abc", 2, 1, "\0e\0\0", 0, 4, "ab\0e\0\0", 0), TEST ("abc", 1, 0, "ee", 0, 2, "aeebc", 0), TEST ("abc", 1, 0, "\0e\0\0", 0, 4, "a\0e\0\0bc", 0), TEST ("a\0b\0\0c", 0, 3, "", 0, 0, "\0\0c", 0), TEST ("\0ab\0\0c", 0, 3, "", 0, 0, "\0\0c", 0), TEST ("a\0b\0\0c", 0, 3, "\0e", 0, 2, "\0e\0\0c", 0), TEST ("a\0b\0\0c", 2, 3, "\0e", 0, 2, "a\0\0ec", 0), TEST ("a\0b\0\0c", 2, 3, "\0e", 1, 1, "a\0ec", 0), TEST ("\0ab\0\0c", 2, 3, "\0e", 0, 2, "\0a\0ec", 0), TEST ("\0ab\0\0c", 2, 3, "\0e\0\0", 1, 3, "\0ae\0\0c", 0), TEST ("a\0b\0\0c", 0, 6, "\0e", 0, 2, "\0e", 0), TEST ("a\0b\0\0c", 0, 6, "\0e", 0, 1, "\0", 0), TEST ("\0ab\0\0c", 0, 0, "\0e", 0, 2, "\0e\0ab\0\0c", 0), TEST ("a\0b\0c\0", 6, 0, "e\0", 0, 2, "a\0b\0c\0e\0", 0), TEST ("\0ab\0\0c", 5, 0, "\0e", 0, 2, "\0ab\0\0\0ec", 0), /////////////////////////////////////////////////////////////////////// // very long strings TEST ("a", 0, 0, "b", 0, -1, "ba", 0), TEST ("a@0", 0, 0, "b@0", 0, -1, "", 0), TEST ("a@0", 0, 0, "b@1", 0, -1, "b", 0), TEST ("a@1", 0, 0, "b@0", 0, -1, "a", 0), TEST ("a@1", 0, 0, "b@1", 0, -1, "ba", 0), TEST ("a@2", 0, 0, "b@2", 0, -1, "bbaa", 0), TEST ("a@1000", 0, 0, "b@1000", 0, -1, "b@1000a@1000", 0), TEST ("a@1000", 0, 1, "b@1001", 0, -1, "b@1001a@999", 0), TEST ("a@1000", 0, 2, "b@1002", 0, -1, "b@1002a@998", 0), TEST ("a@1000", 1, 998, "b@1003", 0, -1, "ab@1003a", 0), TEST ("a@1000", 2, 996, "b@1004", 0, -1, "aab@1004aa", 0), TEST ("a@1000", 500, 250, "b@1005", 0, -1, "a@500b@1005a@250", 0), TEST ("a@1000", 998, 1, "b@1006", 0, -1, "a@998b@1006a", 0), TEST ("a@2000", 1000, -1, "b", 0, -1, "a@1000b", 0), TEST ("a@2000", 1000, 999, "bb", 0, -1, "a@1000bba", 0), TEST ("x@4096", 0, 4095, "ab", 0, 2, "abx", 0), TEST ("x@4096", 1, 4094, "ab", 0, 2, "xabx", 0), TEST ("x@4096", 0, 4094, "ab", 0, 2, "abxx", 0), TEST ("x@4096", 1, 4093, "", 0, 0, "xxx", 0), TEST ("x@4096", 1, 4092, "\0\0", 0, 2, "x\0\0xxx", 0), TEST ("a", 0, 1, "x@4096", 0, 4095, "x@4095", 0), TEST ("x@4096", 0, 4095, "x@4096", 0, 4095, "x@4096", 0), TEST ("x@4096", 0, 2047, "x@4096", 0, 2047, "x@4096", 0), TEST ("", 0, 0, "x@334", 0, 207, "x@207", 0), TEST ("x@20", 1, 10, "x@118", 0, 118, "x@128", 0), TEST ("x@128", 0, 0, "x@129", 50, 79, "x@207", 0), TEST ("x@207", 207, 0, "x@127", 0, 127, "x@334", 0), TEST ("x@208", 128, 1, "x@207", 10, 127, "x@334", 0), TEST ("x@335", 334, 1, "x@208", 2, 206, "x@540", 0), TEST ("x@540", 0, 0, "x@336", 3, 333, "x@873", 0), TEST ("x@334", 0, 334, "x@873", 0, 873, "x@873", 0), TEST ("x@873", 0, 873, "x@541", 1, 540, "x@540", 0), TEST ("x@872", 0, 0, "x@1412", 0, 1412, "x@2284", 0), TEST ("x@1411", 1411, 0, "x@2288", 4, 2284, "x@3695", 0), TEST ("x@873", 540,333, "x@3695",3695, 0, "x@540", 0), TEST ("x@1412", 0, 1412, "x@3696", 0,3695, "x@3695", 0), TEST ("x@4096", 2047, 2048, "x@4096", 0, 2048, "x@4096", 0), TEST ("\0", 2, 0, "", 0, 0, "\0", 1), TEST ("\0", 0, 0, "\0", 2, 0, "\0", 2), TEST ("a", 10, 0, "", 0, 0, "a", 1), TEST ("a", 0, 0, "a", 10, 0, "a", 2), TEST ("x@4096", 4106, 0, "", 0, 0, "x@4096", 1), TEST ("x@4096", 0, 0, "x@4096", 4106, 0, "x@4096", 2), TEST ("a", 0, 1, "x@4096", 0, 4095, "x@4095", 0), /////////////////////////////////////////////////////////////////////// // self-referential replacement TEST ("", 0, 0, 0, 0, 0, "", 0), TEST ("", 0, 0, 0, 0, 1, "", 0), TEST ("", 0, 0, 0, 0, -1, "", 0), TEST ("", 0, 1, 0, 0, 0, "", 0), TEST ("", 0, 1, 0, 0, 1, "", 0), TEST ("", 0, 1, 0, 0, -1, "", 0), TEST ("", 0, -1, 0, 0, 0, "", 0), TEST ("", 0, -1, 0, 0, 1, "", 0), TEST ("", 0, -1, 0, 0, -1, "", 0), TEST ("1", 0, 0, 0, 0, 0, "1", 0), TEST ("2", 0, 0, 0, 0, -1, "22", 0), TEST ("3", 0, 0, 0, 0, 1, "33", 0), TEST ("4", 0, 1, 0, 0, 0, "", 0), TEST ("5", 0, 1, 0, 0, 1, "5", 0), TEST ("6", 0, 1, 0, 0, -1, "6", 0), TEST ("7", 0, -1, 0, 0, 0, "", 0), TEST ("8", 0, -1, 0, 0, 1, "8", 0), TEST ("9", 0, -1, 0, 0, -1, "9", 0), TEST ("x@4096", 0, 0, 0, 0, 0, "x@4096", 0), TEST ("x@4096", 0, 1, 0, 0, 1, "x@4096", 0), TEST ("x@4096", 0, 2, 0, 0, 2, "x@4096", 0), TEST ("x@4096", 0, -1, 0, 0, -1, "x@4096", 0), TEST ("abc", 0, 0, 0, 1, 1, "babc", 0), TEST ("abc", 2, 0, 0, 0, 2, "ababc", 0), TEST ("a\0bc\0\0", 0, 0, 0, 4, 2, "\0\0a\0bc\0\0", 0), TEST ("a\0bc\0\0", 6, 0, 0, 1, 3, "a\0bc\0\0\0bc", 0), TEST ("abcdef", 0, 0, 0, 1, 2, "bcabcdef", 0), TEST ("last", 4, 0, "test", 0, 4, "lasttest", 0) }; /**************************************************************************/ // exercises: // replace (size_type, size_type, value_type, size_type) // replace (iterator, iterator, size_type, value_type) static const StringTestCase iter_iter_size_val_test_cases [] = { // iter_iter_size_val_test_cases serves a double duty #define size_size_size_val_test_cases iter_iter_size_val_test_cases #undef TEST #define TEST(str, off, size, count, val, res, bthrow) { \ __LINE__, off, size, -1, count, val, \ str, sizeof str - 1, \ 0, 0, res, sizeof res - 1, bthrow \ } // +------------------------------------------ controlled sequence // | +----------------------------- replace() pos1 argument // | | +-------------------------- replace() n1 argument // | | | +----------------------- replace() count argument // | | | | +------------------- character to be inserted // | | | | | +-------------- expected result sequence // | | | | | | +------ exception info // | | | | | | | -1 - no exceptions // | | | | | | | 0 - exception safety // | | | | | | | 1,2 - out_of_range // | | | | | | | 3 - length_error // | | | | | | | // | | | | | | +--------+ // | | | | | | | // V V V V V V V TEST ("ab", 0, 0, 1, 'c', "cab", 0), TEST ("", 0, 0, 0, 'c', "", 0), TEST ("", 0, 0, 3, 'c', "ccc", 0), TEST ("ab", 0, 2, 0, 'c', "", 0), TEST ("ab", 0, 1, 0, 'c', "b", 0), TEST ("\0", 0, 1, 0, ' ', "", 0), TEST ("\0", 0, 1, 1, 'a', "a", 0), TEST ("\0", 0, 1, 1, '\0', "\0", 0), TEST ("\0", 0, 1, 2, '\0', "\0\0", 0), TEST ("ah", 0, 1, 1, 'c', "ch", 0), TEST ("ah", 1, 1, 1, 'c', "ac", 0), TEST ("ah", 0, 1, 4, 'c', "cccch", 0), TEST ("ah", 1, 1, 4, 'c', "acccc", 0), TEST ("abc", 0, 2, 2, 'c', "ccc", 0), TEST ("abc", 1, 2, 2, 'c', "acc", 0), TEST ("abc", 0, 3, 1, 'c', "c", 0), TEST ("abc", 0, 3, 5, 'c', "ccccc", 0), TEST ("abc", 2, 1, 1, 'c', "abc", 0), TEST ("abc", 2, 1, 0, 'c', "ab", 0), TEST ("abc", 1, 1, 5, 'c', "acccccc", 0), TEST ("abc", 0, 0, 2, 'c', "ccabc", 0), TEST ("abc", 0, 0, 3, '\0', "\0\0\0abc", 0), TEST ("abc", 2, 0, 2, 'e', "abeec", 0), TEST ("abc", 2, 0, 3, '\0', "ab\0\0\0c", 0), TEST ("abc", 1, 0, 1, '\0', "a\0bc", 0), TEST ("a\0b\0\0c", 0, 3, 1, '\0', "\0\0\0c", 0), TEST ("a\0b\0\0c", 2, 3, 2, '\0', "a\0\0\0c", 0), TEST ("a\0b\0\0c", 2, 2, 1, '\0', "a\0\0\0c", 0), TEST ("\0ab\0\0c", 2, 3, 0, '\0', "\0ac", 0), TEST ("\0ab\0\0c", 2, 1, 2, '\0', "\0a\0\0\0\0c", 0), TEST ("a\0b\0\0c", 0, 6, 2, '\0', "\0\0", 0), TEST ("\0ab\0\0c", 0, 0, 2, '\0', "\0\0\0ab\0\0c", 0), TEST ("a\0b\0c\0", 6, 0, 2, '\0', "a\0b\0c\0\0\0", 0), TEST ("\0ab\0\0c", 5, 0, 1, '\0', "\0ab\0\0\0c", 0), TEST ("x@4096", 0, 4095, 2, 'a', "aax", 0), TEST ("x@4096", 1, 4094, 2, 'a', "xaax", 0), TEST ("x@4096", 0, 4094, 2, 'a', "aaxx", 0), TEST ("x@4096", 1, 4093, 0, 'a', "xxx", 0), TEST ("x@4096", 1, 4092, 1, '\0', "x\0xxx", 0), TEST ("x@127", 0, 0, 1, 'x', "x@128", 0), TEST ("x@200", 128, 7, 14, 'x', "x@207", 0), TEST ("x@331", 331, 1, 3, 'x', "x@334", 0), TEST ("x@539", 539, 0, 1, 'x', "x@540", 0), TEST ("x@539", 0, 0,873, 'x', "x@1412", 0), TEST ("x@873", 873, 0, 1411, 'x', "x@2284", 0), TEST ("x@3694", 128, 1, 2, 'x', "x@3695", 0), TEST ("x@539", 537, 2, 3, 'a', "x@537aaa", 0), TEST ("", 0, 0, 3695, 'x', "x@3695", 0), TEST ("a", 0, 1, 4095, 'x', "x@4095", 0), TEST ("x@4096", 0, 4095, 4095, 'a', "a@4095x", 0), TEST ("x@4096", 0, 2047, 2047, 'b', "b@2047x@2049", 0), TEST ("x@4096", 2047, 2048, 2048, 'x', "x@4096", 0), TEST ("\0", 2, 0, 0, ' ', "\0", 1), TEST ("a", 10, 0, 0, ' ', "a", 1), TEST ("x@4096", 4106, 0, 0, ' ', "x@4096", 1), TEST ("a", 0, 1, 4095, 'x', "x@4095", 0), TEST ("last", 4, 0, 4, 't', "lasttttt", 0) }; /**************************************************************************/ template struct ReplaceBase { typedef std::basic_string String; typedef typename String::iterator StringIter; ReplaceBase () { } virtual ~ReplaceBase () { /* silence warnings */ } virtual String& operator()(String &str, const StringTestCaseData&) const { RW_ASSERT (!"logic error: should be never called"); return str; } virtual String& operator()(String &str, std::size_t off, std::size_t size, const charT* arg_ptr) const { return str.replace (off, size, arg_ptr); } virtual String& operator()(String &str, std::size_t off, std::size_t size, const String &arg_str) const { return str.replace (off, size, arg_str); } virtual String& operator()(String &str, std::size_t off, std::size_t size, const charT* arg_ptr, std::size_t size2) const { return str.replace (off, size, arg_ptr, size2); } virtual String& operator()(String &str, std::size_t off, std::size_t size, const String &arg_str, std::size_t off2, std::size_t size2) const { return str.replace (off, size, arg_str, off2, size2); } virtual String& operator()(String &str, std::size_t off, std::size_t size, std::size_t size2, const charT arg_val) const { return str.replace (off, size, size2, arg_val); } virtual String& operator()(String &str, const StringIter& first, const StringIter& last, const charT* arg_ptr) const { return str.replace (first, last, arg_ptr); } virtual String& operator()(String &str, const StringIter& first, const StringIter& last, const String& arg_str) const { return str.replace (first, last, arg_str); } virtual String& operator()(String &str, const StringIter& first, const StringIter& last, const charT* arg_ptr, std::size_t size2) const { return str.replace (first, last, arg_ptr, size2); } virtual String& operator()(String &str, const StringIter& first, const StringIter& last, std::size_t size2, const charT arg_val) const { return str.replace (first, last, size2, arg_val); } }; /**************************************************************************/ // invokes specializations of the member function template // on the required iterator categories template struct ReplaceRange: ReplaceBase { typedef std::basic_string String; typedef typename String::iterator StringIter; ReplaceRange () { const char* const tname = type_name (Iterator (0, 0, 0), (charT*)0); rw_fprintf (0, "%{$Iterator!:*}", tname); rw_info (0, 0, 0, "%{$CLASS}::replace<%{$Iterator}>" "(iterator, iterator, %{$Iterator}, %{$Iterator})"); } virtual String& operator()(String &str, const StringTestCaseData& tdata) const { const StringTestCase &tcase = tdata.tcase_; // create a pair of iterators into the string object being modified const StringIter first1 (str.begin () + tdata.off1_); const StringIter last1 (first1 + tdata.ext1_); const String &cstr = str; // when (0 == tcase.arg) exercise self-referential modification // (i.e., replacing a range of elements with a subrange of its // own elements) const charT* const beg = (tcase.arg ? tdata.arg_ : cstr.data ()) + tdata.off2_; const charT* const end = beg + tdata.ext2_; const Iterator first2 (beg, beg, end); const Iterator last2 (end, beg, end); return str.replace (first1, last1, first2, last2); } }; /**************************************************************************/ // invokes possible overloads of the member function template // on common RandomAccessIterator types template struct ReplaceRangeOverload: ReplaceBase { typedef std::basic_string String; typedef typename String::pointer StringPtr; typedef typename String::const_pointer StringConstPtr; typedef typename String::iterator StringIter; typedef typename String::const_iterator StringConstIter; typedef typename String::reverse_iterator StringRevIter; typedef typename String::const_reverse_iterator StringConstRevIter; ReplaceRangeOverload (const char *tname) { rw_fprintf (0, "%{$Iterator!:*}", tname); rw_info (0, 0, 0, "%{$CLASS}::replace<%{$Iterator}>" "(iterator, iterator, %{$Iterator}, %{$Iterator})"); } static StringPtr begin (String &str, std::size_t off, std::size_t, StringPtr*) { return _RWSTD_CONST_CAST (StringPtr, str.data ()) + off; } static StringConstPtr begin (const String &str, std::size_t off, std::size_t, StringConstPtr*) { return str.data () + off; } static StringIter begin (String &str, std::size_t off, std::size_t, StringIter*) { return str.begin () + off; } static StringConstIter begin (const String &str, std::size_t off, std::size_t, StringConstIter*) { return str.begin () + off; } static StringRevIter begin (String &str, std::size_t off, std::size_t ext, StringRevIter*) { return str.rbegin () - (off + ext); } static StringConstRevIter begin (const String &str, std::size_t off, std::size_t ext, StringConstRevIter*) { return str.rend () - (off + ext); } virtual String& operator()(String &str, const StringTestCaseData& tdata) const { const StringTestCase &tcase = tdata.tcase_; // create a pair of iterators into the string object being modified const StringIter first1 (str.begin () + tdata.off1_); const StringIter last1 (first1 + tdata.ext1_); const std::size_t off = tdata.off2_; const std::size_t ext = tdata.ext2_; if (0 == tcase.arg) { // exercise self-referential modification (i.e., replacing // a range of elements with a subrange of its own elements) const Iterator first2 (begin (str, off, ext, (Iterator*)0)); const Iterator last2 (first2 + ext); return str.replace (first1, last1, first2, last2); } String str_arg (tdata.arg_, tdata.arglen_); const Iterator first2 (begin (str_arg, off, ext, (Iterator*)0)); const Iterator last2 (first2 + ext); return str.replace (first1, last1, first2, last2); } }; /**************************************************************************/ template void test_replace (charT*, Traits*, Allocator*, const ReplaceBase &rep, const StringTestCaseData &tdata) { typedef std::basic_string String; typedef typename String::iterator StringIter; typedef typename UserTraits::MemFun TraitsFunc; const StringFunc &func = tdata.func_; const StringTestCase &tcase = tdata.tcase_; // construct the string object to be modified // and the (possibly unused) argument string /* const */ String str (tdata.str_, tdata.strlen_); const String arg (tdata.arg_, tdata.arglen_); // save the state of the string object before the call // to detect wxception safety violations (changes to // the state of the object after an exception) const StringState str_state (rw_get_string_state (str)); // create a pair of iterators into the string object being // modified (used only by the iterator overloads) const StringIter first (str.begin () + tdata.off1_); const StringIter last (first + tdata.ext1_); // offset and extent function arguments const std::size_t arg_off = std::size_t (tcase.off); const std::size_t arg_size = std::size_t (tcase.size); const std::size_t arg_off2 = std::size_t (tcase.off2); const std::size_t arg_size2 = 0 <= tcase.size2 ? tcase.size2 : str.max_size () + 1; // string function argument const charT* const arg_ptr = tcase.arg ? arg.data () : str.data (); const String& arg_str = tcase.arg ? arg : str; const charT arg_val = make_char (char (tcase.val), (charT*)0); // get a pointer to the Traits::length() function call counter // or 0 when no such counter exists (i.e., when Traits is not // UserTraits) std::size_t* length_calls = Replace (size_size_cptr) == func.which_ || Replace (iter_iter_cptr) == func.which_ ? rw_get_call_counters ((Traits*)0, (charT*)0) : 0; if (length_calls) { length_calls += TraitsFunc::length; *length_calls = 0; } rwt_free_store* const pst = rwt_get_free_store (0); SharedAlloc* const pal = SharedAlloc::instance (); // out_of_range is only generated from size_type overloads // of replace() and not from the iterator equivalents of // the same functions const bool use_iters = StringIds::arg_iter == StringIds::arg_type (func.which_, 2); // iterate for`throw_count' starting at the next call to operator new, // forcing each call to throw an exception, until the function finally // succeeds (i.e, no exception is thrown) std::size_t throw_count; for (throw_count = 0; ; ++throw_count) { // (name of) expected and caught exception const char* expected = 0; const char* caught = 0; #ifndef _RWSTD_NO_EXCEPTIONS if (1 == tcase.bthrow && !use_iters) expected = exceptions [1]; // out_of_range else if (2 == tcase.bthrow && !use_iters) expected = exceptions [1]; // out_of_range else if (3 == tcase.bthrow && !use_iters) expected = exceptions [2]; // length_error else if (0 == tcase.bthrow) { // by default excercise the exception safety of the function // by iteratively inducing an exception at each call to operator // new or Allocator::allocate() until the call succeeds expected = exceptions [3]; // bad_alloc *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + throw_count + 1; pal->throw_at_calls_ [pal->m_allocate] = pal->throw_at_calls_ [pal->m_allocate] + throw_count + 1; } else { // exceptions disabled for this test case } #else // if defined (_RWSTD_NO_EXCEPTIONS) if (tcase.bthrow) return; #endif // _RWSTD_NO_EXCEPTIONS // pointer to the returned reference const String* ret_ptr = 0; // start checking for memory leaks rw_check_leaks (str.get_allocator ()); try { switch (func.which_) { case Replace (size_size_cptr): ret_ptr = &rep (str, arg_off, arg_size, arg_ptr); break; case Replace (size_size_cstr): ret_ptr = &rep (str, arg_off, arg_size, arg_str); break; case Replace (size_size_cptr_size): ret_ptr = &rep (str, arg_off, arg_size, arg_ptr, arg_size2); break; case Replace (size_size_cstr_size_size): ret_ptr = &rep (str, arg_off, arg_size, arg_str, arg_off2, arg_size2); break; case Replace (size_size_size_val): ret_ptr = &rep (str, arg_off, arg_size, arg_size2, arg_val); break; case Replace (iter_iter_cptr): ret_ptr = &rep (str, first, last, arg_ptr); break; case Replace (iter_iter_cstr): ret_ptr = &rep (str, first, last, arg_str); break; case Replace (iter_iter_cptr_size): ret_ptr = &rep (str, first, last, arg_ptr, arg_size2); break; case Replace (iter_iter_size_val): ret_ptr = &rep (str, first, last, arg_size2, arg_val); break; case Replace (iter_iter_range): ret_ptr = &rep (str, tdata); break; default: RW_ASSERT (!"logic error: unknown replace overload"); } // verify that the reference returned from the function // refers to the modified string object (i.e., *this // within the function) const std::ptrdiff_t ret_off = ret_ptr - &str; // verify the returned value rw_assert (0 == ret_off, 0, tcase.line, "line %d. %{$FUNCALL} returned invalid reference, " "offset is %td", __LINE__, ret_off); // for convenience static const int cwidth = sizeof (charT); // verfiy that the length of the resulting string rw_assert (tdata.reslen_ == str.size (), 0, tcase.line, "line %d. %{$FUNCALL} expected %{/*.*Gs} with " "length %zu, got %{/*.*Gs} with length %zu", __LINE__, cwidth, int (tdata.reslen_), tdata.res_, tdata.reslen_, cwidth, int (str.size ()), str.data (), str.size ()); if (tdata.reslen_ == str.size ()) { // if the result length matches the expected length // (and only then), also verify that the modified // string matches the expected result const std::size_t match = rw_match (tcase.res, str.data (), tcase.nres); rw_assert (match == tdata.reslen_, 0, tcase.line, "line %d. %{$FUNCALL} expected %{/*.*Gs}, " "got %{/*.*Gs}, difference at offset %zu", __LINE__, cwidth, int (tdata.reslen_), tdata.res_, cwidth, int (str.size ()),str.data (), match); } // verify that Traits::length() was used if (length_calls) { rw_assert (0 < *length_calls, 0, tcase.line, "line %d. %{$FUNCALL} doesn't " "use traits_type::length()", __LINE__); } } #ifndef _RWSTD_NO_EXCEPTIONS catch (const std::out_of_range &ex) { caught = exceptions [1]; rw_assert (caught == expected, 0, tcase.line, "line %d. %{$FUNCALL} %{?}expected %s,%{:}" "unexpectedly%{;} caught std::%s(%#s)", __LINE__, 0 != expected, expected, caught, ex.what ()); } catch (const std::length_error &ex) { caught = exceptions [2]; rw_assert (caught == expected, 0, tcase.line, "line %d. %{$FUNCALL} %{?}expected %s,%{:}" "unexpectedly%{;} caught std::%s(%#s)", __LINE__, 0 != expected, expected, caught, ex.what ()); } catch (const std::bad_alloc &ex) { caught = exceptions [3]; rw_assert (0 == tcase.bthrow, 0, tcase.line, "line %d. %{$FUNCALL} %{?}expected %s,%{:}" "unexpectedly%{;} caught std::%s(%#s)", __LINE__, 0 != expected, expected, caught, ex.what ()); } catch (const std::exception &ex) { caught = exceptions [4]; rw_assert (0, 0, tcase.line, "line %d. %{$FUNCALL} %{?}expected %s,%{:}" "unexpectedly%{;} caught std::%s(%#s)", __LINE__, 0 != expected, expected, caught, ex.what ()); } catch (...) { caught = exceptions [0]; rw_assert (0, 0, tcase.line, "line %d. %{$FUNCALL} %{?}expected %s,%{:}" "unexpectedly%{;} caught %s", __LINE__, 0 != expected, expected, caught); } #endif // _RWSTD_NO_EXCEPTIONS // FIXME: verify the number of blocks the function call // is expected to allocate and detect any memory leaks rw_check_leaks (str.get_allocator (), tcase.line, std::size_t (-1), std::size_t (-1)); if (caught) { // verify that the exception didn't cause a change // in the state of the object str_state.assert_equal (rw_get_string_state (str), __LINE__, tcase.line, caught); if (0 == tcase.bthrow) { // allow this call to operator new to succeed and try // to make the next one to fail during the next call // to the same function again continue; } } else if (0 < tcase.bthrow) { rw_assert (caught == expected, 0, tcase.line, "line %d. %{$FUNCALL} %{?}expected %s, caught %s" "%{:}unexpectedly caught %s%{;}", __LINE__, 0 != expected, expected, caught, caught); } break; } #ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE // verify that if exceptions are enabled and when capacity changes // at least one exception is thrown const std::size_t expect_throws = str_state.capacity_ < str.capacity (); #else // if defined (_RWSTD_NO_REPLACEABLE_NEW_DELETE) const std::size_t expect_throws = StringIds::UserAlloc == func.alloc_id_ ? str_state.capacity_ < str.capacity () : 0; #endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE // verify number of exceptions thrown // for range version the allocation may take place several times if (Replace (iter_iter_range) != func.which_) rw_assert (expect_throws == throw_count, 0, tcase.line, "line %d: %{$FUNCALL}: expected exactly 1 %s exception " "while changing capacity from %zu to %zu, got %zu", __LINE__, exceptions [3], str_state.capacity_, str.capacity (), throw_count); else rw_assert (expect_throws <= throw_count, 0, tcase.line, "line %d: %{$FUNCALL}: expected at least 1 %s exception " "while changing capacity from %zu to %zu, got %zu", __LINE__, exceptions [3], str_state.capacity_, str.capacity (), throw_count); // disable bad_alloc exceptions *pst->throw_at_calls_ [0] = 0; pal->throw_at_calls_ [pal->m_allocate] = 0; } /**************************************************************************/ template void test_replace (charT*, Traits*, Allocator*, const StringTestCaseData &tdata) { if (tdata.func_.which_ == Replace (iter_iter_range)) { typedef std::basic_string String; { const char s[] = "pointer"; typedef typename String::pointer Iterator; static const ReplaceRangeOverload rep (s); test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } { const char s[] = "const_pointer"; typedef typename String::const_pointer Iterator; static const ReplaceRangeOverload rep (s); test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } { const char s[] = "iterator"; typedef typename String::iterator Iterator; static const ReplaceRangeOverload rep (s); test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } { const char s[] = "const_iterator"; typedef typename String::const_iterator Iterator; static const ReplaceRangeOverload rep (s); test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } // { // const char s[] = "reverse_iterator"; // typedef typename String::reverse_iterator Iterator; // static const // ReplaceRangeOverload rep (s); // test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); // } // { // const char s[] = "const_reverse_iterator"; // typedef typename String::const_reverse_iterator Iterator; // static const // ReplaceRangeOverload rep (s); // test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); // } { typedef InputIter Iterator; static const ReplaceRange rep; test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } { typedef ConstFwdIter Iterator; static const ReplaceRange rep; test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } { typedef ConstBidirIter Iterator; static const ReplaceRange rep; test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } { typedef ConstRandomAccessIter Iterator; static const ReplaceRange rep; test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } } else { static const ReplaceBase rep; test_replace ((charT*)0, (Traits*)0, (Allocator*)0, rep, tdata); } } /**************************************************************************/ DEFINE_STRING_TEST_FUNCTIONS (test_replace); int main (int argc, char** argv) { static const StringTest tests [] = { #undef TEST #define TEST(sig) { \ Replace (sig), sig ## _test_cases, \ sizeof sig ## _test_cases / sizeof *sig ## _test_cases, \ } TEST (size_size_cptr), TEST (size_size_cstr), TEST (size_size_cptr_size), TEST (size_size_cstr_size_size), TEST (size_size_size_val), TEST (iter_iter_cptr), TEST (iter_iter_cstr), TEST (iter_iter_cptr_size), TEST (iter_iter_size_val), TEST (iter_iter_range) }; const std::size_t test_count = sizeof tests / sizeof *tests; const int status = rw_run_string_test (argc, argv, __FILE__, "lib.string.replace", test_replace_func_array, tests, test_count); return status; } --------------010105090205020104050700--