Skip to content

Commit 1dfede3

Browse files
authored
Add formatting functions and examples (#177)
* Add formatting functions and examples * Fix formatting tests * Apply workaround for constexpr for some standard library implementations in url_format.hpp * Drop support for clang 19 with libc++ so that we can support constexp parse function
1 parent c478728 commit 1dfede3

7 files changed

Lines changed: 486 additions & 52 deletions

File tree

.github/workflows/skyr-url-ci.yml

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,6 @@ jobs:
4747
cxx_standard: 23
4848
}
4949

50-
# Clang-18 (C++23)
51-
- {
52-
name: "Linux Clang 18 Debug (C++23)", artifact: "Linux.tar.xz",
53-
os: ubuntu-24.04,
54-
build_type: Debug,
55-
cc: "clang-18", cxx: "clang++-18",
56-
cxx_standard: 23
57-
}
58-
- {
59-
name: "Linux Clang 18 Release (C++23)", artifact: "Linux.tar.xz",
60-
os: ubuntu-24.04,
61-
build_type: RelWithDebInfo,
62-
cc: "clang-18", cxx: "clang++-18",
63-
cxx_standard: 23
64-
}
65-
6650
# Clang-19 (C++23)
6751
- {
6852
name: "Linux Clang 19 Debug (C++23)", artifact: "Linux.tar.xz",
@@ -111,22 +95,6 @@ jobs:
11195
cxx_standard: 23
11296
}
11397

114-
# macOS Clang-18 (C++23)
115-
- {
116-
name: "macOS Clang 18 Debug (C++23)", artifact: "macOS.tar.xz",
117-
os: macos-latest,
118-
build_type: Debug,
119-
cc: "clang-18", cxx: "clang++-18",
120-
cxx_standard: 23
121-
}
122-
- {
123-
name: "macOS Clang 18 Release (C++23)", artifact: "macOS.tar.xz",
124-
os: macos-latest,
125-
build_type: RelWithDebInfo,
126-
cc: "clang-18", cxx: "clang++-18",
127-
cxx_standard: 23
128-
}
129-
13098
# macOS Clang-19 (C++23)
13199
- {
132100
name: "macOS Clang 19 Debug (C++23)", artifact: "macOS.tar.xz",
@@ -255,7 +223,7 @@ jobs:
255223
COMMAND chmod +x ${cmake_dir}/cmake
256224
)
257225
258-
# GCC 13-14 and Clang 18 are pre-installed on ubuntu-24.04
226+
# GCC 13-14 are pre-installed on ubuntu-24.04
259227
# Clang 19-21 need to be installed from LLVM repository
260228

261229
- name: Install Clang and libc++ (C++23 support)
@@ -266,11 +234,9 @@ jobs:
266234
# Extract version number from compiler name (e.g., clang++-19 -> 19)
267235
CLANG_VERSION=$(echo "${{ matrix.config.cxx }}" | grep -oP '\d+')
268236
269-
# Add LLVM repository for newer versions
270-
if [[ "$CLANG_VERSION" != "18" ]]; then
271-
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
272-
sudo add-apt-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-${CLANG_VERSION} main"
273-
fi
237+
# Add LLVM repository
238+
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
239+
sudo add-apt-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-${CLANG_VERSION} main"
274240
275241
sudo apt-get update
276242

README.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,31 +136,30 @@ URL string and to process the components:
136136
```c++
137137
// url_parts.cpp
138138

139+
#include <print>
140+
139141
#include <skyr/url.hpp>
140-
#include <skyr/percent_encoding/percent_decode.hpp>
141-
#include <iostream>
142+
#include <skyr/url_format.hpp>
142143

143144
int main() {
144145
using namespace skyr::literals;
145146

146147
auto url =
147148
"http://sub.example.إختبار:8090/\xcf\x80?a=1&c=2&b=\xe2\x80\x8d\xf0\x9f\x8c\x88"_url;
148149

149-
std::cout << "Protocol: " << url.protocol() << std::endl;
150-
151-
std::cout << "Domain? " << std::boolalpha << url.is_domain() << std::endl;
152-
std::cout << "Domain: " << url.hostname() << std::endl;
153-
std::cout << "Domain: " << url.u8domain().value() << std::endl;
154-
155-
std::cout << "Port: " << url.port<std::uint16_t>().value() << std::endl;
156150

157-
std::cout << "Pathname: "
158-
<< skyr::percent_decode(url.pathname()).value() << std::endl;
151+
std::println("Origin: {:o}", url);
152+
std::println("Protocol: {:s}", url);
153+
std::println("Domain? {}", url.is_domain());
154+
std::println("Domain: {:h}", url); // Encoded (punycode)
155+
std::println("Domain: {:hd}", url); // Decoded (unicode)
156+
std::println("Port: {:p}", url);
157+
std::println("Pathname: {:Pd}", url); // Decoded pathname
159158

160-
std::cout << "Search parameters:" << std::endl;
159+
std::println("Search parameters:");
161160
const auto &search = url.search_parameters();
162161
for (const auto &[key, value] : search) {
163-
std::cout << " " << "key: " << key << ", value = " << value << std::endl;
162+
std::println(" key: {}, value = {}", key, value);
164163
}
165164
}
166165
```
@@ -189,7 +188,8 @@ target_link_libraries(url_parts PRIVATE skyr::skyr-url)
189188
The output of this program is:
190189

191190
```bash
192-
Protocol: http:
191+
Origin: http://sub.example.xn--kgbechtv:8090
192+
Protocol: http
193193
Domain? true
194194
Domain: sub.example.xn--kgbechtv
195195
Domain: sub.example.إختبار

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ foreach(
1919
example_10.cpp
2020
example_11.cpp
2121
example_12.cpp
22+
example_13.cpp
2223
)
2324
skyr_remove_extension(${file_name} example)
2425
add_executable(${example} ${file_name})

examples/example_13.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2025 Glyn Matthews.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt of copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#include <print>
7+
8+
#include <skyr/url.hpp>
9+
#include <skyr/url_format.hpp>
10+
11+
int main() {
12+
auto url = skyr::url("https://user:pass@api.example.com:8080/v1/users?filter=active&limit=10#results");
13+
14+
std::println("URL Formatting Examples:");
15+
std::println("========================\n");
16+
17+
// Full URL (default)
18+
std::println("Full URL: {}", url);
19+
std::println();
20+
21+
// Individual components (encoded by default)
22+
std::println("Scheme: {:s}", url);
23+
std::println("Hostname: {:h}", url);
24+
std::println("Port: {:p}", url);
25+
std::println("Pathname: {:P}", url);
26+
std::println("Query: {:q}", url);
27+
std::println("Fragment: {:f}", url);
28+
std::println("Origin: {:o}", url);
29+
std::println();
30+
31+
// Practical examples
32+
std::println("API Endpoint: {:o}{:P}", url, url);
33+
std::println("Host:Port: {:h}:{:p}", url, url);
34+
std::println();
35+
36+
// Different URL types
37+
auto https_url = skyr::url("https://example.com/secure");
38+
auto http_url = skyr::url("http://example.org:3000/api");
39+
auto file_url = skyr::url("file:///Users/test/document.txt");
40+
41+
std::println("HTTPS (default port): {:o}", https_url);
42+
std::println("HTTP (custom port): {:o}", http_url);
43+
std::println("File path: {:P}", file_url);
44+
std::println();
45+
46+
// Logging examples
47+
std::println("Logging Examples:");
48+
std::println("-----------------");
49+
std::println("[INFO] Connecting to {:h}:{:p}", url, url);
50+
std::println("[DEBUG] Request path: {:P}{:q}", url, url);
51+
std::println("[TRACE] Full endpoint: {:o}{:P}", url, url);
52+
std::println();
53+
54+
// IP addresses
55+
auto ipv4_url = skyr::url("http://192.168.1.1:8080/admin");
56+
auto ipv6_url = skyr::url("http://[2001:db8::1]:8080/api");
57+
58+
std::println("IPv4: {:h}:{:p}", ipv4_url, ipv4_url);
59+
std::println("IPv6: {:h}:{:p}", ipv6_url, ipv6_url);
60+
std::println();
61+
62+
// Decoded output examples
63+
auto encoded_url = skyr::url("http://example.إختبار/hello%20world?name=John%20Doe&city=Paisley#section%201");
64+
65+
std::println("Encoded vs Decoded:");
66+
std::println("-------------------");
67+
std::println("Hostname (encoded): {:h}", encoded_url);
68+
std::println("Hostname (decoded): {:hd}", encoded_url);
69+
std::println();
70+
std::println("Pathname (encoded): {:P}", encoded_url);
71+
std::println("Pathname (decoded): {:Pd}", encoded_url);
72+
std::println();
73+
std::println("Query (encoded): {:q}", encoded_url);
74+
std::println("Query (decoded): {:qd}", encoded_url);
75+
std::println();
76+
std::println("Fragment (encoded): {:f}", encoded_url);
77+
std::println("Fragment (decoded): {:fd}", encoded_url);
78+
std::println();
79+
80+
// Human-readable logging
81+
std::println("Human-Readable Logging:");
82+
std::println("-----------------------");
83+
std::println("[INFO] User requested: {:Pd}", encoded_url);
84+
std::println("[DEBUG] Query params: {:qd}", encoded_url);
85+
std::println("[TRACE] Host: {:hd}, Path: {:Pd}", encoded_url, encoded_url);
86+
87+
return 0;
88+
}

0 commit comments

Comments
 (0)