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