[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
csArray<>
Index and Size Type Change csArray<>
has been changed to use `size_t' instead of
`int' for array sizes and indices. Probably, the most significant
semantic difference of this change is that `size_t' is usually
unsigned as opposed to `int' which is signed.
Read this paragraph carefully. In actual code, this change may result in nothing more than simple-looking compiler warnings. However, it may have caused semantics to change subtly.
This has the greatest impact in the areas discussed below.
csArray<>
Contents For this purpose, usually, `int' typed variables were used for keeping
track of the index of the current item of an array iteration. Fixing forward
iteration over a csArray<>
to instead use `size_t' is simple:
csArray<...> a; for (int i = 0, n = a.Length(); i < n; i++) { ... } |
Is changed to:
... for (size_t i = 0, n = a.Length(); i < n; i++) ... |
Backward iteration is a bit more problematic. As mentioned before, `size_t' typically is unsigned, so you do not have negative values. This can be a problem in constructs like:
csArray<...> a; for (int i = a.Length() - 1; i >= 0; i--) { ... } |
If the `int' is changed simply to a `size_t', this
for
-loop misbehaves unexpectedly. When `i' becomes 0, the body
of the loop is executed correctly. However, decrementing `i' will
not cause `i' to have a negative value--after all, `size_t'
is unsigned. Instead, decrementing will make `i' wrap around from 0 to
0xffffffff (on 32-bit machines). Clearly, this is greater
than 0, effectively causing an infinite loop. The same thing also happens when
`a' has no items (i.e. `a.Length() == 0'). Here the
-1 in the initialization of `i' causes wrap-around.
Possible solutions include:
int
-typed counter variable and cast the array length to
`int'. This is not entirely elegant, but it does the job in most cases.
csArray<...> a; for (size_t i = a.Length(); i-- > 0;) { ... } |
This code does the same as the `int' version above, iterating from `a.Length() - 1' to 0, inclusively. It also correctly works in the case `a.Length() == 0'. The "trick" is to place the modification of `i' as a post-decrement in the loop condition. This way, as soon as `i' becomes 0, the loop is terminated. The post-decrement ensures that `i' has the expected value in the loop body.
Functions like csArray<>::FindSortedKey()
and csArray<>::Find()
used to return -1 to signify that an item was not found. This is still the
case, but with a twist. Now, `(size_t)-1' is returned. For convenience,
a constant, `csArrayItemNotFound', has been added, which has this exact
value. It can be used in comparisons to make it clear what is actually being
checked.
Apropros comparisons: Recall that `size_t' is unsigned, so checking
whether an index returned by `FindSortedKey()' or `Find()' is
actually a valid index by testing with `>= 0' no longer works since
`(size_t)-1' is always >= 0
. Replace such checks with tests of
equality against `csArrayItemNotFound':
csArray<...> a; int index = a.Find (...); if (index >= 0) { /* Item found */ ... } else { /* Item not found */ ... } |
Must be replaced with:
csArray<...> a; size_t index = a.Find (...); if (index != csArrayItemNotFound) { /* Item found */ ... } else { /* Item not found */ ... } |
The `csutil/garray.h' file, containing the class
csDirtyAccessArray<>
, has been deprecated in favor of the more sensible
file name `csutil/dirtyaccessarray.h'. No functional changes have been
made to the class.
csList<>::Iterator
Normalization The behavior of csList<>::Iterator
has been normalized so that it
functions identically to all other iterators in Crystal Space. In the past, a
newly created csList<>::Iterator
already pointed at the first element in
the container. This differed from all other iterator implementations, in which
the first element, like all other elements, is accessed by an invocation of
Next()
.
Old code which accessed the elements of a csList<>::Iterator
required a
non-standard idiom, such as:
csList<sometype> list = ...; csList<sometype>::Iterator it(list); if (it.HasCurrent()) { do_something(*it); // First value. while (it.HasNext()) { do_something(it.Next()); // Remaining values. } } |
Or, the slightly less complicated, though still somewhat convoluted:
csList<sometype>::Iterator it(list); while (it.HasCurrent()) { do_something(*it); it.Next(); } |
Following normalization, csList<>::Iterator
now works like all other
iterators throughout the toolkit. In particular, for forward iteration, all
elements can be accessed via the standard HasNext()
/ Next()
idiom:
csList<sometype>::Iterator it(list); while (it.HasNext()) { do_something(it.Next()); } |
Likewise, for backward iteration, the HasPrevious()
/ Previous()
idiom works in the obvious and expected inverse fashion.
Finally, csList<>::Iterator::Next()
and Previous()
now return
references to contained elements, rather than pointers. This makes the
interface of csList<>::Iterator
internally consistent, as well as
consistent with other iterators throughout the toolkit, in which these methods
return references.
csSet<>
Relocation and Changes The declaration of csSet<>
was moved out from `csutil/hash.h' and
into its own header file, `csutil/set.h'. The method
csSet<>::GetHash()
has likewise been removed since it unnecessarily
exposed an underlying implementation detail of csSet<>
.
However, this implementation detail still affects the use of csSet<>
as
for storage of pointers in a csSet<>
the csPtrKey<>
wrapper must
be used.
csHash<>
Changes The way csHash<>
handles support for arbitrary key types has been
changed. Previously, a so-called "hash key handler" was passed as an optional
third template parameter that computed hash keys and was able to compare
keys. Now, the hash computation is handled through the new
csHashComputer<>
template, and key comparison through
csComparator<>
. To provide hash computation and comparisons for specific
types used as hash keys, specializations of the templates mentioned above are
needed. Alternatively the default comparator uses the `operator <' and
`operator >' operators, so you can also implement those operators instead
of a csComparator<>
specialization. The default csHashComputer<>
implementation assumes that a type provides a `GetHash()' method that
computes the hash value for an object. However, this means that integral types
need a specialization. As a convenience, Crystal Space already provides
specializations of csHashComputer<>
for a number of commonly used
intergrals. Further, csComparator<>
and/or csHashComputer<>
specializations are provided for the commonly used types `csString',
`const char*' and `csStrKey'; and the default comparison semantics of
`operator <' and `operator >' handle the remaining fundamental types
and any composite types which provide these operators. Pointers (other than
`void*' for which exists a specialization) as hash keys are a special
case: to use a pointer of type `Foo*' as a hash key, employ
`csPtrKey<Foo>' as the key type in the hash declaration.
csHash<>
(and csHashReversible<>
) Table Size The default hash table size and grow rate has been reduced from 257 and 64 to
23 and 5, respectively, to have hashes use less memory. If a hash is expected
to contain a large quantity of elements, those two parameters can be tweaked
upon construction of a csHash<>
or csHashReversible<>
. Consult
the Public API Documentation of csHash<>
for more information.
The long-deprecated `csHashMap', `csHashMapReversible', and
`csHashSet' classes have been removed. Instead, use the templated classes
csHash<>
, csHashReversible<>
, and csSet<>
. For
string-related set functionality, you may also want to consider using
`csStringHash' and `csStringSet'.
csObjectPool<>
Removal The csObjectPool<>
utility class has been removed since it managed
memory poorly, and failed to invoke the destructor of contained objects at the
time they were recycled via csObjectPool<>::Free()
, which meant that the
objects might not release their own resources in a timely fashion. (It did
correctly destroy the freed objects when the pool itself was destroyed, but
should have been doing so at Free()
-time.)
You can use csBlockAllocator<>
(see `csutil/blockallocator.h') as a
drop-in replacement for csObjectPool<>
since the API of
csBlockAllocator<>
is a proper superset of the csObjectPool<>
API. A global search and replace should be sufficient to account for this
change.
`csStringSetIterator' and `csStringHashIterator' have been replaced with the iterator classes `csStringSet::GlobalIterator' and `csStringHash::GlobalIterator', respectively. Rather than instantiating iterators directly, you now ask the set or hash for an iterator. This brings the `csStringSet' and `csStringHash' API's in line with other container classes which vend iterators. Given old code which is using `csStringSetIterator':
csStringSet set; // ...populate set... csStringSetIterator iter(&set); while (iter.HasNext()) { char const* s = iter.Next(); // ...do something with `s'... } |
Convert it like this:
csStringSet::GlobalIterator iter = set.GetIterator(); while (iter.HasNext()) { |
Code using `csStringHashIterator' can be fixed using the same simple transformation.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated using texi2html 1.76.