Commit 620b544d authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[ostreams] Extend AsHex and add AsHexBytes

Add a third parameter to {AsHex} which specifies whether the prefix
"0x" should be printed. Also, add the {AsHexBytes} helper which
outputs the hex number as individual bytes separated by a whitespace.
Also add unit tests for both helpers.

Both helper will be used in an upcoming refactoring of wasm error
messages:
https://chromium-review.googlesource.com/c/565282

R=titzer@chromium.org

Change-Id: I42d5ace9841ffb918cb4d6803b6347229e446097
Reviewed-on: https://chromium-review.googlesource.com/583448
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46859}
parent d8ac28e9
......@@ -107,10 +107,27 @@ std::ostream& operator<<(std::ostream& os, const AsUC32& c) {
}
std::ostream& operator<<(std::ostream& os, const AsHex& hex) {
char buf[20];
snprintf(buf, sizeof(buf), "%.*" PRIx64, hex.min_width, hex.value);
// Each byte uses up to two characters. Plus two characters for the prefix,
// plus null terminator.
DCHECK_GE(sizeof(hex.value) * 2, hex.min_width);
static constexpr size_t kMaxHexLength = 3 + sizeof(hex.value) * 2;
char buf[kMaxHexLength];
snprintf(buf, kMaxHexLength, "%s%.*" PRIx64, hex.with_prefix ? "0x" : "",
hex.min_width, hex.value);
return os << buf;
}
std::ostream& operator<<(std::ostream& os, const AsHexBytes& hex) {
uint8_t bytes = hex.min_bytes;
while (bytes < sizeof(hex.value) && (hex.value >> (bytes * 8) != 0)) ++bytes;
for (uint8_t b = 0; b < bytes; ++b) {
if (b) os << " ";
uint8_t printed_byte =
hex.byte_order == AsHexBytes::kLittleEndian ? b : bytes - b - 1;
os << AsHex((hex.value >> (8 * printed_byte)) & 0xff, 2);
}
return os;
}
} // namespace internal
} // namespace v8
......@@ -67,11 +67,29 @@ struct AsEscapedUC16ForJSON {
uint16_t value;
};
// Output the given value as hex, with a minimum width and optional prefix (0x).
// E.g. AsHex(23, 3, true) produces "0x017". Produces an empty string if both
// {min_width} and the value are 0.
struct AsHex {
explicit AsHex(uint64_t v, uint8_t min_width = 0)
: value(v), min_width(min_width) {}
explicit AsHex(uint64_t v, uint8_t min_width = 1, bool with_prefix = false)
: value(v), min_width(min_width), with_prefix(with_prefix) {}
uint64_t value;
uint8_t min_width;
bool with_prefix;
};
// Output the given value as hex, separated in individual bytes.
// E.g. AsHexBytes(0x231712, 4) produces "12 17 23 00" if output as little
// endian (default), and "00 23 17 12" as big endian. Produces an empty string
// if both {min_bytes} and the value are 0.
struct AsHexBytes {
enum ByteOrder { kLittleEndian, kBigEndian };
explicit AsHexBytes(uint64_t v, uint8_t min_bytes = 1,
ByteOrder byte_order = kLittleEndian)
: value(v), min_bytes(min_bytes), byte_order(byte_order) {}
uint64_t value;
uint8_t min_bytes;
ByteOrder byte_order;
};
// Writes the given character to the output escaping everything outside of
......@@ -91,8 +109,9 @@ std::ostream& operator<<(std::ostream& os, const AsUC16& c);
// of printable ASCII range.
std::ostream& operator<<(std::ostream& os, const AsUC32& c);
// Writes the given number to the output in hexadecimal notation.
std::ostream& operator<<(std::ostream& os, const AsHex& v);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const AsHex& v);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const AsHexBytes& v);
} // namespace internal
} // namespace v8
......
......@@ -29,6 +29,7 @@ v8_executable("unittests") {
"base/ieee754-unittest.cc",
"base/iterator-unittest.cc",
"base/logging-unittest.cc",
"base/ostreams-unittest.cc",
"base/platform/condition-variable-unittest.cc",
"base/platform/mutex-unittest.cc",
"base/platform/platform-unittest.cc",
......
// Copyright 2017 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 "src/ostreams.h"
#include "testing/gtest-support.h"
namespace v8 {
namespace internal {
TEST(Ostream, AsHex) {
auto testAsHex = [](const char* expected, const AsHex& value) {
std::ostringstream out;
out << value;
std::string result = out.str();
EXPECT_EQ(expected, result);
EXPECT_TRUE(result == expected)
<< "\nexpected: " << expected << "\ngot: " << result << "\n";
};
testAsHex("0", AsHex(0));
testAsHex("", AsHex(0, 0));
testAsHex("0x", AsHex(0, 0, true));
testAsHex("0x0", AsHex(0, 1, true));
testAsHex("0x00", AsHex(0, 2, true));
testAsHex("123", AsHex(0x123, 0));
testAsHex("0123", AsHex(0x123, 4));
testAsHex("0x123", AsHex(0x123, 0, true));
testAsHex("0x123", AsHex(0x123, 3, true));
testAsHex("0x0123", AsHex(0x123, 4, true));
testAsHex("0x00000123", AsHex(0x123, 8, true));
}
TEST(Ostream, AsHexBytes) {
auto testAsHexBytes = [](const char* expected, const AsHexBytes& value) {
std::ostringstream out;
out << value;
std::string result = out.str();
EXPECT_EQ(expected, result);
};
// Little endian (default):
testAsHexBytes("00", AsHexBytes(0));
testAsHexBytes("", AsHexBytes(0, 0));
testAsHexBytes("23 01", AsHexBytes(0x123));
testAsHexBytes("23 01", AsHexBytes(0x123, 1));
testAsHexBytes("23 01", AsHexBytes(0x123, 2));
testAsHexBytes("23 01 00", AsHexBytes(0x123, 3));
testAsHexBytes("ff ff ff ff", AsHexBytes(0xffffffff));
testAsHexBytes("00 00 00 00", AsHexBytes(0, 4));
testAsHexBytes("56 34 12", AsHexBytes(0x123456));
// Big endian:
testAsHexBytes("00", AsHexBytes(0, 1, AsHexBytes::kBigEndian));
testAsHexBytes("", AsHexBytes(0, 0, AsHexBytes::kBigEndian));
testAsHexBytes("01 23", AsHexBytes(0x123, 1, AsHexBytes::kBigEndian));
testAsHexBytes("01 23", AsHexBytes(0x123, 1, AsHexBytes::kBigEndian));
testAsHexBytes("01 23", AsHexBytes(0x123, 2, AsHexBytes::kBigEndian));
testAsHexBytes("00 01 23", AsHexBytes(0x123, 3, AsHexBytes::kBigEndian));
testAsHexBytes("ff ff ff ff", AsHexBytes(0xffffffff, AsHexBytes::kBigEndian));
testAsHexBytes("00 00 00 00", AsHexBytes(0, 4, AsHexBytes::kBigEndian));
testAsHexBytes("12 34 56", AsHexBytes(0x123456, 1, AsHexBytes::kBigEndian));
}
} // namespace internal
} // namespace v8
......@@ -26,6 +26,7 @@
'base/ieee754-unittest.cc',
'base/logging-unittest.cc',
'base/iterator-unittest.cc',
'base/ostreams-unittest.cc',
'base/platform/condition-variable-unittest.cc',
'base/platform/mutex-unittest.cc',
'base/platform/platform-unittest.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment