Skip to content

Commit 9a4b6bc

Browse files
committed
Add decimal128_t decoding methods and printer
1 parent 95d6e1f commit 9a4b6bc

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

extra/decimal_printer.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from detail.decode_decimal32 import decode_decimal32
66
from detail.decode_decimal64 import decode_decimal64
7+
from detail.decode_decimal128 import decode_decimal128
78
import lldb
89

910
def decimal32_summary(valobj, internal_dict):
@@ -34,9 +35,27 @@ def decimal64_summary(valobj, internal_dict):
3435
except Exception as e:
3536
return f"<invalid decimal64_t: {e}>"
3637

38+
def decimal128_summary(valobj, internal_dict):
39+
"""
40+
Custom summary for decimal128_t type
41+
Displays in scientific notation with cohort preservation
42+
"""
43+
44+
try:
45+
val = valobj.GetNonSyntheticValue()
46+
bits = val.GetChildMemberWithName("bits_").GetValueAsUnsigned()
47+
bits_high = bits.GetChildMemberWithName("high").GetValueAsUnsigned()
48+
bits_low = bits.GetChildMemberWithName("low").GetValueAsUnsigned()
49+
combined_bits = (bits_high << 64) | bits_low
50+
return decode_decimal128(combined_bits, bits_high)
51+
52+
except Exception as e:
53+
return f"<invalid decimal64_t: {e}>"
54+
3755
def __lldb_init_module(debugger, internal_dict):
3856
decimal32_pattern = r"^(const )?(boost::decimal::decimal32_t|(\w+::)*decimal32_t)( &| \*)?$"
3957
decimal64_pattern = r"^(const )?(boost::decimal::decimal64_t|(\w+::)*decimal64_t)( &| \*)?$"
58+
decimal128_pattern = r"^(const )?(boost::decimal::decimal128_t|(\w+::)*decimal128_t)( &| \*)?$"
4059

4160
debugger.HandleCommand(
4261
f'type summary add -x "{decimal32_pattern}" -e -F decimal_printer.decimal32_summary'
@@ -56,6 +75,15 @@ def __lldb_init_module(debugger, internal_dict):
5675

5776
print("decimal64_t printer loaded successfully")
5877

78+
debugger.HandleCommand(
79+
f'type summary add -x "{decimal128_pattern}" -e -F decimal_printer.decimal128_summary'
80+
)
81+
debugger.HandleCommand(
82+
f'type synthetic add -x "{decimal128_pattern}" -l decimal_printer.DecimalSyntheticProvider'
83+
)
84+
85+
print("decimal128_t printer loaded successfully")
86+
5987
class DecimalSyntheticProvider:
6088
def __init__(self, valobj, internal_dict):
6189
self.valobj = valobj

extra/detail/decode_decimal128.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright 2025 Matt Borland
2+
# Distributed under the Boost Software License, Version 1.0.
3+
# https://www.boost.org/LICENSE_1_0.txt
4+
5+
def decode_decimal128(bits, bits_high):
6+
7+
d128_not_11_significand_mask = (562949953421311 << 64) | 18446744073709551615
8+
d128_11_significand_mask = (140737488355327 << 64) | 18446744073709551615
9+
10+
sign = bits_high & 9223372036854775808 != 0
11+
isnan = False
12+
13+
if bits_high & 8646911284551352320 == 8646911284551352320:
14+
15+
if bits_high & 9079256848778919936 == 9079256848778919936:
16+
result = "-SNAN" if sign else "SNAN"
17+
isnan = True
18+
elif bits_high & 8935141660703064064 == 8935141660703064064:
19+
result = "-SNAN" if sign else "QNAN"
20+
isnan = True
21+
elif bits_high & 8935141660703064064 == 8646911284551352320:
22+
result = "-INF" if sign else "INF"
23+
else:
24+
raise ValueError("Unknown Finite Value")
25+
26+
if isnan:
27+
payload = bits & d128_not_11_significand_mask
28+
if payload > 0:
29+
result += '(' + str(payload) + ')'
30+
31+
else:
32+
# See decimal128_t::to_components()
33+
if bits_high & 6917529027641081856 == 6917529027641081856:
34+
implied_bit = 562949953421312 << 64
35+
significand = implied_bit | (bits & d128_11_significand_mask)
36+
exp = (bits_high & 2305702271725338624) >> 47
37+
else:
38+
significand = bits & d128_not_11_significand_mask
39+
exp = (bits_high & 9222809086901354496) >> 49
40+
41+
exp -= 6176 # Bias Value
42+
43+
if significand == 0:
44+
result = "0.0e+0"
45+
else:
46+
n_digits = len(str(abs(significand)))
47+
48+
# If there is no fractional component we want to remove the decimal point and zero
49+
if n_digits > 1:
50+
normalized = significand / (10 ** (n_digits - 1))
51+
total_exp = exp + n_digits - 1
52+
else:
53+
normalized = significand
54+
total_exp = exp
55+
result = f"{'-' if sign else ''}{normalized:.{n_digits - 1}f}e{total_exp:+}"
56+
57+
return result

0 commit comments

Comments
 (0)