ASCII Table — C++ source
A searchable, filterable reference for all 128 ASCII code points. See the decimal, hex, octal, and binary form of every character, narrow to printable characters only, clamp the code-point range, and click any row to copy. Runs 100% client-side.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// ASCII Table — pure logic (C++ port): the 128-entry ASCII reference table with
// search and range filters.
//
// Language: C++17 — standard library only.
// Source: CosmoDev polyglot showcase port; canonical = src/lib/ascii-table.ts
// + this tool's python.py / rust.rs.
// License: display source — part of CosmoDev's polyglot tool pages.
//
// Each of the 128 ASCII code points is described by its decimal / hex / octal /
// binary forms, a display glyph, a human name, whether it is printable, whether
// it is a control character, and (for control chars that have one) a C-style
// escape sequence.
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <iomanip>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
namespace ascii_table {
/// A single ASCII code point and its derived representations.
struct Entry {
/// Decimal code point, 0–127.
std::uint8_t dec;
/// Uppercase hex, e.g. "0x41".
std::string hex;
/// Zero-padded 3-digit octal, e.g. "101".
std::string oct;
/// Zero-padded 8-bit binary, e.g. "01000001".
std::string binary;
/// Display glyph: the literal char for printables, a control-picture glyph
/// otherwise. (Named `char` in the canonical sources; that is a keyword here.)
std::string char_glyph;
/// Human-readable name, e.g. "Line Feed (LF)", "Uppercase A", "Space".
std::string name;
/// True for 32–126 (visible or space).
bool printable;
/// True for 0–31 and 127.
bool control;
/// C-style escape for control chars that have one (e.g. "\n"); nullopt otherwise.
std::optional<std::string> escape;
};
namespace {
/// Uppercase hex with the 0x prefix, zero-padded to two digits.
std::string format_hex(std::uint8_t code) {
std::ostringstream os;
os << "0x" << std::uppercase << std::hex
<< std::setw(2) << std::setfill('0') << static_cast<int>(code);
return os.str();
}
/// Zero-padded 3-digit octal (the standard streams have no std::bin-style
/// formatter for octal padding beyond setw/setfill, which is what this uses).
std::string format_oct(std::uint8_t code) {
std::ostringstream os;
os << std::oct << std::setw(3) << std::setfill('0') << static_cast<int>(code);
return os.str();
}
/// Zero-padded 8-digit binary (std::format is C++20, so shift bits by hand).
std::string format_binary(std::uint8_t code) {
std::string s(8, '0');
for (int i = 0; i < 8; ++i)
s[7 - i] = static_cast<char>('0' + ((code >> i) & 1));
return s;
}
/// Encode a Unicode scalar (U+0800..U+FFFF) as a 3-byte UTF-8 sequence.
/// Every control-picture glyph used here (U+2400..U+2421) is in that range.
std::string utf8_encode3(unsigned cp) {
std::string s(3, '\0');
s[0] = static_cast<char>(0xE0u | (cp >> 12));
s[1] = static_cast<char>(0x80u | ((cp >> 6) & 0x3Fu));
s[2] = static_cast<char>(0x80u | (cp & 0x3Fu));
return s;
}
/// Official ASCII control-character names for 0–31 and 127.
///
/// Expressed as a switch over every control code point; the default arm is a
/// defensive guard that documents the precondition (the Rust port uses
/// unreachable!() for the same case).
std::string_view control_name(std::uint8_t code) {
switch (code) {
case 0: return "Null (NUL)";
case 1: return "Start of Heading (SOH)";
case 2: return "Start of Text (STX)";
case 3: return "End of Text (ETX)";
case 4: return "End of Transmission (EOT)";
case 5: return "Enquiry (ENQ)";
case 6: return "Acknowledge (ACK)";
case 7: return "Bell (BEL)";
case 8: return "Backspace (BS)";
case 9: return "Horizontal Tab (HT)";
case 10: return "Line Feed (LF)";
case 11: return "Vertical Tab (VT)";
case 12: return "Form Feed (FF)";
case 13: return "Carriage Return (CR)";
case 14: return "Shift Out (SO)";
case 15: return "Shift In (SI)";
case 16: return "Data Link Escape (DLE)";
case 17: return "Device Control 1 (DC1)";
case 18: return "Device Control 2 (DC2)";
case 19: return "Device Control 3 (DC3)";
case 20: return "Device Control 4 (DC4)";
case 21: return "Negative Acknowledge (NAK)";
case 22: return "Synchronous Idle (SYN)";
case 23: return "End of Transmission Block (ETB)";
case 24: return "Cancel (CAN)";
case 25: return "End of Medium (EM)";
case 26: return "Substitute (SUB)";
case 27: return "Escape (ESC)";
case 28: return "File Separator (FS)";
case 29: return "Group Separator (GS)";
case 30: return "Record Separator (RS)";
case 31: return "Unit Separator (US)";
case 127: return "Delete (DEL)";
default: return ""; // unreachable with control codes; defensive guard
}
}
/// C-style escape for the control chars that own a standard/common one.
/// Returns the literal 2-character source token (backslash + letter), or nullopt.
std::optional<std::string_view> control_escape(std::uint8_t code) {
switch (code) {
case 0: return "\\0";
case 7: return "\\a";
case 8: return "\\b";
case 9: return "\\t";
case 10: return "\\n";
case 11: return "\\v";
case 12: return "\\f";
case 13: return "\\r";
case 27: return "\\e";
default: return std::nullopt;
}
}
/// Name for a printable punctuation / symbol glyph, or nullopt.
/// Letters and digits are derived in letter_name().
std::optional<std::string_view> symbol_name(std::uint8_t code) {
switch (code) {
case 32: return "Space";
case 33: return "Exclamation mark";
case 34: return "Quotation mark";
case 35: return "Number sign";
case 36: return "Dollar sign";
case 37: return "Percent sign";
case 38: return "Ampersand";
case 39: return "Apostrophe";
case 40: return "Left parenthesis";
case 41: return "Right parenthesis";
case 42: return "Asterisk";
case 43: return "Plus sign";
case 44: return "Comma";
case 45: return "Hyphen / Minus";
case 46: return "Full stop";
case 47: return "Slash";
case 58: return "Colon";
case 59: return "Semicolon";
case 60: return "Less-than sign";
case 61: return "Equals sign";
case 62: return "Greater-than sign";
case 63: return "Question mark";
case 64: return "At sign";
case 91: return "Left bracket";
case 92: return "Backslash";
case 93: return "Right bracket";
case 94: return "Circumflex / Caret";
case 95: return "Underscore";
case 96: return "Grave accent";
case 123: return "Left brace";
case 124: return "Vertical bar";
case 125: return "Right brace";
case 126: return "Tilde";
default: return std::nullopt;
}
}
/// Derive a name for a printable letter or digit.
std::string letter_name(std::uint8_t code) {
if (code >= 48 && code <= 57) // '0'..'9'
return "Digit " + std::to_string(code - 48);
if (code >= 65 && code <= 90) // 'A'..'Z'
return std::string("Uppercase ") + static_cast<char>(code);
if (code >= 97 && code <= 122) // 'a'..'z'
return std::string("Lowercase ") + static_cast<char>(code);
return std::string(1, static_cast<char>(code));
}
/// Build a single entry from its code point (0–127).
Entry make_entry(std::uint8_t code) {
const bool control = code <= 31 || code == 127;
// Control-picture glyph: U+2400 for 0–31, U+2421 ("symbol for delete") for DEL.
const std::string char_glyph =
control ? utf8_encode3(code == 127 ? 0x2421u : 0x2400u + code)
: std::string(1, static_cast<char>(code));
std::string name;
if (control) {
name = std::string(control_name(code));
} else if (auto sym = symbol_name(code)) {
name = std::string(*sym);
} else {
name = letter_name(code);
}
return Entry{
code,
format_hex(code),
format_oct(code),
format_binary(code),
char_glyph,
name,
!control,
control,
control ? std::optional<std::string>(std::string(*control_escape(code)))
: std::nullopt,
};
}
/// Case-insensitive substring test over ASCII text: both sides are lowered
/// byte-for-byte, matching the reference implementations.
bool ci_contains(std::string_view haystack, std::string_view needle) {
const auto lower = [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
};
return std::search(haystack.begin(), haystack.end(),
needle.begin(), needle.end(),
[&](char a, char b) { return lower(a) == lower(b); }) != haystack.end();
}
} // namespace
// The 128-entry table is built once and cached for the lifetime of the
// program. A function-local static is initialized exactly once, thread-safely
// ([stmt.dcl]/4) — the standard-library equivalent of Rust's OnceLock.
const std::vector<Entry>& entries() {
static const std::vector<Entry> table = [] {
std::vector<Entry> v;
v.reserve(128);
for (unsigned i = 0; i <= 127; ++i)
v.push_back(make_entry(static_cast<std::uint8_t>(i)));
return v;
}();
return table;
}
/// Look up a single entry by code point.
///
/// Returns a pointer into the shared static table, or nullptr for out-of-range
/// input — the idiomatic C++ equivalent of Rust's Option<&Entry> and the
/// TypeScript variant's null.
const Entry* get_entry(int code) {
if (code < 0 || code > 127)
return nullptr;
return &entries()[static_cast<std::size_t>(code)];
}
/// Filter the table.
///
/// `query` is a case-insensitive substring matched against dec / hex / oct /
/// binary / name / char / escape. `printable_only` hides controls. `min` /
/// `max` clamp the decimal range (defaults 0–127). Returns pointers into the
/// shared static table, so filtering allocates nothing beyond the result vector.
std::vector<const Entry*> filter_table(const std::string& query = "",
bool printable_only = false,
int min = 0, int max = 127) {
// Trim surrounding whitespace (string_view over the original string).
std::string_view q = query;
while (!q.empty() && std::isspace(static_cast<unsigned char>(q.front())))
q.remove_prefix(1);
while (!q.empty() && std::isspace(static_cast<unsigned char>(q.back())))
q.remove_suffix(1);
std::vector<const Entry*> out;
for (const Entry& e : entries()) {
if (printable_only && !e.printable)
continue;
if (e.dec < min || e.dec > max)
continue;
if (!q.empty()) {
const std::string dec = std::to_string(e.dec);
const std::string esc = e.escape ? *e.escape : "";
const bool hit = ci_contains(dec, q) || ci_contains(e.hex, q) ||
ci_contains(e.oct, q) || ci_contains(e.binary, q) ||
ci_contains(e.name, q) || ci_contains(e.char_glyph, q) ||
ci_contains(esc, q);
if (!hit)
continue;
}
out.push_back(&e);
}
return out;
}
} // namespace ascii_table
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →