Bug 1060419 - templatize SprintfState and move to jsprf.h; r?froydnj
MozReview-Commit-ID: I11rtaVaJot
--- 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);