From 8ccdd8568fe4d9b3aab1e2a43f425e13457c6106 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Thu, 4 Jan 2018 13:34:32 -0800 Subject: [PATCH] doc: Move conventions to STYLE; ircd: Add additional README related. --- doc/STYLE.md | 50 ++++++++++++++++++++++++ include/ircd/README.md | 88 +++++++++++++----------------------------- include/ircd/stdinc.h | 10 ----- ircd/README.md | 35 +++++++++++++++++ 4 files changed, 111 insertions(+), 72 deletions(-) diff --git a/doc/STYLE.md b/doc/STYLE.md index cfc6c22d8..5c8bb9d61 100644 --- a/doc/STYLE.md +++ b/doc/STYLE.md @@ -280,3 +280,53 @@ other words, if you have a prototype like `foo(const std::string &message)` you `message` because std::string is common and *what* the string is for is otherwise opaque. OTOH, if you have `foo(const options &options, const std::string &message)` one should skip the name for `options &` as it just adds redundant text to the prototype. + +### Conventions + +These are things you should know when mulling over the code as a whole. +Importantly, knowing these things will help you avoid various gotchas and not +waste your time debugging little surprises. You may or may not agree with some +of these choices (specifically the lack of choices in many cases) but that's +why they're explicitly discussed here. + +#### Null termination + +- We don't rely on null terminated strings. We always carry around two points +of data to indicate such vectoring. Ideally this is a pair of pointers +indicating the `begin`/`end` like an STL iterator range. `string_view` et al +and the `buffer::` suite work this way. + +- Null terminated strings can still be used and we even still create them in +many places on purpose just because we can. + +- Null terminated creations use the BSD `strl*` style and *not* the `strn*` +style. Take note of this. When out of buffer space, such an `strl*` style +will *always* add a null to the end of the buffer. Since we almost always +have vectoring data and don't really need this null, a character of the string +may be lost. This can happen when creating a buffer tight to the length of an +expected string without a `+ 1`. This is actually the foundation of a case +to move *back* to `strn*` style but it's not prudent at this time. + +- Anything named `print*` like `print(mutable_buffer, T)` always composes null +terminated output into the buffer. These functions usually return a size_t +which count characters printed *not including null*. They may return a +`string_view`/`const_buffer` of that size (never viewing the null). + +#### assert() volatility + +- Consider any code inside a runtime `assert()` statement to **entirely** +disappear in optimized builds. Some implementations of `assert()` may only +elide the boolean check and thus preserve the inner statement and the effects +of its execution. We do not rely on this. Do not use `assert()` to check +return values of statements that need to be executed in optimized builds. + +- Furthermore, consider the **assert statement itself to be physically erased** +from the code during optimized builds. Thus the following is a big mistake: + +``` + if(foo) + assert(!bar); + + if(baz) + bam(); +``` diff --git a/include/ircd/README.md b/include/ircd/README.md index 144758cd4..1da10b2f9 100644 --- a/include/ircd/README.md +++ b/include/ircd/README.md @@ -1,8 +1,15 @@ # IRCd Library API -### Getting Around +#### Project Namespaces -##### libircd headers are organized into several aggregate "stacks" +* `IRCD_` Preprocessor #define and macro namespace. +* `RB_` Preprocessor #define and macro namespace (legacy / low-level). +* `ircd_` C namespace and demangled bindings. +* `ircd::` C++ namespace scope. + +#### What To Include + +##### libircd headers are organized into several aggregates groups As a C++ project there are a lot of header files. Header files depend on other header files. We don't expect the developer of a compilation unit to figure out @@ -10,75 +17,32 @@ an exact list of header files necessary to include for that unit. Instead we have aggregated groups of header files which are then precompiled. These aggregations are mostly oriented around a specific project dependency. -- Standard Include stack is the main header group. This stack +> Note: The term 'stack' may be found in place of the preferred term 'group' +in other documentation. + +- Standard Include group `` is the main header group. This group involves the standard library and most of libircd. This is what an embedder will be working with. These headers will expose our own interfaces wrapping -3rd party dependencies which are not included there. Note that the actual file -to properly include this stack is (not stdinc.h). +3rd party dependencies which are not included there. -- Boost ASIO include stack is a header group exposing the + There are actually two files in play here: `` and ``. + We have to offer two different pre-compilations: one with `-fPIC` + and one without. Therefor the contents are in `` and the + preprocessor determination for which is in ``. + +- Boost ASIO include group `` is a header group exposing the boost::asio library. We only involve this header in compilation units working directly with asio for networking et al. Involving this header file slows down -compilation compared with the standard stack. +compilation compared with the standard group. -- Boost Spirit include stack is a header group exposing the +- Boost Spirit include group `` is a header group exposing the spirit parser framework to compilation units which involve formal grammars. Involving this header is a *monumental* slowdown when compiling. -- JavaScript include stack is a header group exposing symbols +- JavaScript include group `` is a header group exposing symbols from the SpiderMonkey JS engine. Alternatively, is part of the -standard include stack which includes any wrapping to hide SpiderMonkey. +standard include group which includes any wrapping to hide SpiderMonkey. -- MAPI include stack is the standard header group for modules. -This stack is an extension to the standard include stack but has specific +- MAPI include group `` is the standard header group for modules. +This group is an extension to the standard include group but has specific tools for pluggable modules which are not part of the libircd core. - -### Conventions - -These are things you should know when mulling over the code as a whole. -Importantly, knowing these things will help you avoid various gotchas and not -waste your time debugging little surprises. You may or may not agree with some -of these choices (specifically the lack of choices in many cases) but that's -why they're explicitly discussed here. - -#### Null termination - -- We don't rely on null terminated strings. We always carry around two points -of data to indicate such vectoring. Ideally this is a pair of pointers -indicating the `begin`/`end` like an STL iterator range. `string_view` et al -and the `buffer::` suite work this way. - -- Null terminated strings can still be used and we even still create them in -many places on purpose just because we can. - -- Null terminated creations use the BSD `strl*` style and *not* the `strn*` -style. Take note of this. When out of buffer space, such an `strl*` style -will *always* add a null to the end of the buffer. Since we almost always -have vectoring data and don't really need this null, a character of the string -may be lost. This can happen when creating a buffer tight to the length of an -expected string without a `+ 1`. This is actually the foundation of a case -to move *back* to `strn*` style but it's not prudent at this time. - -- Anything named `print*` like `print(mutable_buffer, T)` always composes null -terminated output into the buffer. These functions usually return a size_t -which count characters printed *not including null*. They may return a -`string_view`/`const_buffer` of that size (never viewing the null). - -#### assert() volatility - -- Consider any code inside a runtime `assert()` statement to **entirely** -disappear in optimized builds. Some implementations of `assert()` may only -elide the boolean check and thus preserve the inner statement and the effects -of its execution. We do not rely on this. Do not use `assert()` to check -return values of statements that need to be executed in optimized builds. - -- Furthermore, consider the **assert statement itself to be physically erased** -from the code during optimized builds. Thus the following is a big mistake: - -``` - if(foo) - assert(!bar); - - if(baz) - bam(); -``` diff --git a/include/ircd/stdinc.h b/include/ircd/stdinc.h index bde48a72b..4a4b286bb 100644 --- a/include/ircd/stdinc.h +++ b/include/ircd/stdinc.h @@ -20,16 +20,6 @@ * */ -/////////////////////////////////////////////////////////////////////////////// -// -// IRCd's namespacing is as follows: -// -// IRCD_ #define and macro namespace -// RB_ #define and macro namespace (legacy, low-level) -// ircd_ C namespace and demangled bindings -// ircd:: C++ namespace -// - /////////////////////////////////////////////////////////////////////////////// // // Standard includes diff --git a/ircd/README.md b/ircd/README.md index ccd75569b..cb650ce0b 100644 --- a/ircd/README.md +++ b/ircd/README.md @@ -1,3 +1,38 @@ # IRCd Library Definitions This directory contains definitions and linkage for `libircd` + +### Overview + +`libircd` is designed specifically as a shared object library. The purpose of its +shared'ness is to facilitate IRCd's modular design: IRCd ships with many other +shared objects which introduce the "business logic" and features of the daemon. If +`libircd` was not a shared object, every single module would have to include large +amounts of duplicate code drawn from the static library. This would be a huge drag +on both compilation and the runtime performance. + +``` + (module) (module) + | | + | | + V V + |-------------| +---------------------- | | < ---- (module) +| | | | +| User's executable | <---- | libircd | +| | | | +---------------------- | | < ---- (module) + |-------------| + ^ ^ + | | + | | + (module) (module) + +``` + +The user (which we may also refer to as the "embedder" elsewhere in +documentation) only deals directly with `libircd` and not the modules. +`libircd` is generally loaded with its symbols bound globally in the executable +and on most platforms cannot be unloaded (or even loaded) manually and has not +been tested to do so. As an aside, we do not summarily dismiss the idea of +reload capability and would like to see it made possible.