blob: 0ae55ec186d3a90938ac62984c9293938bee17bd [file] [log] [blame]
// Copyright 2018 The Fuchsia 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/developer/debug/zxdb/common/string_util.h"
#include <inttypes.h>
#include <iomanip>
#include <sstream>
namespace zxdb {
namespace {
std::string DoToHexString(uint64_t value, int digits, bool include_prefix) {
std::ostringstream out;
if (include_prefix)
out << "0x";
if (digits)
out << std::setw(digits) << std::setfill('0');
out << std::hex << value;
return out.str();
}
} // namespace
bool StringStartsWith(std::string_view str, std::string_view begins_with) {
if (begins_with.size() > str.size())
return false;
std::string_view source = str.substr(0, begins_with.size());
return source == begins_with;
}
bool StringEndsWith(std::string_view str, std::string_view ends_with) {
if (ends_with.size() > str.size())
return false;
std::string_view source = str.substr(str.size() - ends_with.size(), ends_with.size());
return source == ends_with;
}
// Cast signed numbers to their unsigned variant before converting to 64-bit to avoid sign
// extension.
std::string to_hex_string(int8_t i, int digits, bool include_prefix) {
return DoToHexString(static_cast<uint8_t>(i), digits, include_prefix);
}
std::string to_hex_string(uint8_t i, int digits, bool include_prefix) {
return DoToHexString(i, digits, include_prefix);
}
std::string to_hex_string(int16_t i, int digits, bool include_prefix) {
return DoToHexString(static_cast<uint16_t>(i), digits, include_prefix);
}
std::string to_hex_string(uint16_t i, int digits, bool include_prefix) {
return DoToHexString(i, digits, include_prefix);
}
std::string to_hex_string(int32_t i, int digits, bool include_prefix) {
return DoToHexString(static_cast<uint32_t>(i), digits, include_prefix);
}
std::string to_hex_string(uint32_t i, int digits, bool include_prefix) {
return DoToHexString(i, digits, include_prefix);
}
std::string to_hex_string(int64_t i, int digits, bool include_prefix) {
return DoToHexString(static_cast<uint64_t>(i), digits, include_prefix);
}
std::string to_hex_string(uint64_t i, int digits, bool include_prefix) {
return DoToHexString(i, digits, include_prefix);
}
// Format the 128-bit numbers as two 64-bit ones.
std::string to_hex_string(int128_t i, int digits, bool include_prefix) {
return to_hex_string(static_cast<uint128_t>(i), digits, include_prefix);
}
std::string to_hex_string(uint128_t i, int digits, bool include_prefix) {
if (i <= std::numeric_limits<uint64_t>::max())
return to_hex_string(static_cast<uint64_t>(i), digits, include_prefix);
// Compute the padding to apply to just the high 64 bits. The low 64 bits will always have 16.
int high_digits = 0;
if (digits > 16)
high_digits = digits - 16;
std::string result = to_hex_string(static_cast<uint64_t>(i >> 64), high_digits, include_prefix);
result += to_hex_string(static_cast<uint64_t>(i), 16, false);
return result;
}
template <typename T>
std::string to_bin_string(T value, int digits, bool include_prefix, char byte_separator) {
std::ostringstream out;
if (include_prefix)
out << "0b";
// When no padding is requested, always output at least one digit.
if (digits == 0)
digits = 1;
int high_bit = sizeof(T) * 8 - 1; // Largest bit of the input type (0-based).
bool written_digit = false; // Set when we've written any digit.
int cur_bit = std::max(digits - 1, high_bit); // 0-based bit index (counting from low bit).
// Computes whether a byte separator is needed at cur_bit.
auto needs_separator = [&]() {
return written_digit && // Don't do a leading separator.
byte_separator && // Separator requested.
(cur_bit + 1) % 8 == 0; // Byte boundary.
};
// Left 0-padding for padding beyond the range of the input type.
while (cur_bit > high_bit) {
if (needs_separator())
out << byte_separator;
out << '0';
written_digit = true;
cur_bit--;
}
while (cur_bit >= 0) {
if (needs_separator())
out << byte_separator;
bool bit_value = value & (static_cast<T>(1) << cur_bit);
if (bit_value || written_digit || (cur_bit + 1) <= digits) {
out << (bit_value ? '1' : '0');
written_digit = true;
}
cur_bit--;
}
return out.str();
}
template std::string to_bin_string<int8_t>(int8_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<uint8_t>(uint8_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<int16_t>(int16_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<uint16_t>(uint16_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<int32_t>(int32_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<uint32_t>(uint32_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<int64_t>(int64_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<uint64_t>(uint64_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<int128_t>(int128_t i, int digits, bool include_prefix,
char byte_separator);
template std::string to_bin_string<uint128_t>(uint128_t i, int digits, bool include_prefix,
char byte_separator);
} // namespace zxdb