summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/range.cc83
-rw-r--r--base/range.hh418
-rw-r--r--test/Makefile2
-rw-r--r--test/rangetest.cc78
4 files changed, 371 insertions, 210 deletions
diff --git a/base/range.cc b/base/range.cc
new file mode 100644
index 000000000..0a4876e89
--- /dev/null
+++ b/base/range.cc
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "base/intmath.hh"
+#include "base/range.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+template <class T>
+bool
+__x_parse_range(const std::string &str, T &start, T &end)
+{
+ 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;
+
+ return true;
+}
+
+#define RANGE_PARSE(type) \
+template<> bool \
+__parse_range(const std::string &s, type &start, type &end) \
+{ return __x_parse_range(s, start, end); }
+
+RANGE_PARSE(unsigned long long);
+RANGE_PARSE(signed long long);
+RANGE_PARSE(unsigned long);
+RANGE_PARSE(signed long);
+RANGE_PARSE(unsigned int);
+RANGE_PARSE(signed int);
+RANGE_PARSE(unsigned short);
+RANGE_PARSE(signed short);
+RANGE_PARSE(unsigned char);
+RANGE_PARSE(signed char);
diff --git a/base/range.hh b/base/range.hh
index 3443bf246..34bd34136 100644
--- a/base/range.hh
+++ b/base/range.hh
@@ -29,232 +29,340 @@
#ifndef __RANGE_HH__
#define __RANGE_HH__
-#include <assert.h>
+#include <cassert>
+#include <string>
-#include "base/intmath.hh"
-#include "base/str.hh"
+template <class T>
+bool __parse_range(const std::string &s, T &start, T &end);
-template<class T>
-class Range
+template <class T>
+struct Range
{
private:
- bool valid;
+ /**
+ * @param s range string
+ * Ranges are in the following format:
+ * <range> := {<start_val>}:{<end>}
+ * <end> := <end_val> | +<delta>
+ */
+ void
+ parse(const std::string &s)
+ {
+ if (!__parse_range(s, start, end))
+ invalidate();
+ }
public:
T start;
T end;
public:
- Range() {}
+ Range()
+ {
+ invalidate();
+ }
+
+ template <class U>
+ Range(const Range<U> &r)
+ : start(r.start), end(r.end)
+ {}
- Range(const Range &r) { operator=(r); }
+ template <class U>
+ Range(const std::pair<U, U> &r)
+ : start(r.first), end(r.second)
+ {}
- Range(const T &s, const T &e)
- : start(s), end(e)
+ Range(const std::string &s)
{
- valid = (start <= end);
+ parse(s);
}
- Range(const std::string &s) { valid = parse(s); }
+ template <class U>
+ const Range<T> &operator=(const Range<U> &r)
+ {
+ start = r.start;
+ end = r.end;
+ return *this;
+ }
- ~Range() {}
+ template <class U>
+ const Range<T> &operator=(const std::pair<U, U> &r)
+ {
+ start = r.first;
+ end = r.second;
+ return *this;
+ }
- int compare(const T &p);
- bool parse(const std::string &s);
- const Range &operator=(const Range &r);
+ const Range &operator=(const std::string &s)
+ {
+ parse(s);
+ return *this;
+ }
- bool isValid() const { return valid; }
+ void invalidate() { start = 0; end = 0; }
+ bool size() const { return end - start; }
+ bool valid() const { return start < end; }
};
-
template<class T>
-inline int
-Range<T>::compare(const T &p)
+inline std::ostream &
+operator<<(std::ostream &o, const Range<T> &r)
{
- assert(isValid());
-
- if (p < start)
- return -1;
- else if (p > end)
- return 1;
- else
- return 0;
+ // don't currently support output of invalid ranges
+ assert(r.valid());
+ o << r.start << ":" << r.end;
+ return o;
}
-// Parse a range string
+////////////////////////////////////////////////////////////////////////
//
-// Ranges are in the following format:
-// <range> := {<start_val>}:{<end>}
-// <end> := <end_val> | +<delta>
-template<class T>
+// Range to Range Comparisons
+//
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 and range2 are identical.
+ */
+template<class T, class U>
inline bool
-Range<T>::parse(const std::string &str)
+operator==(const Range<T> &range1, const Range<U> &range2)
{
- 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;
+ assert(range1.valid() && range2.valid());
+ return range1.start == range2.start && range1.end == range2.end;
}
-
-template<class T>
-inline const Range<T> &
-Range<T>::operator=(const Range<T> &r)
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 and range2 are not identical.
+ */
+template<class T, class U>
+inline bool
+operator!=(const Range<T> &range1, const Range<U> &range2)
{
- if (this != &r) {
- start = r.start;
- end = r.end;
-
- valid = r.valid;
- }
- else {
- valid = false;
- }
+ assert(range1.valid() && range2.valid());
+ return range1.start != range2.start || range1.end != range2.end;
+}
- return *this;
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is less than range2 and does not overlap range1.
+ */
+template<class T, class U>
+inline bool
+operator<(const Range<T> &range1, const Range<U> &range2)
+{
+ assert(range1.valid() && range2.valid());
+ return range1.end <= range2.start;
}
-template<class T>
-inline std::ostream &
-operator<<(std::ostream &o, const Range<T> &r)
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is less than range2. range1 may overlap range2,
+ * but not extend beyond the end of range2.
+ */
+template<class T, class U>
+inline bool
+operator<=(const Range<T> &range1, const Range<U> &range2)
{
- // don't currently support output of invalid ranges
- assert(r.isValid());
- o << r.start << ":" << r.end;
- return o;
+ assert(range1.valid() && range2.valid());
+ return range1.start <= range2.start && range1.end <= range2.end;
}
-//////////////////////////////////////////
-//
-// Compare two ranges
-//
-template<class T>
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is greater than range2 and does not overlap range2.
+ */
+template<class T, class U>
inline bool
-operator==(const Range<T> &l, const Range<T> &r)
+operator>(const Range<T> &range1, const Range<U> &range2)
{
- // ranges must both be valid to be equal
- return (l.isValid() && r.isValid() &&
- (l.start == r.start) && (l.end == r.end));
+ assert(range1.valid() && range2.valid());
+ return range1.start >= range2.end;
}
-template<class T>
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is greater than range2. range1 may overlap range2,
+ * but not extend beyond the beginning of range2.
+ */
+template<class T, class U>
inline bool
-operator!=(const Range<T> &l, const Range<T> &r)
+operator>=(const Range<T> &range1, const Range<U> &range2)
{
- // 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));
+ assert(range1.valid() && range2.valid());
+ return range1.start >= range2.start && range1.end >= range2.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.
+////////////////////////////////////////////////////////////////////////
//
+// Position to Range Comparisons
//
-//
-// Basic comparisons
-//
-template<class T>
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is within the range.
+ */
+template<class T, class U>
inline bool
-operator==(const T &pos, const Range<T> &range)
-{ return range.isValid() && pos >= range.start && pos <= range.end; }
+operator==(const T &pos, const Range<U> &range)
+{
+ assert(range.valid());
+ return pos >= range.start && pos < range.end;
+}
-template<class T>
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is not within the range.
+ */
+template<class T, class U>
inline bool
-operator<(const T &pos, const Range<T> &range)
-{ assert(range.isValid()); return pos < range.start; }
+operator!=(const T &pos, const Range<U> &range)
+{
+ assert(range.valid());
+ return pos < range.start || pos >= range.end;
+}
-template<class T>
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is below the range.
+ */
+template<class T, class U>
inline bool
-operator>(const T &pos, const Range<T> &range)
-{ assert(range.isValid()); return pos > range.end; }
+operator<(const T &pos, const Range<U> &range)
+{
+ assert(range.valid());
+ return pos < range.start;
+}
-//
-// Derived comparisons
-//
-template<class T>
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is below or in the range.
+ */
+template<class T, class U>
inline bool
-operator<=(const T &pos, const Range<T> &range)
-{ assert(range.isValid()); return pos <= range.end; }
+operator<=(const T &pos, const Range<U> &range)
+{
+ assert(range.valid());
+ return pos < range.end;
+}
-template<class T>
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is above the range.
+ */
+template<class T, class U>
inline bool
-operator>=(const T &pos, const Range<T> &range)
-{ assert(range.isValid()); return pos >= range.start; }
+operator>(const T &pos, const Range<U> &range)
+{
+ assert(range.valid());
+ return pos >= range.end;
+}
-template<class T>
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is above or in the range.
+ */
+template<class T, class U>
inline bool
-operator!=(const T &pos, const Range<T> &range)
-{ return !(pos == range); }
+operator>=(const T &pos, const Range<U> &range)
+{
+ assert(range.valid());
+ return pos >= range.start;
+}
+////////////////////////////////////////////////////////////////////////
//
-// Define symmetric comparisons based on above
+// Range to Position Comparisons (for symmetry)
//
-template<class T>
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is within the range.
+ */
+template<class T, class U>
inline bool
-operator>(const Range<T> &range, const T &pos)
-{ return pos < range; }
+operator==(const Range<T> &range, const U &pos)
+{
+ assert(range.valid());
+ return pos >= range.start && pos < range.end;
+}
-template<class T>
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is not within the range.
+ */
+template<class T, class U>
inline bool
-operator<(const Range<T> &range, const T &pos)
-{ return pos > range; }
+operator!=(const Range<T> &range, const U &pos)
+{
+ assert(range.valid());
+ return pos < range.start || pos >= range.end;
+}
-template<class T>
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is above the range.
+ */
+template<class T, class U>
inline bool
-operator<=(const Range<T> &range, const T &pos)
-{ return pos >= range; }
+operator<(const Range<T> &range, const U &pos)
+{
+ assert(range.valid());
+ return range.end <= pos;
+}
-template<class T>
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is above or in the range.
+ */
+template<class T, class U>
inline bool
-operator>=(const Range<T> &range, const T &pos)
-{ return pos <= range; }
+operator<=(const Range<T> &range, const U &pos)
+{
+ assert(range.valid());
+ return range.start <= pos;
+}
-template<class T>
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * 'range > pos' indicates that position pos is below the range.
+ */
+template<class T, class U>
inline bool
-operator==(const Range<T> &range, const T &pos)
-{ return (pos == range); }
+operator>(const Range<T> &range, const U &pos)
+{
+ assert(range.valid());
+ return range.start > pos;
+}
-template<class T>
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * 'range >= pos' indicates that position pos is below or in the range.
+ */
+template<class T, class U>
inline bool
-operator!=(const Range<T> &range, const T &pos)
-{ return (pos != range); }
+operator>=(const Range<T> &range, const U &pos)
+{
+ assert(range.valid());
+ return range.end > pos;
+}
#endif // __RANGE_HH__
diff --git a/test/Makefile b/test/Makefile
index 2c3780c93..d62dba64a 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -49,7 +49,7 @@ nmtest: nmtest.o object_file.o symtab.o misc.o str.o
offtest: offtest.o
$(CXX) $(LFLAGS) -o $@ $^
-rangetest: rangetest.o str.o
+rangetest: rangetest.o range.o str.o
$(CXX) $(LFLAGS) -o $@ $^
stattest: cprintf.o hostinfo.o misc.o python.o statistics.o stattest.o \
diff --git a/test/rangetest.cc b/test/rangetest.cc
index f44d835b7..c38c13fd1 100644
--- a/test/rangetest.cc
+++ b/test/rangetest.cc
@@ -31,11 +31,12 @@
#include "base/range.hh"
+using namespace std;
int
main()
{
- Range<int> r1(9, 28);
+ Range<int> r1(make_pair(9, 28));
Range<unsigned> r2("0x1000:+0x100");
cout << r1 << "\n"
@@ -44,61 +45,30 @@ main()
#define RANGETEST(X, C, Y) \
cout << X << " "#C" " << Y << " => " << ((X C Y) ? "true" : "false") << "\n"
- int i1 = 10;
- int i2 = 0x1001;
- RANGETEST(i1, < , r1);
- RANGETEST(i1, <=, r1);
- RANGETEST(i1, > , r1);
- RANGETEST(i1, >=, r1);
- RANGETEST(i1, ==, r1);
- RANGETEST(i1, !=, r1);
- RANGETEST(r1, < , i1);
- RANGETEST(r1, <=, i1);
- RANGETEST(r1, > , i1);
- RANGETEST(r1, >=, i1);
- RANGETEST(r1, ==, i1);
- RANGETEST(r1, !=, i1);
+#define TESTEM(X, Y) do { \
+ RANGETEST(X, < , Y); \
+ RANGETEST(X, <=, Y); \
+ RANGETEST(X, > , Y); \
+ RANGETEST(X, >=, Y); \
+ RANGETEST(X, ==, Y); \
+ RANGETEST(X, !=, Y); \
+ RANGETEST(Y, < , X); \
+ RANGETEST(Y, <=, X); \
+ RANGETEST(Y, > , X); \
+ RANGETEST(Y, >=, X); \
+ RANGETEST(Y, ==, X); \
+ RANGETEST(Y, !=, X); \
+} while (0)
- RANGETEST(i2, < , r1);
- RANGETEST(i2, <=, r1);
- RANGETEST(i2, > , r1);
- RANGETEST(i2, >=, r1);
- RANGETEST(i2, ==, r1);
- RANGETEST(i2, !=, r1);
- RANGETEST(r1, < , i2);
- RANGETEST(r1, <=, i2);
- RANGETEST(r1, > , i2);
- RANGETEST(r1, >=, i2);
- RANGETEST(r1, ==, i2);
- RANGETEST(r1, !=, i2);
+ TESTEM(8, r1);
+ TESTEM(9, r1);
+ TESTEM(27, r1);
+ TESTEM(28, r1);
- unsigned u1 = 10;
- unsigned u2 = 0x1001;
- RANGETEST(u1, < , r2);
- RANGETEST(u1, <=, r2);
- RANGETEST(u1, > , r2);
- RANGETEST(u1, >=, r2);
- RANGETEST(u1, ==, r2);
- RANGETEST(u1, !=, r2);
- RANGETEST(r2, < , u1);
- RANGETEST(r2, <=, u1);
- RANGETEST(r2, > , u1);
- RANGETEST(r2, >=, u1);
- RANGETEST(r2, ==, u1);
- RANGETEST(r2, !=, u1);
-
- RANGETEST(u2, < , r2);
- RANGETEST(u2, <=, r2);
- RANGETEST(u2, > , r2);
- RANGETEST(u2, >=, r2);
- RANGETEST(u2, ==, r2);
- RANGETEST(u2, !=, r2);
- RANGETEST(r2, < , u2);
- RANGETEST(r2, <=, u2);
- RANGETEST(r2, > , u2);
- RANGETEST(r2, >=, u2);
- RANGETEST(r2, ==, u2);
- RANGETEST(r2, !=, u2);
+ TESTEM(0x0fff, r2);
+ TESTEM(0x1000, r2);
+ TESTEM(0x10ff, r2);
+ TESTEM(0x1100, r2);
return 0;
}