2 // This file is part of the aMule Project.
4 // Copyright (c) 2004-2008 Mikkel Schubert ( xaignar@users.sourceforge.net )
5 // Copyright (c) 2004-2008 aMule Team ( admin@amule.org / http://www.amule.org )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include <common/MuleDebug.h>
36 * Default helper structure for normal CRangeMap instantations.
38 * Specializations should must have the following properties.
39 * - The four value typedefs (see comments for details).
40 * - A template-defined member variable named 'first'.
41 * - A comparison operator that doesn't consider the 'first' field.
43 * The typedefs are used to specify the return values of iterators.
45 template <typename VALUE
, typename KEYTYPE
>
46 struct CRangeMapHelper
48 //! Typedef specifying the type to use when a non-const pointer is expected.
49 typedef VALUE
* ValuePtr
;
50 //! Typedef specifying the type to use when a non-const referenecs is expected.
51 typedef VALUE
& ValueRef
;
52 //! Typedef specifying the type to use when a const referenecs is expected.
53 typedef const VALUE
& ConstValueRef
;
54 //! Typedef specifying the type to use when a const pointer is expected.
55 typedef const VALUE
* ConstValuePtr
;
57 //! Used internally by CRangeMap to specify the end of a range.
59 //! Contains the value of a given range.
62 //! Compares the user-values of this range with another.
63 bool operator==(const CRangeMapHelper
<VALUE
, KEYTYPE
>& o
) const {
64 return second
== o
.second
;
70 * Helper structure for CRangeSet (CRangeMap with void as value).
72 template <typename KEYTYPE
>
73 struct CRangeMapHelper
<void, KEYTYPE
>
75 typedef void ValuePtr
;
76 typedef void ValueRef
;
77 typedef void ConstValueRef
;
78 typedef void ConstValuePtr
;
82 bool operator==(const CRangeMapHelper
<void, KEYTYPE
>&) const {
89 * This class represents a map of non-overlapping ranges.
91 * Each range has a user-specified value associated. The map supports quick
92 * lookup of which range covers a particular key-value, and will merge or
93 * split existing ranges when new ranges are added.
95 * The decision on whenever to split/resize a range or to merge the two ranges
96 * involved is based on equality of the user-specified value, using the
97 * equality operator. Thus if two ranges with the same user-value are placed
98 * adjacent to each other or partially overlapping each other, then they will
99 * be merged into a single range. If the user-values of the two ranges are
100 * different, then the old range will be either resized or split, based on the
101 * position of the new range.
103 * In cases where ranges are split into two parts, copies will be made of the
104 * user-specified value, such that each new part contains the same user-value.
106 * It is currently not possible to manipulate existing ranges by hand, other
107 * than by erasing and then re-inserting them.
109 * A specialization of this class exists (typedef'd as CRangeSet), which does
110 * not assosiate a value with each range.
112 * NOTE: KEYTYPE is assumed to be an unsigned integer type!
114 template <typename VALUE
, typename KEYTYPE
= uint64
>
117 typedef CRangeMapHelper
<VALUE
, KEYTYPE
> HELPER
;
119 //! The map uses the start-key as key and the User-value and end-key pair as value
120 typedef std::map
<KEYTYPE
, HELPER
> RangeMap
;
121 //! Shortcut for the pair used by the RangeMap.
122 typedef std::pair
<KEYTYPE
, HELPER
> RangePair
;
124 //! Typedefs used to distinguish between our custom iterator and the real ones.
125 typedef typename
RangeMap::iterator RangeIterator
;
126 typedef typename
RangeMap::const_iterator ConstRangeIterator
;
128 //! The raw map of range values.
132 * This class provides a wrapper around the raw iterators used by CRangeMap.
134 * It will act as a normal iterator and also give access the the range values.
135 * When used as a per normal, it will return the value specified by the user
138 * Special member-functions are keyStart() and keyEnd().
140 template <typename RealIterator
, typename ReturnTypeRef
, typename ReturnTypePtr
>
141 class iterator_base
{
142 friend class CRangeMap
<VALUE
, KEYTYPE
>;
144 iterator_base( const RealIterator
& it
)
149 //! Equality operator
150 bool operator==( const iterator_base
& other
) const {
151 return m_it
== other
.m_it
;
154 //! Non-equality operator
155 bool operator!=( const iterator_base
& other
) const {
156 return m_it
!= other
.m_it
;
160 //! Returns the starting point of the range
161 KEYTYPE
keyStart() const {
165 //! Returns the end-point of the range
166 KEYTYPE
keyEnd() const {
167 return m_it
->second
.first
;
171 //! Prefix increment.
172 iterator_base
& operator++() {
178 //! Postfix increment.
179 iterator_base
operator++(int) {
180 return iterator_base( m_it
++ );
184 //! Prefix decrement.
185 iterator_base
& operator--() {
191 //! Postfix decrement.
192 iterator_base
operator--(int) {
193 return iterator_base( m_it
-- );
197 //! Deference operator, returning the user-specified value.
198 ReturnTypeRef
operator*() const {
199 return m_it
->second
.second
;
202 //! Member access operator, returning the user-specified value.
203 ReturnTypePtr
operator->() const {
204 return &m_it
->second
.second
;
212 typedef typename
HELPER::ValueRef ValueRef
;
213 typedef typename
HELPER::ValuePtr ValuePtr
;
214 typedef typename
HELPER::ConstValueRef ConstValueRef
;
215 typedef typename
HELPER::ConstValuePtr ConstValuePtr
;
218 typedef iterator_base
<RangeIterator
, ValueRef
, ValuePtr
> iterator
;
219 typedef iterator_base
<ConstRangeIterator
, ConstValueRef
, ConstValuePtr
> const_iterator
;
221 //! The type used to specify size, ie size().
222 typedef typename
RangeMap::size_type size_type
;
224 //! The type of user-data saved with each range.
225 typedef VALUE value_type
;
228 * Default constructor.
236 CRangeMap(const CRangeMap
<VALUE
, KEYTYPE
>& other
)
237 : m_ranges( other
.m_ranges
)
242 * Assignment operator.
244 CRangeMap
& operator=(const CRangeMap
<VALUE
, KEYTYPE
>& other
) {
245 m_ranges
= other
.m_ranges
;
251 * Swaps the contents of the two rangemaps.
253 void swap(CRangeMap
<VALUE
, KEYTYPE
>& other
) {
254 std::swap(m_ranges
, other
.m_ranges
);
259 * Equality operator for two ranges.
261 * @returns True if both ranges contain the same ranges and values.
263 bool operator==( const CRangeMap
<VALUE
, KEYTYPE
>& other
) const {
264 // Check if we are comparing with ourselves
265 if ( this == &other
) {
269 // Check size, must be the same
270 if ( size() != other
.size() ) {
274 return (m_ranges
== other
.m_ranges
);
279 * Returns an iterator pointing to the first range.
282 return m_ranges
.begin();
286 * Returns an iterator pointing past the last range.
289 return m_ranges
.end();
293 * Returns a const iterator pointing to the first range.
295 const_iterator
begin() const {
296 return m_ranges
.begin();
300 * Returns a const iterator pointing past the last range.
302 const_iterator
end() const {
303 return m_ranges
.end();
308 * Erases the specified range and returns the range next to it.
310 * @param pos The iterator of the range to be erased.
311 * @return The iterator of the range after the erased range.
313 * Attempting to erase the end() iterator is an invalid operation.
315 iterator
erase(iterator pos
) {
316 MULE_VALIDATE_PARAMS(pos
!= end(), wxT("Cannot erase 'end'"));
318 RangeIterator temp
= pos
.m_it
++;
320 m_ranges
.erase(temp
);
327 * Returns the number of ranges in the map.
329 size_type
size() const {
330 return m_ranges
.size();
334 * Returns true if the map is empty.
337 return m_ranges
.empty();
342 * Removes all ranges from the map.
350 * Returns the range covering the specified key-value.
352 * @param key A value that may or may not be covered by a range.
353 * @return end() or the iterator of the range covering key.
355 * A range is considered to cover a value if the value is greather than or
356 * equal to the start-key and less than or equal to the end-key.
358 // Find the range which contains key (it->first <= key <= it->second->first)
359 iterator
find_range( KEYTYPE key
) {
360 if ( !m_ranges
.empty() ) {
361 // Find first range whose start comes after key
362 // Thus: key < it->first, but (--it)->first <= key
363 RangeIterator it
= m_ranges
.upper_bound( key
);
365 // Our target range must come before the one we found; does it exist?
366 if ( it
!= m_ranges
.begin() ) {
367 // Go back to the last range which starts at or before key
370 // Check if this range covers the key
371 if ( key
<= it
->second
.first
) {
381 void erase_range(KEYTYPE startPos
, KEYTYPE endPos
) {
382 // Create default initialized entry, which ensures that all fields are initialized.
383 HELPER entry
= HELPER();
384 // Need to set the 'end' field.
385 entry
.first
= endPos
;
387 // Insert without merging, which forces the creation of an entry that
388 // only covers the specified range, which will crop existing ranges.
389 erase(do_insert(startPos
, entry
, false));
394 * Inserts a new range into the map, potentially erasing/changing old ranges.
396 * @param startPos The start position of the range, also considered part of the range.
397 * @param endPos The end position of the range, also considered part of the range.
398 * @param object The user-data to be assosiated with the range.
399 * @return An iterator pointing to the resulting range, covering at least the specified range.
401 * This function inserts the specified range into the map, while overwriting
402 * or resizing existing ranges if there is any conflict. Ranges might also
403 * be merged, if the object of each evaluates to being equal, in which case
404 * the old range will be removed and the new extended to include the old
405 * range. This also includes ranges placed directly after or in front of each
406 * other, which will also be merged if their type is the same.
408 * This has the result that the iterator returned can point to a range quite
409 * different from what was originally specified. If this is not desired, then
410 * the VALUE type should simply be made to return false on all equality tests.
411 * Otherwise, the only promise that is made is that the resulting range has
412 * the same user-data (based on the equality operator) as the what was specified.
414 * Note that the start position must be smaller than or equal to the end-position.
417 iterator
insert(KEYTYPE startPos
, KEYTYPE endPos
) {
418 HELPER entry
= {endPos
};
419 return do_insert(startPos
, entry
);
421 template <typename TYPE
>
422 iterator
insert(KEYTYPE startPos
, KEYTYPE endPos
, const TYPE
& value
) {
423 HELPER entry
= {endPos
, value
};
424 return do_insert(startPos
, entry
);
430 * Inserts the specified range.
432 * @param start The starting position of the range.
433 * @param entry A helper-struct, containing the end position and possibly user-data.
434 * @param merge Specifies if ranges should be merged when possible.
435 * @return An iterator pointing to the range covering at least the specified range.
437 iterator
do_insert(KEYTYPE start
, HELPER entry
, bool merge
= true) {
438 MULE_VALIDATE_PARAMS(start
<= entry
.first
, wxT("Not a valid range."));
440 RangeIterator it
= get_insert_it(start
);
441 while ( it
!= m_ranges
.end() ) {
442 // Begins before the current span
443 if ( start
<= it
->first
) {
444 // Never touches the current span, it follows that start < it->first
445 // (it->first) is used to avoid checking against (uintXX)-1 by accident
446 if ( entry
.first
< it
->first
- 1 && it
->first
) {
450 // Stops just before the current span, it follows that start < it->first
451 // (it->first) is used to avoid checking against (uintXX)-1 by accident
452 else if ( entry
.first
== it
->first
- 1 && it
->first
) {
453 // If same type: Merge
454 if (merge
&& (entry
== it
->second
)) {
455 entry
.first
= it
->second
.first
;
456 m_ranges
.erase( it
++ );
462 // Covers part of the span
463 else if ( entry
.first
< it
->second
.first
) {
465 if (merge
&& (entry
== it
->second
)) {
466 entry
.first
= it
->second
.first
;
467 m_ranges
.erase( it
++ );
469 // Resize the partially covered span and get the next one
470 it
= ++resize( entry
.first
+ 1, it
->second
.first
, it
);
475 // It covers the entire span
476 m_ranges
.erase( it
++ );
480 // Starts inside the current span or after the current span
482 // Starts inside the current span
483 if ( start
<= it
->second
.first
) {
484 // Ends inside the current span
485 if ( entry
.first
< it
->second
.first
) {
486 // Adding a span with same type inside a existing span is fruitless
487 if (merge
&& (entry
== it
->second
)) {
491 // Insert the new span
492 m_ranges
.insert(it
, RangePair(entry
.first
+ 1, it
->second
));
494 // Resize the current span to fit before the new span
495 it
->second
.first
= start
- 1;
499 // Ends past the current span, resize or merge
500 if (merge
&& (entry
== it
->second
)) {
502 m_ranges
.erase( it
++ );
504 // Resize the partially covered span and get the next one
505 it
= ++resize( it
->first
, start
- 1, it
);
509 // Start past the current span
510 if ( start
== it
->second
.first
+ 1 ) {
511 // Touches the current span
512 if (merge
&& (entry
== it
->second
)) {
514 m_ranges
.erase( it
++ );
519 // Starts after the current span, nothing to do
526 return m_ranges
.insert(it
, RangePair(start
, entry
));
531 * Finds the optimal location to start looking for insertion points.
533 * This is the first range whose start comes after the new start. We check
534 * the last element first, since sequential insertions are commen.
536 RangeIterator
get_insert_it(KEYTYPE start
)
538 if ( m_ranges
.empty() ) {
539 return m_ranges
.end();
542 // The start-key of the last element must be smaller than our start-key
543 // Otherwise there is the possibility that we can merge with the one before that
544 RangeIterator it
= --m_ranges
.end();
545 if ( start
<= it
->first
) {
546 // If the two starts are equal, then we only need to go back another
547 // step to see if the range prior to this one is mergeable
548 if ( start
!= it
->first
) {
549 it
= m_ranges
.lower_bound( start
);
552 if ( it
!= m_ranges
.begin() ) {
553 // Go back to the last range which starts at or before key
562 //! Helper function that resizes an existing range to the specified size.
563 RangeIterator
resize( KEYTYPE startPos
, KEYTYPE endPos
, RangeIterator it
) {
564 HELPER item
= it
->second
;
567 m_ranges
.erase( it
++ );
569 return m_ranges
.insert(it
, RangePair(startPos
, item
));
574 //! CRangeSet is simply a partial specialization of CRangeMap
575 typedef CRangeMap
<void> CRangeSet
;
580 /** @see CRangeMap::swap */
581 template <typename VALUE_TYPE
, typename KEY_TYPE
>
582 void swap(CRangeMap
<VALUE_TYPE
, KEY_TYPE
>& a
, CRangeMap
<VALUE_TYPE
, KEY_TYPE
>& b
)
591 // File_checked_for_headers