| // 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 | |
| // 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 |