Library: shorten display of unsigned types
I changed the rendering of unsigned types in diagnostic output to use the short notation, e.g. `uint` instead of `unsigned int`. This dramatically improves the legibility of verification strings. Moreover, I took the opportunigy to look through the existing page with codeing style guides to explicitly write down some conventions formed over years of usage. I did not just »make up« those light heartedly, rather these conventions are the result of a craftsman's ''attentive observation and self-reflection.''
This commit is contained in:
parent
26bf32525b
commit
dcbde6d163
13 changed files with 109 additions and 60 deletions
|
|
@ -1,16 +1,20 @@
|
|||
Coding Guidelines
|
||||
=================
|
||||
:Date: Spring 2023
|
||||
:Date: Autumn 2024
|
||||
:toc:
|
||||
|
||||
|
||||
_this page summarises some style and coding guidelines for the Lumiera code base_
|
||||
.Basic Tenet
|
||||
Code is written for humans. Use your judgement and common sense above all.
|
||||
|
||||
|
||||
|
||||
Style Guide
|
||||
-----------
|
||||
The Lumiera project uses GNU indentation style with slight adaptations.
|
||||
|
||||
- *no tabs* please. The typical ``semi indent'' of GNU style thus becomes 2 spaces.
|
||||
- *no tabs* please. +
|
||||
The typical ``semi indent'' of GNU style thus becomes 2 spaces.
|
||||
- maximum line length is rather around *110 characters*.footnote:[This is not a hard
|
||||
limit, rather a guideline -- however, you should never try to stuff several distinct
|
||||
topics into a single line...]
|
||||
|
|
@ -20,26 +24,60 @@ The Lumiera project uses GNU indentation style with slight adaptations.
|
|||
* the braces for a class scope are indented by 2 spaces
|
||||
* the access modifiers start at this brace level, while all declarations and definitions
|
||||
within the class are again indented by 2 spaces
|
||||
* the braces for free-standing functions however are not indented and thus placed directly
|
||||
below the name of the function in the definition. This holds also for member functions
|
||||
defined out-line and not within the class body.
|
||||
* the line breaking rules are relaxed. Definitions and statements may be written as single line,
|
||||
provided that the length remains below 110 chars and the result _remains legible_. Otherwise,
|
||||
we'll fall back to the default and wrap the lines. More specifically
|
||||
provided that the length remains below 110 chars and the result _remains legible_.
|
||||
More specifically...
|
||||
|
||||
** function declarations may be written in one line
|
||||
** same for definitions with just a single statement in the body
|
||||
** same for simple if-statements without else-branch.
|
||||
** If in doubt however, we prefer to wrap the lines.
|
||||
|
||||
* it is OK to write if-then-else without braces, but only as long as the structure
|
||||
is uttermost clear and poses no danger for maintenance. Use your common sense on this one.
|
||||
Often, a ternary operator is a viable alternative. When a `?` ... `:` becomes long and
|
||||
hard to read, the alternative clause starting with `:` is placed directly below the `?`
|
||||
* the space between function name and opening parenthesis of the argument list is not
|
||||
enforced when this doesn't make sense, esp. for argument-less functions, chained calls
|
||||
enforced when this doesn't make sense, notably for argument-less functions, chained calls
|
||||
or constructor syntax. But in all other cases, we really value this additional space,
|
||||
it improves legibility.
|
||||
* template argument declarations are _always_ written on a separate line, above the
|
||||
return type declaration. This rule holds even if the rest of a definition can be
|
||||
written within a single line.
|
||||
* the body of λ-functions is indented beyond the capture clause, i.e. it is rather
|
||||
starkly offset with respect to the regular code. When capture clauses become complicated
|
||||
beyond just a short list of names -- especially when including initialisers -- they are
|
||||
preferably written on a separate line, directly above the argument list in parenthesis
|
||||
* the opening brace of namespaces is placed on the same line. Optionally, the namespace
|
||||
body may be indented, as long as this helps underpinning the nesting structure. But
|
||||
there is no need to use 3 indents on a 3 level nested namespace. One level is enough
|
||||
to highlight the presence of a nesting.
|
||||
|
||||
- the shorthand type names `uint`, `ulong`, `uchar`, `short`, `ushort`, `llong`, `ullong`
|
||||
are preferred, as it is clearer to write the fundamental type in a single word. Index
|
||||
variables _should always be unsigned._ Use `size_t` whenever applicable.footnote:[yet it is OK
|
||||
to use `uint` in a for-loop where the limits are clear; likewise it is acceptable to use
|
||||
a direct conversion signed ⟷ unsigned when the situation is simple and obvious. No need
|
||||
to be pedantic on everything]
|
||||
When the bit-size matters, please use explicit designations like `int32_t`, `uint64_t`.
|
||||
- we prefer to highlight the _typing as distinct_ from the names and entities; notably
|
||||
the `*` pointer and `&` reference modifier are attached post-fix to the type, as opposed
|
||||
to sticking it to the name: write ```int* thing`'', not ```int *thing`''. Whenever types
|
||||
become difficult to parse, we introduce a type alias (`using Alias =`... with an uppercase
|
||||
type alias name). This is especially relevant with function pointers, where we prefer
|
||||
to define a type alias for the _function signature_ first.
|
||||
- in a similar vein, we distinguish between an ```const object`'' which _is really in-itself_
|
||||
unmodifiable, as opposed to _taking a const-reference,_ which is always spelled out
|
||||
post-fix as `object const&`, or a constant-pointer spelled as `const*`.
|
||||
- we use the textual form of the boolean operators `and`, `or` and `not`, because this
|
||||
allows to make the code resemble complete meaningful sentences in human language.
|
||||
We _do use_ the »line noise« variant however for all low-level bit manipulation,
|
||||
`&`,`|`, `^`, sometimes also for `!` -- using those is taken as an indication of
|
||||
entering the ``danger zone''...
|
||||
|
||||
Naming conventions
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Naming conventions are used to characterise the kind of element at hand and give a visual
|
||||
|
|
@ -159,7 +197,7 @@ Recommendations at code level
|
|||
* always consider the _ownership_ and _lifecycle_ -- value objects can not have any, should
|
||||
ideally be immutable, and stored inline or avoid heap allocation. If in doubt, decompose
|
||||
and turn unclear and changing parts into a service / dependency, attached by (value) handle
|
||||
* objects with reference semantics should be made _noncopyable_, while value objects should use
|
||||
* objects with reference semantics should be made _non-copyable_, while value objects should use
|
||||
default copy semantics. Use 'lib/nocopy.hpp' to express the flavours of move only / no copy.
|
||||
* equality comparisons of ref objects are to be based on their identity solely, while for
|
||||
value objects, all properties must be included which are tangible and independently variable.
|
||||
|
|
@ -175,7 +213,7 @@ Recommendations at code level
|
|||
+
|
||||
* if is something is ``just a number'' yet has some specific meaning,
|
||||
better use a lightweight wrapper object to tag it with semantics
|
||||
* if a common pattern works involving distinct, unrelated entities,
|
||||
* if a common pattern works by involving distinct, unrelated entities,
|
||||
then better use generic programming or even higher-kinded types,
|
||||
instead of forcing unrelated types to inherit from some supertype.
|
||||
* avoid downcasts, `void*` and switch-on-type programming; this
|
||||
|
|
|
|||
|
|
@ -207,6 +207,11 @@ apologies for that."
|
|||
"|lumiera::"
|
||||
, regex::ECMAScript | regex::optimize};
|
||||
|
||||
static regex lolong {"long long"
|
||||
, regex::ECMAScript | regex::optimize};
|
||||
static regex unSigned {"unsigned (\\w+)"
|
||||
, regex::ECMAScript | regex::optimize};
|
||||
|
||||
static regex stdString {"(__cxx11::)?basic_string<char, char_traits<char>, allocator<char>\\s*>(\\s+\\B)?"
|
||||
, regex::ECMAScript | regex::optimize};
|
||||
|
||||
|
|
@ -219,7 +224,7 @@ apologies for that."
|
|||
static regex uniquePtr {"unique_ptr<(\\w+), default_delete<\\1>\\s*"
|
||||
, regex::ECMAScript | regex::optimize};
|
||||
|
||||
static regex lumieraP {"P<(\\w+), shared_ptr<\\1>\\s*"
|
||||
static regex lumieraP {"P<(\\w+), shared_ptr<\\1>\\s*"
|
||||
, regex::ECMAScript | regex::optimize};
|
||||
|
||||
|
||||
|
|
@ -227,6 +232,8 @@ apologies for that."
|
|||
auto end = typeName.end();
|
||||
|
||||
end = regex_replace(pos, pos, end, commonPrefixes, "");
|
||||
end = regex_replace(pos, pos, end, lolong, "llong");
|
||||
end = regex_replace(pos, pos, end, unSigned, "u$1");
|
||||
end = regex_replace(pos, pos, end, stdString, "string");
|
||||
end = regex_replace(pos, pos, end, stdAllocator, "$1");
|
||||
end = regex_replace(pos, pos, end, mapAllocator, "$1");
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@
|
|||
#include <cstdint>
|
||||
|
||||
/* === minimal common place === */
|
||||
using uchar = unsigned char;
|
||||
using uint = unsigned int;
|
||||
using uchar = unsigned char;
|
||||
using ulong = unsigned long int;
|
||||
using llong = long long int;
|
||||
using ullong = unsigned long long int;
|
||||
using ushort = unsigned short int;
|
||||
|
||||
using f128 = long double;
|
||||
static_assert(10 <= sizeof(f128));
|
||||
|
|
|
|||
|
|
@ -495,19 +495,19 @@ namespace util {
|
|||
/* === Literals for common size designations === */
|
||||
|
||||
inline uint
|
||||
operator""_KiB (unsigned long long const siz)
|
||||
operator""_KiB (ullong const siz)
|
||||
{
|
||||
return uint(siz) * 1024u;
|
||||
}
|
||||
|
||||
inline uint
|
||||
operator""_MiB (unsigned long long const siz)
|
||||
operator""_MiB (ullong const siz)
|
||||
{
|
||||
return uint(siz) * 1024u*1024u;
|
||||
}
|
||||
|
||||
inline unsigned long long
|
||||
operator""_GiB (unsigned long long const siz)
|
||||
inline ullong
|
||||
operator""_GiB (ullong const siz)
|
||||
{
|
||||
return siz * 1024uLL*1024uLL*1024uLL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ namespace util {
|
|||
* \endcode
|
||||
*/
|
||||
inline util::Rat
|
||||
operator""_r (unsigned long long num)
|
||||
operator""_r (ullong num)
|
||||
{
|
||||
return util::Rat{num};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ namespace time {
|
|||
return *this;
|
||||
}
|
||||
|
||||
/// Support mixing with plain long int arithmetics
|
||||
/// Support mixing with plain 64bit int arithmetics
|
||||
operator gavl_time_t() const { return t_; }
|
||||
/// Support for micro-tick precise time arithmetics
|
||||
operator FSecs() const { return FSecs{t_, TimeValue::SCALE}; }
|
||||
|
|
|
|||
|
|
@ -69,10 +69,10 @@ namespace util {
|
|||
};
|
||||
|
||||
template<>
|
||||
struct IDiv<long long>
|
||||
struct IDiv<llong>
|
||||
: lldiv_t
|
||||
{
|
||||
IDiv<long long> (long long num, long long den)
|
||||
IDiv<llong> (llong num, llong den)
|
||||
: lldiv_t(lldiv (num,den))
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -160,8 +160,8 @@ out-lit: Digxel<int, digxel::Formatter<int> >--empty-- 0--(val=123)--123|
|
|||
out-lit: Digxel<double, digxel::Formatter<double> >--empty--00.000--(val=123.457)--123.457|
|
||||
out-lit: Digxel<int, digxel::SexaFormatter>--empty--00--(val=42)--42|
|
||||
out-lit: Digxel<int, digxel::SexaFormatter>--empty--00--(val=-5)---5|
|
||||
out-lit: Digxel<unsigned int, digxel::HexaFormatter>--empty--00--(val=12)--0C|
|
||||
out-lit: Digxel<unsigned int, digxel::HexaFormatter>--empty--00--(val=111)--6F|
|
||||
out-lit: Digxel<uint, digxel::HexaFormatter>--empty--00--(val=12)--0C|
|
||||
out-lit: Digxel<uint, digxel::HexaFormatter>--empty--00--(val=111)--6F|
|
||||
out-lit: Digxel<long, digxel::CountFormatter>--empty--0000--(val=-1234567890)---1234567890|
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ namespace test{
|
|||
CHECK(not ii.getRestElms());
|
||||
CHECK (materialise(ii.getGroupedElms()) == "23-22-21-20-19"_expect);
|
||||
|
||||
CHECK ( test::showType<decltype(*ii)>()== "array<unsigned int, 5ul>&"_expect);
|
||||
CHECK ( test::showType<decltype(*ii)>()== "array<uint, 5ul>&"_expect);
|
||||
|
||||
uint s = *(ii.getGroupedElms());
|
||||
for ( ; ii; ++ii)
|
||||
|
|
|
|||
|
|
@ -53,14 +53,14 @@ namespace test{
|
|||
double funny (char, char, string);
|
||||
void funky() const;
|
||||
short fuzzy (float, float);
|
||||
long long fuzzy();
|
||||
llong fuzzy();
|
||||
double fully;
|
||||
};
|
||||
|
||||
class Fishy
|
||||
{
|
||||
/** @note private function can never be detected */
|
||||
long long fuzzy();
|
||||
llong fuzzy();
|
||||
|
||||
/** @note type Fishy exposes an extension point `fun` */
|
||||
friend void fun (Fishy&);
|
||||
|
|
@ -94,7 +94,7 @@ namespace test{
|
|||
META_DETECT_EXTENSION_POINT (fun);
|
||||
|
||||
META_DETECT_FUNCTION (double, funny, (char, char, string));
|
||||
META_DETECT_FUNCTION (long long, fuzzy, (void));
|
||||
META_DETECT_FUNCTION (llong, fuzzy, (void));
|
||||
META_DETECT_FUNCTION_NAME (funny);
|
||||
META_DETECT_FUNCTION_NAME (funky);
|
||||
META_DETECT_FUNCTION_NAME (fuzzy);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ namespace test {
|
|||
// this is how the key trick of the _Fun traits template works:
|
||||
// for anything "function like" we retrieve a member-pointer to the function call operator
|
||||
// which we then pass on to the dedicated overload for member pointers
|
||||
CHECK ("int (Functor::*)(unsigned int)" == typeStr<decltype(&Functor::operator())>());
|
||||
CHECK ("int (Functor::*)(uint)" == typeStr<decltype(&Functor::operator())>());
|
||||
|
||||
|
||||
Func f1{freeFun};
|
||||
|
|
@ -150,60 +150,60 @@ namespace test {
|
|||
|
||||
Func f5{lambda};
|
||||
|
||||
CHECK ("int (unsigned int)" == showSig (freeFun));
|
||||
CHECK ("int (unsigned int)" == showSig (&freeFun));
|
||||
CHECK ("int (unsigned int)" == showSig (Functor::staticFun));
|
||||
CHECK ("int (unsigned int)" == showSig (lambda));
|
||||
CHECK ("int (unsigned int)" == showSig (f5));
|
||||
CHECK ("int (uint)" == showSig (freeFun));
|
||||
CHECK ("int (uint)" == showSig (&freeFun));
|
||||
CHECK ("int (uint)" == showSig (Functor::staticFun));
|
||||
CHECK ("int (uint)" == showSig (lambda));
|
||||
CHECK ("int (uint)" == showSig (f5));
|
||||
|
||||
|
||||
CHECK ("int (unsigned int)" == showSigRef (freeFun));
|
||||
CHECK ("int (unsigned int)" == showSigRef (lambda));
|
||||
CHECK ("int (unsigned int)" == showSigRef (f5));
|
||||
CHECK ("int (uint)" == showSigRef (freeFun));
|
||||
CHECK ("int (uint)" == showSigRef (lambda));
|
||||
CHECK ("int (uint)" == showSigRef (f5));
|
||||
|
||||
CHECK ("int (unsigned int)" == showSigCRef (freeFun));
|
||||
CHECK ("int (unsigned int)" == showSigCRef (lambda));
|
||||
CHECK ("int (unsigned int)" == showSigCRef (f5));
|
||||
CHECK ("int (uint)" == showSigCRef (freeFun));
|
||||
CHECK ("int (uint)" == showSigCRef (lambda));
|
||||
CHECK ("int (uint)" == showSigCRef (f5));
|
||||
|
||||
CHECK ("int (unsigned int)" == showSigRRef (move(lambda)));
|
||||
CHECK ("int (unsigned int)" == showSigRRef (move(f5)));
|
||||
CHECK ("int (uint)" == showSigRRef (move(lambda)));
|
||||
CHECK ("int (uint)" == showSigRRef (move(f5)));
|
||||
|
||||
CHECK ("int (unsigned int)" == showSig (move(&freeFun)));
|
||||
CHECK ("int (unsigned int)" == showSig (move(lambda)));
|
||||
CHECK ("int (unsigned int)" == showSig (move(f5)));
|
||||
CHECK ("int (uint)" == showSig (move(&freeFun)));
|
||||
CHECK ("int (uint)" == showSig (move(lambda)));
|
||||
CHECK ("int (uint)" == showSig (move(f5)));
|
||||
|
||||
|
||||
Func& funRef = f1;
|
||||
Functor& funkyRef = funk;
|
||||
Func const& funCRef = f1;
|
||||
Functor const& funkyCRef = funk;
|
||||
CHECK ("int (unsigned int)" == showSig (funRef));
|
||||
CHECK ("int (unsigned int)" == showSig (funkyRef));
|
||||
CHECK ("int (unsigned int)" == showSig (funCRef));
|
||||
CHECK ("int (unsigned int)" == showSig (funkyCRef));
|
||||
CHECK ("int (uint)" == showSig (funRef));
|
||||
CHECK ("int (uint)" == showSig (funkyRef));
|
||||
CHECK ("int (uint)" == showSig (funCRef));
|
||||
CHECK ("int (uint)" == showSig (funkyCRef));
|
||||
|
||||
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<int(uint)>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Func&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Func&&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Func const&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Functor&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Functor&&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Functor const&>::Sig>());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<int(uint)>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Func&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Func&&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Func const&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Functor&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Functor&&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Functor const&>::Sig>());
|
||||
|
||||
using Siggy = _Fun<Func>::Sig;
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy&&>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy const&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Siggy&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Siggy&&>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<Siggy const&>::Sig >());
|
||||
|
||||
|
||||
auto memfunP = &Functor::fun;
|
||||
FuncF fM{memfunP};
|
||||
Func fMF{bind (fM, funk, _1)};
|
||||
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<decltype(memfunP)>::Sig>());
|
||||
CHECK ("int (Functor&, unsigned int)" == typeStr<_Fun<decltype(fM)>::Sig >());
|
||||
CHECK ("int (unsigned int)" == typeStr<_Fun<decltype(fMF)>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<decltype(memfunP)>::Sig>());
|
||||
CHECK ("int (Functor&, uint)" == typeStr<_Fun<decltype(fM)>::Sig >());
|
||||
CHECK ("int (uint)" == typeStr<_Fun<decltype(fMF)>::Sig >());
|
||||
|
||||
|
||||
// _Fun<F> can be used for metaprogramming with enable_if
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ namespace test{
|
|||
|
||||
auto breed = Result{evil, 55ll}; // an odd number...
|
||||
VERIFY_ERROR (STATE, breed.maybeThrow() );
|
||||
CHECK (Type(breed) == "Result<long long>"_expect);
|
||||
CHECK (Type(breed) == "Result<llong>"_expect);
|
||||
|
||||
auto dead = Result{[]{ throw 55; }};
|
||||
auto deed = Result{[]{ /* :-) */ }};
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ namespace test {
|
|||
verifyIntegerTypes<long>();
|
||||
verifyIntegerTypes<short>();
|
||||
verifyIntegerTypes<int64_t>();
|
||||
verifyIntegerTypes<long long int>();
|
||||
verifyIntegerTypes<llong>();
|
||||
|
||||
if (!isnil (arg))
|
||||
runPerformanceTest();
|
||||
|
|
|
|||
Loading…
Reference in a new issue