Bug 1060419 - templatize SprintfState and move to jsprf.h; r?froydnj draft
authorTom Tromey <tom@tromey.com>
Fri, 13 Jan 2017 10:00:31 -0700
changeset 486139 37f022114148d61e3a87124344d2a3722ee154b0
parent 486138 597beae78106c1611757d2410b2b38502027419f
child 486140 f4fd06af8693cbe51d28fa695c104973bdd8da9a
push id45909
push userbmo:ttromey@mozilla.com
push dateFri, 17 Feb 2017 16:00:11 +0000
reviewersfroydnj
bugs1060419
milestone54.0a1
Bug 1060419 - templatize SprintfState and move to jsprf.h; r?froydnj MozReview-Commit-ID: I11rtaVaJot
js/src/jsprf.cpp
js/src/jsprf.h
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -34,25 +34,16 @@ using namespace js;
 #ifdef HAVE_VA_COPY
 #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo, bar)
 #elif defined(HAVE_VA_LIST_AS_ARRAY)
 #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
 #else
 #define VARARGS_ASSIGN(foo, bar)        (foo) = (bar)
 #endif
 
-struct SprintfState : public mozilla::PrintfTarget
-{
-    virtual bool append(const char* sp, size_t len);
-
-    char* base;
-    char* cur;
-    size_t maxlen;
-};
-
 /*
  * Numbered Argument State
  */
 struct NumArgState
 {
     int type;       // type of the current ap
     va_list ap;     // point to the corresponding position on ap
 };
@@ -843,123 +834,16 @@ mozilla::PrintfTarget::print(const char*
     va_list ap;
 
     va_start(ap, format);
     bool result = vprint(format, ap);
     va_end(ap);
     return result;
 }
 
-/*
- * Stuff routine that automatically grows the js_malloc'd output buffer
- * before it overflows.
- */
-bool
-SprintfState::append(const char* sp, size_t len)
-{
-    ptrdiff_t off;
-    char* newbase;
-    size_t newlen;
-
-    off = cur - base;
-    if (off + len >= maxlen) {
-        /* Grow the buffer */
-        newlen = maxlen + ((len > 32) ? len : 32);
-        newbase = static_cast<char*>(js_realloc(base, newlen));
-        if (!newbase) {
-            /* Ran out of memory */
-            return false;
-        }
-        base = newbase;
-        maxlen = newlen;
-        cur = base + off;
-    }
-
-    /* Copy data */
-    while (len) {
-        --len;
-        *cur++ = *sp++;
-    }
-    MOZ_ASSERT(size_t(cur - base) <= maxlen);
-    return true;
-}
-
-/*
- * sprintf into a js_malloc'd buffer
- */
-char*
-mozilla::Smprintf(const char* fmt, ...)
-{
-    va_list ap;
-    char* rv;
-
-    va_start(ap, fmt);
-    rv = mozilla::Vsmprintf(fmt, ap);
-    va_end(ap);
-    return rv;
-}
-
-/*
- * Free memory allocated, for the caller, by mozilla::Smprintf
- */
-void
-mozilla::SmprintfFree(char* mem)
-{
-    js_free(mem);
-}
-
-char*
-mozilla::Vsmprintf(const char* fmt, va_list ap)
-{
-    SprintfState ss;
-
-    ss.base = 0;
-    ss.cur = 0;
-    ss.maxlen = 0;
-    if (!ss.vprint(fmt, ap)) {
-        js_free(ss.base);
-        return 0;
-    }
-    return ss.base;
-}
-
-char*
-mozilla::SmprintfAppend(char* last, const char* fmt, ...)
-{
-    va_list ap;
-    char* rv;
-
-    va_start(ap, fmt);
-    rv = mozilla::VsmprintfAppend(last, fmt, ap);
-    va_end(ap);
-    return rv;
-}
-
-char*
-mozilla::VsmprintfAppend(char* last, const char* fmt, va_list ap)
-{
-    SprintfState ss;
-
-    if (last) {
-        size_t lastlen = strlen(last);
-        ss.base = last;
-        ss.cur = last + lastlen;
-        ss.maxlen = lastlen;
-    } else {
-        ss.base = 0;
-        ss.cur = 0;
-        ss.maxlen = 0;
-    }
-    if (!ss.vprint(fmt, ap)) {
-        js_free(ss.base);
-        return 0;
-    }
-    return ss.base;
-}
-
 #undef TYPE_SHORT
 #undef TYPE_USHORT
 #undef TYPE_INTN
 #undef TYPE_UINTN
 #undef TYPE_LONG
 #undef TYPE_ULONG
 #undef TYPE_LONGLONG
 #undef TYPE_ULONGLONG
@@ -974,36 +858,36 @@ mozilla::VsmprintfAppend(char* last, con
 #undef FLAG_SPACED
 #undef FLAG_ZEROS
 #undef FLAG_NEG
 
 JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    char* result = mozilla::Vsmprintf(fmt, ap);
+    char* result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
     va_end(ap);
     return result;
 }
 
 JS_PUBLIC_API(void) JS_smprintf_free(char* mem)
 {
-    mozilla::SmprintfFree(mem);
+    mozilla::SmprintfFree<js::SystemAllocPolicy>(mem);
 }
 
 JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    char* result = mozilla::VsmprintfAppend(last, fmt, ap);
+    char* result = mozilla::VsmprintfAppend<js::SystemAllocPolicy>(last, fmt, ap);
     va_end(ap);
     return result;
 }
 
 JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap)
 {
-    return mozilla::Vsmprintf(fmt, ap);
+    return mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
 }
 
 JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap)
 {
-    return mozilla::VsmprintfAppend(last, fmt, ap);
+    return mozilla::VsmprintfAppend<js::SystemAllocPolicy>(last, fmt, ap);
 }
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -22,58 +22,31 @@
 **           You should use PRI*SIZE macros instead
 **      %s - string
 **      %c - character
 **      %p - pointer (deals with machine dependent pointer size)
 **      %f - float
 **      %g - float
 */
 
+#include "mozilla/AllocPolicy.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/Types.h"
 
 #include <stdarg.h>
+#include <string.h>
 
 #include "jstypes.h"
 
 namespace mozilla {
 
 /*
-** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
-** buffer on success, nullptr on failure. Call "SmprintfFree" to release
-** the memory returned.
-*/
-extern MFBT_API char* Smprintf(const char* fmt, ...)
-    MOZ_FORMAT_PRINTF(1, 2);
-
-/*
-** Free the memory allocated, for the caller, by Smprintf
-*/
-extern MFBT_API void SmprintfFree(char* mem);
-
-/*
-** "append" sprintf into a malloc'd buffer. "last" is the last value of
-** the malloc'd buffer. sprintf will append data to the end of last,
-** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
-** will allocate the initial string. The return value is the new value of
-** last for subsequent calls, or nullptr if there is a malloc failure.
-*/
-extern MFBT_API char* SmprintfAppend(char* last, const char* fmt, ...)
-    MOZ_FORMAT_PRINTF(2, 3);
-
-/*
-** va_list forms of the above.
-*/
-extern MFBT_API char* Vsmprintf(const char* fmt, va_list ap);
-extern MFBT_API char* VsmprintfAppend(char* last, const char* fmt, va_list ap);
-
-/*
  * This class may be subclassed to provide a way to get the output of
  * a printf-like call, as the output is generated.
  */
 class PrintfTarget
 {
 public:
     /* The Printf-like interface.  */
     bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3);
@@ -105,16 +78,146 @@ private:
     bool fill2(const char* src, int srclen, int width, int flags);
     bool fill_n(const char* src, int srclen, int width, int prec, int type, int flags);
     bool cvt_l(long num, int width, int prec, int radix, int type, int flags, const char* hxp);
     bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, const char* hexp);
     bool cvt_f(double d, const char* fmt0, const char* fmt1);
     bool cvt_s(const char* s, int width, int prec, int flags);
 };
 
+// Used in the implementation of Smprintf et al.
+template<typename AllocPolicy>
+class MOZ_STACK_CLASS SprintfState final : public mozilla::PrintfTarget, private AllocPolicy
+{
+ public:
+    explicit SprintfState(char* base)
+        : mMaxlen(base ? strlen(base) : 0)
+        , mBase(base)
+        , mCur(base ? base + mMaxlen : 0)
+    {
+    }
+
+    ~SprintfState() {
+        this->free_(mBase);
+    }
+
+    char* release() {
+        char* result = mBase;
+        mBase = nullptr;
+        return result;
+    }
+
+ protected:
+
+    bool append(const char* sp, size_t len) override {
+        ptrdiff_t off;
+        char* newbase;
+        size_t newlen;
+
+        off = mCur - mBase;
+        if (off + len >= mMaxlen) {
+            /* Grow the buffer */
+            newlen = mMaxlen + ((len > 32) ? len : 32);
+            newbase = static_cast<char*>(this->maybe_pod_realloc(mBase, mMaxlen, newlen));
+            if (!newbase) {
+                /* Ran out of memory */
+                return false;
+            }
+            mBase = newbase;
+            mMaxlen = newlen;
+            mCur = mBase + off;
+        }
+
+        /* Copy data */
+        memcpy(mCur, sp, len);
+        mCur += len;
+        MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen);
+        return true;
+    }
+
+ private:
+
+    size_t mMaxlen;
+    char* mBase;
+    char* mCur;
+};
+
+/*
+** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
+** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release
+** the memory returned.
+*/
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+MOZ_FORMAT_PRINTF(1, 2)
+char* Smprintf(const char* fmt, ...)
+{
+    SprintfState<AllocPolicy> ss(nullptr);
+    va_list ap;
+    va_start(ap, fmt);
+    bool r = ss.vprint(fmt, ap);
+    va_end(ap);
+    if (!r) {
+        return nullptr;
+    }
+    return ss.release();
+}
+
+/*
+** "append" sprintf into a malloc'd buffer. "last" is the last value of
+** the malloc'd buffer. sprintf will append data to the end of last,
+** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
+** will allocate the initial string. The return value is the new value of
+** last for subsequent calls, or nullptr if there is a malloc failure.
+*/
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+MOZ_FORMAT_PRINTF(2, 3)
+char* SmprintfAppend(char* last, const char* fmt, ...)
+{
+    SprintfState<AllocPolicy> ss(last);
+    va_list ap;
+    va_start(ap, fmt);
+    bool r = ss.vprint(fmt, ap);
+    va_end(ap);
+    if (!r) {
+        return nullptr;
+    }
+    return ss.release();
+}
+
+/*
+** va_list forms of the above.
+*/
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+char* Vsmprintf(const char* fmt, va_list ap)
+{
+    SprintfState<AllocPolicy> ss(nullptr);
+    if (!ss.vprint(fmt, ap))
+        return nullptr;
+    return ss.release();
+}
+
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+char* VsmprintfAppend(char* last, const char* fmt, va_list ap)
+{
+    SprintfState<AllocPolicy> ss(last);
+    if (!ss.vprint(fmt, ap))
+        return nullptr;
+    return ss.release();
+}
+
+/*
+** Free the memory allocated, for the caller, by Smprintf.
+*/
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+void SmprintfFree(char* mem)
+{
+    AllocPolicy allocator;
+    allocator.free_(mem);
+}
+
 } // namespace mozilla
 
 /* Wrappers for mozilla::Smprintf and friends that are used throughout
    JS.  */
 
 extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...)
     MOZ_FORMAT_PRINTF(1, 2);