Skip to content

Commit 7930a3f

Browse files
committed
Documentation for literals
Give them more clear names, and add longer explanations for each one with examples.
1 parent 5b2da1a commit 7930a3f

File tree

9 files changed

+239
-44
lines changed

9 files changed

+239
-44
lines changed

subdoc/gen_tests/subdoc-test-style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ pre > code span.punct {
268268
}
269269
code {
270270
color: rgb(124, 216, 204);
271+
white-space: nowrap;
272+
}
273+
pre code {
274+
white-space: pre;
271275
}
272276
.description h1, .description h2 {
273277
font-size: 100%;

subdoc/lib/database.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ struct FunctionOverload {
187187
bool is_deleted = false;
188188
// Used to look for uniqueness to avoid adding each forward decl and get
189189
// multiple overloads of the same function.
190-
std::string signature;
190+
std::string signature_key;
191191

192192
// TODO: `noexcept` stuff from FunctionDecl::getExceptionSpecType().
193193
};
@@ -253,7 +253,8 @@ struct AliasElement : public TypeElement {
253253
struct FunctionElement : public CommentElement {
254254
explicit FunctionElement(sus::Vec<Namespace> containing_namespaces,
255255
Comment comment, std::string name,
256-
std::string signature, bool is_operator,
256+
std::string signature_name,
257+
std::string signature_key, bool is_operator,
257258
LinkedType return_type,
258259
sus::Option<RequiresConstraints> constraints,
259260
sus::Vec<std::string> template_params,
@@ -263,6 +264,7 @@ struct FunctionElement : public CommentElement {
263264
sus::Vec<std::string> record_path, u32 sort_key)
264265
: CommentElement(sus::move(containing_namespaces), sus::move(comment),
265266
sus::move(name), sort_key),
267+
signature_name(sus::move(signature_name)),
266268
is_operator(is_operator),
267269
overload_set(sus::move(overload_set)),
268270
record_path(sus::move(record_path)) {
@@ -273,10 +275,15 @@ struct FunctionElement : public CommentElement {
273275
.constraints = sus::move(constraints),
274276
.template_params = sus::move(template_params),
275277
.is_deleted = is_deleted,
276-
.signature = sus::move(signature),
278+
.signature_key = sus::move(signature_key),
277279
});
278280
}
279281

282+
/// Typically the same as the function `name`, but whereas the former is used
283+
/// in links and titles for the function, this name is used in the
284+
/// representation of the function signature. It differs for UDLs, for
285+
/// example, which have a more descriptive display name.
286+
std::string signature_name;
280287
bool is_operator;
281288
sus::Vec<FunctionOverload> overloads;
282289
sus::Option<std::string> overload_set;

subdoc/lib/gen/generate_function.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ sus::Result<void, MarkdownToHtmlError> generate_function(
324324
auto name_anchor = signature_div.open_a();
325325
name_anchor.add_href("#");
326326
name_anchor.add_class("function-name");
327-
name_anchor.write_text(element.name);
327+
name_anchor.write_text(element.signature_name);
328328
}
329329
generate_function_params(signature_div, overload);
330330
// This is generating a function that is not a method, so there's always

subdoc/lib/visit.cc

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,8 +1127,7 @@ class Visitor : public clang::RecursiveASTVisitor<Visitor> {
11271127
auto* fdecl = clang::cast<clang::FunctionDecl>(decl->getFriendDecl());
11281128
// Friend forward declarations are not visited, they would create an
11291129
// overload which does not actually exist.
1130-
if (fdecl->getDefinition() != fdecl)
1131-
return true;
1130+
if (fdecl->getDefinition() != fdecl) return true;
11321131

11331132
if (should_skip_decl(cx_, fdecl)) return true;
11341133

@@ -1193,7 +1192,7 @@ class Visitor : public clang::RecursiveASTVisitor<Visitor> {
11931192
constraints = collect_function_constraints(decl, preprocessor_);
11941193
}
11951194

1196-
std::string function_name = [&] {
1195+
std::string signature_name = [&] {
11971196
if (auto* mdecl = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
11981197
return mdecl->getThisType()
11991198
->getPointeeType()
@@ -1209,6 +1208,14 @@ class Visitor : public clang::RecursiveASTVisitor<Visitor> {
12091208
return decl->getNameAsString();
12101209
}
12111210
}();
1211+
std::string function_name = [&] {
1212+
if (auto* lit = decl->getLiteralIdentifier()) {
1213+
// User-defined literals are displayed... less literally.
1214+
return std::string(lit->getName()) + std::string(" literal");
1215+
} else {
1216+
return signature_name;
1217+
}
1218+
}();
12121219

12131220
// Make a copy before moving `comment` to the contructor argument.
12141221
sus::Option<std::string> overload_set =
@@ -1265,7 +1272,8 @@ class Visitor : public clang::RecursiveASTVisitor<Visitor> {
12651272
FunctionId db_key = key_for_function(decl, overload_set);
12661273
auto fe = FunctionElement(
12671274
iter_namespace_path(decl).collect_vec(), sus::move(comment),
1268-
sus::move(function_name), sus::move(signature),
1275+
sus::move(function_name), sus::move(signature_name),
1276+
sus::move(signature),
12691277
decl->isOverloadedOperator() || decl->getLiteralIdentifier() != nullptr,
12701278
sus::move(linked_return_type), sus::move(constraints),
12711279
sus::move(template_params), decl->isDeleted(), sus::move(params),
@@ -1379,7 +1387,8 @@ class Visitor : public clang::RecursiveASTVisitor<Visitor> {
13791387

13801388
bool exists = db_map.at(key).overloads.iter().any(
13811389
[&db_element](const FunctionOverload& overload) {
1382-
return overload.signature == db_element.overloads[0u].signature;
1390+
return overload.signature_key ==
1391+
db_element.overloads[0u].signature_key;
13831392
});
13841393
if (!exists)
13851394
db_map.at(key).overloads.push(sus::move(db_element.overloads[0u]));

sus/num/__private/literals.h

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
#pragma once
1818

1919
#if _MSC_VER
20-
#include "sus/assertions/check.h"
20+
# include "sus/assertions/check.h"
21+
# include "sus/num/cast.h"
2122
#endif
2223

2324
#if _MSC_VER && !defined(__clang__)
2425
/// Literal integer value.
25-
#define _sus__integer_literal(Name, T) \
26-
/* A `constexpr` workaround for MSVC bug that doesn't constant-evaluate \
26+
# define _sus__integer_literal(Name, T) \
27+
/* A `constexpr` workaround for MSVC bug that doesn't constant-evaluate \
2728
* user-defined literals in all cases: \
2829
* https://developercommunity.visualstudio.com/t/User-defined-literals-not-constant-expre/10108165 \
2930
* \
@@ -34,25 +35,25 @@
3435
* However that triggers a different MSVC bug when used with any \
3536
* unary/binary operator in a templated function: \
3637
* https://developercommunity.visualstudio.com/t/MSVC-Compiler-bug-with:-numeric-literal/10108160 \
37-
*/ \
38-
T inline constexpr operator""_##Name(unsigned long long val) noexcept { \
39-
sus_check(val <= static_cast<unsigned long long>(T::MAX_PRIMITIVE)); \
40-
return T(static_cast<decltype(T::primitive_value)>(val)); \
41-
}
38+
*/ \
39+
T inline constexpr operator""_##Name(unsigned long long val) noexcept { \
40+
sus_check(val <= static_cast<unsigned long long>(T::MAX_PRIMITIVE)); \
41+
return T(static_cast<decltype(T::primitive_value)>(val)); \
42+
}
4243
#else
4344
/// Literal integer value.
44-
#define _sus__integer_literal(Name, T) \
45-
T inline consteval operator""_##Name(unsigned long long val) { \
46-
if (val > static_cast<unsigned long long>(T::MAX_PRIMITIVE)) \
47-
throw "Integer literal out of bounds for ##T##"; \
48-
return T(static_cast<decltype(T::primitive_value)>(val)); \
49-
}
45+
# define _sus__integer_literal(Name, T) \
46+
T inline consteval operator""_##Name(unsigned long long val) { \
47+
if (val > static_cast<unsigned long long>(T::MAX_PRIMITIVE)) \
48+
throw "Integer literal out of bounds for ##T##"; \
49+
return T(static_cast<decltype(T::primitive_value)>(val)); \
50+
}
5051
#endif
5152

5253
#if _MSC_VER
5354
/// Literal float value.
54-
#define _sus__float_literal(Name, T) \
55-
/* A `constexpr` workaround for MSVC bug that doesn't constant-evaluate \
55+
# define _sus__float_literal(Name, T) \
56+
/* A `constexpr` workaround for MSVC bug that doesn't constant-evaluate \
5657
* user-defined literals in all cases: \
5758
* https://developercommunity.visualstudio.com/t/User-defined-literals-not-constant-expre/10108165 \
5859
* \
@@ -63,24 +64,24 @@
6364
* However that triggers a different MSVC bug when used with any \
6465
* unary/binary operator in a templated function: \
6566
* https://developercommunity.visualstudio.com/t/MSVC-Compiler-bug-with:-numeric-literal/10108160 \
66-
*/ \
67-
T inline constexpr operator""_##Name(long double val) noexcept { \
68-
sus_check(val <= static_cast<long double>(T::MAX_PRIMITIVE)); \
69-
return T(static_cast<decltype(T::primitive_value)>(val)); \
70-
} \
71-
T inline constexpr operator""_##Name(unsigned long long val) noexcept { \
72-
return T(static_cast<decltype(T::primitive_value)>(val)); \
73-
}
67+
*/ \
68+
T inline constexpr operator""_##Name(long double val) noexcept { \
69+
sus_check(val <= static_cast<long double>(T::MAX_PRIMITIVE)); \
70+
return T(static_cast<decltype(T::primitive_value)>(val)); \
71+
} \
72+
T inline constexpr operator""_##Name(unsigned long long val) noexcept { \
73+
return T(::sus::cast<decltype(T::primitive_value)>(val)); \
74+
}
7475

7576
#else
7677
/// Literal float value.
77-
#define _sus__float_literal(Name, T) \
78-
T inline consteval operator""_##Name(long double val) { \
79-
if (val > static_cast<long double>(T::MAX_PRIMITIVE)) \
80-
throw "Float literal out of bounds for ##T##"; \
81-
return T(static_cast<decltype(T::primitive_value)>(val)); \
82-
} \
83-
T inline consteval operator""_##Name(unsigned long long val) { \
84-
return T(static_cast<decltype(T::primitive_value)>(val)); \
85-
}
78+
# define _sus__float_literal(Name, T) \
79+
T inline consteval operator""_##Name(long double val) { \
80+
if (val > static_cast<long double>(T::MAX_PRIMITIVE)) \
81+
throw "Float literal out of bounds for ##T##"; \
82+
return T(static_cast<decltype(T::primitive_value)>(val)); \
83+
} \
84+
T inline consteval operator""_##Name(unsigned long long val) { \
85+
return T(::sus::cast<decltype(T::primitive_value)>(val)); \
86+
}
8687
#endif

sus/num/float.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,36 @@ struct [[_sus_trivial_abi]] f64 final {
8282
} // namespace sus::num
8383

8484
/// For writing [`f32`]($sus::num::f32) literals.
85+
///
86+
/// Floating point literals qualified with `f` are also 32 bits large, but the
87+
/// `_f32` suffix forces a safe numeric type instead of a primitive value when
88+
/// this is needed (such as for templates or member function access).
89+
///
90+
/// Integer values that are not representable by [`f32`]($sus::num::f32) will
91+
/// converted by the same rules as for [`Cast`]($sus::construct::Cast).
92+
/// Floating point values out of range for [`f32`]($sus::num::f32) will fail to
93+
/// compile.
94+
///
95+
/// # Examples
96+
/// ```
97+
/// auto i = 123_f32 - (5_f32).abs();
98+
/// sus_check(i == 118_f32);
99+
/// ```
85100
_sus__float_literal(f32, ::sus::num::f32);
86101
/// For writing [`f64`]($sus::num::f64) literals.
102+
///
103+
/// Floating point literals without a qualifier are also 64 bits large, but the
104+
/// `_f64` suffix forces a safe numeric type instead of a primitive value when
105+
/// this is needed (such as for templates or member function access).
106+
///
107+
/// Integer values that are not representable by [`f64`]($sus::num::f64) will
108+
/// converted by the same rules as for [`Cast`]($sus::construct::Cast).
109+
///
110+
/// # Examples
111+
/// ```
112+
/// auto i = 123_f64- (5_f64).abs();
113+
/// sus_check(i == 118_f64);
114+
/// ```
87115
_sus__float_literal(f64, ::sus::num::f64);
88116

89117
// Promote floating point types into the `sus` namespace.

sus/num/signed_integer.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,14 +417,80 @@ constexpr inline isize operator>>(isize l, U r) noexcept = delete;
417417
} // namespace sus::num
418418

419419
/// For writing [`i8`]($sus::num::i8) literals.
420+
///
421+
/// Un-qualified integer literals are 32 bits large (the size of `int`)
422+
/// unless a literal suffix modifies them, such as with `_i8` which creates
423+
/// an 8-bit value.
424+
///
425+
/// Values out of range for [`i8`]($sus::num::i8) will fail to compile.
426+
///
427+
/// # Examples
428+
/// ```
429+
/// auto i = 123_i8 - (5_i8).abs();
430+
/// sus_check(i == 118_i8);
431+
/// ```
420432
_sus__integer_literal(i8, ::sus::num::i8);
421433
/// For writing [`i16`]($sus::num::i16) literals.
434+
///
435+
/// Un-qualified integer literals are 32 bits large (the size of `int`)
436+
/// unless a literal suffix modifies them, such as with `_i16` which creates
437+
/// an 16-bit value.
438+
///
439+
/// Values out of range for [`i16`]($sus::num::i16) will fail to compile.
440+
///
441+
/// # Examples
442+
/// ```
443+
/// auto i = 123_i16 - (5_i16).abs();
444+
/// sus_check(i == 118_i16);
445+
/// ```
422446
_sus__integer_literal(i16, ::sus::num::i16);
423447
/// For writing [`i32`]($sus::num::i32) literals.
448+
///
449+
/// Un-qualified integer literals are 32 bits large (the size of `int`), unless
450+
/// a literal suffix modifies them. The `_i32` suffix creates an 32-bit value
451+
/// which is the same as not adding a suffix at all, except that it forces a
452+
/// safe numeric type instead of a primitive value when this is needed (such as
453+
/// for templates or member function access).
454+
///
455+
/// Values out of range for [`i32`]($sus::num::i32) will fail to compile.
456+
///
457+
/// # Examples
458+
/// ```
459+
/// auto i = 123_i32 - (5_i32).abs();
460+
/// sus_check(i == 118_i32);
461+
/// ```
424462
_sus__integer_literal(i32, ::sus::num::i32);
425463
/// For writing [`i64`]($sus::num::i64) literals.
464+
///
465+
/// Un-qualified integer literals are 32 bits large (the size of `int`), unless
466+
/// a literal suffix modifies them, such as with `_i64` which creates a 64-bit
467+
/// value. On Windows, this is the same as the `l` suffix (which makes a
468+
/// `long`) but is platform agnostic, and forces a safe numeric type instead of
469+
/// a primitive value when this is needed (such as for templates or member
470+
/// function access).
471+
///
472+
/// Values out of range for [`i64`]($sus::num::i64) will fail to compile.
473+
///
474+
/// # Examples
475+
/// ```
476+
/// auto i = 123_i64 - (5_i64).abs();
477+
/// sus_check(i == 118_i64);
478+
/// ```
426479
_sus__integer_literal(i64, ::sus::num::i64);
427480
/// For writing [`isize`]($sus::num::isize) literals.
481+
///
482+
/// Un-qualified integer literals are 32 bits large (the size of `int`), unless
483+
/// a literal suffix modifies them, such as with `_isize` which creates an
484+
/// address-sized value. This is 32 bits for 32-bit targets and 64 bits for
485+
/// 64-bit targets.
486+
///
487+
/// Values out of range for [`isize`]($sus::num::isize) will fail to compile.
488+
///
489+
/// # Examples
490+
/// ```
491+
/// auto i = 123_isize - (5_isize).abs();
492+
/// sus_check(i == 118_isize);
493+
/// ```
428494
_sus__integer_literal(isize, ::sus::num::isize);
429495

430496
// Promote signed integer types into the `sus` namespace.

0 commit comments

Comments
 (0)