Added slim versions of output streams.
authorsvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 27 Jun 2014 08:42:17 +0000 (08:42 +0000)
committersvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 27 Jun 2014 08:42:17 +0000 (08:42 +0000)
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
build/standalone.gypi
src/ostreams.cc [new file with mode: 0644]
src/ostreams.h [new file with mode: 0644]
test/cctest/cctest.gyp
test/cctest/test-ostreams.cc [new file with mode: 0644]
tools/gyp/v8.gyp

index 2cf0b0f..9f4d83d 100644 (file)
--- 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",
index 7952bdc..cf448f3 100644 (file)
        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 (file)
index 0000000..a5d8d6e
--- /dev/null
@@ -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 <algorithm>
+
+#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<class T>
+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 (file)
index 0000000..7853e31
--- /dev/null
@@ -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 <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#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<class T> 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_
index f366131..1f3e81f 100644 (file)
@@ -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 (file)
index 0000000..3d9e2e7
--- /dev/null
@@ -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 <string.h>
+#include <limits>
+
+#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<int>(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 <class T>
+static void check(const char* expected, T value) {
+  OStringStream oss;
+  oss << value << " " << hex << value;
+  CHECK_EQ(expected, oss.c_str());
+}
+
+
+TEST(NumericFormatting) {
+  check<bool>("0 0", false);
+  check<bool>("1 1", true);
+
+  check<int16_t>("-12345 cfc7", -12345);
+  check<int16_t>("-32768 8000", std::numeric_limits<int16_t>::min());
+  check<int16_t>("32767 7fff", std::numeric_limits<int16_t>::max());
+
+  check<uint16_t>("34567 8707", 34567);
+  check<uint16_t>("0 0", std::numeric_limits<uint16_t>::min());
+  check<uint16_t>("65535 ffff", std::numeric_limits<uint16_t>::max());
+
+  check<int32_t>("-1234567 ffed2979", -1234567);
+  check<int32_t>("-2147483648 80000000", std::numeric_limits<int32_t>::min());
+  check<int32_t>("2147483647 7fffffff", std::numeric_limits<int32_t>::max());
+
+  check<uint32_t>("3456789 34bf15", 3456789);
+  check<uint32_t>("0 0", std::numeric_limits<uint32_t>::min());
+  check<uint32_t>("4294967295 ffffffff", std::numeric_limits<uint32_t>::max());
+
+  check<int64_t>("-1234567 ffffffffffed2979", -1234567);
+  check<int64_t>("-9223372036854775808 8000000000000000",
+                 std::numeric_limits<int64_t>::min());
+  check<int64_t>("9223372036854775807 7fffffffffffffff",
+                 std::numeric_limits<int64_t>::max());
+
+  check<uint64_t>("3456789 34bf15", 3456789);
+  check<uint64_t>("0 0", std::numeric_limits<uint64_t>::min());
+  check<uint64_t>("18446744073709551615 ffffffffffffffff",
+                  std::numeric_limits<uint64_t>::max());
+
+  check<float>("0 0", 0.0f);
+  check<float>("123 123", 123.0f);
+  check<float>("-0.5 -0.5", -0.5f);
+  check<float>("1.25 1.25", 1.25f);
+  check<float>("0.0625 0.0625", 6.25e-2f);
+
+  check<double>("0 0", 0.0);
+  check<double>("123 123", 123.0);
+  check<double>("-0.5 -0.5", -0.5);
+  check<double>("1.25 1.25", 1.25);
+  check<double>("0.0625 0.0625", 6.25e-2);
+}
+
+
+TEST(CharacterOutput) {
+  check<char>("a a", 'a');
+  check<signed char>("B B", 'B');
+  check<unsigned char>("9 9", '9');
+  check<const char*>("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());
+}
index 06990c7..708c091 100644 (file)
         '../../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',