diff --git a/format.h b/format.h index 34506e86..0531dd22 100644 --- a/format.h +++ b/format.h @@ -59,17 +59,50 @@ namespace fmt { namespace internal { -#ifdef _MSC_VER +#if _SECURE_SCL template -inline stdext::checked_array_iterator - CheckIterator(T *ptr, std::size_t size) { +inline stdext::checked_array_iterator CheckPtr(T *ptr, std::size_t size) { return stdext::checked_array_iterator(ptr, size); } #else template -inline T *CheckIterator(T *ptr, std::size_t) { - return ptr; +inline T *CheckPtr(T *ptr, std::size_t) { return ptr; } +#endif + +#ifndef _MSC_VER + +inline int SignBit(double value) { + // When compiled in C++11 mode signbit is no longer a macro but a function + // defined in namespace std and the macro is undefined. + using namespace std; + return signbit(value); } + +inline int IsInf(double x) { +#ifdef isinf + return isinf(x); +#else + return std::isinf(x); +#endif +} + +#define FMT_SNPRINTF snprintf + +#else + +inline int SignBit(double value) { + if (value < 0) return 1; + if (value == value) return 0; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); + return sign; +} + +inline int IsInf(double x) { return !_finite(x); } + +#define FMT_SNPRINTF sprintf_s + #endif // _MSC_VER // A simple array for POD types with the first SIZE elements stored in @@ -131,7 +164,7 @@ template void Array::Grow(std::size_t size) { capacity_ = (std::max)(size, capacity_ + capacity_ / 2); T *p = new T[capacity_]; - std::copy(ptr_, ptr_ + size_, CheckIterator(p, capacity_)); + std::copy(ptr_, ptr_ + size_, CheckPtr(p, capacity_)); if (ptr_ != data_) delete [] ptr_; ptr_ = p; @@ -142,7 +175,7 @@ void Array::append(const T *begin, const T *end) { std::ptrdiff_t num_elements = end - begin; if (size_ + num_elements > capacity_) Grow(num_elements); - std::copy(begin, end, CheckIterator(ptr_ + size_, capacity_ - size_)); + std::copy(begin, end, CheckPtr(ptr_, capacity_) + size_); size_ += num_elements; } @@ -194,42 +227,6 @@ inline unsigned CountDigits(uint64_t n) { } } -#ifndef _MSC_VER - -inline int SignBit(double value) { - // When compiled in C++11 mode signbit is no longer a macro but a function - // defined in namespace std and the macro is undefined. - using namespace std; - return signbit(value); -} - -inline int IsInf(double x) { -#ifdef isinf - return isinf(x); -#else - return std::isinf(x); -#endif -} - -#define FMT_SNPRINTF snprintf - -#else - -inline int SignBit(double value) { - if (value < 0) return 1; - if (value == value) return 0; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); - return sign; -} - -inline int IsInf(double x) { return !_finite(x); } - -#define FMT_SNPRINTF sprintf_s - -#endif - template class ArgInserter; @@ -440,11 +437,21 @@ DEFINE_INT_FORMATTERS(unsigned long) template class BasicWriter { - private: - static void FormatDecimal(Char *buffer, uint64_t value, unsigned num_digits); + protected: +#if _SECURE_SCL + typedef stdext::checked_array_iterator CharPtr; + static Char *GetBase(CharPtr p) { return p.base(); } +#else + typedef Char *CharPtr; + static Char *GetBase(Char *p) { return p; } +#endif + +private: + static void FormatDecimal( + CharPtr buffer, uint64_t value, unsigned num_digits); protected: - static Char *FillPadding(Char *buffer, + static CharPtr FillPadding(CharPtr buffer, unsigned total_size, std::size_t content_size, char fill); enum { INLINE_BUFFER_SIZE = 500 }; @@ -452,19 +459,19 @@ class BasicWriter { // Grows the buffer by n characters and returns a pointer to the newly // allocated area. - Char *GrowBuffer(std::size_t n) { + CharPtr GrowBuffer(std::size_t n) { std::size_t size = buffer_.size(); buffer_.resize(size + n); - return &buffer_[size]; + return internal::CheckPtr(&buffer_[size], n); } - Char *PrepareFilledBuffer(unsigned size, const Spec &, char sign) { - Char *p = GrowBuffer(size); + CharPtr PrepareFilledBuffer(unsigned size, const Spec &, char sign) { + CharPtr p = GrowBuffer(size); *p = sign; return p + size - 1; } - Char *PrepareFilledBuffer(unsigned size, const AlignSpec &spec, char sign); + CharPtr PrepareFilledBuffer(unsigned size, const AlignSpec &spec, char sign); // Formats an integer. template @@ -476,7 +483,7 @@ class BasicWriter { template void FormatDouble(T value, const FormatSpec &spec, int precision); - char *FormatString(const char *s, std::size_t size, const FormatSpec &spec); + CharPtr FormatString(const char *s, std::size_t size, const FormatSpec &spec); public: /** @@ -546,20 +553,20 @@ class BasicWriter { // Fills the padding around the content and returns the pointer to the // content area. template -Char *BasicWriter::FillPadding(Char *buffer, - unsigned total_size, std::size_t content_size, char fill) { +typename BasicWriter::CharPtr BasicWriter::FillPadding( + CharPtr buffer, unsigned total_size, std::size_t content_size, char fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; std::fill_n(buffer, left_padding, fill); buffer += left_padding; - Char *content = buffer; + CharPtr content = buffer; std::fill_n(buffer + content_size, padding - left_padding, fill); return content; } template void BasicWriter::FormatDecimal( - Char *buffer, uint64_t value, unsigned num_digits) { + CharPtr buffer, uint64_t value, unsigned num_digits) { --num_digits; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead @@ -581,16 +588,16 @@ void BasicWriter::FormatDecimal( } template -Char *BasicWriter::PrepareFilledBuffer( +typename BasicWriter::CharPtr BasicWriter::PrepareFilledBuffer( unsigned size, const AlignSpec &spec, char sign) { unsigned width = spec.width(); if (width <= size) { - Char *p = GrowBuffer(size); + CharPtr p = GrowBuffer(size); *p = sign; return p + size - 1; } - char *p = GrowBuffer(width); - char *end = p + width; + CharPtr p = GrowBuffer(width); + CharPtr end = p + width; Alignment align = spec.align(); if (align == ALIGN_LEFT) { *p = sign; @@ -661,7 +668,7 @@ void BasicWriter::FormatDouble( --size; ++nan; } - char *out = FormatString(nan, size, spec); + CharPtr out = FormatString(nan, size, spec); if (sign) *out = sign; return; @@ -676,7 +683,7 @@ void BasicWriter::FormatDouble( --size; ++inf; } - char *out = FormatString(inf, size, spec); + CharPtr out = FormatString(inf, size, spec); if (sign) *out = sign; return; @@ -744,8 +751,9 @@ void BasicWriter::FormatDouble( } if (spec.align() == ALIGN_CENTER && spec.width() > static_cast(n)) { - char *p = GrowBuffer(spec.width()); - std::copy(p, p + n, p + (spec.width() - n) / 2); + unsigned width = spec.width(); + CharPtr p = GrowBuffer(width); + std::copy(p, p + n, p + (width - n) / 2); FillPadding(p, spec.width(), n, spec.fill()); return; } @@ -763,9 +771,9 @@ void BasicWriter::FormatDouble( } template -char *BasicWriter::FormatString( +typename BasicWriter::CharPtr BasicWriter::FormatString( const char *s, std::size_t size, const FormatSpec &spec) { - char *out = 0; + CharPtr out = CharPtr(); if (spec.width() > size) { out = GrowBuffer(spec.width()); if (spec.align() == ALIGN_RIGHT) { @@ -803,7 +811,8 @@ BasicWriter &BasicWriter::operator<<( switch (f.type()) { case 0: case 'd': { unsigned num_digits = internal::CountDigits(abs_value); - Char *p = PrepareFilledBuffer(size + num_digits, f, sign) - num_digits + 1; + CharPtr p = + PrepareFilledBuffer(size + num_digits, f, sign) + 1 - num_digits; BasicWriter::FormatDecimal(p, abs_value, num_digits); break; } @@ -814,7 +823,7 @@ BasicWriter &BasicWriter::operator<<( do { ++size; } while ((n >>= 4) != 0); - Char *p = PrepareFilledBuffer(size, f, sign); + Char *p = GetBase(PrepareFilledBuffer(size, f, sign)); n = abs_value; const char *digits = f.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; @@ -834,7 +843,7 @@ BasicWriter &BasicWriter::operator<<( do { ++size; } while ((n >>= 3) != 0); - Char *p = PrepareFilledBuffer(size, f, sign); + Char *p = GetBase(PrepareFilledBuffer(size, f, sign)); n = abs_value; do { *p-- = '0' + (n & 7); @@ -1529,12 +1538,12 @@ void BasicFormatter::DoFormat() { case CHAR: { if (spec.type_ && spec.type_ != 'c') internal::ReportUnknownType(spec.type_, "char"); - char *out = 0; + typedef typename BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); if (spec.width_ > 1) { out = this->GrowBuffer(spec.width_); if (spec.align_ == ALIGN_RIGHT) { - std::fill_n(internal::CheckIterator(out, spec.width_), - spec.width_ - 1, spec.fill_); + std::fill_n(out, spec.width_ - 1, spec.fill_); out += spec.width_ - 1; } else if (spec.align_ == ALIGN_CENTER) { out = this->FillPadding(out, spec.width_, 1, spec.fill_);