Skip to content

Commit 826c6db

Browse files
authored
Merge pull request #123 from jagerman/constexpr-hex
Bump oxen-encoding for constexpr _hex and C++20 changes
2 parents 6dd9d16 + 02e8189 commit 826c6db

23 files changed

+141
-112
lines changed

external/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ set(OXEN_LOGGING_SOURCE_ROOT "${OXEN_LOGGING_SOURCE_ROOT};${PROJECT_SOURCE_DIR}"
8686

8787
# oxenc
8888
if (NOT TARGET oxenc)
89-
system_or_submodule(OXENC oxenc liboxenc>=1.0.10 oxen-encoding)
89+
system_or_submodule(OXENC oxenc liboxenc>=1.1.0 oxen-encoding)
9090
endif()
9191

9292
# libevent

include/oxen/quic/address.hpp

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ namespace oxen::quic
2121
{
2222
inline constexpr std::array<uint8_t, 16> _ipv6_any_addr = {0};
2323

24+
template <typename T>
25+
concept RawSockAddr = std::same_as<T, sockaddr> || std::same_as<T, sockaddr_in> || std::same_as<T, sockaddr_in6>;
26+
2427
// Holds an address, with a ngtcp2_addr held for easier passing into ngtcp2 functions
2528
struct Address
2629
{
@@ -64,11 +67,7 @@ namespace oxen::quic
6467
explicit Address(ipv6 v6, uint16_t port = 0);
6568

6669
// Assignment from a sockaddr pointer; we copy the sockaddr's contents
67-
template <
68-
typename T,
69-
std::enable_if_t<
70-
std::is_same_v<T, sockaddr> || std::is_same_v<T, sockaddr_in> || std::is_same_v<T, sockaddr_in6>,
71-
int> = 0>
70+
template <RawSockAddr T>
7271
Address& operator=(const T* s)
7372
{
7473
_addr.addrlen = std::is_same_v<T, sockaddr>
@@ -212,20 +211,12 @@ namespace oxen::quic
212211
// pointer to other things (like bool) won't occur.
213212
//
214213
// If the given pointer is mutated you *must* call update_socklen() afterwards.
215-
template <
216-
typename T,
217-
std::enable_if_t<
218-
std::is_same_v<T, sockaddr> || std::is_same_v<T, sockaddr_in> || std::is_same_v<T, sockaddr_in6>,
219-
int> = 0>
214+
template <RawSockAddr T>
220215
operator T*()
221216
{
222217
return reinterpret_cast<T*>(&_sock_addr);
223218
}
224-
template <
225-
typename T,
226-
std::enable_if_t<
227-
std::is_same_v<T, sockaddr> || std::is_same_v<T, sockaddr_in> || std::is_same_v<T, sockaddr_in6>,
228-
int> = 0>
219+
template <RawSockAddr T>
229220
operator const T*() const
230221
{
231222
return reinterpret_cast<const T*>(&_sock_addr);
@@ -234,7 +225,8 @@ namespace oxen::quic
234225
// Conversion to a const ngtcp2_addr reference and pointer. We don't provide non-const
235226
// access because this points at our internal data.
236227
operator const ngtcp2_addr&() const { return _addr; }
237-
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_addr*>, int> = 0>
228+
template <typename T>
229+
requires std::same_as<T, ngtcp2_addr>
238230
operator const T*() const
239231
{
240232
return &_addr;
@@ -369,12 +361,14 @@ namespace oxen::quic
369361
}
370362

371363
// template code to pass Path as ngtcp2_path into ngtcp2 functions
372-
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_path>, int> = 0>
364+
template <typename T>
365+
requires std::same_as<T, ngtcp2_path>
373366
operator T*()
374367
{
375368
return &_path;
376369
}
377-
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_path>, int> = 0>
370+
template <typename T>
371+
requires std::same_as<T, ngtcp2_path>
378372
operator const T*() const
379373
{
380374
return &_path;

include/oxen/quic/btstream.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ namespace oxen::quic
8080
// }
8181
explicit operator bool() const { return !timed_out && !is_error(); }
8282

83-
template <typename Char = char, typename = std::enable_if_t<sizeof(Char) == 1>>
83+
template <oxenc::basic_char Char = char>
8484
std::basic_string_view<Char> view() const
8585
{
8686
return {reinterpret_cast<const Char*>(data.data()), data.size()};
@@ -94,13 +94,13 @@ namespace oxen::quic
9494
std::string_view endpoint() const { return {reinterpret_cast<const char*>(data.data()) + ep.first, ep.second}; }
9595
std::string endpoint_str() const { return std::string{endpoint()}; }
9696

97-
template <typename Char = char, typename = std::enable_if_t<sizeof(Char) == 1>>
97+
template <oxenc::basic_char Char = char>
9898
std::basic_string_view<Char> body() const
9999
{
100100
return {reinterpret_cast<const Char*>(data.data()) + req_body.first, req_body.second};
101101
}
102102

103-
template <typename Char = char, typename = std::enable_if_t<sizeof(Char) == 1>>
103+
template <oxenc::basic_char Char = char>
104104
std::basic_string<Char> body_str() const
105105
{
106106
return std::basic_string<Char>{body<Char>()};

include/oxen/quic/connection.hpp

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <concepts>
34
#include <cstddef>
45
#include <cstdint>
56
#include <cstdio>
@@ -24,6 +25,9 @@ namespace oxen::quic
2425
inline constexpr uint64_t MAX_ACTIVE_CIDS{8};
2526
inline constexpr size_t NGTCP2_RETRY_SCIDLEN{18};
2627

28+
template <typename T>
29+
concept StreamDerived = std::derived_from<T, Stream>;
30+
2731
class connection_interface : public std::enable_shared_from_this<connection_interface>
2832
{
2933
protected:
@@ -41,11 +45,7 @@ namespace oxen::quic
4145
/// ID; it will be made ready once the associated stream id is seen from the remote
4246
/// connection. Note that this constructor bypasses the stream constructor callback for the
4347
/// applicable stream id.
44-
template <
45-
typename StreamT,
46-
typename... Args,
47-
typename EndpointDeferred = Endpoint,
48-
std::enable_if_t<std::is_base_of_v<Stream, StreamT>, int> = 0>
48+
template <StreamDerived StreamT, typename... Args, typename EndpointDeferred = Endpoint>
4949
std::shared_ptr<StreamT> queue_incoming_stream(Args&&... args)
5050
{
5151
// We defer resolution of `Endpoint` here via `EndpointDeferred` because the header only
@@ -70,11 +70,8 @@ namespace oxen::quic
7070
/// such as from an increase in available stream ids resulting from the closure of an
7171
/// existing stream. Note that this constructor bypasses the stream constructor callback
7272
/// for the applicable stream id.
73-
template <
74-
typename StreamT,
75-
typename... Args,
76-
typename EndpointDeferred = Endpoint,
77-
std::enable_if_t<std::is_base_of_v<Stream, StreamT>, int> = 0>
73+
template <StreamDerived StreamT, typename... Args, typename EndpointDeferred = Endpoint>
74+
requires std::derived_from<StreamT, Stream>
7875
std::shared_ptr<StreamT> open_stream(Args&&... args)
7976
{
8077
return std::static_pointer_cast<StreamT>(open_stream_impl([&](Connection& c, EndpointDeferred& e) {
@@ -93,13 +90,13 @@ namespace oxen::quic
9390
/// StreamT is specified, is of the given Stream subclass). Returns nullptr if the id is
9491
/// not currently an open stream; throws std::invalid_argument if the stream exists but is
9592
/// not an instance of the given StreamT type.
96-
template <typename StreamT = Stream, std::enable_if_t<std::is_base_of_v<Stream, StreamT>, int> = 0>
93+
template <StreamDerived StreamT = Stream>
9794
std::shared_ptr<StreamT> maybe_stream(int64_t id)
9895
{
9996
auto s = get_stream_impl(id);
10097
if (!s)
10198
return nullptr;
102-
if constexpr (!std::is_same_v<StreamT, Stream>)
99+
if constexpr (!std::same_as<StreamT, Stream>)
103100
{
104101
if (auto st = std::dynamic_pointer_cast<StreamT>(std::move(s)))
105102
return st;
@@ -114,31 +111,30 @@ namespace oxen::quic
114111
/// StreamT is specified, is of the given Stream subclass). Otherwise throws
115112
/// std::out_of_range if the stream was not found, and std::invalid_argument if the stream
116113
/// was found, but is not an instance of StreamT.
117-
template <typename StreamT = Stream, std::enable_if_t<std::is_base_of_v<Stream, StreamT>, int> = 0>
114+
template <StreamDerived StreamT = Stream>
118115
std::shared_ptr<StreamT> get_stream(int64_t id)
119116
{
120117
if (auto s = maybe_stream<StreamT>(id))
121118
return s;
122119
throw std::out_of_range{"Could not find a stream with ID " + std::to_string(id)};
123120
}
124121

125-
template <
126-
typename CharType,
127-
std::enable_if_t<sizeof(CharType) == 1 && !std::is_same_v<CharType, std::byte>, int> = 0>
122+
template <oxenc::basic_char CharType>
123+
requires(!std::same_as<CharType, std::byte>)
128124
void send_datagram(std::basic_string_view<CharType> data, std::shared_ptr<void> keep_alive = nullptr)
129125
{
130126
send_datagram(convert_sv<std::byte>(data), std::move(keep_alive));
131127
}
132128

133-
template <typename Char, std::enable_if_t<sizeof(Char) == 1, int> = 0>
129+
template <oxenc::basic_char Char>
134130
void send_datagram(std::vector<Char>&& buf)
135131
{
136132
send_datagram(
137133
std::basic_string_view<Char>{buf.data(), buf.size()},
138134
std::make_shared<std::vector<Char>>(std::move(buf)));
139135
}
140136

141-
template <typename CharType>
137+
template <oxenc::basic_char CharType>
142138
void send_datagram(std::basic_string<CharType>&& data)
143139
{
144140
auto keep_alive = std::make_shared<std::basic_string<CharType>>(std::move(data));
@@ -503,12 +499,14 @@ namespace oxen::quic
503499

504500
// Implicit conversion of Connection to the underlying ngtcp2_conn* (so that you can pass a
505501
// Connection directly to ngtcp2 functions taking a ngtcp2_conn* argument).
506-
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_conn>, int> = 0>
502+
template <typename T>
503+
requires std::same_as<T, ngtcp2_conn>
507504
operator const T*() const
508505
{
509506
return conn.get();
510507
}
511-
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_conn>, int> = 0>
508+
template <typename T>
509+
requires std::same_as<T, ngtcp2_conn>
512510
operator T*()
513511
{
514512
return conn.get();

include/oxen/quic/datagram.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,20 @@ namespace oxen::quic
2626

2727
std::shared_ptr<connection_interface> get_conn_interface();
2828

29-
template <
30-
typename CharType,
31-
std::enable_if_t<sizeof(CharType) == 1 && !std::is_same_v<CharType, std::byte>, int> = 0>
29+
template <oxenc::basic_char CharType>
30+
requires(!std::same_as<CharType, std::byte>)
3231
void reply(std::basic_string_view<CharType> data, std::shared_ptr<void> keep_alive = nullptr)
3332
{
3433
reply(convert_sv<std::byte>(data), std::move(keep_alive));
3534
}
3635

37-
template <typename Char, std::enable_if_t<sizeof(Char) == 1, int> = 0>
36+
template <oxenc::basic_char Char>
3837
void send_datagram(std::vector<Char>&& buf)
3938
{
4039
reply(std::basic_string_view<Char>{buf.data(), buf.size()}, std::make_shared<std::vector<Char>>(std::move(buf)));
4140
}
4241

43-
template <typename CharType>
42+
template <oxenc::basic_char CharType>
4443
void reply(std::basic_string<CharType>&& data)
4544
{
4645
auto keep_alive = std::make_shared<std::basic_string<CharType>>(std::move(data));

include/oxen/quic/format.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// library).
77

88
#include <fmt/format.h>
9+
#include <oxenc/common.h>
910

1011
#include <iostream>
1112

@@ -19,24 +20,24 @@ namespace oxen::quic
1920

2021
// Constructed from any type of string_view<T> for a single-byte T (char, std::byte,
2122
// uint8_t, etc.)
22-
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
23+
template <oxenc::basic_char T>
2324
explicit buffer_printer(std::basic_string_view<T> buf) :
2425
buf{reinterpret_cast<const std::byte*>(buf.data()), buf.size()}
2526
{}
2627

2728
// Constructed from any type of lvalue string<T> for a single-byte T (char, std::byte,
2829
// uint8_t, etc.)
29-
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
30+
template <oxenc::basic_char T>
3031
explicit buffer_printer(const std::basic_string<T>& buf) : buffer_printer(std::basic_string_view<T>{buf})
3132
{}
3233

3334
// *Not* constructable from a string<T> rvalue (because we only hold a view and do not take
3435
// ownership).
35-
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
36+
template <oxenc::basic_char T>
3637
explicit buffer_printer(std::basic_string<T>&& buf) = delete;
3738

3839
// Constructable from a (T*, size) argument pair, for byte-sized T's.
39-
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
40+
template <oxenc::basic_char T>
4041
explicit buffer_printer(const T* data, size_t size) : buffer_printer(std::basic_string_view<T>{data, size})
4142
{}
4243

include/oxen/quic/gnutls_crypto.hpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace oxen::quic
1313
{
14+
using namespace oxenc::literals;
15+
1416
class Connection;
1517

1618
const std::string translate_key_format(gnutls_x509_crt_fmt_t crt);
@@ -49,9 +51,9 @@ namespace oxen::quic
4951
inline constexpr size_t GNUTLS_SECRET_KEY_SIZE = 64;
5052

5153
// These bytes mean "this is a raw Ed25519 private key" in ASN.1 (or something like that)
52-
inline const std::string ASN_ED25519_SEED_PREFIX = oxenc::from_hex("302e020100300506032b657004220420"sv);
54+
inline constexpr auto ASN_ED25519_SEED_PREFIX = "302e020100300506032b657004220420"_hex;
5355
// These bytes mean "this is a raw Ed25519 public key" in ASN.1 (or something like that)
54-
inline const std::string ASN_ED25519_PUBKEY_PREFIX = oxenc::from_hex("302a300506032b6570032100"sv);
56+
inline constexpr auto ASN_ED25519_PUBKEY_PREFIX = "302a300506032b6570032100"_hex;
5557

5658
struct gnutls_key
5759
{
@@ -217,7 +219,8 @@ namespace oxen::quic
217219
//
218220
// Hidden behind a template so that implicit conversion to pointer doesn't cause trouble via
219221
// other unwanted implicit conversions.
220-
template <typename T, std::enable_if_t<std::is_same_v<T, gnutls_datum_t>, int> = 0>
222+
template <typename T>
223+
requires std::same_as<T, gnutls_datum_t>
221224
operator const T*() const
222225
{
223226
return &mem;
@@ -238,7 +241,8 @@ namespace oxen::quic
238241
//
239242
// Hidden behind a template so that implicit conversion to pointer doesn't cause trouble via
240243
// other unwanted implicit conversions.
241-
template <typename T, std::enable_if_t<std::is_same_v<T, char>, int> = 0>
244+
template <typename T>
245+
requires std::same_as<T, char>
242246
operator const T*() const
243247
{
244248
if (auto* p = std::get_if<fs::path>(&source))
@@ -261,7 +265,7 @@ namespace oxen::quic
261265

262266
private:
263267
// Construct from raw Ed25519 keys
264-
GNUTLSCreds(std::string ed_seed, std::string ed_pubkey);
268+
GNUTLSCreds(std::string_view ed_seed, std::string_view ed_pubkey);
265269

266270
public:
267271
gnutls_pcert_st pcrt;
@@ -281,9 +285,9 @@ namespace oxen::quic
281285

282286
void set_key_verify_callback(key_verify_callback cb) { key_verify = std::move(cb); }
283287

284-
static std::shared_ptr<GNUTLSCreds> make_from_ed_keys(std::string seed, std::string pubkey);
288+
static std::shared_ptr<GNUTLSCreds> make_from_ed_keys(std::string_view seed, std::string_view pubkey);
285289

286-
static std::shared_ptr<GNUTLSCreds> make_from_ed_seckey(std::string sk);
290+
static std::shared_ptr<GNUTLSCreds> make_from_ed_seckey(std::string_view sk);
287291

288292
std::unique_ptr<TLSSession> make_session(Connection& c, const std::vector<ustring>& alpns) override;
289293
};

include/oxen/quic/iochannel.hpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#pragma once
2+
#include <concepts>
3+
24
#include "connection_ids.hpp"
35
#include "messages.hpp"
46
#include "utils.hpp"
@@ -45,21 +47,21 @@ namespace oxen::quic
4547
Address local() const;
4648
Address remote() const;
4749

48-
template <typename CharType, std::enable_if_t<sizeof(CharType) == 1, int> = 0>
50+
template <oxenc::basic_char CharType>
4951
void send(std::basic_string_view<CharType> data, std::shared_ptr<void> keep_alive = nullptr)
5052
{
5153
send_impl(convert_sv<std::byte>(data), std::move(keep_alive));
5254
}
5355

54-
template <typename CharType>
56+
template <oxenc::basic_char CharType>
5557
void send(std::basic_string<CharType>&& data)
5658
{
5759
auto keep_alive = std::make_shared<std::basic_string<CharType>>(std::move(data));
5860
std::basic_string_view<CharType> view{*keep_alive};
5961
send(view, std::move(keep_alive));
6062
}
6163

62-
template <typename Char, std::enable_if_t<sizeof(Char) == 1, int> = 0>
64+
template <oxenc::basic_char Char>
6365
void send(std::vector<Char>&& buf)
6466
{
6567
send(std::basic_string_view<Char>{buf.data(), buf.size()}, std::make_shared<std::vector<Char>>(std::move(buf)));
@@ -92,11 +94,8 @@ namespace oxen::quic
9294
// Wraps an IOChannel (or derived type) accessor member function pointer in a call_get for
9395
// synchronous access that always returns by value (even if the member function returns by
9496
// reference).
95-
template <
96-
typename Class,
97-
typename T,
98-
typename Ret = std::remove_cvref_t<T>,
99-
typename EP = std::enable_if_t<std::is_base_of_v<IOChannel, Class>, Endpoint>>
97+
template <typename Class, typename T, typename Ret = std::remove_cvref_t<T>, typename EP = Endpoint>
98+
requires std::derived_from<Class, IOChannel>
10099
Ret call_get_accessor(T (Class::*getter)() const) const
101100
{
102101
return static_cast<EP&>(endpoint).call_get(

0 commit comments

Comments
 (0)