You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@stdcxx.apache.org by Anton Pevtsov <an...@moscow.vdiweb.com> on 2006/03/21 16:23:14 UTC

test for 21.string.swap

The attached file contains the test for lib.string.swap.
It seems to be useful to exercise that the swap takes constant time, but
I am not sure that we have an apropriate mechanism for this check,
especially for char and char_traits.
Also, this test become intresting than different allocators are used. If
they are the same the std::swap results in the trivial pointers swap.

With best wishes,
Anton Pevtsov


Re: test for 21.string.swap

Posted by Martin Sebor <se...@roguewave.com>.
Btw., I didn't emphasize this even though I should have. Arguably
the most important use case for swap() is the ability to release
all memory used by an object:

     std::string str ("...");
     // use str, possibly growing the object to a large size
     // ...
     // reset str to zero size *and* zero capacity, releasing
     // all storage occupied by the object back to the pool
     std::string ().swap (str);

No other function is guaranteed to do this but swap(). The test
needs to exercise this case and verify that the function doesn't
leak any memory.

Martin

Martin Sebor wrote:
> Anton Pevtsov wrote:
> 
>> The attached file contains the test for lib.string.swap.
>> It seems to be useful to exercise that the swap takes constant time, but
>> I am not sure that we have an apropriate mechanism for this check,
>> especially for char and char_traits.
> 
> 
> We do:
> 
>     std::string s1 ("foo");
>     std::string s2 ("bar");
> 
>     const char* const p1 = s1.data ();
>     const char* const p2 = s2.data ();
> 
>     s1.swap ();
> 
>     assert (s1.data () == p2);
>     assert (s2.data () == p1);
> 
> With a user-defined allocator we should also check that the function
> doesn't call allocator_type::allocate() (or deallocate). Even without
> a user-defined allocator we can check the complexity of the function
> in user-defined traits: by verifying that none of its linear members
> (assign, copy, or move) is called (that is the true test; allocation
> itself doesn't necessarily imply anything about the complexity of a
> function, even though in practice it usually does).
> 
>> Also, this test become intresting than different allocators are used. If
>> they are the same the std::swap results in the trivial pointers swap.
> 
> 
> Yes, we should definitely exercise swap with unequal allocators.
> 
>>
> [...]
> 
>>     static charT wstr1 [LLEN];
>>     static charT wstr2 [LLEN];
>>
>>     // construct strings
>>     rw_widen (wstr1, cs.str1, cs.str1_len);
>>     rw_widen (wstr2, cs.str2, cs.str2_len);
>>
>>     TestString str1 (wstr1, cs.str1_len);
>>     TestString str2 (wstr2, cs.str2_len);
> 
> 
> Instead of using the buffers here could we widen the narrow char
> arrays directly into the strings:
> 
>     TestString str1;
>     str1.resize (cs.str1_len);
>     rw_widen (&str1 [0], cs.str1, cs.str1_len);
> 
>>
>>     str1.swap (str2);
>>
>> #define 
>> CALLFMAT                                                             \
>>     "line %d. std::basic_string<%s, %s<%2$s>, 
>> %s<%2$s>>(%{#*s})."            \
>>     "swap (%{#*s})"
>>
>> #define 
>> CALLARGS                                                             \
>>     __LINE__, pfid->cname_, pfid->tname_, pfid->aname_, int 
>> (cs.str1_len),   \
>>     cs.str1, int (cs.str2_len), rw_narrow (tmp1, wstr2, cs.str2_len)
>>
>>     bool success =         !TestString::traits_type::compare (wstr1, 
>> str2.c_str(), cs.str1_len);
> 
> 
> Rather than relying on Traits I think it would be better to use
> rw_match() to compare the contents of the string objects against
> the original narrow char array. That's what the function is for:
> to allow comparisons of heterogeneous arrays of characters. It
> also returns the index of the first mismatched character which
> can be helpful in diagnostics.
> 
> More important, though, we should be comparing the data() pointers
> for equality (when the allocators compare equal).
> 
>>
>>     // strings used for output
>>     static char tmp1[LLEN];
>>     static char tmp2[LLEN];
>>     static char tmp3[LLEN];
>>
>>     rw_assert (success, 0, cs.line,
>>                CALLFMAT " this == %{#*s}, got this = %{#*s}", 
>> CALLARGS,                int (cs.str2_len), rw_narrow (tmp2, wstr2, 
>> cs.str2_len),
>>                int (str1.size ()),                rw_narrow (tmp3, 
>> str1.c_str (), str1.size ()));
> 
> 
> I would prefer to keep the rw_assert() argument list as "simple" as
> possible (they tend to be complicated enough with all the conditional
> directives) and keep function calls separate.
> 
> Also, since these arrays are big (over 4K each), I think we should
> keep their number to the necessary minimum and avoid them if at all
> possible. Here, we should be able to use the new %{/Gs} directive
> to print out the contents of the strings directly without calling
> rw_narrow().
> 
> Martin
> 


Re: test for 21.string.swap

Posted by Martin Sebor <se...@roguewave.com>.
Anton Pevtsov wrote:
> The attached file contains the test for lib.string.swap.
> It seems to be useful to exercise that the swap takes constant time, but
> I am not sure that we have an apropriate mechanism for this check,
> especially for char and char_traits.

We do:

     std::string s1 ("foo");
     std::string s2 ("bar");

     const char* const p1 = s1.data ();
     const char* const p2 = s2.data ();

     s1.swap ();

     assert (s1.data () == p2);
     assert (s2.data () == p1);

With a user-defined allocator we should also check that the function
doesn't call allocator_type::allocate() (or deallocate). Even without
a user-defined allocator we can check the complexity of the function
in user-defined traits: by verifying that none of its linear members
(assign, copy, or move) is called (that is the true test; allocation
itself doesn't necessarily imply anything about the complexity of a
function, even though in practice it usually does).

> Also, this test become intresting than different allocators are used. If
> they are the same the std::swap results in the trivial pointers swap.

Yes, we should definitely exercise swap with unequal allocators.

> 
[...]
>     static charT wstr1 [LLEN];
>     static charT wstr2 [LLEN];
> 
>     // construct strings
>     rw_widen (wstr1, cs.str1, cs.str1_len);
>     rw_widen (wstr2, cs.str2, cs.str2_len);
> 
>     TestString str1 (wstr1, cs.str1_len);
>     TestString str2 (wstr2, cs.str2_len);

Instead of using the buffers here could we widen the narrow char
arrays directly into the strings:

     TestString str1;
     str1.resize (cs.str1_len);
     rw_widen (&str1 [0], cs.str1, cs.str1_len);

> 
>     str1.swap (str2);
> 
> #define CALLFMAT                                                             \
>     "line %d. std::basic_string<%s, %s<%2$s>, %s<%2$s>>(%{#*s})."            \
>     "swap (%{#*s})"
> 
> #define CALLARGS                                                             \
>     __LINE__, pfid->cname_, pfid->tname_, pfid->aname_, int (cs.str1_len),   \
>     cs.str1, int (cs.str2_len), rw_narrow (tmp1, wstr2, cs.str2_len)
> 
>     bool success = 
>         !TestString::traits_type::compare (wstr1, str2.c_str(), cs.str1_len);

Rather than relying on Traits I think it would be better to use
rw_match() to compare the contents of the string objects against
the original narrow char array. That's what the function is for:
to allow comparisons of heterogeneous arrays of characters. It
also returns the index of the first mismatched character which
can be helpful in diagnostics.

More important, though, we should be comparing the data() pointers
for equality (when the allocators compare equal).

> 
>     // strings used for output
>     static char tmp1[LLEN];
>     static char tmp2[LLEN];
>     static char tmp3[LLEN];
> 
>     rw_assert (success, 0, cs.line,
>                CALLFMAT " this == %{#*s}, got this = %{#*s}", CALLARGS, 
>                int (cs.str2_len), rw_narrow (tmp2, wstr2, cs.str2_len),
>                int (str1.size ()), 
>                rw_narrow (tmp3, str1.c_str (), str1.size ()));

I would prefer to keep the rw_assert() argument list as "simple" as
possible (they tend to be complicated enough with all the conditional
directives) and keep function calls separate.

Also, since these arrays are big (over 4K each), I think we should
keep their number to the necessary minimum and avoid them if at all
possible. Here, we should be able to use the new %{/Gs} directive
to print out the contents of the strings directly without calling
rw_narrow().

Martin