diff options
Diffstat (limited to 'base/range.hh')
-rw-r--r-- | base/range.hh | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/base/range.hh b/base/range.hh new file mode 100644 index 000000000..254e71460 --- /dev/null +++ b/base/range.hh @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RANGE_HH__ +#define __RANGE_HH__ + +#include <assert.h> + +#include "str.hh" +#include "intmath.h" + +template<class T> +class Range +{ + private: + bool valid; + + public: + T start; + T end; + + public: + Range() {} + + Range(const Range &r) { operator=(r); } + + Range(const T& s, const T& e) + : start(s), end(e) + { + valid = (start <= end); + } + + Range(const std::string &s) { valid = parse(s); } + + ~Range() {} + + int compare(const T &p); + bool parse(const std::string &s); + const Range &operator=(const Range &r); + + bool isValid() const { return valid; } +}; + + +template<class T> +inline int +Range<T>::compare(const T &p) +{ + assert(isValid()); + + if (p < start) + return -1; + else if (p > end) + return 1; + else + return 0; +} + +// Parse a range string +// +// Ranges are in the following format: +// <range> := {<start_val>}:{<end>} +// <end> := <end_val> | +<delta> +template<class T> +inline bool +Range<T>::parse(const std::string &str) +{ + std::vector<std::string> values; + tokenize(values, str, ':'); + + T thestart, theend; + + if (values.size() != 2) + return false; + + std::string s = values[0]; + std::string e = values[1]; + + if (!to_number(s, thestart)) + return false; + + bool increment = (e[0] == '+'); + if (increment) + e = e.substr(1); + + if (!to_number(e, theend)) + return false; + + if (increment) + theend += thestart; + + start = thestart; + end = theend; + + if (start > end) + return false; + + return true; +} + + +template<class T> +inline const Range<T> & +Range<T>::operator=(const Range<T> &r) +{ + if (this != &r) { + start = r.start; + end = r.end; + + valid = r.valid; + } + else { + valid = false; + } + + return *this; +} + +template<class T> +inline std::ostream & +operator<<(std::ostream &o, const Range<T> &r) +{ + // don't currently support output of invalid ranges + assert(r.isValid()); + o << r.start << ":" << r.end; + return o; +} + +////////////////////////////////////////// +// +// Compare two ranges +// +template<class T> +inline bool +operator==(const Range<T> &l, const Range<T> &r) +{ + // ranges must both be valid to be equal + return (l.isValid() && r.isValid() && + (l.start == r.start) && (l.end == r.end)); +} + +template<class T> +inline bool +operator!=(const Range<T> &l, const Range<T> &r) +{ + // for symmetry with ==, an invalid range is not equal to any other + return (!l.isValid() || !r.isValid() || + (l.start != r.start) || (l.end != r.end)); +} + +////////////////////////////////////////// +// +// Compare position to a range +// +// - 'pos == range' indicates that position pos is within the given range. +// This test always returns false if the range is invalid. +// +// - 'pos < range' and 'pos > range' indicate that the position is +// before the start of or after the end of the range, respectively. +// The range must be valid for these comparisons to be made. +// +// All other comparisons do the obvious thing based on these definitions. +// +// + +// +// Basic comparisons +// +template<class T> +inline bool +operator==(const T &pos, const Range<T> &range) +{ return range.isValid() && pos >= range.start && pos <= range.end; } + +template<class T> +inline bool +operator<(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos < range.start; } + +template<class T> +inline bool +operator>(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos > range.end; } + +// +// Derived comparisons +// +template<class T> +inline bool +operator<=(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos <= range.end; } + +template<class T> +inline bool +operator>=(const T &pos, const Range<T> &range) +{ assert(range.isValid()); return pos >= range.start; } + +template<class T> +inline bool +operator!=(const T &pos, const Range<T> &range) +{ return !(pos == range); } + +// +// Define symmetric comparisons based on above +// +template<class T> +inline bool +operator>(const Range<T> &range, const T &pos) +{ return pos < range; } + +template<class T> +inline bool +operator<(const Range<T> &range, const T &pos) +{ return pos > range; } + +template<class T> +inline bool +operator<=(const Range<T> &range, const T &pos) +{ return pos >= range; } + +template<class T> +inline bool +operator>=(const Range<T> &range, const T &pos) +{ return pos <= range; } + +template<class T> +inline bool +operator==(const Range<T> &range, const T &pos) +{ return (pos == range); } + +template<class T> +inline bool +operator!=(const Range<T> &range, const T &pos) +{ return (pos != range); } + +#endif // __RANGE_HH__ |