Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,6 @@ jobs:
source_keys:
- "https://apt.llvm.org/llvm-snapshot.gpg.key"

- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-13
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-14
Expand Down Expand Up @@ -623,7 +620,6 @@ jobs:
include:
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15

Expand Down Expand Up @@ -670,7 +666,6 @@ jobs:
fail-fast: false
matrix:
include:
- os: macos-13
- os: macos-14
- os: macos-15

Expand Down Expand Up @@ -729,7 +724,6 @@ jobs:
include:
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15

Expand Down Expand Up @@ -786,7 +780,6 @@ jobs:
include:
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15

Expand Down Expand Up @@ -959,7 +952,6 @@ jobs:
matrix:
include:
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15

Expand Down
2 changes: 2 additions & 0 deletions doc/int128.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Matt Borland

include::int128/overview.adoc[]

include::int128/printer.adoc[]

include::int128/api_reference.adoc[]

include::int128/file_structure.adoc[]
Expand Down
21 changes: 21 additions & 0 deletions doc/int128/printer.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
////
Copyright 2025 Matt Borland
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////

[#pretty_printer]
= Pretty Printers
:idprefix: pretty_printers_

The library contains a pretty printer for LLDB in the `extra/` folder.
To use this, add the following line to your `~/.lldbinit` file:

[source]
----
command script import /path/to/int128/extra/int128_printer.py
----

If this is successful, you should see the following message in your debugger upon startup:

"int128_t and uint128_t pretty printers loaded successfully"
116 changes: 116 additions & 0 deletions extra/int128_printer_gdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Copyright 2025 Matt Borland
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
#
# Struct definitions:
# struct uint128_t { std::uint64_t low; std::uint64_t high; };
# struct int128_t { std::uint64_t low; std::int64_t high; };
#
# On big endian machines the word order is reversed
#
# Usage: source int128_printer.py

import gdb
import gdb.printing
import re

class Uint128Printer:
"""Pretty printer for uint128_t type"""

def __init__(self, val):
self.val = val

def to_string(self):
try:
high = int(self.val["high"]) & 0xFFFFFFFFFFFFFFFF # Treat as unsigned
low = int(self.val["low"]) & 0xFFFFFFFFFFFFFFFF

value = (high << 64) | low
return f"{value:,}"
except Exception as e:
return f"<invalid uint128_t: {e}>"

def children(self):
yield "low", self.val["low"]
yield "high", self.val["high"]

def display_hint(self):
return None


class Int128Printer:
"""Pretty printer for int128_t type"""

def __init__(self, val):
self.val = val

def to_string(self):
try:
# high is std::int64_t (signed)
high = int(self.val["high"])
# Ensure high is treated as signed 64-bit
if high >= 0x8000000000000000:
high -= 0x10000000000000000

# low is std::uint64_t (unsigned)
low = int(self.val["low"]) & 0xFFFFFFFFFFFFFFFF

value = (high << 64) + low
return f"{value:,}"
except Exception as e:
return f"<invalid int128_t: {e}>"

def children(self):
yield "low", self.val["low"]
yield "high", self.val["high"]

def display_hint(self):
return None


def lookup_int128_type(val):
"""
Lookup function to detect if a type should use our pretty printers.
Returns the appropriate printer or None.
"""
# Get the basic type name, stripping references and const qualifiers
type_obj = val.type

# Handle references and pointers
if type_obj.code == gdb.TYPE_CODE_REF:
type_obj = type_obj.target()
if type_obj.code == gdb.TYPE_CODE_PTR:
return None # Don't handle pointers directly

# Strip const/volatile qualifiers
type_obj = type_obj.unqualified()

type_name = str(type_obj)

# Patterns to match uint128_t and int128_t types
uint128_pattern = re.compile(
r"^(boost::int128::uint128_t|(\w+::)*uint128_t|uint128_t)$"
)
int128_pattern = re.compile(
r"^(boost::int128::int128_t|(\w+::)*int128_t|int128_t)$"
)

if uint128_pattern.match(type_name):
return Uint128Printer(val)
if int128_pattern.match(type_name):
return Int128Printer(val)

return None


def register_int128_printers(objfile=None):
"""Register the int128 pretty printers."""
if objfile is None:
objfile = gdb

objfile.pretty_printers.append(lookup_int128_type)


# Auto-register when the script is sourced
register_int128_printers()
print("int128_t and uint128_t pretty printers loaded successfully")
117 changes: 117 additions & 0 deletions extra/int128_printer_lldb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Copyright 2025 Matt Borland
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
#
# Struct definitions:
# struct uint128_t { std::uint64_t low; std::uint64_t high; };
# struct int128_t { std::uint64_t low; std::int64_t high; };
#
# On big endian machines the word order is reversed

import lldb

def uint128_summary(valobj, internal_dict):
"""
Custom summary for uint128_t type (unsigned).
Displays as decimal (base 10).
"""
try:
val = valobj.GetNonSyntheticValue()
high = val.GetChildMemberWithName("high").GetValueAsUnsigned()
low = val.GetChildMemberWithName("low").GetValueAsUnsigned()

value = (high << 64) | low
return f"{value:,}"
except Exception as e:
return f"<invalid uint128_t: {e}>"

def int128_summary(valobj, internal_dict):
"""
Custom summary for int128_t type (signed).
Displays as decimal (base 10).
"""
try:
val = valobj.GetNonSyntheticValue()
# high is std::int64_t, so use GetValueAsSigned()
high = val.GetChildMemberWithName("high").GetValueAsSigned()
# low is std::uint64_t, so use GetValueAsUnsigned()
low = val.GetChildMemberWithName("low").GetValueAsUnsigned()

value = (high << 64) + low
return f"{value:,}"
except Exception as e:
return f"<invalid int128_t: {e}>"

def __lldb_init_module(debugger, internal_dict):
uint128_pattern = r"^(const )?(boost::int128::uint128_t|(\w+::)*uint128_t)( &| \*)?$"
int128_pattern = r"^(const )?(boost::int128::int128_t|(\w+::)*int128_t)( &| \*)?$"

debugger.HandleCommand(
f'type summary add -x "{uint128_pattern}" -e -F int128_printer_lldb.uint128_summary'
)
debugger.HandleCommand(
f'type synthetic add -x "{uint128_pattern}" -l int128_printer_lldb.Uint128SyntheticProvider'
)

debugger.HandleCommand(
f'type summary add -x "{int128_pattern}" -e -F int128_printer_lldb.int128_summary'
)
debugger.HandleCommand(
f'type synthetic add -x "{int128_pattern}" -l int128_printer_lldb.Int128SyntheticProvider'
)

print("int128_t and uint128_t pretty printers loaded successfully")

class Uint128SyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj

def num_children(self):
return 2

def get_child_index(self, name):
if name == "low":
return 0
elif name == "high":
return 1
return -1

def get_child_at_index(self, index):
if index == 0:
return self.valobj.GetChildMemberWithName("low")
elif index == 1:
return self.valobj.GetChildMemberWithName("high")
return None

def update(self):
pass

def has_children(self):
return True

class Int128SyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj

def num_children(self):
return 2

def get_child_index(self, name):
if name == "low":
return 0
elif name == "high":
return 1
return -1

def get_child_at_index(self, index):
if index == 0:
return self.valobj.GetChildMemberWithName("low")
elif index == 1:
return self.valobj.GetChildMemberWithName("high")
return None

def update(self):
pass

def has_children(self):
return True
24 changes: 16 additions & 8 deletions include/boost/int128/detail/uint128_imp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,8 +677,10 @@ BOOST_INT128_EXPORT constexpr bool operator<(const uint128_t lhs, const uint128_
}
else
{
const uint32_t* l = reinterpret_cast<const uint32_t*>(&lhs);
const uint32_t* r = reinterpret_cast<const uint32_t*>(&rhs);
std::uint32_t l[4] {};
std::uint32_t r[4] {};
std::memcpy(l, &lhs, sizeof(lhs));
std::memcpy(r, &rhs, sizeof(rhs));

if (l[3] != r[3])
{
Expand Down Expand Up @@ -830,8 +832,10 @@ BOOST_INT128_EXPORT constexpr bool operator<=(const uint128_t lhs, const uint128
}
else
{
const uint32_t* l = reinterpret_cast<const uint32_t*>(&lhs);
const uint32_t* r = reinterpret_cast<const uint32_t*>(&rhs);
std::uint32_t l[4] {};
std::uint32_t r[4] {};
std::memcpy(l, &lhs, sizeof(lhs));
std::memcpy(r, &rhs, sizeof(rhs));

if (l[3] != r[3])
{
Expand Down Expand Up @@ -983,8 +987,10 @@ BOOST_INT128_EXPORT constexpr bool operator>(const uint128_t lhs, const uint128_
}
else
{
const uint32_t* l = reinterpret_cast<const uint32_t*>(&lhs);
const uint32_t* r = reinterpret_cast<const uint32_t*>(&rhs);
std::uint32_t l[4] {};
std::uint32_t r[4] {};
std::memcpy(l, &lhs, sizeof(lhs));
std::memcpy(r, &rhs, sizeof(rhs));

if (l[3] != r[3])
{
Expand Down Expand Up @@ -1136,8 +1142,10 @@ BOOST_INT128_EXPORT constexpr bool operator>=(const uint128_t lhs, const uint128
}
else
{
const uint32_t* l = reinterpret_cast<const uint32_t*>(&lhs);
const uint32_t* r = reinterpret_cast<const uint32_t*>(&rhs);
std::uint32_t l[4] {};
std::uint32_t r[4] {};
std::memcpy(l, &lhs, sizeof(lhs));
std::memcpy(r, &rhs, sizeof(rhs));

if (l[3] != r[3])
{
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ run ../examples/charconv.cpp ;
run limits_link_1.cpp limits_link_2.cpp limits_link_3.cpp ;

# Github Issues
run decimal_github_issue_1260.cpp ;
run github_issue_207.cpp ;
run github_issue_210.cpp ;
run github_issue_221.cpp ;
Expand Down
Loading