From e25f83349602770d745f6e9854cfbee8160618cc Mon Sep 17 00:00:00 2001 From: "svenpanne@chromium.org" Date: Fri, 27 Jun 2014 08:42:17 +0000 Subject: [PATCH] Added slim versions of output streams. R=bmeurer@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/352823003 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22049 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- BUILD.gn | 4 +- build/standalone.gypi | 3 +- src/ostreams.cc | 161 +++++++++++++++++++++++++++++++++++++++++++ src/ostreams.h | 121 ++++++++++++++++++++++++++++++++ test/cctest/cctest.gyp | 1 + test/cctest/test-ostreams.cc | 147 +++++++++++++++++++++++++++++++++++++++ tools/gyp/v8.gyp | 4 +- 7 files changed, 438 insertions(+), 3 deletions(-) create mode 100644 src/ostreams.cc create mode 100644 src/ostreams.h create mode 100644 test/cctest/test-ostreams.cc diff --git a/BUILD.gn b/BUILD.gn index 2cf0b0f..9f4d83d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -674,8 +674,10 @@ source_set("v8_base") { "src/objects-visiting.h", "src/objects.cc", "src/objects.h", - "src/optimizing-compiler-thread.h", "src/optimizing-compiler-thread.cc", + "src/optimizing-compiler-thread.h", + "src/ostreams.cc", + "src/ostreams.h", "src/parser.cc", "src/parser.h", "src/platform/elapsed-timer.h", diff --git a/build/standalone.gypi b/build/standalone.gypi index 7952bdc..cf448f3 100644 --- a/build/standalone.gypi +++ b/build/standalone.gypi @@ -189,7 +189,8 @@ or OS=="netbsd"', { 'target_defaults': { 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', - '-pthread', '-fno-exceptions', '-pedantic' ], + '-Wno-long-long', '-pthread', '-fno-exceptions', + '-pedantic' ], 'cflags_cc': [ '-Wnon-virtual-dtor', '-fno-rtti' ], 'ldflags': [ '-pthread', ], 'conditions': [ diff --git a/src/ostreams.cc b/src/ostreams.cc new file mode 100644 index 0000000..a5d8d6e --- /dev/null +++ b/src/ostreams.cc @@ -0,0 +1,161 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "src/ostreams.h" + +#if V8_CC_MSVC +#define snprintf sprintf_s +#endif + +namespace v8 { +namespace internal { + +// Be lazy and delegate the value=>char conversion to snprintf. +template +OStream& OStream::print(const char* format, T x) { + char buf[32]; + int n = snprintf(buf, sizeof(buf), format, x); + return (n < 0) ? *this : write(buf, n); +} + + +OStream& OStream::operator<<(short x) { // NOLINT(runtime/int) + return print(hex_ ? "%hx" : "%hd", x); +} + + +OStream& OStream::operator<<(unsigned short x) { // NOLINT(runtime/int) + return print(hex_ ? "%hx" : "%hu", x); +} + + +OStream& OStream::operator<<(int x) { + return print(hex_ ? "%x" : "%d", x); +} + + +OStream& OStream::operator<<(unsigned int x) { + return print(hex_ ? "%x" : "%u", x); +} + + +OStream& OStream::operator<<(long x) { // NOLINT(runtime/int) + return print(hex_ ? "%lx" : "%ld", x); +} + + +OStream& OStream::operator<<(unsigned long x) { // NOLINT(runtime/int) + return print(hex_ ? "%lx" : "%lu", x); +} + + +OStream& OStream::operator<<(long long x) { // NOLINT(runtime/int) + return print(hex_ ? "%llx" : "%lld", x); +} + + +OStream& OStream::operator<<(unsigned long long x) { // NOLINT(runtime/int) + return print(hex_ ? "%llx" : "%llu", x); +} + + +OStream& OStream::operator<<(double x) { + return print("%g", x); +} + + +OStream& OStream::operator<<(void* x) { + return print("%p", x); +} + + +OStream& OStream::operator<<(char x) { + return put(x); +} + + +OStream& OStream::operator<<(signed char x) { + return put(x); +} + + +OStream& OStream::operator<<(unsigned char x) { + return put(x); +} + + +OStream& OStream::dec() { + hex_ = false; + return *this; +} + + +OStream& OStream::hex() { + hex_ = true; + return *this; +} + + +OStream& flush(OStream& os) { // NOLINT(runtime/references) + return os.flush(); +} + + +OStream& endl(OStream& os) { // NOLINT(runtime/references) + return flush(os.put('\n')); +} + + +OStream& hex(OStream& os) { // NOLINT(runtime/references) + return os.hex(); +} + + +OStream& dec(OStream& os) { // NOLINT(runtime/references) + return os.dec(); +} + + +OStringStream& OStringStream::write(const char* s, size_t n) { + size_t new_size = size_ + n; + if (new_size < size_) return *this; // Overflow => no-op. + reserve(new_size + 1); + memcpy(data_ + size_, s, n); + size_ = new_size; + data_[size_] = '\0'; + return *this; +} + + +OStringStream& OStringStream::flush() { + return *this; +} + + +void OStringStream::reserve(size_t requested_capacity) { + if (requested_capacity <= capacity_) return; + size_t new_capacity = // Handle possible overflow by not doubling. + std::max(std::max(capacity_ * 2, capacity_), requested_capacity); + char * new_data = allocate(new_capacity); + memcpy(new_data, data_, size_); + deallocate(data_, capacity_); + capacity_ = new_capacity; + data_ = new_data; +} + + +OFStream& OFStream::write(const char* s, size_t n) { + if (f_) fwrite(s, n, 1, f_); + return *this; +} + + +OFStream& OFStream::flush() { + if (f_) fflush(f_); + return *this; +} + +} } // namespace v8::internal diff --git a/src/ostreams.h b/src/ostreams.h new file mode 100644 index 0000000..7853e31 --- /dev/null +++ b/src/ostreams.h @@ -0,0 +1,121 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_OSTREAMS_H_ +#define V8_OSTREAMS_H_ + +#include +#include +#include + +#include "include/v8config.h" +#include "src/base/macros.h" + +namespace v8 { +namespace internal { + +// An abstract base class for output streams with a cut-down standard interface. +class OStream { + public: + OStream() : hex_(false) { } + virtual ~OStream() { } + + // For manipulators like 'os << endl' or 'os << flush', etc. + OStream& operator<<(OStream& (*manipulator)(OStream& os)) { + return manipulator(*this); + } + + // Numeric conversions. + OStream& operator<<(short x); // NOLINT(runtime/int) + OStream& operator<<(unsigned short x); // NOLINT(runtime/int) + OStream& operator<<(int x); + OStream& operator<<(unsigned int x); + OStream& operator<<(long x); // NOLINT(runtime/int) + OStream& operator<<(unsigned long x); // NOLINT(runtime/int) + OStream& operator<<(long long x); // NOLINT(runtime/int) + OStream& operator<<(unsigned long long x); // NOLINT(runtime/int) + OStream& operator<<(double x); + OStream& operator<<(void* x); + + // Character output. + OStream& operator<<(char x); + OStream& operator<<(signed char x); + OStream& operator<<(unsigned char x); + OStream& operator<<(const char* s) { return write(s, strlen(s)); } + OStream& put(char c) { return write(&c, 1); } + + // Primitive format flag handling, can be extended if needed. + OStream& dec(); + OStream& hex(); + + virtual OStream& write(const char* s, size_t n) = 0; + virtual OStream& flush() = 0; + + private: + template OStream& print(const char* format, T x); + + bool hex_; + + DISALLOW_COPY_AND_ASSIGN(OStream); +}; + + +// Some manipulators. +OStream& flush(OStream& os); // NOLINT(runtime/references) +OStream& endl(OStream& os); // NOLINT(runtime/references) +OStream& dec(OStream& os); // NOLINT(runtime/references) +OStream& hex(OStream& os); // NOLINT(runtime/references) + + +// An output stream writing to a character buffer. +class OStringStream: public OStream { + public: + OStringStream() : size_(0), capacity_(32), data_(allocate(capacity_)) { + data_[0] = '\0'; + } + ~OStringStream() { deallocate(data_, capacity_); } + + size_t size() const { return size_; } + size_t capacity() const { return capacity_; } + const char* data() const { return data_; } + + // Internally, our character data is always 0-terminated. + const char* c_str() const { return data(); } + + virtual OStringStream& write(const char* s, size_t n) V8_OVERRIDE; + virtual OStringStream& flush() V8_OVERRIDE; + + private: + // Primitive allocator interface, can be extracted if needed. + static char* allocate (size_t n) { return new char[n]; } + static void deallocate (char* s, size_t n) { delete[] s; } + + void reserve(size_t requested_capacity); + + size_t size_; + size_t capacity_; + char* data_; + + DISALLOW_COPY_AND_ASSIGN(OStringStream); +}; + + +// An output stream writing to a file. +class OFStream: public OStream { + public: + explicit OFStream(FILE* f) : f_(f) { } + virtual ~OFStream() { } + + virtual OFStream& write(const char* s, size_t n) V8_OVERRIDE; + virtual OFStream& flush() V8_OVERRIDE; + + private: + FILE* const f_; + + DISALLOW_COPY_AND_ASSIGN(OFStream); +}; + +} } // namespace v8::internal + +#endif // V8_OSTREAMS_H_ diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index f366131..1f3e81f 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -96,6 +96,7 @@ 'test-mutex.cc', 'test-object-observe.cc', 'test-ordered-hash-table.cc', + 'test-ostreams.cc', 'test-parsing.cc', 'test-platform.cc', 'test-platform-tls.cc', diff --git a/test/cctest/test-ostreams.cc b/test/cctest/test-ostreams.cc new file mode 100644 index 0000000..3d9e2e7 --- /dev/null +++ b/test/cctest/test-ostreams.cc @@ -0,0 +1,147 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "include/v8stdint.h" +#include "src/ostreams.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +TEST(OStringStreamConstructor) { + OStringStream oss; + CHECK_EQ(0, oss.size()); + CHECK_GT(oss.capacity(), 0); + CHECK_NE(NULL, oss.data()); + CHECK_EQ("", oss.c_str()); +} + + +#define TEST_STRING \ + "Ash nazg durbatuluk, " \ + "ash nazg gimbatul, " \ + "ash nazg thrakatuluk, " \ + "agh burzum-ishi krimpatul." + +TEST(OStringStreamGrow) { + OStringStream oss; + const int repeat = 30; + size_t len = strlen(TEST_STRING); + for (int i = 0; i < repeat; ++i) { + oss.write(TEST_STRING, len); + } + const char* expected = + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING; + const size_t expected_len = len * repeat; + CHECK_EQ(static_cast(expected_len), oss.size()); + CHECK_GT(oss.capacity(), 0); + CHECK_EQ(0, strncmp(expected, oss.data(), expected_len)); + CHECK_EQ(expected, oss.c_str()); +} + + +template +static void check(const char* expected, T value) { + OStringStream oss; + oss << value << " " << hex << value; + CHECK_EQ(expected, oss.c_str()); +} + + +TEST(NumericFormatting) { + check("0 0", false); + check("1 1", true); + + check("-12345 cfc7", -12345); + check("-32768 8000", std::numeric_limits::min()); + check("32767 7fff", std::numeric_limits::max()); + + check("34567 8707", 34567); + check("0 0", std::numeric_limits::min()); + check("65535 ffff", std::numeric_limits::max()); + + check("-1234567 ffed2979", -1234567); + check("-2147483648 80000000", std::numeric_limits::min()); + check("2147483647 7fffffff", std::numeric_limits::max()); + + check("3456789 34bf15", 3456789); + check("0 0", std::numeric_limits::min()); + check("4294967295 ffffffff", std::numeric_limits::max()); + + check("-1234567 ffffffffffed2979", -1234567); + check("-9223372036854775808 8000000000000000", + std::numeric_limits::min()); + check("9223372036854775807 7fffffffffffffff", + std::numeric_limits::max()); + + check("3456789 34bf15", 3456789); + check("0 0", std::numeric_limits::min()); + check("18446744073709551615 ffffffffffffffff", + std::numeric_limits::max()); + + check("0 0", 0.0f); + check("123 123", 123.0f); + check("-0.5 -0.5", -0.5f); + check("1.25 1.25", 1.25f); + check("0.0625 0.0625", 6.25e-2f); + + check("0 0", 0.0); + check("123 123", 123.0); + check("-0.5 -0.5", -0.5); + check("1.25 1.25", 1.25); + check("0.0625 0.0625", 6.25e-2); +} + + +TEST(CharacterOutput) { + check("a a", 'a'); + check("B B", 'B'); + check("9 9", '9'); + check("bye bye", "bye"); + + OStringStream os; + os.put('H').write("ello", 4); + CHECK_EQ("Hello", os.c_str()); +} + + +TEST(Manipulators) { + OStringStream os; + os << 123 << hex << 123 << endl << 123 << dec << 123 << 123; + CHECK_EQ("1237b\n7b123123", os.c_str()); +} + + +class MiscStuff { + public: + MiscStuff(int i, double d, const char* s) : i_(i), d_(d), s_(s) { } + + private: + friend OStream& operator<<(OStream& os, const MiscStuff& m); + + int i_; + double d_; + const char* s_; +}; + + +OStream& operator<<(OStream& os, const MiscStuff& m) { + return os << "{i:" << m.i_ << ", d:" << m.d_ << ", s:'" << m.s_ << "'}"; +} + + +TEST(CustomOutput) { + OStringStream os; + MiscStuff m(123, 4.5, "Hurz!"); + os << m; + CHECK_EQ("{i:123, d:4.5, s:'Hurz!'}", os.c_str()); +} diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 06990c7..708c091 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -570,8 +570,10 @@ '../../src/objects-visiting.h', '../../src/objects.cc', '../../src/objects.h', - '../../src/optimizing-compiler-thread.h', '../../src/optimizing-compiler-thread.cc', + '../../src/optimizing-compiler-thread.h', + '../../src/ostreams.cc', + '../../src/ostreams.h', '../../src/parser.cc', '../../src/parser.h', '../../src/platform/elapsed-timer.h', -- 2.7.4