Figure 1: Partial listing of range_set.h — defines the range_set class

#ifndef RANGE_SET_H
#define RANGE_SET_H

// Copyright 1998 (c) Andrew W. Phillips
// You can freely use this software for any purpose
// as long as you preserve this copyright notice.

#include <list>
#include <iterator>
#include <utility>                  // for make_pair<T1,T2>()   
#include <functional>               // for less<T>
#include <istream>                  // used in << and >>
#include <ios>
#include <cassert>                  // for assert()

template <class T, class Pred = std::less<T>,
          class Alloc = std::allocator<T> >
class range_set
{
public:
    // Define standard types for STL container
    typedef Alloc allocator_type;
    typedef Alloc::size_type size_type;
    typedef Alloc::difference_type difference_type;
    typedef Alloc::pointer pointer;
    typedef Alloc::const_pointer const_pointer;
    typedef Alloc::reference reference;
    typedef Alloc::const_reference const_reference;
    typedef Alloc::value_type value_type;
    typedef Pred value_compare;
    typedef value_type key_type;        // Value == key for sets
    typedef value_compare key_compare;

    // All iterators are const (mods via iterators not allowed)
    class const_iterator;
    typedef const_iterator iterator;

private:
    friend class const_iterator;

    // Class segment: one contiguous block from the set
    // Note: we could have just used std::pair<T,T> rather
    // than creating this class, but this may have hindered
    // future additions.
    struct segment
    {
        T sfirst;           // Bottom of segment
        T slast;            // One past the top of the segment

        // Constructor
        segment(T fst, T lst) : sfirst(fst), slast(lst) { }
    };
    typedef std::list<segment> range_t;
    mutable range_t range_; // All segments for this range_set
    Pred compare_;          // Object used for comparing elts
    Alloc allocator_;       // Object used for allocating elts
    bool increasing_;       // compare_ uses increasing order?

    // not shown: functions insert_helper(), erase_helper()

    T one_more(const T &v) const
    {
        // Since we store "half-open" ranges we need a way to
        // work out what is "one more" than a value.  If we're
        // using less<T> for comparisons this is done by adding
        // 1 but if using greater<T> then we must subtract.
        return increasing_ ? v + T(1) : v - T(1);
    }
    T one_less(const T &v) const
    {
        // We similarly obtain the value "before" another value.
        return increasing_ ? v - T(1) : v + T(1);
    }

public:
    // Iterators
    class const_iterator :
        public std::iterator<std::bidirectional_iterator_tag,
                             T, difference_type>
    {
    private:
        // Since the container does not "contain" all the actual
        // values the iterator itself must contain the current
        // value pointed to.  We must also store an iterator
        // into the list of segments so we know what the
        // valid values are.
        T value_;                      // The value "pointed" to
        mutable range_t::iterator pr_; // Segment with the value

        // We must also access a few things in the container.
        const range_set *pc_;          // Pointer to container

        const_iterator(const range_t::iterator &p,
                       const range_set *pc, const T &v)
            : pr_(p), pc_(pc), value_(v)
        {
            // Check that we are creating a valid iterator
            assert(pr_ == pc_->range_.end() || 
                   (!pc_->compare_(v, pr_->sfirst) && 
                    pc_->compare_(v, pr_->slast)));
        }

    public:
        friend class range_set<T,Pred,Alloc>;
        const_iterator() : pc_(0)   // Default constructor
        {
        }

        // Use compiler generated copy constructor,
        // copy assignment operator, and destructor

        const_reference operator*() const
        {
            // Check that the iterator is valid and
            // that we don't dereference end()
            assert(pc_ != 0);
            assert(pr_ != pc_->range_.end());

            return value_;
        }
        const_pointer operator->() const
        {
            assert(pc_ != 0);
            assert(pr_ != pc_->range_.end());

            return &value_;
        }
        const_iterator &operator++()
        {
            // Check that the iterator is valid and
            // that we don't try to move past the end()
            assert(pc_ != 0);
            assert(pr_ != pc_->range_.end());

            value_ = pc_->one_more(value_);
            if (!pc_->compare_(value_,pr_->slast) &&
                ++pr_ != pc_->range_.end())
            {
                value_ = pr_->sfirst;
            }
            return *this;
        }
        const_iterator operator++(int)
        {
            assert(pc_ != 0);           // Ensure iter is valid
            const_iterator tmp(*this);
            ++*this;
            return tmp;
        }
        const_iterator &operator--()
        {
            assert(pc_ != 0);           // Ensure iter is valid

            // Check that we don't move back before start
            assert(pc_->range_.begin() != pc_->range_.end());
            assert(pr_ != pc_->range_.begin() ||
                   pc_->compare_(pr_->sfirst, value_));

            value_ = pc_->one_less(value_);
            if (pr_ == pc_->range_.end() || 
                pc_->compare_(value_, pr_->sfirst))
            {
                --pr_;
                value_ = pc_->one_less(pr_->slast);
            }
            return *this;
        }
        const_iterator operator--(int)
        {
            assert(pc_ != 0);           // Ensure iter is valid
            const_iterator tmp(*this);
            --*this;
            return tmp;
        }
        bool operator==(const const_iterator& p) const
        {
            assert(pc_ != 0);           // Ensure iter is valid
            assert(pc_ == p.pc_);       // Same container?

            if (pr_ != p.pr_)
                // Different segments so they must be different
                return false;
            else if (pr_ == pc_->range_.end())
                // Both are at end so they compare the same
                return true;
            else
                // The iterators are now the same if their 
                // value_s are the same.  The following tests
                // for equality using compare_.
                // [Note that A == B is equivalent to
                //  A >= B && A <= B  or  !(A < B) && !(B < A)]
                return !pc_->compare_(value_, p.value_) && 
                       !pc_->compare_(p.value_, value_);
        }
        bool operator!=(const const_iterator& p) const
        {
            return !operator==(p);
        }
    };

    // Create a reverse iterator based on normal (forward) iter
    typedef std::reverse_bidirectional_iterator<const_iterator,
                                value_type, const_reference,
                                const_pointer, difference_type>
            const_reverse_iterator;
    typedef const_reverse_iterator reverse_iterator;

    // Constructors
    explicit range_set(const Pred &p = Pred(),
                       const Alloc &a = Alloc())
        : compare_(p), allocator_(a)
    {
        increasing_ = compare_(T(0), T(1));
    }

    // not shown, range_set constructor based on member templates
    // ...

    range_set(const T *p1, const T *p2,
              const Pred &p = Pred(), const Alloc &a = Alloc())
        : compare_(p), allocator_(a)
    {
        increasing_ = compare_(T(0), T(1));

        const_iterator last_pos = begin();
        while (p1 != p2)
            last_pos = insert(last_pos, *p1++);
    }
    range_set(const_iterator p1, const const_iterator &p2,
              const Pred &p = Pred(), const Alloc &a = Alloc())
        : compare_(p), allocator_(a)
    {
        assert(p1.pc_ == p2.pc_);       // Same container?
        assert(p1.pc_ != 0);            // ... and valid?

        increasing_ = compare_(T(0), T(1));

        const_iterator last_pos = begin();
        while (p1 != p2)
            last_pos = insert(last_pos, *p1++);
    }

    // Use compiler generated copy constructor,
    // copy assignment operator, and destructor

    // not shown: functions begin(), end(), rbegin(), rend(), 
    // get_allocator(), max_size(), size(), empty(), and insert()
 
    std::pair<const_iterator, const_iterator>
    insert_range(const value_type &ss, const value_type &ee)
    {
        return insert_helper(range_.begin(), ss, ee);
    }
    std::pair<const_iterator, const_iterator>
    insert_range(const const_iterator &p, const value_type &ss,
                 const value_type &ee)
    {
        assert(p.pc_ == this);          // For this container?
        return insert_helper(p.pr_, ss, ee);
    }

    // not shown: erase() functions

    const_iterator erase_range(const key_type &ss,
                               const key_type &ee)
    {
        return erase_helper(range_.begin(), ss, ee);
    }
    const_iterator erase_range(const const_iterator &p,
                       const key_type &ss, const key_type &ee)
    {
        assert(p.pc_ == this);         // For this container?
        return erase_helper(p.pr_, ss, ee);
    }

    // not shown: functions clear(), swap(), key_comp(), find(),
    // count(), lower_bound(), upper_bound(), operator>>(),
    // operator<<(), operator==(), operator!=(), operator<(),
    // operator>(), operator<=(), operator>=()
};
#endif