Bug 1842999 - Part 25: Support testing elements are present in resizable typed arrays...
[gecko.git] / mozglue / misc / Printf.h
blob3f4fa2c1bb89bd56628903ee152beb778a3e9198
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Printf-like functions, with canned variants that malloc their result. */
9 #ifndef mozilla_Printf_h
10 #define mozilla_Printf_h
13 ** API for PR printf like routines.
15 ** These exist partly for historical reasons -- initially they were in
16 ** NSPR, then forked in tree and modified in js/ -- but now the prime
17 ** motivation is both closer control over the exact formatting (with
18 ** one exception, see below) and also the ability to control where
19 ** exactly the generated results are sent.
21 ** It might seem that this could all be dispensed with in favor of a
22 ** wrapper around |vsnprintf| -- except that this implementation
23 ** guarantees that the %s format will accept a NULL pointer, whereas
24 ** with standard functions this is undefined.
26 ** This supports the following formats. It implements a subset of the
27 ** standard formats; due to the use of MOZ_FORMAT_PRINTF, it is not
28 ** permissible to extend the standard, aside from relaxing undefined
29 ** behavior.
31 ** %d - decimal
32 ** %u - unsigned decimal
33 ** %x - unsigned hex
34 ** %X - unsigned uppercase hex
35 ** %o - unsigned octal
36 ** %hd, %hu, %hx, %hX, %ho - "short" versions of above
37 ** %ld, %lu, %lx, %lX, %lo - "long" versions of above
38 ** %lld, %llu, %llx, %llX, %llo - "long long" versions of above
39 ** %zd, %zo, %zu, %zx, %zX - size_t versions of above
40 ** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat).
41 ** Note that MSVC 2015 and newer supports the z length modifier so
42 ** users should prefer using %z instead of %I. We are supporting %I in
43 ** addition to %z in case third-party code that uses %I gets routed to
44 ** use this printf implementation.
45 ** %s - string
46 ** %S, %ls - wide string, that is wchar_t*
47 ** %c - character
48 ** %p - pointer (deals with machine dependent pointer size)
49 ** %f - float; note that this is actually formatted using the
50 ** system's native printf, and so the results may vary
51 ** %g - float; note that this is actually formatted using the
52 ** system's native printf, and so the results may vary
55 #include "mozilla/AllocPolicy.h"
56 #include "mozilla/Assertions.h"
57 #include "mozilla/Attributes.h"
58 #include "mozilla/IntegerPrintfMacros.h"
59 #include "mozilla/Types.h"
60 #include "mozilla/UniquePtr.h"
62 #include <stdarg.h>
63 #include <string.h>
65 namespace mozilla {
68 * This class may be subclassed to provide a way to get the output of
69 * a printf-like call, as the output is generated.
71 class PrintfTarget {
72 public:
73 /* The Printf-like interface. */
74 bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3);
76 /* The Vprintf-like interface. */
77 bool MFBT_API vprint(const char* fmt, va_list) MOZ_FORMAT_PRINTF(2, 0);
79 /* Fast paths for formatting integers as though by %d, %o, %u, or %x.
80 Since octal and hex formatting always treat numbers as unsigned, there
81 are no signed overloads for AppendInt{Oct,Hex}. */
82 bool MFBT_API appendIntDec(int32_t);
83 bool MFBT_API appendIntDec(uint32_t);
84 bool MFBT_API appendIntOct(uint32_t);
85 bool MFBT_API appendIntHex(uint32_t);
86 bool MFBT_API appendIntDec(int64_t);
87 bool MFBT_API appendIntDec(uint64_t);
88 bool MFBT_API appendIntOct(uint64_t);
89 bool MFBT_API appendIntHex(uint64_t);
91 inline size_t emitted() { return mEmitted; }
93 protected:
94 MFBT_API PrintfTarget();
95 virtual ~PrintfTarget() = default;
97 /* Subclasses override this. It is called when more output is
98 available. It may be called with len==0. This should return
99 true on success, or false on failure. */
100 virtual bool append(const char* sp, size_t len) = 0;
102 private:
103 /* Number of bytes emitted so far. */
104 size_t mEmitted;
106 /* The implementation calls this to emit bytes and update
107 mEmitted. */
108 bool emit(const char* sp, size_t len) {
109 mEmitted += len;
110 return append(sp, len);
113 bool fill2(const char* src, int srclen, int width, int flags);
114 bool fill_n(const char* src, int srclen, int width, int prec, int type,
115 int flags);
116 bool cvt_l(long num, int width, int prec, int radix, int type, int flags,
117 const char* hexp);
118 bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags,
119 const char* hexp);
120 bool cvt_f(double d, char c, int width, int prec, int flags);
121 bool cvt_s(const char* s, int width, int prec, int flags);
124 namespace detail {
126 template <typename AllocPolicy = mozilla::MallocAllocPolicy>
127 struct AllocPolicyBasedFreePolicy {
128 void operator()(const void* ptr) {
129 AllocPolicy policy;
130 policy.free_(const_cast<void*>(ptr));
134 } // namespace detail
136 // The type returned by Smprintf and friends.
137 template <typename AllocPolicy>
138 using SmprintfPolicyPointer =
139 mozilla::UniquePtr<char, detail::AllocPolicyBasedFreePolicy<AllocPolicy>>;
141 // The default type if no alloc policy is specified.
142 typedef SmprintfPolicyPointer<mozilla::MallocAllocPolicy> SmprintfPointer;
144 // Used in the implementation of Smprintf et al.
145 template <typename AllocPolicy>
146 class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget,
147 private AllocPolicy {
148 public:
149 explicit SprintfState(char* base)
150 : mMaxlen(base ? strlen(base) : 0),
151 mBase(base),
152 mCur(base ? base + mMaxlen : 0) {}
154 ~SprintfState() { this->free_(mBase); }
156 bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) {
157 // The "" here has a single \0 character, which is what we're
158 // trying to append.
159 return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1);
162 SmprintfPolicyPointer<AllocPolicy> release() {
163 SmprintfPolicyPointer<AllocPolicy> result(mBase);
164 mBase = nullptr;
165 return result;
168 protected:
169 bool append(const char* sp, size_t len) override {
170 ptrdiff_t off;
171 char* newbase;
172 size_t newlen;
174 off = mCur - mBase;
175 if (off + len >= mMaxlen) {
176 /* Grow the buffer */
177 newlen = mMaxlen + ((len > 32) ? len : 32);
178 newbase = this->template maybe_pod_malloc<char>(newlen);
179 if (!newbase) {
180 /* Ran out of memory */
181 return false;
183 memcpy(newbase, mBase, mMaxlen);
184 this->free_(mBase);
185 mBase = newbase;
186 mMaxlen = newlen;
187 mCur = mBase + off;
190 /* Copy data */
191 memcpy(mCur, sp, len);
192 mCur += len;
193 MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen);
194 return true;
197 private:
198 size_t mMaxlen;
199 char* mBase;
200 char* mCur;
204 ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
205 ** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release
206 ** the memory returned.
208 template <typename AllocPolicy = mozilla::MallocAllocPolicy>
209 MOZ_FORMAT_PRINTF(1, 2)
210 SmprintfPolicyPointer<AllocPolicy> Smprintf(const char* fmt, ...) {
211 SprintfState<AllocPolicy> ss(nullptr);
212 va_list ap;
213 va_start(ap, fmt);
214 bool r = ss.vprint(fmt, ap);
215 va_end(ap);
216 if (!r) {
217 return nullptr;
219 return ss.release();
223 ** "append" sprintf into a malloc'd buffer. "last" is the last value of
224 ** the malloc'd buffer. sprintf will append data to the end of last,
225 ** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
226 ** will allocate the initial string. The return value is the new value of
227 ** last for subsequent calls, or nullptr if there is a malloc failure.
229 template <typename AllocPolicy = mozilla::MallocAllocPolicy>
230 MOZ_FORMAT_PRINTF(2, 3)
231 SmprintfPolicyPointer<AllocPolicy> SmprintfAppend(
232 SmprintfPolicyPointer<AllocPolicy>&& last, const char* fmt, ...) {
233 SprintfState<AllocPolicy> ss(last.release());
234 va_list ap;
235 va_start(ap, fmt);
236 bool r = ss.vprint(fmt, ap);
237 va_end(ap);
238 if (!r) {
239 return nullptr;
241 return ss.release();
245 ** va_list forms of the above.
247 template <typename AllocPolicy = mozilla::MallocAllocPolicy>
248 MOZ_FORMAT_PRINTF(1, 0)
249 SmprintfPolicyPointer<AllocPolicy> Vsmprintf(const char* fmt, va_list ap) {
250 SprintfState<AllocPolicy> ss(nullptr);
251 if (!ss.vprint(fmt, ap)) return nullptr;
252 return ss.release();
255 template <typename AllocPolicy = mozilla::MallocAllocPolicy>
256 MOZ_FORMAT_PRINTF(2, 0)
257 SmprintfPolicyPointer<AllocPolicy> VsmprintfAppend(
258 SmprintfPolicyPointer<AllocPolicy>&& last, const char* fmt, va_list ap) {
259 SprintfState<AllocPolicy> ss(last.release());
260 if (!ss.vprint(fmt, ap)) return nullptr;
261 return ss.release();
264 } // namespace mozilla
266 #endif /* mozilla_Printf_h */