error: use a wrapper object for hexadecimal output

PiperOrigin-RevId: 540584755
Change-Id: I9d08b47f61c87768f3b0dabbb3c643d791ca8a81
diff --git a/dwarf_processor.cc b/dwarf_processor.cc
index 10642ff..0924b4f 100644
--- a/dwarf_processor.cc
+++ b/dwarf_processor.cc
@@ -42,7 +42,7 @@
 
 std::string EntryToString(Entry& entry) {
   std::ostringstream os;
-  os << "DWARF entry <0x" << std::hex << entry.GetOffset() << ">";
+  os << "DWARF entry <" << Hex(entry.GetOffset()) << ">";
   return os.str();
 }
 
@@ -108,7 +108,7 @@
     case DW_ATE_UTF:
       return Primitive::Encoding::UTF;
     default:
-      Die() << "Unknown encoding 0x" << std::hex << *dwarf_encoding << " for "
+      Die() << "Unknown encoding " << Hex(*dwarf_encoding) << " for "
             << EntryToString(entry);
   }
 }
@@ -344,8 +344,7 @@
   void CheckUnresolvedIds() const {
     for (const auto& [offset, id] : id_map_) {
       if (!graph_.Is(id)) {
-        Die() << "unresolved id " << id << ", DWARF offset 0x" << std::hex
-              << offset;
+        Die() << "unresolved id " << id << ", DWARF offset " << Hex(offset);
       }
     }
   }
diff --git a/dwarf_wrappers.cc b/dwarf_wrappers.cc
index 3d66145..b9f89d2 100644
--- a/dwarf_wrappers.cc
+++ b/dwarf_wrappers.cc
@@ -82,7 +82,7 @@
     const char* errmsg = dwfl_errmsg(dwfl_error);
     if (errmsg == nullptr) {
       // There are some cases when DWFL fails to produce an error message.
-      Die() << caller << " returned error code 0x" << std::hex << dwfl_error;
+      Die() << caller << " returned error code " << Hex(dwfl_error);
     }
     Die() << caller << " returned error: " << errmsg;
   }
diff --git a/elf_reader.cc b/elf_reader.cc
index 148599d..0498acd 100644
--- a/elf_reader.cc
+++ b/elf_reader.cc
@@ -253,8 +253,8 @@
         // TODO: allow "compatible" duplicates, for example
         // "void foo(int bar)" vs "void foo(const int bar)"
         if (!IsEqual(symbol, other)) {
-          Die() << "Duplicate DWARF symbol: address=0x" << std::hex
-                << symbol.address << std::dec << ", name=" << symbol.name;
+          Die() << "Duplicate DWARF symbol: address=" << Hex(symbol.address)
+                << ", name=" << symbol.name;
         }
       }
     }
diff --git a/error.h b/error.h
index 5a4f26f..6eed80e 100644
--- a/error.h
+++ b/error.h
@@ -21,6 +21,7 @@
 #define STG_ERROR_H_
 
 #include <exception>
+#include <ios>
 #include <iostream>
 #include <optional>
 #include <ostream>
@@ -105,6 +106,23 @@
   return os << std::system_error(error.number, std::generic_category()).what();
 }
 
+template <typename T>
+struct Hex {
+  explicit Hex(const T& value) : value(value) {}
+  const T& value;
+};
+
+template <typename T> Hex(const T&) -> Hex<T>;
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const Hex<T>& hex_value) {
+  // not quite right if an exception is thrown
+  const auto flags = os.flags();
+  os << std::hex << std::showbase << hex_value.value;
+  os.flags(flags);
+  return os;
+}
+
 }  // namespace stg
 
 #endif  // STG_ERROR_H_
diff --git a/graph.cc b/graph.cc
index b1d8bdd..0153710 100644
--- a/graph.cc
+++ b/graph.cc
@@ -140,7 +140,7 @@
 }
 
 std::ostream& operator<<(std::ostream& os, ElfSymbol::CRC crc) {
-  return os << "0x" << std::hex << crc.number;
+  return os << Hex(crc.number);
 }
 
 std::ostream& operator<<(std::ostream& os, Primitive::Encoding encoding) {