LCOV - code coverage report
Current view: top level - lunchbox - intervalSet.ipp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 130 146 89.0 %
Date: 2018-10-03 05:33:11 Functions: 17 17 100.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2008-2016, Juan Hernando <jhernando@fi.upm.es>
       3             :  *                          Daniel Nachbaur <danielnachbaur@epfl.ch>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #include <lunchbox/debug.h>
      20             : 
      21             : #include <boost/iterator/iterator_facade.hpp>
      22             : 
      23             : /** @cond IGNORE */
      24             : namespace lunchbox
      25             : {
      26             : template <typename T>
      27             : class IntervalSet<T>::const_iterator
      28             :     : public boost::iterator_facade<typename IntervalSet<T>::const_iterator, T,
      29             :                                     std::forward_iterator_tag, T>
      30             : {
      31             : public:
      32             :     // Default constructor to an end() iterator.
      33             :     const_iterator() {}
      34             : private:
      35             :     friend class boost::iterator_core_access;
      36             :     friend class IntervalSet;
      37             : 
      38             :     typedef typename IntervalSet<T>::EdgeSet::const_iterator edge_iterator;
      39             : 
      40          15 :     const_iterator(const IntervalSet& set, const edge_iterator& interval)
      41             :         : _intervalIteratorEnd(set._intervals.end())
      42          15 :         , _startEdge(interval)
      43             :     {
      44          15 :         if (_startEdge != _intervalIteratorEnd)
      45           2 :             _value = _startEdge->first;
      46          15 :     }
      47             : 
      48           4 :     const_iterator(const IntervalSet& set, const edge_iterator& interval,
      49             :                    const T& current)
      50             :         : _value(current)
      51             :         , _intervalIteratorEnd(set._intervals.end())
      52           4 :         , _startEdge(interval)
      53             :     {
      54           4 :     }
      55             : 
      56           9 :     void increment()
      57             :     {
      58           9 :         if (_startEdge == _intervalIteratorEnd)
      59           0 :             return;
      60             : 
      61           9 :         edge_iterator endEdge = _startEdge;
      62           9 :         ++endEdge;
      63             :         // Next element is inside the current interval.
      64           9 :         if (_value >= _startEdge->first && _value < endEdge->first)
      65           7 :             ++_value;
      66             :         else
      67             :         {
      68           2 :             ++_startEdge;
      69           2 :             ++_startEdge;
      70           2 :             if (_startEdge != _intervalIteratorEnd)
      71           1 :                 _value = _startEdge->first;
      72             :         }
      73             :     }
      74             : 
      75          11 :     bool equal(const const_iterator& rhs) const
      76             :     {
      77          14 :         return (_startEdge == _intervalIteratorEnd &&
      78          22 :                 rhs._startEdge == _intervalIteratorEnd) ||
      79          19 :                (_startEdge == rhs._startEdge && _value == rhs._value);
      80             :     }
      81             : 
      82          11 :     T dereference() const { return _value; }
      83             :     T _value;
      84             :     edge_iterator _intervalIteratorEnd;
      85             :     edge_iterator _startEdge;
      86             : };
      87             : 
      88             : template <typename T>
      89           1 : IntervalSet<T>::IntervalSet()
      90           1 :     : _size(0)
      91             : {
      92           1 : }
      93             : 
      94             : template <typename T>
      95           1 : void IntervalSet<T>::insert(const T& element)
      96             : {
      97           1 :     insert(element, element);
      98           1 : }
      99             : 
     100             : template <typename T>
     101           1 : void IntervalSet<T>::erase(const T& element)
     102             : {
     103           1 :     erase(element, element);
     104           1 : }
     105             : 
     106             : template <typename T>
     107           6 : void IntervalSet<T>::insert(const T& startElement, const T& endElement)
     108             : {
     109           6 :     LBASSERT(startElement <= endElement);
     110             : 
     111           6 :     Edge startValue(startElement, true);
     112           6 :     Edge endValue(endElement, false);
     113             : 
     114           6 :     if (_intervals.empty())
     115             :     {
     116           2 :         _intervals.insert(startValue);
     117           2 :         _intervals.insert(endValue);
     118           2 :         _size = endElement - startElement + 1;
     119           2 :         return;
     120             :     }
     121             : 
     122             :     // Finding the first edge whose value is less or equal than startElement.
     123             :     typename EdgeSet::iterator previous_to_start =
     124           4 :         _intervals.lower_bound(startValue);
     125           4 :     if (previous_to_start != _intervals.end())
     126             :     {
     127           3 :         if (previous_to_start == _intervals.begin())
     128             :         {
     129           2 :             if (startValue.first < previous_to_start->first)
     130           1 :                 previous_to_start = _intervals.end();
     131             :         }
     132             :         else
     133           1 :             previous_to_start--;
     134             :     }
     135             :     else
     136           1 :         previous_to_start = (++_intervals.rbegin()).base();
     137             : 
     138             :     // Adding start edge as needed.
     139           4 :     typename EdgeSet::iterator position;
     140             :     bool fallsInside;
     141           4 :     size_t overlappingPortion = 0;
     142           4 :     T overlappingStart = T(); // initialized to silent a warning.
     143             : 
     144           4 :     if (previous_to_start == _intervals.end())
     145             :     {
     146             :         // Previous element doesn't exist and there is neither any of
     147             :         // equal value.
     148             :         // We have to insert start.
     149           1 :         position = _intervals.insert(startValue);
     150           1 :         fallsInside = false;
     151             :     }
     152           3 :     else if (!previous_to_start->second)
     153             :     {
     154             :         // Previous element is the end of one interval.
     155           1 :         if (previous_to_start->first + 1 == startElement)
     156             :         {
     157             :             // The end of previous interval end is one unit less than the start
     158             :             // of this interval. Removing the edge to fuse both.
     159           0 :             position = previous_to_start;
     160           0 :             position--;
     161           0 :             _intervals.erase(previous_to_start);
     162             :         }
     163             :         else
     164             :             // We have to insert start.
     165           1 :             position = _intervals.insert(previous_to_start, startValue);
     166           1 :         fallsInside = false;
     167             :     }
     168             :     else
     169             :     {
     170             :         // Start has fallen inside another interval we don't have to insert it.
     171           2 :         position = previous_to_start;
     172           2 :         fallsInside = true;
     173           2 :         overlappingStart = startElement;
     174             :     }
     175             : 
     176             :     // Now we have to check where the end goes.
     177           4 :     ++position;
     178          10 :     while (position != _intervals.end() && position->first <= endElement)
     179             :     {
     180             :         // Calculating the length of a possible interval overlapping the
     181             :         // interval being inserted.
     182           3 :         if (fallsInside)
     183             :         {
     184             :             // Previous position was the start of an overlapping interval.
     185           2 :             LBASSERT(!position->second);
     186           2 :             overlappingPortion += position->first - overlappingStart + 1;
     187             :         }
     188             :         else
     189           1 :             overlappingStart = position->first;
     190             : 
     191           3 :         fallsInside = position->second;
     192             : 
     193             :         // Note that the post-increment is evaluated before the function call
     194             :         // So position is actually pointing to the next one before the previous
     195             :         // element is erased.
     196           3 :         _intervals.erase(position++);
     197             :     }
     198             : 
     199           4 :     if (position != _intervals.end() && position->second &&
     200           0 :         position->first == endElement + 1)
     201             :     {
     202             :         // The end of the interval connects with the start of the next one.
     203             :         // We remove the start of the following one and don't insert this
     204             :         // edge.
     205           0 :         _intervals.erase(position);
     206             :     }
     207           4 :     else if (!fallsInside)
     208             :     {
     209             :         // End edge is not inside a previously existing interval so we
     210             :         // have to add it.
     211           3 :         _intervals.insert(position, endValue);
     212             :     }
     213             :     else
     214           1 :         overlappingPortion += endElement - overlappingStart + 1;
     215             : 
     216           4 :     _size += size_t(endElement - startElement + 1) - overlappingPortion;
     217           4 :     LBASSERT(_intervals.size() % 2 == 0);
     218             : }
     219             : 
     220             : template <typename T>
     221           4 : void IntervalSet<T>::erase(const T& startElement, const T& endElement)
     222             : {
     223           4 :     LBASSERT(startElement <= endElement);
     224             : 
     225           4 :     if (_intervals.empty())
     226           1 :         return;
     227             : 
     228             :     // Finding the first edge whose value is less or equal than startElement.
     229             :     typename EdgeSet::iterator nextToStart =
     230           4 :         _intervals.lower_bound(std::make_pair(startElement, true));
     231           4 :     typename EdgeSet::iterator previousToStart = nextToStart;
     232           4 :     if (nextToStart == _intervals.begin())
     233           0 :         previousToStart = _intervals.end();
     234           4 :     else if (nextToStart == _intervals.end())
     235             :         // Nothing to remove here
     236           1 :         return;
     237             :     else
     238           3 :         --previousToStart;
     239             : 
     240           3 :     typename EdgeSet::iterator position;
     241             :     bool inside;
     242           3 :     T overlappingStart = 0;
     243           3 :     size_t overlapping_portion = 0;
     244             : 
     245           3 :     if (previousToStart != _intervals.end())
     246             :     {
     247             :         // startElement is greater or equal than some interval edge.
     248           3 :         if (previousToStart->second)
     249             :         {
     250             :             // Inserting the new end of the interval starting at
     251             :             // previous_to_start.
     252           3 :             position =
     253           6 :                 _intervals.insert(std::make_pair(startElement - 1, false));
     254           3 :             inside = true;
     255           3 :             overlappingStart = startElement;
     256             :         }
     257             :         else
     258             :         {
     259           0 :             position = previousToStart;
     260           0 :             inside = false;
     261             :         }
     262           3 :         ++position;
     263             :     }
     264             :     else
     265             :     {
     266             :         // startElement is less than the start of any interval.
     267           0 :         inside = false;
     268           0 :         position = _intervals.begin();
     269           0 :         overlappingStart = position->first;
     270             :     }
     271             :     // Position has the next edge after the last interval before the removal
     272             :     // interval.
     273             : 
     274           7 :     while (position != _intervals.end() && position->first <= endElement)
     275             :     {
     276           2 :         if (inside)
     277           2 :             overlapping_portion += position->first - overlappingStart + 1;
     278             :         else
     279           0 :             overlappingStart = position->first;
     280             : 
     281           2 :         inside = position->second;
     282             : 
     283             :         // Note that the post-increment is evaluated before the function call
     284             :         // So position is actually pointing to the next one before the previous
     285             :         // element is erased.
     286           2 :         _intervals.erase(position++);
     287             :     }
     288             : 
     289           3 :     if (inside)
     290             :     {
     291           1 :         LBASSERT(position != _intervals.end());
     292             :         // End edge is not inside a previously existing interval so we
     293             :         // have to add it.
     294           1 :         _intervals.insert(std::make_pair(endElement + 1, true));
     295           1 :         overlapping_portion += endElement - overlappingStart + 1;
     296             :     }
     297             : 
     298           3 :     _size -= overlapping_portion;
     299           3 :     LBASSERT(_intervals.size() % 2 == 0);
     300             : }
     301             : 
     302             : template <typename T>
     303             : void IntervalSet<T>::insert(const IntervalSet& rhs)
     304             : {
     305             :     for (typename EdgeSet::const_iterator i = rhs._intervals.begin();
     306             :          i != rhs._intervals.end(); ++i)
     307             :     {
     308             :         insert(i->first, i->second);
     309             :     }
     310             : }
     311             : 
     312             : template <typename T>
     313           1 : void IntervalSet<T>::clear()
     314             : {
     315           1 :     _intervals.clear();
     316           1 :     _size = 0;
     317           1 : }
     318             : 
     319             : template <typename T>
     320           3 : bool IntervalSet<T>::exists(const T& element) const
     321             : {
     322           3 :     return find(element) != end();
     323             : }
     324             : 
     325             : template <typename T>
     326           6 : typename IntervalSet<T>::const_iterator IntervalSet<T>::find(
     327             :     const T& element) const
     328             : {
     329           6 :     if (_intervals.empty())
     330           0 :         return end();
     331             : 
     332             :     typename EdgeSet::const_iterator next =
     333           6 :         _intervals.lower_bound(std::make_pair(element, false));
     334             :     // Note that if x equals the start edge of any interval then
     335             :     // next will be the end edge due to the use of (x, false) in the
     336             :     // search.
     337           6 :     if (next == _intervals.end() || next == _intervals.begin())
     338             :         // x cannot be inside any interval.
     339           2 :         return end();
     340             : 
     341           4 :     typename EdgeSet::const_iterator previous = next;
     342           4 :     --previous;
     343           4 :     if (previous->second)
     344           4 :         return const_iterator(*this, previous, element);
     345           0 :     return end();
     346             : }
     347             : 
     348             : template <typename T>
     349           2 : typename IntervalSet<T>::const_iterator IntervalSet<T>::begin() const
     350             : {
     351           2 :     if (_intervals.empty())
     352           0 :         return end();
     353           2 :     return const_iterator(*this, _intervals.begin());
     354             : }
     355             : 
     356             : template <typename T>
     357          13 : typename IntervalSet<T>::const_iterator IntervalSet<T>::end() const
     358             : {
     359          13 :     return const_iterator(*this, _intervals.end());
     360             : }
     361             : 
     362             : template <typename T>
     363          12 : size_t IntervalSet<T>::size() const
     364             : {
     365          12 :     return _size;
     366             : }
     367             : 
     368             : template <typename T>
     369           2 : bool IntervalSet<T>::empty() const
     370             : {
     371           2 :     return size() == 0;
     372             : }
     373             : 
     374             : template <typename T>
     375             : void IntervalSet<T>::swap(IntervalSet& rhs)
     376             : {
     377             :     _intervals.swap(rhs._intervals);
     378             : }
     379             : }
     380             : /** @endcond */

Generated by: LCOV version 1.11