Bug 645205 - Implement RangeCheckedPointer<T>, a smart pointer restricted to a range defined at construction. r=luke
authorJeff Walden <jwalden@mit.edu>
Mon, 28 Mar 2011 19:27:02 -0700
changeset 67920 5170b2b6bc72896b82327eaa0e33753138f3c794
parent 67919 d030c439c7cb5e983c2b4a2b962d1dcaa6d93cd3
child 67921 0906d9490eafecf27156c2d38b2a78dd1c45df0a
push id19455
push usercleary@mozilla.com
push dateTue, 12 Apr 2011 03:42:33 +0000
treeherdermozilla-central@d208845094bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs645205
milestone2.2a1pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 645205 - Implement RangeCheckedPointer<T>, a smart pointer restricted to a range defined at construction. r=luke
js/src/jsapi-tests/Makefile.in
js/src/jstl.h
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -80,16 +80,22 @@ CPPSRCS = \
   testUTF8.cpp \
   testVersion.cpp \
   testXDR.cpp \
   testCustomIterator.cpp \
   $(NULL)
 
 DEFINES         += -DEXPORT_JS_API
 
+# Some platforms that have stdint.h include it in system headers.  So
+# to reliably get limit macros defined, we'd always have to define the
+# one below before including any header, but that's obscure and
+# fragile, so we do it here.
+DEFINES         += -D__STDC_LIMIT_MACROS
+
 LIBS      = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS)
 
 LOCAL_INCLUDES += -I$(topsrcdir) -I..
 
 ifdef _MSC_VER
 ifdef WINCE
 WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup
 endif
--- a/js/src/jstl.h
+++ b/js/src/jstl.h
@@ -37,16 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jstl_h_
 #define jstl_h_
 
 #include "jsbit.h"
 #include "jsstaticcheck.h"
+#include "jsstdint.h"
 
 #include <new>
 #include <string.h>
 
 namespace js {
 
 /* JavaScript Template Library. */
 namespace tl {
@@ -485,11 +486,172 @@ Max(T t1, T t2)
 /* Allows a const variable to be initialized after its declaration. */
 template <class T>
 static T&
 InitConst(const T &t)
 {
     return const_cast<T &>(t);
 }
 
+/* Smart pointer, restricted to a range defined at construction. */
+template <class T>
+class RangeCheckedPointer
+{
+    T *ptr;
+
+#ifdef DEBUG
+    T * const rangeStart;
+    T * const rangeEnd;
+#endif
+
+    void sanityChecks() {
+        JS_ASSERT(rangeStart <= ptr);
+        JS_ASSERT(ptr <= rangeEnd);
+    }
+
+    /* Creates a new pointer for |ptr|, restricted to this pointer's range. */
+    RangeCheckedPointer<T> create(T *ptr) const {
+#ifdef DEBUG
+        return RangeCheckedPointer<T>(ptr, rangeStart, rangeEnd);
+#else
+        return RangeCheckedPointer<T>(ptr, NULL, size_t(0));
+#endif
+    }
+
+  public:
+    RangeCheckedPointer(T *p, T *start, T *end)
+      : ptr(p)
+#ifdef DEBUG
+      , rangeStart(start), rangeEnd(end)
+#endif
+    {
+        JS_ASSERT(rangeStart <= rangeEnd);
+        sanityChecks();
+    }
+    RangeCheckedPointer(T *p, T *start, size_t length)
+      : ptr(p)
+#ifdef DEBUG
+      , rangeStart(start), rangeEnd(start + length)
+#endif
+    {
+        JS_ASSERT(length <= size_t(-1) / sizeof(T));
+        JS_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
+        sanityChecks();
+    }
+
+    RangeCheckedPointer<T> &operator=(const RangeCheckedPointer<T> &other) {
+        JS_ASSERT(rangeStart == other.rangeStart);
+        JS_ASSERT(rangeEnd == other.rangeEnd);
+        ptr = other.ptr;
+        sanityChecks();
+        return *this;
+    }
+
+    RangeCheckedPointer<T> operator+(size_t inc) {
+        JS_ASSERT(inc <= size_t(-1) / sizeof(T));
+        JS_ASSERT(ptr + inc > ptr);
+        return create(ptr + inc);
+    }
+
+    RangeCheckedPointer<T> operator-(size_t dec) {
+        JS_ASSERT(dec <= size_t(-1) / sizeof(T));
+        JS_ASSERT(ptr - dec < ptr);
+        return create(ptr - dec);
+    }
+
+    template <class U>
+    RangeCheckedPointer<T> &operator=(U *p) {
+        *this = create(p);
+        return *this;
+    }
+
+    template <class U>
+    RangeCheckedPointer<T> &operator=(const RangeCheckedPointer<U> &p) {
+        JS_ASSERT(rangeStart <= p.ptr);
+        JS_ASSERT(p.ptr <= rangeEnd);
+        ptr = p.ptr;
+        sanityChecks();
+        return *this;
+    }
+
+    RangeCheckedPointer<T> &operator++() {
+        return (*this += 1);
+    }
+
+    RangeCheckedPointer<T> operator++(int) {
+        RangeCheckedPointer<T> rcp = *this;
+        ++*this;
+        return rcp;
+    }
+
+    RangeCheckedPointer<T> &operator--() {
+        return (*this -= 1);
+    }
+
+    RangeCheckedPointer<T> operator--(int) {
+        RangeCheckedPointer<T> rcp = *this;
+        --*this;
+        return rcp;
+    }
+
+    RangeCheckedPointer<T> &operator+=(size_t inc) {
+        this->operator=<T>(*this + inc);
+        return *this;
+    }
+
+    RangeCheckedPointer<T> &operator-=(size_t dec) {
+        this->operator=<T>(*this - dec);
+        return *this;
+    }
+
+    T &operator[](intptr_t index) const {
+        JS_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
+        return *create(ptr + index);
+    }
+
+    T &operator*() const {
+        return *ptr;
+    }
+
+    operator T*() const {
+        return ptr;
+    }
+
+    template <class U>
+    bool operator==(const RangeCheckedPointer<U> &other) const {
+        return ptr == other.ptr;
+    }
+    template <class U>
+    bool operator!=(const RangeCheckedPointer<U> &other) const {
+        return !(*this == other);
+    }
+
+    template <class U>
+    bool operator<(const RangeCheckedPointer<U> &other) const {
+        return ptr < other.ptr;
+    }
+    template <class U>
+    bool operator<=(const RangeCheckedPointer<U> &other) const {
+        return ptr <= other.ptr;
+    }
+
+    template <class U>
+    bool operator>(const RangeCheckedPointer<U> &other) const {
+        return ptr > other.ptr;
+    }
+    template <class U>
+    bool operator>=(const RangeCheckedPointer<U> &other) const {
+        return ptr >= other.ptr;
+    }
+
+    size_t operator-(const RangeCheckedPointer<T> &other) const {
+        JS_ASSERT(ptr >= other.ptr);
+        return PointerRangeSize(other.ptr, ptr);
+    }
+
+  private:
+    RangeCheckedPointer();
+    T *operator&();
+};
+
 } /* namespace js */
 
 #endif /* jstl_h_ */