├── .gitignore ├── .gitmodules ├── 59001.png ├── C++23-status.svg ├── Codepage-437.png ├── D1859.md ├── D1859R1.md ├── D1949R0.md ├── D1949R1.md ├── Makefile ├── UAX31-EWG-slides.html ├── UAX31-EWG-slides.org ├── building-c++-reliably.md ├── building-c++-reliably.org ├── c++-package-management.org ├── c++20-is-design-complete.org ├── cppcon21 ├── algebraic-bestiary-slides.org ├── algebraic-bestiary.html ├── algebraic-bestiary.org ├── cofun.html └── cofun.org ├── cppnow ├── CrashCourseTitle.png ├── ModuleTitle.png ├── StateMachineTitle.png ├── bbg-footer.el ├── clang-modules │ ├── Makefile │ ├── client.cpp │ └── math.cpp ├── convert-state-machine-coroutine-slides.html ├── convert-state-machine-coroutine-slides.md ├── convert-state-machine-coroutine-slides.org ├── convert-state-machine-coroutine.org ├── crash-course-unicode-slides.org ├── crash-course-unicode.org ├── footer.css ├── fringetree │ ├── Makefile │ ├── fringetree.cpp │ ├── fringetree.h │ ├── fringetree.t.cpp │ ├── main.cpp │ └── prepend.cpp ├── modulating-a-component-slides.html ├── modulating-a-component-slides.org ├── modulating-a-component.org ├── module-hw │ ├── Makefile │ ├── hello.cpp │ └── main.cpp └── t2.png ├── cppnow23 ├── .clang-format ├── async_control.org ├── async_title.png ├── footer.css ├── images │ ├── just.png │ ├── let_value.png │ ├── sender.png │ └── then.png ├── my_theme.css ├── operandi-tinted.css └── vivendi-tinted.css ├── d1949.md ├── d2071.md ├── empty-product-ranges.html ├── empty-product-ranges.org ├── ewgi-20191418.org ├── generated ├── D1859.html ├── D1859.latex ├── D1859R1.html ├── D1949R0.html ├── D1949R1.html ├── d1949.html ├── d2071.html ├── d2071r1.html ├── local-class-template.html ├── new-basic-characters.html ├── pmr-stacktrace.html ├── test.html └── view-maybe.html ├── humans-bad-components.md ├── humans-bad-components.org ├── lewg-monday-morning.org ├── lewg-wednesday.org ├── local-class-template.md ├── manylinux.org ├── networking-polls.org ├── new-basic-characters.md ├── notes.org ├── numerics-notes.org ├── pmr-stacktrace.md ├── sd2018-tuesday.org ├── sg16-notes.org ├── sg16-review-rubric.md ├── sg16-review-rubric.org ├── unicode-strawman.org ├── unicode-transcode.org ├── view-maybe-lewgi.org ├── view-maybe.md ├── view-maybe.org ├── vivendi.css ├── wg21-status.org └── why-modules.org /.gitignore: -------------------------------------------------------------------------------- 1 | manylinux.html 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wg21"] 2 | path = wg21 3 | url = https://github.com/mpark/wg21.git 4 | [submodule "cppnow/fringetree/googletest"] 5 | path = cppnow/fringetree/googletest 6 | url = https://github.com/google/googletest.git 7 | -------------------------------------------------------------------------------- /59001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/59001.png -------------------------------------------------------------------------------- /Codepage-437.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/Codepage-437.png -------------------------------------------------------------------------------- /D1859.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Standard terminology character sets and encodings 3 | document: D1859R1 4 | date: today 5 | audience: 6 | - SG16 7 | - EWG 8 | - CWG 9 | author: 10 | - name: Steve Downey 11 | email: , 12 | toc: false 13 | --- 14 | 15 | Abstract: This document proposes new standard terms for the various encodings for character and string literals, and the encodings associated with some character types. It also proposes that the wording used for [lex.charset], [lex.ccon], [lex.string], and [basic.fundamental.8] be modified to reflect the new terminology. This paper does not intend to propose any changes that would require changes in any currently conforming implementation. 16 | 17 | 18 | # Introduction 19 | In discussions around understanding the current capabilities of C++ and proposing new capabilities and facilities, SG16 has found that the current standard wording is often unclear, and does not match well the language currently used in 10646 and the Unicode Standard. This makes having technical discussions difficult. For example, the phrase "execution encoding" often comes up, or "presumed execution encoding", trying to describe the encodings of `char` literals and strings as interpreted by the character classification functions. This conflates several concepts, and is not actually standard terminology. It would be useful to have standard terminology that did cover these concepts. 20 | 21 | Execution character set is a standard term, however it defines what _abstract characters_ must be included in the _character repertoire_ of the character set used to encode C++, specifically the various kinds of character literals. That character set is a strict superset of the source character set, which defines the _abstract characters_ must be in the _character repertoire_ of the character set used to write C++ source code. The encodings of those character sets are not specified, and in fact there may be several encodings used depending on the context or kind of literal. 22 | 23 | There are five encodings that are associated with the five kinds of character literals, corresponding to `char`, `wchar_t`, `char8_t`, `char16_t`, and `char32_t`. For 8, 16, and 32, the encodings must be UTF-8, UTF-16, and UTF-32. There are no associated encodings for `unsigned char` or `signed char`. 24 | 25 | The encoding used for narrow and wide character and string literals is implementation defined, and is, of course, fixed at translation time. 26 | 27 | At runtime, however, interpretation of character data is usually controlled by `locale`, either explicitly, or via the `locale` specified by `setlocale()`. The dynamic locale may not be the same as the literal encoding used at translation time. This is a source of errors in text processing. 28 | 29 | Another source of problems is the baked in assumption that a single `wchar_t` can encode any representation character. For ABIs where `wchar_t` is 16 bits, this is not true, and many of the NTMBS functions are incomplete, as they do not allow for stateful wide character encodings. 30 | 31 | # Proposal 32 | - Introduce new, more precise, terms, and use them throughout. 33 | - Clarfiy when literal vs dynamic encoding is intended, where not already clear. 34 | - Clarify that wchar_t may be a UTF-16 encoded type. 35 | - This can be separated from the rest of the proposal. It is certainly the most controversial as it involves admiting the standard is broken in places, albeit without requiring any implementation to change. 36 | 37 | 38 | # Terms 39 | 40 | Narrow Literal Encoding and Wide Literal Encoding 41 | : The encoding used for character and wide character and string literals in a translation unit. 42 | 43 | Dynamic Encoding 44 | : The encoding implied by the LC_CTYPE category of the current locale. 45 | 46 | Character Set [https://unicode.org/glossary/#character_set] 47 | : A collection of elements used to represent textual information. 48 | 49 | Abstract Character [https://unicode.org/glossary/#abstract_character] 50 | : A unit of information used for the organization, control, or representation of textual data. 51 | 52 | Character Repertoire [https://unicode.org/glossary/#character_repertoire] 53 | : The collection of characters included in a character set. 54 | 55 | Source character set 56 | : The abstract characters that must be representable in the internal _character set_ used after phase 1 of translation. All characters not in the source character set are converted to universal-character-names, which are made up of characters from the basic character set. The abstract parser only sees characters in the source character set. 57 | 58 | Basic execution character set 59 | : The abstract characters the _character repertoire_ of the _character set_ used for literals must include. A superset of the abstract characters in the basic source character set. 60 | 61 | Execution character set 62 | : The set of abstract characters representable by a `char` or `char` string literal 63 | 64 | Excecution wide-character set 65 | : The set of abstract characters representable by a `wchar_t` or `wchar_t` string literal 66 | 67 | Associated Encoding 68 | : There are 5 types with associated encodings, `char`, `wchar_t`, `char8_t`, `char16_t`, and `char32_t`. For the latter three, the association is fixed to the UTF encoding of the same size, UTF-8, UTF-16, and UTF-32. For `char` and `wchar_t` the association is determined dynamically, based on the current `locale`. For each it is the scheme used to decode data of that type into code points. 69 | 70 | # Example of use of new _words_ (not an actual proposal, yet) 71 | 72 | ## Proposal Dnnnn 73 | Loosly modeled after `source_position`, the callable objects `literal_encoding` and `wide_literal_encoding` provide mechanism for the compiler to expose information to the translation unit, in this case how to invert the mapping that the compiler knew when it encoded character and string literals. 74 | 75 | ### `literal_encoding` 76 | Returns an _unspecified_ callable taking a `range` of elements of type `char` and returning a `view` of of code points decoded from the input range treating them as being in the _literal encoding_ used for the current translation unit. For latin-1 it might be 77 | 78 | ```c++ 79 | [](auto&& r){return views::transform(r, [](unsigned char c) -> char32_t {return c;}); 80 | ``` 81 | 82 | For any other single byte encoding a static lookup table of char32_t[256] could be used. 83 | 84 | ### `wide_literal_encoding` 85 | Returns an _unspecified_ callable taking a `range` of elements of type `char` and returning a `view` of of code points decoded from the input range treating them as being in the _wide literal encoding_ used for the current translation unit. 86 | 87 | ## Discussion of proposal Dnnnn 88 | Still woefully underspecified, it is at least clearer what is being discussed, and how it might be something a compiler could implement. Without the terms _literal encoding_ and _wide literal encoding_ discussion gets bogged down quickly around the difference between what the compiler does and what locale and the _dynamic encoding_ imply for character conversions. 89 | 90 | # Wording 91 | ## lex.charset 92 | [lex.charset.1]{.pnum} 93 | The basic source character set consists of 96 [abstract]{.add} characters: the space character, the control characters representing horizontal tab, vertical tab, form feed, and new-line, plus the following 91 graphical characters: 94 | 95 | ~~~~ 96 | a b c d e f g h i j k l m n o p q r s t u v w x y z 97 | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 98 | 0 1 2 3 4 5 6 7 8 9 99 | _ { } \[ \] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " ' 100 | ~~~~ 101 | 102 | Editorial Note: Should really be a list of unicode names or universal names, aka code points 103 | e.g. 104 | ~~~~ 105 | 0041..005A ; L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z 106 | 0061..007A ; L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z 107 | 0030..0039 ; Nd [10] DIGIT ZERO..DIGIT NINE 108 | 0020 ; Zs SPACE 109 | 0021 ; Po EXCLAMATION MARK 110 | 0022 ; Po QUOTATION MARK 111 | 0023 ; Po NUMBER SIGN 112 | 0025 ; Po PERCENT SIGN 113 | 0026 ; Po AMPERSAND 114 | 0027 ; Po APOSTROPHE 115 | 0028 ; Ps LEFT PARENTHESIS 116 | 0029 ; Pe RIGHT PARENTHESIS 117 | 002A ; Po ASTERISK 118 | 002B ; Sm PLUS SIGN 119 | 002C ; Po COMMA 120 | 002D ; Pd HYPHEN-MINUS 121 | 002E ; Po FULL STOP 122 | 002F ; Po SOLIDUS 123 | 003A ; Po COLON 124 | 003B ; Po SEMICOLON 125 | 003C ; Sm LESS-THAN SIGN 126 | 003D ; Sm EQUALS SIGN 127 | 003E ; Sm GREATER-THAN SIGN 128 | 003F ; Po QUESTION MARK 129 | 005B ; Ps LEFT SQUARE BRACKET 130 | 005C ; Po REVERSE SOLIDUS 131 | 005D ; Pe RIGHT SQUARE BRACKET 132 | 005E ; Sk CIRCUMFLEX ACCENT 133 | 005F ; Pc LOW LINE 134 | 007B ; Ps LEFT CURLY BRACKET 135 | 007C ; Sm VERTICAL LINE 136 | 007D ; Pe RIGHT CURLY BRACKET 137 | 007E ; Sm TILDE 138 | ~~~~ 139 | 140 | [lex.charset.3]{.pnum} 141 | The basic execution character set and the basic execution wide-character set shall each contain all the [members]{.rm} [abstract characters]{.add} of the basic source character set, plus control characters representing alert, backspace, and carriage return, plus a null character (respectively, null wide character), whose value is 0. For each [element in the]{.add} basic execution character set, the [encoded]{.add} values of the members shall be non-negative and distinct from one another. In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous. The execution character set and the execution wide-character set are implementation-defined supersets of the basic execution character set and the basic execution wide-character set, respectively. The [encoded]{.add} values of the members of the execution character sets [and the sets of additional members]{.rm} are [implementation defined]{.add}[locale-specific]{.rm}. 142 | 143 | ## lex.con 144 | 145 | [lex.conn.2] 146 | A character literal that does not begin with u8, u, U, or L is an ordinary character literal. An ordinary character literal that contains a single c-char representable in the execution character set has type char, with value equal to the numerical value of [the encoding of]{.rm} the c-char in the [literal encoding]{.add}. An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharacter literal, or an ordinary character literal containing a single c-char not representable in the execution character set, is conditionally-supported, has type int, and has an implementation-defined value. 147 | 148 | [lex.conn.6] 149 | A character literal that begins with the letter L, such as L'z', is a wide-character literal. A wide-character literal has type `wchar_t`. The value of a wide-character literal containing a single c-char has value equal to the numerical value of the encoding of the c-char in the [execution wide-character set]{.rm}[wide literal encoding]{.add}, unless the c-char has no representation in the execution wide-character set, in which case the value is implementation-defined. [[ Note: The type wchar_t is able to represent all members of the execution wide-character set (see [basic.fundamental]). — end note ]]{.rm} The value of a wide-character literal containing multiple c-chars is implementation-defined. 150 | 151 | ## lex.string 152 | 153 | [lex.string.6] 154 | After translation phase 6, a string-literal that does not begin with an encoding-prefix is an ordinary string literal. An ordinary string literal has type “array of n const char” where n is the size of the string as defined below, has static storage duration ([basic.stc]), and is initialized with the [given characters]{.rm}[values of the characters in the narrow literal encoding]{.add}. 155 | 156 | [lex.string.8] 157 | Ordinary string literals [and UTF-8 string literals]{.rm} are also referred to as narrow string literals. 158 | 159 | ## basic.fundemental 160 | 161 | [basic.fundemental.8] 162 | Type `wchar_t` is a distinct type that has an implementation-defined signed or unsigned integer type as its underlying type. [The values of type `wchar_t` can represent distinct codes for all members of the largest extended character set specified among the supported locales ([locale]).]{.rm} 163 | 164 | 165 | ## Addition somewhere in [lex] 166 | 167 | The literal and string literal for `char`, `wchar_t`, `char8_t`, `char16_t`, and `char32_t` have associated encodings. For `char8_t`, `char16_t`, and `char32_t`, the encodings are fixed both for compile and execution as UTF-8, UTF-16, and UTF-32. There are no associated encodings for `unsigned char` or `signed char`. The associated encodings for `char` and `wchar_t` types are implementation defined. [Note: it is unspecified how translation units with differing associated encodings for `char` and `wchar_t` combine. Differing visible definitions will be ODR violations.] 168 | 169 | # Conclusions 170 | 171 | Moving to a more modern and consistent terminology for character sets, character encodings, and a better definition of what types have associated encodings when, will make it more straight-forward to understand the current technical issues with text and to enable simpler proposals for text in the future. 172 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include wg21/Makefile 2 | -------------------------------------------------------------------------------- /UAX31-EWG-slides.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:nil \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:nil p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:nil title:t toc:nil todo:t |:t 5 | #+title: C++ Identifiers using UAX 31 6 | #+author: Steve Downey 7 | #+email: sdowney@sdowney.org 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | #+OPTIONS: reveal_width:1600 reveal_height:900 35 | #+REVEAL_THEME: black 36 | #+REVEAL_TRANS: fade 37 | #+REVEAL_MATHJAX_URL: https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML 38 | 39 | #+HTML_HEAD: 40 | #+REVEAL_EXTRA_CSS: http://sdowney.org/css/smd-zenburn.css 41 | #+REVEAL_EXTRA_CSS: ./footer.css 42 | 43 | #+REVEAL_ROOT: https://cdn.jsdelivr.net/npm/reveal.js 44 | #+REVEAL_VERSION: 4 45 | 46 | 47 | * C++ Identifier Syntax using Unicode Standard Annex 31 48 | - That C++ identifiers match the pattern 49 | #+begin_quote 50 | (XID_Start + _ ) + XID_Continue*. 51 | #+end_quote 52 | - That portable source is required to be normalized as NFC. 53 | - That using unassigned code points be ill-formed. 54 | 55 | ** Problem this fixes : NL 029 56 | 57 | #+begin_quote 58 | Allowed characters include those from U+200b until U+206x; these are zero-width and control characters that lead to impossible to type names, indistinguishable names and unusable code & compile errors (such as those accidentally including RTL modifiers). 59 | #+end_quote 60 | 61 | ** Status Quo: we allow other "weird identifier code points" 62 | - The middle dot · which looks like an operator. 63 | - Many non-combining "modifiers" and accent marks, such as ´ and ¨ and ꓻ which don't really make sense on their own. 64 | - "Tone marks" from various languages, including ˫ (similar to a box-drawing character ├ which is an operator). 65 | - The "Greek question mark" ; 66 | - Symbols which are simply not linguistic, such as ۞ and ༒. 67 | 68 | https://gist.github.com/jtbandes/c0b0c072181dcd22c3147802025d0b59#weird-identifier-code-points 69 | 70 | ** UAX 31 - Unicode Identifier and Pattern Syntax 71 | - Follows the same principles as originally used for C++ 72 | - Actively maintained 73 | - Stable 74 | 75 | ** XID_Start and XID_Continue 76 | - Unicode database defined properties 77 | - Closed under normalization for all four forms 78 | - Once a code point has the property it is never removed 79 | - Roughly: 80 | - Start == letters 81 | - Continue == Start + numbers + some punctuation 82 | 83 | * The Emoji Problem 84 | - The emoji-like code points that we knew about were excluded 85 | - We included all unassigned code points 86 | - Status Quo Emoji 'support' is an accident, incomplete, and broken 87 | 88 | ** Status quo is broken 89 | *** Some Status Quo examples 90 | | Not Valid | Valid | 91 | |-------------+-------------| 92 | | int ⏰ = 0; | int 🕐 = 0; | 93 | | int ☠️ = 0; | int 💀 = 0; | 94 | | int ✋️ = 0; | int 👊 = 0; | 95 | | int ✈️ = 0; | int 🚀 = 0; | 96 | | int ☹️ = 0; | int 😀 = 0; | 97 | 98 | 99 | When the character was added to Unicode controls validity 100 | 101 | *** Status Quo: ♀ and ♂ are disallowed 102 | Gendered variants of emoji are selected by using a zero width joiner together 103 | with the male and female sign. 104 | 105 | #+begin_src C++ 106 | // Valid 107 | bool 👷 = true; // Construction Worker 108 | // Not valid 109 | bool 👷‍♀ = false; // Woman Construction Worker ({Construction Worker}{ZWJ}{Female Sign}) 110 | 111 | #+end_src 112 | ** Problems adding Emoji as identifiers 113 | 114 | *** Emoji are complex 115 | - Not just code points 116 | - Need grapheme cluster analysis 117 | - May incur costs even for code not using emoji 118 | 119 | *** Emoji are not "Stable" in Unicode 120 | From the emoji spec 121 | #+begin_quote 122 | isEmoji(♟)=false for Emoji Version 5.0, but true for Version 11.0. 123 | #+end_quote 124 | It is possible that the emoji property could be removed. 125 | 126 | *** Identifying Emoji is difficult 127 | The unicode standard provides a regex that will reject non-emoji, but does not guarantee a valid emoji sequence. 128 | #+begin_example 129 | \p{RI} \p{RI} 130 | | \p{Emoji} 131 | ( \p{EMod} 132 | | \x{FE0F} \x{20E3}? 133 | | [\x{E0020}-\x{E007E}]+ \x{E007F} )? 134 | (\x{200D} \p{Emoji} 135 | ( \p{EMod} 136 | | \x{FE0F} \x{20E3}? 137 | | [\x{E0020}-\x{E007E}]+ \x{E007F} )? 138 | )* 139 | #+end_example 140 | 141 | It's not clear how much of the unicode database would be required for complete support. 142 | 143 | 144 | [[https://unicode.org/reports/tr51/][UNICODE EMOJI]] 145 | 146 | *** Some surprising things are emoji 147 | #+begin_example 148 | 002A ; Emoji # E0.0 [1] (*️) asterisk 149 | 0030..0039 ; Emoji # E0.0 [10] (0️..9️) digit zero..digit nine 150 | #+end_example 151 | 152 | #+begin_example 153 | {DIGIT ONE}{VARIATION SELECTOR-16}{COMBINING ENCLOSING KEYCAP} 1️⃣ 154 | 155 | {ASTERISK}{VARIATION SELECTOR-16}{COMBINING ENCLOSING KEYCAP} *️⃣ 156 | #+end_example 157 | #+begin_src C++ 158 | /// would this be valid? 159 | int 1️⃣ = 1; 160 | 161 | #+end_src 162 | *** Fixing the emoji problem would mean being inventive 163 | 164 | Being inventive in an area outside our expertise is HARD 165 | 166 | Adopting UAX31 as a base to move forward is conservative 167 | 168 | UAX 31 is a known good state 169 | 170 | * Script Issues 171 | Some scripts require characters to control display or require punctuation that are not in the identifier set. 172 | 173 | ** This includes English 174 | - Apostrophe and dash 175 | - ~won't~ 176 | - ~can't~ 177 | - ~mustn't~ 178 | - ~mother-in-law~ 179 | - Programmers are used to this and do not notice 180 | 181 | ** Zero Width characters are excluded by UAX 31 182 | Status quo allows these invisible characters 183 | 184 | #+begin_src C++ 185 | int tmp = 0; 186 | int t‍‍mp = 0; 187 | #+end_src 188 | * clang 10 warns 189 | 190 | :2:6: warning: identifier contains Unicode character that is invisible in some environments [-Wunicode-zero-width] 191 | 192 | 193 | int tmp = 0; 194 | 195 | ** ZWJ and ZWNJ 196 | However zero width joiner and non joiner are used in some scripts 197 | 198 | | Farsi word "names" | 199 | | نامهای | 200 | | NOON + ALEF + MEEM + HEH + ALEF + FARSI YEH | 201 | | [[https://www.unicode.org/reports/tr31/images/uax31-figure-2-farsi-ex1-v1-web.jpg]] | 202 | 203 | | Farsi word "a letter" | 204 | | نامه‌ای | 205 | | NOON + ALEF + MEEM + HEH + *ZWNJ* + ALEF + FARSI YEH | 206 | | [[https://www.unicode.org/reports/tr31/images/uax31-figure-2-farsi-ex2-v1-web.jpg]] | 207 | 208 | Anecdotally, these issues are understood and worked around 209 | 210 | ** UAX 31 has an expensive solution 211 | Identifiers can be checked for what script the code points in the identifier are used, and the rules for allowed characters can be tailored. This requires a Unicode database and would require extensive analysis during lexing. 212 | 213 | SG 16 does not recommend this. 214 | 215 | * Other adopters 216 | - Java (https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.8) 217 | - Python 3 https://www.python.org/dev/peps/pep-3131/ 218 | - Erlang https://www.erlang.org/erlang-enhancement-proposals/eep-0040.html 219 | - Rust https://rust-lang.github.io/rfcs/2457-non-ascii-idents.html 220 | - JS https://tc39.es/ecma262/ 221 | -------------------------------------------------------------------------------- /building-c++-reliably.md: -------------------------------------------------------------------------------- 1 |
2 | Abstract: Building C++ is especially difficult to do reliably. Modern infrastructure and tools can help. 3 | 4 |
5 | 6 | 7 | # Introduction 8 | 9 | Among modern programming languages, C++ is notable for not providing a package management system by which developers can easily install and reuse code developed by others in their own projects. It shares this with C -- and for similar reasons. Until recently, source distribution was the exception, rather than the rule, and pre-compiled libraries are fragile, as they generally must use the exact same set of dependent libraries compiled the same way. This largely limits the reuse of packages to those provided by an OS or distro vendor. A modern Linux or BSD system may provide thousands of such packages; however, changing any of them may cause the entire system to fail. This creates a huge tension between Long Term Support versions and making current packages available. 10 | 11 | # Risks 12 | 13 | 14 | ## No standardised package manager 15 | 16 | Unlike tools such as node.js, python, or rust, there is no standard package manager. There isn't even a widely used one that isn't what comes with an OS. This is partly because C++ is not a single vendor system, so no vendor is in a position to standardise a solution, and also because of actual technical difficulties with shippint C++ binaries that will work. 17 | 18 | 19 | ## Library ABI is a problem – C++ leaks across boundaries 20 | 21 | C++ libraries usually pass by value, which means that layout of an object must match exactly. Inline functions also cross between translation units, which means that even if an object is passed by reference or pointer, manipulating it requires agreement on layout. This is also true transitively, so that any type used by a library must be the same everywhere in a program. There's an official rule, the One Definition Rule, and if it is broken, there is no defined behavior, which usually means crashing. 22 | 23 | 24 | ## Dependency changes require rebuilds 25 | 26 | If anything your C++ code depends on changes, to be safe you must recompile your code, as well as all other code that depends on that. If you are library code, you now have to rebuild everything that depends on you. Package build managers like debian'a sbuild do some of this work, keeping a distro in sync. 27 | 28 | 29 | ## Replacing OS supplied packages is risky 30 | 31 | You're using system supplied packages because they are easily available and most Linux systems provide a wide range of them. But you want to upgrade one of them because you need a new feature. So you upgrade it, put it in /usr/lib and now your OS won't boot properly because some other critical component used it. The standard solution for this is install in /usr/local, but that has similar scaling issues. The more software in /usr/local, the harder it is to just swap out one library. 32 | 33 | 34 | ## Shared libraries are risky - DLLHell 35 | 36 | Shared libraries have versioning issues. It's possible to specify that a shared library is compatible with older versions, but it's very easy to get wrong. See the library ABI issues from before. 37 | 38 | 39 | # Approaches that can work 40 | 41 | 42 | ## Source Integration 43 | 44 | A common approach for smaller applications is to integrate libraries into the build of the application itself. The upside is that the library should be built consistently with your application. The downside is adapting the libraries builds into your own. Some build systems make this more straightforward than others. For cmake, for example, it may be as simple as: 45 | 46 | ```cmake 47 | add_subdirectory(extern/googletest EXCLUDE_FROM_ALL) 48 | ``` 49 | 50 | Then googletest will be built as part of your cmake build, and the gtest and gmock targets will be available to be depended upon. This approach has scalability issues. As the number of applications grows, integrating and building each library consumes more time and effort. 51 | 52 | 53 | ## Use Stock OS Libraries 54 | 55 | Modern Linux and BSD based systems provide a huge number of libraries that can be used from the system. Adding new libraries is as simple as `apt install libxyzzy-dev`. The downside is that you are then stuck with those versions, and upgrading the OS becomes painful because it may also mean rewriting parts of your code to match the new libraries. 56 | 57 | 58 | ## Consistent Isolated Builds 59 | 60 | Producing a consistent, if small, distro of the libraries that are used, built against each other, using the same toolchain and options, gives the most flexibility and reliability. Upgrading a package is under your control. If the promotion into the distro fails, no harm is done. Binary artifacts can be shared and reused, so individual developers don't have to waste time rebuilding everything from scratch. It is also feasible using modern tools without needing extra machines to keep things isolated. The downside is that it does require some discipline. Upgrading a package at the bottom of the dependency DAG can take time, even if you know it is "safe". 61 | 62 | 63 | # Building C++ 64 | 65 | 66 | ## Containers and Build Isolation 67 | 68 | Dpkg has been using isolation in the form of \`chroot\` jails basically forever. This forces software being built to not look outside a particular directory tree in the filesystem, changing the root of the filesystem. Containers such as docker take this to a greater level, providing even more isolation. Isolating the build of your system from everything else can give you fine grained control of your environment and during the build. It can be useful to build software to be deployed into an organization standard location that is separate from any other system software. For example building software systems to run in \`/opt/bb/\` with a GNU style FHS within there – \`/opt/bb/bin/\`, \`/opt/bb/etc/\`, \`/opt/bb/share\`, and so forth. This helps prevent collision, and since the only things in the container are what you choose to put there, the chances of accident are low. 69 | 70 | 71 | ## Deployment Isolation 72 | 73 | Containers also provide deployment isolation. You don't have to worry about incompatible shared object libraries from some other application or system because there are no other applications or systems in the container. However, because of the dependency problem, shared objects do not provide huge benefits. Many C++ experts prefer and recommend static linking, rather than deferring the link to runtime. 74 | 75 | 76 | # Quick automated demo 77 | 78 | Hey, Rocky! Watch me pull the rabbit out of my hat! 79 | 80 | Build and run a medium sized C++ project using docker, cmake, library export and import, then run the application in a container. 81 | 82 |
83 | Audience Takeaways: A better sense of why the C++ package ecosystem is so awful, why building C++ is so hard, and some tools and techniques for improving the situation. 84 | 85 |
86 | -------------------------------------------------------------------------------- /building-c++-reliably.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Building C++ Reliably 6 | #+DATE: <2018-10-07 Sun> 7 | #+AUTHOR: Steve Downey 8 | #+EMAIL: sdowney2@bloomberg.net 9 | #+LANGUAGE: en 10 | #+SELECT_TAGS: export 11 | #+EXCLUDE_TAGS: noexport 12 | #+CREATOR: Emacs 26.1 (Org mode 9.1.14) 13 | #+LATEX_CLASS: report 14 | #+LATEX_CLASS_OPTIONS: 15 | #+LATEX_HEADER: 16 | #+LATEX_HEADER_EXTRA: 17 | #+DESCRIPTION: 18 | #+KEYWORDS: 19 | #+SUBTITLE: 20 | #+LATEX_COMPILER: pdflatex 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:auto html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | #+CREATOR: Emacs 26.1 (Org mode 9.1.14) 35 | #+LATEX_HEADER: 36 | #+STARTUP: showeverything 37 | 38 | #+BEGIN_ABSTRACT 39 | Abstract: Building C++ is especially difficult to do reliably. Modern infrastructure and tools can help. 40 | #+END_ABSTRACT 41 | 42 | 43 | * Introduction 44 | C++ is notable among modern languages in not providing a package management system by which developers can easily install and reuse code developed by others into their own projects. It shares this with C, and for similar reasons. Until recently, source distribution was the exception, rather than the rule, and pre-compiled libraries are fragile, as they must, in general, use the exact same set of dependent libraries, compiled the same way. This largely limits reuse of packages to those provided by an OS or distro vendor. A modern Linux or BSD system may provide 1000s of such packages, however changing any of them may cause the entire system to fail. There is huge tension between Long Term Support versions and making current packages available. 45 | 46 | * Risks 47 | ** No standardised package manager 48 | Unlike tools such as node.js, python, or rust, there is no standard package manager. There isn't even a widely used one that isn't what comes with an OS. This is partly because C++ is not a single vendor system, so no vendor is in a position to standardise a solution, and also because of actual technical difficulties with shippint C++ binaries that will work. 49 | 50 | ** Library ABI is a problem -- C++ leaks across boundaries 51 | C++ libraries usually pass by value, which means that layout of an object must match exactly. Inline functions also cross between translation units, which means that even if an object is passed by reference or pointer, manipulating it requires agreement on layout. This is also true transitively, so that any type used by a library must be the same everywhere in a program. There's an official rule, the One Definition Rule, and if it is broken, there is no defined behavior, which usually means crashing. 52 | 53 | ** Dependency changes require rebuilds 54 | If anything your C++ code depends on changes, to be safe you must recompile your code, as well as all other code that depends on that. If you are library code, you now have to rebuild everything that depends on you. Package build managers like debian'a sbuild do some of this work, keeping a distro in sync. 55 | 56 | ** Replacing OS supplied packages is risky 57 | You're using system supplied packages because they are easily available and most Linux systems provide a wide range of them. But you want to upgrade one of them because you need a new feature. So you upgrade it, put it in /usr/lib and now your OS won't boot properly because some other critical component used it. The standard solution for this is install in /usr/local, but that has similar scaling issues. The more software in /usr/local, the harder it is to just swap out one library. 58 | ** Shared libraries are risky - DLLHell 59 | Shared libraries have versioning issues. It's possible to specify that a shared library is compatible with older versions, but it's very easy to get wrong. See the library ABI issues from before. 60 | 61 | * Approaches that can work 62 | ** Source Integration 63 | A common approach for smaller applications is to integrate libraries into the build of the application itself. The upside is that the library should be built consistently with your application. The downside is adapting the libraries builds into your own. Some build systems make this more straightforward than others. For cmake, for example, it may be as simple as: 64 | #+BEGIN_SRC cmake 65 | add_subdirectory(extern/googletest EXCLUDE_FROM_ALL) 66 | #+END_SRC 67 | Then googletest will be built as part of your cmake build, and the gtest and gmock targets will be available to be depended upon. 68 | This approach has scalability issues. As the number of applications grows, integrating and building each library consumes more time and effort. 69 | 70 | ** Use Stock OS Libraries 71 | Modern Linux and BSD based systems provide a huge number of libraries that can be used from the system. Adding new libraries is as simple as ~apt install libxyzzy-dev~. The downside is that you are then stuck with those versions, and upgrading the OS becomes painful because it may also mean rewriting parts of your code to match the new libraries. 72 | 73 | ** Consistent Isolated Builds 74 | Producing a consistent, if small, distro of the libraries that are used, built against each other, using the same toolchain and options, gives the most flexibility and reliability. Upgrading a package is under your control. If the promotion into the distro fails, no harm is done. Binary artifacts can be shared and reused, so individual developers don't have to waste time rebuilding everything from scratch. It is also feasible using modern tools without needing extra machines to keep things isolated. The downside is that it does require some discipline. Upgrading a package at the bottom of the dependency DAG can take time, even if you know it is "safe". 75 | 76 | * Building C++ 77 | 78 | ** Containers and Build Isolation 79 | Dpkg has been using isolation in the form of `chroot` jails basically forever. This forces software being built to not look outside a particular directory tree in the filesystem, changing the root of the filesystem. Containers such as docker take this to a greater level, providing even more isolation. Isolating the build of your system from everything else can give you fine grained control of your environment and during the build. It can be useful to build software to be deployed into an organization standard location that is separate from any other system software. For example building software systems to run in `/opt/bb/` with a GNU style FHS within there -- `/opt/bb/bin/`, `/opt/bb/etc/`, `/opt/bb/share`, and so forth. This helps prevent collision, and since the only things in the container are what you choose to put there, the chances of accident are low. 80 | 81 | ** Deployment Isolation 82 | Containers also provide deployment isolation. You don't have to worry about incompatible shared object libraries from some other application or system because there are no other applications or systems in the container. However, because of the dependency problem, shared objects do not provide huge benefits. Many C++ experts prefer and recommend static linking, rather than deferring the link to runtime. 83 | 84 | * Quick automated demo 85 | Hey, Rocky! Watch me pull the rabbit out of my hat! 86 | 87 | Build and run a medium sized C++ project using docker, cmake, library export and import, then run the application in a container. 88 | 89 | #+BEGIN_ABSTRACT 90 | Audience Takeaways: A better sense of why the C++ package ecosystem is so awful, why building C++ is so hard, and some tools and techniques for improving the situation. 91 | #+END_ABSTRACT 92 | 93 | 94 | # Local Variables: 95 | # org-html-htmlize-output-type: inline-css 96 | # End: 97 | -------------------------------------------------------------------------------- /c++20-is-design-complete.org: -------------------------------------------------------------------------------- 1 | #+options: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:t 2 | #+options: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t 3 | #+options: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+options: tasks:t tex:t timestamp:t title:t toc:t todo:t |:t 5 | #+title: c++ 20 is design complete 6 | #+date: <2019-04-25 Thu> 7 | #+author: Steve Downey 8 | #+email: sdowney@sdowney.org 9 | #+language: en 10 | #+select_tags: export 11 | #+exclude_tags: noexport 12 | #+creator: Emacs 26.1.91 (Org mode 9.2.3) 13 | #+options: html-link-use-abs-url:nil html-postamble:auto html-preamble:t 14 | #+options: html-scripts:t html-style:t html5-fancy:nil tex:t 15 | 16 | #+STARTUP: showall 17 | #+OPTIONS: reveal_center:nil reveal_progress:t reveal_history:nil reveal_control:t 18 | #+OPTIONS: reveal_rolling_links:t reveal_keyboard:t reveal_overview:t num:nil 19 | #+OPTIONS: reveal_width:1400 reveal_height:1000 20 | #+OPTIONS: toc:1 21 | 22 | #+REVEAL_MARGIN: 0.1 23 | #+REVEAL_MIN_SCALE: 0.5 24 | #+REVEAL_MAX_SCALE: 2.5 25 | #+REVEAL_TRANS: cube 26 | #+REVEAL_THEME: moon 27 | #+REVEAL_HLEVEL: 2 28 | 29 | #+REVEAL_MATHJAX_URL: https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML 30 | #+REVEAL_HIGHLIGHT_CSS: %r/lib/css/zenburn.css 31 | #+REVEAL_PLUGINS: (markdown notes) 32 | 33 | * As of the KONA meeting C++ 20 is Design Complete 34 | - All Major Features are in or out 35 | - No new features not already seen 36 | - It is big 37 | 38 | * What isn't in 39 | - Networking 40 | - Executors 41 | - Static Exception (Herbceptions) 42 | - Reflection 43 | 44 | * Core Features 45 | - Contracts 46 | - Coroutines 47 | - Concepts 48 | - Comparison, three-way 49 | - Modules 50 | - String Literals as Template Parameters 51 | - ~consteval~ 52 | - char8_t 53 | - char{N}_t is UTF-{N} 54 | 55 | * Library Features 56 | - Ranges 57 | 58 | * Contracts 59 | #+begin_src C++ 60 | int z; 61 | bool is_prime(int k); 62 | void f(int x) 63 | [[expects: x > 0]] 64 | [[expects audit: is_prime(x)]] 65 | [[ensures: z > 10]] 66 | { 67 | /* ... */ 68 | } 69 | #+end_src 70 | * Coroutines 71 | - "Stackless" : on the callers stack, not thread like 72 | - Heap allocated activation record 73 | - Transfer of control deterministic from a language point of view 74 | ** Example 75 | #+begin_src c++ 76 | namespace 77 | { 78 | cppcoro::generator range(int start, int end) 79 | { 80 | for (; start < end; ++start) 81 | { 82 | co_yield start; 83 | } 84 | } 85 | } 86 | 87 | TEST_CASE("fmap operator") 88 | { 89 | cppcoro::generator gen = range(0, 5) 90 | | cppcoro::fmap([](int x) { return x * 3; }); 91 | 92 | auto it = gen.begin(); 93 | CHECK(*it == 0); 94 | CHECK(*++it == 3); 95 | CHECK(*++it == 6); 96 | CHECK(*++it == 9); 97 | CHECK(*++it == 12); 98 | CHECK(++it == gen.end()); 99 | } 100 | 101 | #+end_src 102 | 103 | ** Example Task 104 | #+begin_src C++ 105 | cppcoro::task count_lines(std::string path) 106 | { 107 | auto file = co_await cppcoro::read_only_file::open(path); 108 | int lineCount = 0; 109 | char buffer[1024]; 110 | size_t bytesRead; 111 | std::uint64_t offset = 0; 112 | do 113 | { 114 | bytesRead = co_await file.read(offset, buffer, sizeof(buffer)); 115 | lineCount += std::count(buffer, buffer + bytesRead, '\n'); 116 | offset += bytesRead; 117 | } while (bytesRead > 0); 118 | 119 | co_return lineCount; 120 | } 121 | 122 | cppcoro::task<> usage_example() 123 | { 124 | cppcoro::task countTask = count_lines("foo.txt"); 125 | 126 | // ... 127 | 128 | // Coroutine is only started when we later co_await the task. 129 | int lineCount = co_await countTask; 130 | std::cout << "line count = " << lineCount << std::endl; 131 | } 132 | 133 | #+end_src 134 | * Concepts 135 | - boolean requirements used to constrain types 136 | - Syntax checks, not semantic checks 137 | - No checking of template instantiations 138 | - means that you can os << t even if you didn't require an ostreamable t 139 | ** Example 140 | #+begin_src C++ 141 | template 142 | concept bool Nullable = 143 | std::is_object_v && 144 | requires(T& t, const T& ct) { 145 | bool(ct); 146 | *t; 147 | *ct; 148 | }; 149 | 150 | template 151 | requires ranges::CopyConstructible 152 | class maybe_view // ... 153 | {//... 154 | }; 155 | 156 | #+end_src 157 | * Comparison, three-way 158 | The SpaceShip Operator ~<=>~ 159 | #+begin_src C++ 160 | (a <=> b) < 0 //true if a < b 161 | (a <=> b) > 0 //true if a > b 162 | (a <=> b) == 0 //true if a is equal/equivalent to b 163 | #+end_src 164 | The language can use this if you define it to derive *all* the comparison operators 165 | ** Example 166 | #+begin_src C++ 167 | struct bar 168 | { 169 | int i; 170 | std::strong_ordering operator<=>(bar const& rhs) { return i <=> rhs.i; } 171 | }; 172 | #+end_src 173 | * Modules 174 | - Nothing to do with packaging. 175 | - Probably breaks packaging. 176 | - All about controlled access to names and visibility of components 177 | 178 | - Two kinds 179 | - Header Units 180 | - macros come out 181 | - everything else does 182 | - Modules 183 | - macros do not 184 | - control of what is visible 185 | 186 | * String Literals as Template Parameters 187 | Compile Time Regular Expressions! 188 | 189 | #+begin_src C++ 190 | std::optional 191 | extract_number(std::string_view s) noexcept 192 | { 193 | if (auto m = ctre::match<"^[a-z]++([0-9]++)$">(s)) 194 | { 195 | return m.get<1>().to_view(); 196 | } else { 197 | return std::nullopt; 198 | } 199 | } 200 | #+end_src 201 | * ~consteval~ 202 | Constexpr all the things! 203 | 204 | #+begin_src c++ 205 | consteval int sqr(int n) { 206 | return n*n; 207 | } 208 | constexpr int r = sqr(100); 209 | #+end_src 210 | * char8_t 211 | A new character type which is always encoded as UTF-8 212 | 213 | * char{N}_t is UTF-{N} 214 | char16_t is UTF-16 215 | 216 | char32 is UTF-32 217 | 218 | Everyone did this, but now it's actually *Standard* 219 | 220 | * Ranges 221 | The Haskell List Monad ported to C++ (don't tell) 222 | 223 | 224 | # Local Variables: 225 | # org-html-htmlize-output-type: inline-css 226 | # End: 227 | -------------------------------------------------------------------------------- /cppcon21/algebraic-bestiary.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:3 p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Sums, Products, Exponents, Monoids, Functors, Oh My! 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2021-01-20 Wed> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | C++Con Proposal 36 | 37 | Proposal submissions due July 19 38 | 39 | Conference October 24-29 2021 40 | 41 | * Abstract 42 | This talk will outline various algebraic types and structures, such as sum product and exponential types, structures such as monoids and groups, and higher order structures such as functors and monads. In particular, we'll look at why an API designer should be aware of them and supply operations that respect these structures' laws. Doing so will help you provide predictable APIs that can be reused more widely. 43 | 44 | * IPWG Publication Checklist :noexport: 45 | 46 | ** Will any client data be used? 47 | No 48 | 49 | ** Will any proprietary data be published? 50 | No 51 | 52 | 53 | ** Will the publication expose information about our internal operations, practices, policies or security? 54 | No 55 | 56 | 57 | ** Will the publication give away any critical competitive advantage? 58 | No 59 | 60 | 61 | ** Will the publication reveal any product functionality that hasn’t yet been released? 62 | No 63 | 64 | 65 | ** Will the publication paint Bloomberg or its technology in a negative light? 66 | No 67 | 68 | 69 | ** Will the publication disparage another company and/or paint it in a negative light? 70 | No 71 | 72 | 73 | ** Will any code be published? Will the publication mention any code which has not been published? 74 | Yes. The code will be de novo for the talk, but is implemented in terms of std library components. 75 | 76 | 77 | ** Will any proprietary data be used? 78 | No 79 | 80 | 81 | ** Will the publication reveal confidential or proprietary information belonging to or pertaining to our vendors, partners, licensors, etc.? 82 | No 83 | 84 | 85 | ** Will the publication mention (in any form) any of Bloomberg's vendors or partners, or any commercial products? 86 | No 87 | 88 | 89 | ** Will any software not originating at Bloomberg be used? 90 | No 91 | 92 | 93 | ** Will any data not originating at Bloomberg be used? 94 | No 95 | 96 | * An Algebraic Bestiary 97 | Sums, Products, Exponents, Monoids, Functors, Oh My! 98 | 99 | Why Should I Care?—Or—Abstract Nonsense in Practice. 100 | 101 | 102 | * Types and Structures 103 | ** Algebraic Types 104 | Composition of Types 105 | ** Basic Structures 106 | Patterns of Operations on Types 107 | ** Categorical Structures 108 | Patterns of Composition of Operations 109 | 110 | * Algebraic Types 111 | ** Counting how many objects in a type 112 | ** Product Types 113 | Structs 114 | Pairs 115 | Tuples 116 | ** Sum Typles 117 | Unions 118 | Variants 119 | Optional/Expected 120 | ** Exponential Types 121 | Functions from A to B are B^A 122 | ** "The Same Type" 123 | *** Isomorphism 124 | Same Shape 125 | Mapping in both directions 126 | *** Normal Form is Sum of Products 127 | Types with the Same NF are Isomorphic 128 | ** Examples of Type Formulas 129 | | Type | Formula | 130 | |-----------------------------+-----------| 131 | | optional | 1 + A | 132 | | pair | A x B | 133 | | monostate | 1 | 134 | | bool | 2 | 135 | | {true, false, FileNotFound} | 3 | 136 | | struct {A a; B b}; | A x B | 137 | | A -> B | B ^ A | 138 | | union {A a; B b}; | A + B | 139 | | variant | A + B + C | 140 | | | | 141 | ** Formula Manipulation 142 | variant ==> A + A ==> 2A 143 | pair ==> 2 x A ==> 2A 144 | 145 | A tagged pair is equivalent to a variant. 146 | 147 | tuple ==> A x A x A = A ^ 3 148 | 3 -> A ==> A ^ 3 149 | a function that takes an index and returns an A is equivalent to a 3-tuple, or Array 150 | ** Recursive Types 151 | A list is either null or a value followed by a list 152 | 153 | L = 1 + AL 154 | 155 | We can expand in L 156 | 157 | L = 1 + A + AL 158 | L = 1 + A + AA + AL 159 | L = 1 + A + AA + AAA + AL 160 | 161 | So a list of A is either null or A or two A or three A and so on. 162 | 163 | ** Calculus 164 | It's been recently demonstrated that the first derivative of an algebraic type is the type of its one hole context, which is the "zipper" datatype 165 | 166 | * Types with Operation(s) 167 | These kinds of structures guide not only how operations should behave, but also inform what constructors should be provided for a type. 168 | 169 | ** Monoid 170 | ** (Abelian) Group 171 | ** SemiRing or Rig 172 | ** Field (number) 173 | 174 | * Categorical Structures 175 | Category theory studies morphisms, or arrows, largely ignoring the objects. It's concerned with how operations compose, and what structures allow us to reason about those compositions. Category theory has provided many useful results, and a lot of terrible names. 176 | 177 | Like C++ Concepts, these structures have semantic requirements that can't be derived syntactically, usually known as Laws. 178 | 179 | ** Functor 180 | 181 | *** Interface 182 | 183 | *** Laws 184 | 185 | *** C++ 186 | ** Applicative (unusual in C++) 187 | *** Interface 188 | 189 | *** Laws 190 | 191 | *** C++ 192 | ** Monad 193 | *** Interface 194 | 195 | *** Laws 196 | 197 | *** C++ 198 | ** Arrow 199 | *** Interface 200 | 201 | *** Laws 202 | 203 | *** C++ 204 | -------------------------------------------------------------------------------- /cppcon21/cofun.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:3 p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Function Suspension with Coroutines for Lazy Thunking Evaluation 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2021-01-20 Wed> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | C++Con Proposal 36 | 37 | Proposal submissions due July 19 38 | 39 | Conference October 24-29 2021 40 | 41 | * Abstract 42 | This talk will outline how to create function suspensions for lazy evaluation, how to memoize using thunking suspensions, how to use suspensions for infinite data streams, and how to write functor and monad instances for lazy functions. The coroutine nature is not required to be visible to clients of the code. In this talk, I will cover the mechanics of coroutine promises and handles. 43 | 44 | https://github.com/steve-downey/co_fun 45 | 46 | * IPWG Publication Checklist :noexport: 47 | 48 | ** Will any client data be used? 49 | No 50 | 51 | ** Will any proprietary data be published? 52 | No 53 | 54 | 55 | ** Will the publication expose information about our internal operations, practices, policies or security? 56 | No 57 | 58 | 59 | ** Will the publication give away any critical competitive advantage? 60 | No 61 | 62 | 63 | ** Will the publication reveal any product functionality that hasn’t yet been released? 64 | No 65 | 66 | 67 | ** Will the publication paint Bloomberg or its technology in a negative light? 68 | No 69 | 70 | 71 | ** Will the publication disparage another company and/or paint it in a negative light? 72 | No 73 | 74 | 75 | ** Will any code be published? Will the publication mention any code which has not been published? 76 | Yes. The code will be de novo for the talk, but is implemented in terms of std library components. 77 | 78 | 79 | ** Will any proprietary data be used? 80 | No 81 | 82 | 83 | ** Will the publication reveal confidential or proprietary information belonging to or pertaining to our vendors, partners, licensors, etc.? 84 | No 85 | 86 | 87 | ** Will the publication mention (in any form) any of Bloomberg's vendors or partners, or any commercial products? 88 | No 89 | 90 | 91 | ** Will any software not originating at Bloomberg be used? 92 | No 93 | 94 | 95 | ** Will any data not originating at Bloomberg be used? 96 | No 97 | 98 | * Super brief and not totally inaccurate summary of C++20 Coroutines 99 | ** If it co_awaits, it's a coroutine 100 | - ~co_await~ 101 | - ~co_yield~ 102 | * is a co_await 103 | - ~co_return~ 104 | * is a very special co_await 105 | 106 | ** A Coroutine's body 107 | ** Terms defined 108 | ** Awaitable and Promise 109 | **** Awaitables are easy: 110 | **** Minimal Example 111 | **** Promises are a little harder: 112 | ** Minimal Boring Coroutine 113 | * Building a lazy evaluator with coroutines 114 | ** Models a pure value 115 | ** Promise and Holder 116 | *** Manage the lifetime of the coroutine frame 117 | *** Mediate access to the returned value 118 | ** Can be used directly 119 | ** Can be used to implement a generic lazy evaluation 120 | #+begin_src C++ 121 | template 122 | auto lazy(F f, Args... args) -> Lazy> { 123 | co_return std::invoke(f, args...); 124 | } 125 | #+end_src 126 | * Extending lazy with memoization: Thunking 127 | By the time you need to think about it, it's already been thunk. 128 | ** Modeling a (const) object rather than a value 129 | ** Differences between thunk and lazy 130 | *** Shared state 131 | *** Not move-only 132 | *** evaluates to value const& rather than value&& 133 | * std::async, std::defered, shared_future, and future 134 | ** Provide similar mechanisms at greater cost 135 | * The functor and monad instances of lazy and thunk 136 | - transform 137 | - join 138 | - bind 139 | - make_lazy/thunk 140 | * Why suspend a function? 141 | The best optimization is not executing code at all 142 | ** Example: Infinite streams 143 | *** Cons cells with thunks 144 | *** Recursive work abandoned 145 | *** Appending infinities 146 | *** Avoiding revaluation, zipping streams 147 | ** Sender/Receiver [P2300] 148 | *** Explicit lazy forms 149 | -------------------------------------------------------------------------------- /cppnow/CrashCourseTitle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow/CrashCourseTitle.png -------------------------------------------------------------------------------- /cppnow/ModuleTitle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow/ModuleTitle.png -------------------------------------------------------------------------------- /cppnow/StateMachineTitle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow/StateMachineTitle.png -------------------------------------------------------------------------------- /cppnow/bbg-footer.el: -------------------------------------------------------------------------------- 1 | (setq org-re-reveal-postamble 2 | " 21 | 22 | 23 |
24 |
25 |
© 2023 Bloomberg Finance L.P. All rights reserved
26 |
27 |
28 | 29 | 30 | 42 | ") 43 | -------------------------------------------------------------------------------- /cppnow/clang-modules/Makefile: -------------------------------------------------------------------------------- 1 | client : client.o math.o 2 | clang++ -std=c++2a -stdlib=libc++ -fmodules -fprebuilt-module-path=. -fimplicit-modules *.o -o client 3 | 4 | client.o : client.cpp math.pcm 5 | clang++ -std=c++2a -stdlib=libc++ -fmodules -fprebuilt-module-path=. -fimplicit-modules -c client.cpp -o client.o 6 | 7 | math.o: math.cpp 8 | clang++ -std=c++2a -stdlib=libc++ -fmodules -fprebuilt-module-path=. -fimplicit-modules -c math.cpp -o math.o 9 | 10 | math.pcm : math.cpp 11 | clang++ -std=c++2a -stdlib=libc++ -c math.cpp -fmodules -Xclang -emit-module-interface -o math.pcm 12 | 13 | clean: 14 | rm math.o client.o math.pcm 15 | 16 | clean-gcm: 17 | rm math.pcm 18 | 19 | test: 20 | ./client 21 | 22 | all: client 23 | -------------------------------------------------------------------------------- /cppnow/clang-modules/client.cpp: -------------------------------------------------------------------------------- 1 | // client.cpp 2 | 3 | import math; 4 | import std; 5 | int main() { 6 | 7 | add(2000, 20); 8 | greeting("Steve"); 9 | } 10 | -------------------------------------------------------------------------------- /cppnow/clang-modules/math.cpp: -------------------------------------------------------------------------------- 1 | module; 2 | 3 | export module math; 4 | import std; 5 | 6 | export int add(int fir, int sec){ 7 | return fir + sec; 8 | } 9 | 10 | export void greeting(std::string_view name) { 11 | std::cout << "Hello, " << name << "!\n"; 12 | } 13 | -------------------------------------------------------------------------------- /cppnow/convert-state-machine-coroutine.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:2 p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Converting a State Machine to a C++ 20 Coroutine 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2021-01-20 Wed> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | C++Now Proposal 36 | Proposal submissions due February 14 37 | Conference May 2, 2021 - May 7, 2021 38 | * Abstract 39 | C++ 20 coroutines can naturally express in linear code components that are today written as state machines that wait on async operations. This talk walks through using the low-level machinery and customization points in C++ 20 to convert a state machine, which waits at the end of steps for async service operations to complete, into a single coroutine that `co_awaits` those operations. 40 | 41 | * IPWG :noexport: 42 | 43 | ** Will any client data be used? 44 | No 45 | 46 | ** Will any proprietary data be published? 47 | No 48 | 49 | 50 | ** Will the publication expose information about our internal operations, practices, policies or security? 51 | No 52 | 53 | 54 | ** Will the publication give away any critical competitive advantage? 55 | No 56 | 57 | 58 | ** Will the publication reveal any product functionality that hasn’t yet been released? 59 | No 60 | 61 | 62 | ** Will the publication paint Bloomberg or its technology in a negative light? 63 | No 64 | 65 | 66 | ** Will the publication disparage another company and/or paint it in a negative light? 67 | No 68 | 69 | 70 | ** Will any code be published? Will the publication mention any code which has not been published? 71 | Yes. The code will be de novo for the talk, but is likely to use existing BDE components, and to describe an async callback interface like BAS presents, without actually using BAS code. The state machine with steps is implemented in IB, but the actual code will not be used at all. 72 | 73 | 74 | 75 | ** Will any proprietary data be used? 76 | No 77 | 78 | 79 | ** Will the publication reveal confidential or proprietary information belonging to or pertaining to our vendors, partners, licensors, etc.? 80 | No 81 | 82 | 83 | ** Will the publication mention (in any form) any of Bloomberg's vendors or partners, or any commercial products? 84 | No 85 | 86 | 87 | ** Will any software not originating at Bloomberg be used? 88 | No, although cppcoro may be referenced. 89 | 90 | 91 | ** Will any data not originating at Bloomberg be used? 92 | No 93 | 94 | * The core coroutine transform is to a state machine 95 | ** The Transform 96 | ** State is maintained in the corotine frame 97 | ** `co_await` points are the states 98 | ** resumptions are transitions firing 99 | 100 | * State machines are more than regexps 101 | 102 | * A bit of theory 103 | ** UML State Diagrams 104 | ** Harel State Charts 105 | ** Model, not necessarily Code 106 | ** But is was Aliens 107 | 108 | * Most state machines are simple 109 | ** Golden Path, Error Path, Failure Path 110 | ** Rule of 5 to 9 and resorting to state machine tools 111 | ** Generality might mean `goto` 112 | ** Suspension and Decision 113 | 114 | * No std library solutions 115 | ** Handcrafting types not wrong 116 | ** Influences standardization 117 | ** Will continue to work 118 | 119 | * Code: simple multistep async operations 120 | ** Lookup user or create 121 | ** Validate request with "compliance" 122 | ** Broadcast Operation 123 | ** Return status for request 124 | ** Natural non-async code is the inverse coroutine transform 125 | ** while not done 126 | 127 | * Async Callbacks and Threads 128 | ** `void callback(void* context, void* response, void* error)` 129 | ** Context: this pointer or coroutine frame -- Yes 130 | ** Whose thread is this anyway - rescheduling 131 | ** Making an awaitable for a primitive async call 132 | 133 | * Coroutines are NOT async 134 | ** Suspension is not async 135 | ** Transfer of control is sync 136 | ** Coroutines are deterministic 137 | ** Async is external to the coroutine 138 | 139 | * Code: This looks like what you expect 140 | ** Changes to machinery 141 | ** Logic is clearer 142 | ** Writing new async state machines easier 143 | -------------------------------------------------------------------------------- /cppnow/crash-course-unicode.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:2 p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: A Crash Course in Unicode for C++ Developers 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2021-01-20 Wed> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | C++Now Proposal 36 | Proposal submissions due February 14 37 | Conference May 2, 2021 - May 7, 2021 38 | * Abstract 39 | C++ is starting to make Unicode easier to use, although it does not, yet, have standard APIs for processing Unicode text. There are a number of concepts that Unicode introduces that are important for being able to use Unicode correctly, and the concepts build on each other. This talk will give you a crash course so you can understand how unicode encodings work, what code units, code points, and grapheme clusters are, decode and encode algorithms into and out of Unicode text, what Unicode normalization does and what the various forms are for, and what the various Unicode algorithms for text processing are. This will give you the tools to understand how not to break your users text, at least not too much or often. 40 | 41 | * IPWG :noexport: 42 | 43 | ** Will any client data be used? 44 | No 45 | 46 | ** Will any proprietary data be published? 47 | No 48 | 49 | 50 | ** Will the publication expose information about our internal operations, practices, policies or security? 51 | No 52 | 53 | 54 | ** Will the publication give away any critical competitive advantage? 55 | No 56 | 57 | 58 | ** Will the publication reveal any product functionality that hasn’t yet been released? 59 | No 60 | 61 | 62 | ** Will the publication paint Bloomberg or its technology in a negative light? 63 | No 64 | 65 | 66 | ** Will the publication disparage another company and/or paint it in a negative light? 67 | No 68 | 69 | 70 | ** Will any code be published? Will the publication mention any code which has not been published? 71 | No 72 | 73 | 74 | 75 | ** Will any proprietary data be used? 76 | No 77 | 78 | 79 | ** Will the publication reveal confidential or proprietary information belonging to or pertaining to our vendors, partners, licensors, etc.? 80 | No 81 | 82 | 83 | ** Will the publication mention (in any form) any of Bloomberg's vendors or partners, or any commercial products? 84 | No 85 | 86 | 87 | ** Will any software not originating at Bloomberg be used? 88 | ICU, Boost::Text, possibly other open source projects. 89 | 90 | 91 | ** Will any data not originating at Bloomberg be used? 92 | No 93 | 94 | This talk will give you a crash course so you can understand how unicode encodings work, what code units, code points, and grapheme clusters are, decode and encode algorithms into and out of Unicode text, what Unicode normalization does and what the various forms are for, and what the various Unicode algorithms for text processing are. This will give you the tools to understand how not to break your users text, at least not too much or often. 95 | * Primum non nocere: First, Do No Harm 96 | 97 | * Encodings 98 | ** UTF-8 99 | ** UTF-16 100 | ** UTF-32 101 | ** UCS-2, UCS-4 102 | ** UTF-WTF 103 | 104 | * The Basic Parts 105 | ** Code Units 106 | ** Code Points and Scalar Values 107 | ** Grapheme Clusters, Extended Grapheme Clusters 108 | 109 | * Encodinging 110 | ** Encoders and Decoders 111 | ** UTF-8 112 | ** UTF-16BE, UTF-16LE, Byte Order Marks 113 | ** Legacy 114 | *** Single byte 115 | *** Multibyte 116 | ** Transcoding 117 | 118 | * Normalization, or there's more than one way to write that 119 | ** Canonical Equivalence and Compatible Equivalence 120 | ** Decomposed and Composed 121 | ** NFD, NFC, NFKD, NFKC 122 | ** Why Use Which 123 | ** The Algorithm 124 | ** Testing Normalization, isNFC 125 | ** Stream-safe Text Format 126 | 127 | * The Unicode Database 128 | 129 | * Algorithms 130 | ** Bidirectional 131 | ** Line Breaking 132 | ** Text Segmentation 133 | *** Grapheme Cluster Boundaries 134 | *** Word Boundaries 135 | *** Sentence Boundaries 136 | -------------------------------------------------------------------------------- /cppnow/footer.css: -------------------------------------------------------------------------------- 1 | .reveal .slides .slide-footer { 2 | position: absolute; 3 | bottom: -10em; 4 | left: 0; 5 | font-size: 0.5em; 6 | } 7 | 8 | footer 9 | { 10 | position: absolute; 11 | bottom: 0; 12 | height: 3rem; 13 | 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | 18 | /* 19 | * Use Flexbox to put the footer at the bottom of the screen if the content doesn't 20 | * push it to the bottom. 21 | */ 22 | 23 | /* Add a little margin on the left to the index */ 24 | body.index 25 | { 26 | margin-left: 2em; 27 | display: flex; 28 | flex-direction: column; 29 | } 30 | 31 | .index div.content 32 | { 33 | flex: 1 0 auto; 34 | } 35 | 36 | .index div.footer 37 | { 38 | flex-shrink: 0; 39 | } 40 | 41 | 42 | /* Copyright text in footer */ 43 | div.copyright 44 | { 45 | font-family: 'Arial Narrow', Arial, sans-serif; 46 | font-size: 1em; 47 | 48 | padding-bottom: 0.5em; 49 | 50 | text-align: start; 51 | } 52 | 53 | 54 | img.footerlogo 55 | { 56 | width: 50rem; 57 | } 58 | -------------------------------------------------------------------------------- /cppnow/fringetree/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | main : main.o fringetree.o 4 | g++ -o main $< 5 | 6 | prepend : prepend.o fringetree.o 7 | g++ -o prepend $< 8 | 9 | fringetree.t : fringetree.t.o fringetree.o 10 | g++ -o fringetree.t ./googletest/build/lib/libgtest_main.a ./googletest/build/lib/libgtest.a $< 11 | 12 | %.o: %.cpp 13 | g++ -I.. -I./googletest/googletest/include/ -fPIC -fmodules-ts -std=c++20 -o $@ -c $< 14 | 15 | main.o: gcm.cache/smd.fringtree.gcm 16 | prepend.o: gcm.cache/smd.fringtree.gcm 17 | 18 | gcm.cache/smd.fringtree.gcm: fringetree.o 19 | @test -f $@ || rm -f $< 20 | @test -f $@ || $(MAKE) $< 21 | 22 | clean: 23 | -rm -rf *.o gcm.cache/smd.fingetree.gcm 24 | 25 | clean-gcm: 26 | rm gcm.cache/* 27 | 28 | test: 29 | ./main 30 | 31 | all: main prepend 32 | 33 | .PHONY: all test clean clean-gcm 34 | -------------------------------------------------------------------------------- /cppnow/fringetree/fringetree.cpp: -------------------------------------------------------------------------------- 1 | // fringetree.cpp -*-C++-*- 2 | module; 3 | 4 | import ; 5 | import ; 6 | import ; 7 | 8 | export module smd.fringetree; 9 | 10 | export namespace fringetree { 11 | 12 | template 13 | class Branch; 14 | 15 | template 16 | class Leaf; 17 | 18 | template 19 | class Empty; 20 | 21 | template 22 | class Tree; 23 | 24 | template 25 | class Branch { 26 | Tag tag_; 27 | std::shared_ptr> left_; 28 | std::shared_ptr> right_; 29 | 30 | public: 31 | Branch() : tag_(0), left_(0), right_(0) {} 32 | Branch(Tag tag, 33 | std::shared_ptr> left, 34 | std::shared_ptr> right) 35 | : tag_(tag), left_(left), right_(right) {} 36 | auto tag() const -> Tag { return tag_; } 37 | auto left() const { return left_; } 38 | auto right() const { return right_; } 39 | }; 40 | 41 | template 42 | class Leaf { 43 | Tag tag_; 44 | Value v_; 45 | 46 | public: 47 | Leaf() : tag_(0), v_(0){}; 48 | Leaf(Tag tag, Value v) : tag_(tag), v_(v) {} 49 | auto tag() const -> Tag { return tag_; } 50 | auto value() const -> Value { return v_; } 51 | }; 52 | 53 | template 54 | class Empty { 55 | public: 56 | Empty(){}; 57 | auto tag() const -> Tag { return {}; }; 58 | }; 59 | 60 | template 61 | class Tree { 62 | public: 63 | using Tag_ = Tag; 64 | using Value_ = Value; 65 | using Leaf_ = Leaf; 66 | using Branch_ = Branch; 67 | using Empty_ = Empty; 68 | 69 | private: 70 | std::variant data_; 71 | 72 | public: 73 | Tree(Empty_ const& empty) : data_(empty) {} 74 | Tree(Leaf_ const& leaf) : data_(leaf) {} 75 | Tree(Branch_ const& branch) : data_(branch) {} 76 | 77 | auto tag() -> Tag { 78 | return std::visit([](auto&& v) { return v.tag(); }, data_); 79 | } 80 | 81 | static auto empty() -> std::shared_ptr { 82 | return std::make_shared(Empty_{}); 83 | } 84 | 85 | static auto leaf(Value const& v) -> std::shared_ptr { 86 | return std::make_shared(Leaf_{1, v}); 87 | } 88 | 89 | static auto branch(std::shared_ptr left, std::shared_ptr right) 90 | -> std::shared_ptr { 91 | return std::make_shared( 92 | Branch_{(left->tag() + right->tag()), left, right}); 93 | } 94 | 95 | template 96 | auto visit(Callable&& c) const { 97 | return std::visit(c, data_); 98 | } 99 | 100 | bool isEmpty() { return std::holds_alternative(data_); } 101 | }; 102 | 103 | constexpr auto tag = [](auto tree) { return tree->tag(); }; 104 | 105 | constexpr inline struct breadth { 106 | template 107 | auto operator()(Empty const&) const -> T { 108 | return 0; 109 | } 110 | 111 | template 112 | auto operator()(Leaf const&) const -> T { 113 | return 1; 114 | } 115 | 116 | template 117 | auto operator()(Branch const& b) const -> T { 118 | return b.left()->visit(*this) + b.right()->visit(*this); 119 | } 120 | } breadth_; 121 | 122 | constexpr auto breadth = [](auto tree) { return tree->visit(breadth_); }; 123 | 124 | constexpr inline struct depth { 125 | template 126 | auto operator()(Empty const&) const -> T { 127 | return 0; 128 | } 129 | 130 | template 131 | auto operator()(Leaf const&) const -> T { 132 | return 1; 133 | } 134 | 135 | template 136 | auto operator()(Branch const& b) const -> T { 137 | auto leftDepth = (b.left()->visit(*this)) + 1; 138 | auto rightDepth = (b.right()->visit(*this)) + 1; 139 | 140 | return (leftDepth > rightDepth) ? leftDepth : rightDepth; 141 | } 142 | } depth_; 143 | 144 | constexpr auto depth = [](auto tree) { return tree->visit(depth_); }; 145 | 146 | constexpr inline struct flatten { 147 | template 148 | auto operator()(Empty const&) const -> std::vector { 149 | return std::vector{}; 150 | } 151 | 152 | template 153 | auto operator()(Leaf const& l) const -> std::vector { 154 | std::vector v; 155 | v.emplace_back(l.value()); 156 | return v; 157 | } 158 | 159 | template 160 | auto operator()(Branch const& b) const -> std::vector { 161 | auto leftFlatten = b.left()->visit(*this); 162 | auto rightFlatten = b.right()->visit(*this); 163 | leftFlatten.insert( 164 | leftFlatten.end(), rightFlatten.begin(), rightFlatten.end()); 165 | return leftFlatten; 166 | } 167 | } flatten_; 168 | 169 | constexpr auto flatten = [](auto tree) { return tree->visit(flatten_); }; 170 | 171 | template 172 | struct printer_ { 173 | OS& os_; 174 | printer_(OS& os) : os_(os){}; 175 | 176 | template 177 | void operator()(Empty const& e) const { 178 | os_ << '"' << (&e) << '"' << '\n'; 179 | } 180 | 181 | template 182 | void operator()(Leaf const& l) const { 183 | os_ << '"' << (&l) << '"' 184 | << " [shape=record label=\" value=" << l.value() 185 | << "\\n tag=" << l.tag() << "\"]\n"; 186 | } 187 | 188 | template 189 | void operator()(Branch const& b) const { 190 | os_ << '"' << (&b) << '"' 191 | << " [shape=record label=\" | tag=" << b.tag() 192 | << "| \" ]\n"; 193 | os_ << '"' << (&b) << "\":f0 -> \"" << (b.left().get()) << "\":f1\n"; 194 | os_ << '"' << (&b) << "\":f2 -> \"" << (b.right().get()) << "\":f1\n"; 195 | (b.left()->visit(*this)); 196 | (b.right()->visit(*this)); 197 | } 198 | }; 199 | 200 | constexpr auto printer = [](auto& os, auto tree) { 201 | os << "digraph G {\n"; 202 | printer_ p(os); 203 | tree->visit(p); 204 | os << "}\n"; 205 | return; 206 | }; 207 | 208 | template 209 | class prepend_ { 210 | private: 211 | V v_; 212 | 213 | public: 214 | prepend_(V const& v) : v_(v){}; 215 | prepend_(V&& v) : v_(v){}; 216 | 217 | template 218 | auto operator()(Empty const&) const -> std::shared_ptr> { 219 | return Tree::leaf(v_); 220 | } 221 | 222 | template 223 | auto operator()(Leaf const& l) const -> std::shared_ptr> { 224 | return Tree::branch(Tree::leaf(v_), 225 | Tree::leaf(l.value())); 226 | } 227 | 228 | template 229 | auto operator()(Branch const& b) const 230 | -> std::shared_ptr> { 231 | return Tree::branch(Tree::leaf(v_), 232 | Tree::branch(b.left(), b.right())); 233 | ; 234 | } 235 | }; 236 | 237 | constexpr auto prepend = [](auto v, auto tree) { 238 | prepend_ p(v); 239 | return tree->visit(p); 240 | }; 241 | 242 | template 243 | class append_ { 244 | private: 245 | V v_; 246 | 247 | public: 248 | append_(V const& v) : v_(v){}; 249 | append_(V&& v) : v_(v){}; 250 | 251 | template 252 | auto operator()(Empty const&) const -> std::shared_ptr> { 253 | return Tree::leaf(v_); 254 | } 255 | 256 | template 257 | auto operator()(Leaf const& l) const -> std::shared_ptr> { 258 | return Tree::branch(Tree::leaf(l.value()), 259 | Tree::leaf(v_)); 260 | } 261 | 262 | template 263 | auto operator()(Branch const& b) const 264 | -> std::shared_ptr> { 265 | return Tree::branch(Tree::branch(b.left(), b.right()), 266 | Tree::leaf(v_)); 267 | ; 268 | } 269 | }; 270 | 271 | inline constexpr auto append = [](auto v, auto tree) { 272 | append_ p(v); 273 | return tree->visit(p); 274 | }; 275 | 276 | template 277 | struct View { 278 | private: 279 | struct View_ { 280 | typename Tree::Value_ v_; 281 | std::shared_ptr tree_; 282 | }; 283 | 284 | struct Nil_ {}; 285 | 286 | std::variant view_; 287 | 288 | public: 289 | View(typename Tree::Value_ const& v, std::shared_ptr t) 290 | : view_(View_{v, t}) {} 291 | 292 | View() : view_(Nil_{}) {} 293 | 294 | bool isNil() { return std::holds_alternative(view_); } 295 | 296 | bool isView() { return std::holds_alternative(view_); } 297 | 298 | auto value() { return std::get(view_).v_; } 299 | auto tree() { return std::get(view_).tree_; } 300 | }; 301 | 302 | constexpr inline struct view_l { 303 | template 304 | auto operator()(Empty const&) const -> View> { 305 | return View>{}; 306 | } 307 | 308 | template 309 | auto operator()(Leaf const& l) const -> View> { 310 | return View>{l.value(), Tree::empty()}; 311 | } 312 | 313 | template 314 | auto operator()(Branch const& b) const -> View> { 315 | if (b.left()->isEmpty() && b.right()->isEmpty()) { 316 | return View>{}; 317 | } 318 | 319 | if (b.left()->isEmpty()) { 320 | return b.right()->visit(*this); 321 | } 322 | 323 | auto r = b.left()->visit(*this); 324 | return View>{r.value(), 325 | Tree::branch(r.tree(), b.right())}; 326 | } 327 | } view_l_; 328 | 329 | constexpr auto view_l = [](auto tree) { return tree->visit(view_l_); }; 330 | 331 | constexpr inline struct view_r { 332 | template 333 | auto operator()(Empty const&) const -> View> { 334 | return View>{}; 335 | } 336 | 337 | template 338 | auto operator()(Leaf const& l) const -> View> { 339 | return View>{l.value(), Tree::empty()}; 340 | } 341 | 342 | template 343 | auto operator()(Branch const& b) const -> View> { 344 | if (b.left()->isEmpty() && b.right()->isEmpty()) { 345 | return View>{}; 346 | } 347 | 348 | if (b.right()->isEmpty()) { 349 | return b.left()->visit(*this); 350 | } 351 | 352 | auto r = b.right()->visit(*this); 353 | return View>{r.value(), 354 | Tree::branch(b.left(), r.tree())}; 355 | } 356 | } view_r_; 357 | 358 | constexpr auto view_r = [](auto tree) { return tree->visit(view_r_); }; 359 | 360 | constexpr auto head = [](auto tree) { 361 | auto view = tree->visit(view_l_); 362 | return view.value(); 363 | }; 364 | 365 | constexpr auto tail = [](auto tree) { 366 | auto view = tree->visit(view_l_); 367 | return view.tree(); 368 | }; 369 | 370 | constexpr auto last = [](auto tree) { 371 | auto view = tree->visit(view_r_); 372 | return view.value(); 373 | }; 374 | 375 | constexpr auto init = [](auto tree) { 376 | auto view = tree->visit(view_r_); 377 | return view.tree(); 378 | }; 379 | 380 | constexpr auto is_empty = [](auto tree) { 381 | auto view = tree->visit(view_r_); 382 | return view.isNil(); 383 | }; 384 | 385 | template 386 | class concat_ { 387 | private: 388 | std::shared_ptr> t_; 389 | 390 | public: 391 | concat_(std::shared_ptr> const& t) : t_(t){}; 392 | concat_(std::shared_ptr>&& t) : t_(t){}; 393 | 394 | auto operator()(Empty const&) const -> std::shared_ptr> { 395 | return t_; 396 | } 397 | 398 | auto operator()(Leaf const& leaf) const 399 | -> std::shared_ptr> { 400 | auto view = view_l_(leaf); 401 | return append(view.value(), t_); 402 | } 403 | 404 | auto operator()(Branch const& branch) const 405 | -> std::shared_ptr> { 406 | auto view = view_l_(branch); 407 | auto left = append(view.value(), t_); 408 | concat_ c(left); 409 | return view.tree()->visit(c); 410 | } 411 | }; 412 | 413 | constexpr auto concat = [](auto left, auto right) { 414 | concat_ c(left); 415 | return right->visit(c); 416 | }; 417 | 418 | // ============================================================================ 419 | // INLINE FUNCTION AND FUNCTION TEMPLATE DEFINITIONS 420 | // ============================================================================ 421 | 422 | } // namespace fringetree 423 | -------------------------------------------------------------------------------- /cppnow/fringetree/fringetree.h: -------------------------------------------------------------------------------- 1 | // fringetree.h -*-C++-*- 2 | #ifndef INCLUDED_FRINGETREE 3 | #define INCLUDED_FRINGETREE 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace fringetree { 10 | 11 | template 12 | class Branch; 13 | 14 | template 15 | class Leaf; 16 | 17 | template 18 | class Empty; 19 | 20 | template 21 | class Tree; 22 | 23 | template 24 | class Branch { 25 | Tag tag_; 26 | std::shared_ptr> left_; 27 | std::shared_ptr> right_; 28 | 29 | public: 30 | Branch() : tag_(0), left_(0), right_(0) {} 31 | Branch(Tag tag, 32 | std::shared_ptr> left, 33 | std::shared_ptr> right) 34 | : tag_(tag), left_(left), right_(right) {} 35 | auto tag() const -> Tag { return tag_; } 36 | auto left() const { return left_; } 37 | auto right() const { return right_; } 38 | }; 39 | 40 | template 41 | class Leaf { 42 | Tag tag_; 43 | Value v_; 44 | 45 | public: 46 | Leaf() : tag_(0), v_(0){}; 47 | Leaf(Tag tag, Value v) : tag_(tag), v_(v) {} 48 | auto tag() const -> Tag { return tag_; } 49 | auto value() const -> Value { return v_; } 50 | }; 51 | 52 | template 53 | class Empty { 54 | public: 55 | Empty(){}; 56 | auto tag() const -> Tag { return {}; }; 57 | }; 58 | 59 | template 60 | class Tree { 61 | public: 62 | using Tag_ = Tag; 63 | using Value_ = Value; 64 | using Leaf_ = Leaf; 65 | using Branch_ = Branch; 66 | using Empty_ = Empty; 67 | 68 | private: 69 | std::variant data_; 70 | 71 | public: 72 | Tree(Empty_ const& empty) : data_(empty) {} 73 | Tree(Leaf_ const& leaf) : data_(leaf) {} 74 | Tree(Branch_ const& branch) : data_(branch) {} 75 | 76 | auto tag() -> Tag { 77 | return std::visit([](auto&& v) { return v.tag(); }, data_); 78 | } 79 | 80 | static auto empty() -> std::shared_ptr { 81 | return std::make_shared(Empty_{}); 82 | } 83 | 84 | static auto leaf(Value const& v) -> std::shared_ptr { 85 | return std::make_shared(Leaf_{1, v}); 86 | } 87 | 88 | static auto branch(std::shared_ptr left, std::shared_ptr right) 89 | -> std::shared_ptr { 90 | return std::make_shared( 91 | Branch_{(left->tag() + right->tag()), left, right}); 92 | } 93 | 94 | template 95 | auto visit(Callable&& c) const { 96 | return std::visit(c, data_); 97 | } 98 | 99 | bool isEmpty() { return std::holds_alternative(data_); } 100 | }; 101 | 102 | constexpr auto tag = [](auto tree) { return tree->tag(); }; 103 | 104 | constexpr inline struct breadth { 105 | template 106 | auto operator()(Empty const&) const -> T { 107 | return 0; 108 | } 109 | 110 | template 111 | auto operator()(Leaf const&) const -> T { 112 | return 1; 113 | } 114 | 115 | template 116 | auto operator()(Branch const& b) const -> T { 117 | return b.left()->visit(*this) + b.right()->visit(*this); 118 | } 119 | } breadth_; 120 | 121 | constexpr auto breadth = [](auto tree) { return tree->visit(breadth_); }; 122 | 123 | constexpr inline struct depth { 124 | template 125 | auto operator()(Empty const&) const -> T { 126 | return 0; 127 | } 128 | 129 | template 130 | auto operator()(Leaf const&) const -> T { 131 | return 1; 132 | } 133 | 134 | template 135 | auto operator()(Branch const& b) const -> T { 136 | auto leftDepth = (b.left()->visit(*this)) + 1; 137 | auto rightDepth = (b.right()->visit(*this)) + 1; 138 | 139 | return (leftDepth > rightDepth) ? leftDepth : rightDepth; 140 | } 141 | } depth_; 142 | 143 | constexpr auto depth = [](auto tree) { return tree->visit(depth_); }; 144 | 145 | constexpr inline struct flatten { 146 | template 147 | auto operator()(Empty const&) const -> std::vector { 148 | return std::vector{}; 149 | } 150 | 151 | template 152 | auto operator()(Leaf const& l) const -> std::vector { 153 | std::vector v; 154 | v.emplace_back(l.value()); 155 | return v; 156 | } 157 | 158 | template 159 | auto operator()(Branch const& b) const -> std::vector { 160 | auto leftFlatten = b.left()->visit(*this); 161 | auto rightFlatten = b.right()->visit(*this); 162 | leftFlatten.insert( 163 | leftFlatten.end(), rightFlatten.begin(), rightFlatten.end()); 164 | return leftFlatten; 165 | } 166 | } flatten_; 167 | 168 | constexpr auto flatten = [](auto tree) { return tree->visit(flatten_); }; 169 | 170 | template 171 | struct printer_ { 172 | OS& os_; 173 | printer_(OS& os) : os_(os){}; 174 | 175 | template 176 | void operator()(Empty const& e) const { 177 | os_ << '"' << (&e) << '"' << '\n'; 178 | } 179 | 180 | template 181 | void operator()(Leaf const& l) const { 182 | os_ << '"' << (&l) << '"' 183 | << " [shape=record label=\" value=" << l.value() 184 | << "\\n tag=" << l.tag() << "\"]\n"; 185 | } 186 | 187 | template 188 | void operator()(Branch const& b) const { 189 | os_ << '"' << (&b) << '"' 190 | << " [shape=record label=\" | tag=" << b.tag() 191 | << "| \" ]\n"; 192 | os_ << '"' << (&b) << "\":f0 -> \"" << (b.left().get()) << "\":f1\n"; 193 | os_ << '"' << (&b) << "\":f2 -> \"" << (b.right().get()) << "\":f1\n"; 194 | (b.left()->visit(*this)); 195 | (b.right()->visit(*this)); 196 | } 197 | }; 198 | 199 | constexpr auto printer = [](auto& os, auto tree) { 200 | os << "digraph G {\n"; 201 | printer_ p(os); 202 | tree->visit(p); 203 | os << "}\n"; 204 | return; 205 | }; 206 | 207 | template 208 | class prepend_ { 209 | private: 210 | V v_; 211 | 212 | public: 213 | prepend_(V const& v) : v_(v){}; 214 | prepend_(V&& v) : v_(v){}; 215 | 216 | template 217 | auto operator()(Empty const&) const -> std::shared_ptr> { 218 | return Tree::leaf(v_); 219 | } 220 | 221 | template 222 | auto operator()(Leaf const& l) const -> std::shared_ptr> { 223 | return Tree::branch(Tree::leaf(v_), 224 | Tree::leaf(l.value())); 225 | } 226 | 227 | template 228 | auto operator()(Branch const& b) const 229 | -> std::shared_ptr> { 230 | return Tree::branch(Tree::leaf(v_), 231 | Tree::branch(b.left(), b.right())); 232 | ; 233 | } 234 | }; 235 | 236 | constexpr auto prepend = [](auto v, auto tree) { 237 | prepend_ p(v); 238 | return tree->visit(p); 239 | }; 240 | 241 | template 242 | class append_ { 243 | private: 244 | V v_; 245 | 246 | public: 247 | append_(V const& v) : v_(v){}; 248 | append_(V&& v) : v_(v){}; 249 | 250 | template 251 | auto operator()(Empty const&) const -> std::shared_ptr> { 252 | return Tree::leaf(v_); 253 | } 254 | 255 | template 256 | auto operator()(Leaf const& l) const -> std::shared_ptr> { 257 | return Tree::branch(Tree::leaf(l.value()), 258 | Tree::leaf(v_)); 259 | } 260 | 261 | template 262 | auto operator()(Branch const& b) const 263 | -> std::shared_ptr> { 264 | return Tree::branch(Tree::branch(b.left(), b.right()), 265 | Tree::leaf(v_)); 266 | ; 267 | } 268 | }; 269 | 270 | constexpr auto append = [](auto v, auto tree) { 271 | append_ p(v); 272 | return tree->visit(p); 273 | }; 274 | 275 | template 276 | struct View { 277 | private: 278 | struct View_ { 279 | typename Tree::Value_ v_; 280 | std::shared_ptr tree_; 281 | }; 282 | 283 | struct Nil_ {}; 284 | 285 | std::variant view_; 286 | 287 | public: 288 | View(typename Tree::Value_ const& v, std::shared_ptr t) 289 | : view_(View_{v, t}) {} 290 | 291 | View() : view_(Nil_{}) {} 292 | 293 | bool isNil() { return std::holds_alternative(view_); } 294 | 295 | bool isView() { return std::holds_alternative(view_); } 296 | 297 | auto value() { return std::get(view_).v_; } 298 | auto tree() { return std::get(view_).tree_; } 299 | }; 300 | 301 | constexpr inline struct view_l { 302 | template 303 | auto operator()(Empty const&) const -> View> { 304 | return View>{}; 305 | } 306 | 307 | template 308 | auto operator()(Leaf const& l) const -> View> { 309 | return View>{l.value(), Tree::empty()}; 310 | } 311 | 312 | template 313 | auto operator()(Branch const& b) const -> View> { 314 | if (b.left()->isEmpty() && b.right()->isEmpty()) { 315 | return View>{}; 316 | } 317 | 318 | if (b.left()->isEmpty()) { 319 | return b.right()->visit(*this); 320 | } 321 | 322 | auto r = b.left()->visit(*this); 323 | return View>{r.value(), 324 | Tree::branch(r.tree(), b.right())}; 325 | } 326 | } view_l_; 327 | 328 | constexpr auto view_l = [](auto tree) { return tree->visit(view_l_); }; 329 | 330 | constexpr inline struct view_r { 331 | template 332 | auto operator()(Empty const&) const -> View> { 333 | return View>{}; 334 | } 335 | 336 | template 337 | auto operator()(Leaf const& l) const -> View> { 338 | return View>{l.value(), Tree::empty()}; 339 | } 340 | 341 | template 342 | auto operator()(Branch const& b) const -> View> { 343 | if (b.left()->isEmpty() && b.right()->isEmpty()) { 344 | return View>{}; 345 | } 346 | 347 | if (b.right()->isEmpty()) { 348 | return b.left()->visit(*this); 349 | } 350 | 351 | auto r = b.right()->visit(*this); 352 | return View>{r.value(), 353 | Tree::branch(b.left(), r.tree())}; 354 | } 355 | } view_r_; 356 | 357 | constexpr auto view_r = [](auto tree) { return tree->visit(view_r_); }; 358 | 359 | constexpr auto head = [](auto tree) { 360 | auto view = tree->visit(view_l_); 361 | return view.value(); 362 | }; 363 | 364 | constexpr auto tail = [](auto tree) { 365 | auto view = tree->visit(view_l_); 366 | return view.tree(); 367 | }; 368 | 369 | constexpr auto last = [](auto tree) { 370 | auto view = tree->visit(view_r_); 371 | return view.value(); 372 | }; 373 | 374 | constexpr auto init = [](auto tree) { 375 | auto view = tree->visit(view_r_); 376 | return view.tree(); 377 | }; 378 | 379 | constexpr auto is_empty = [](auto tree) { 380 | auto view = tree->visit(view_r_); 381 | return view.isNil(); 382 | }; 383 | 384 | template 385 | class concat_ { 386 | private: 387 | std::shared_ptr> t_; 388 | 389 | public: 390 | concat_(std::shared_ptr> const& t) : t_(t){}; 391 | concat_(std::shared_ptr>&& t) : t_(t){}; 392 | 393 | auto operator()(Empty const&) const -> std::shared_ptr> { 394 | return t_; 395 | } 396 | 397 | auto operator()(Leaf const& leaf) const 398 | -> std::shared_ptr> { 399 | auto view = view_l_(leaf); 400 | return append(view.value(), t_); 401 | } 402 | 403 | auto operator()(Branch const& branch) const 404 | -> std::shared_ptr> { 405 | auto view = view_l_(branch); 406 | auto left = append(view.value(), t_); 407 | concat_ c(left); 408 | return view.tree()->visit(c); 409 | } 410 | }; 411 | 412 | constexpr auto concat = [](auto left, auto right) { 413 | concat_ c(left); 414 | return right->visit(c); 415 | }; 416 | 417 | // ============================================================================ 418 | // INLINE FUNCTION AND FUNCTION TEMPLATE DEFINITIONS 419 | // ============================================================================ 420 | 421 | } // namespace fringetree 422 | 423 | #endif 424 | -------------------------------------------------------------------------------- /cppnow/fringetree/fringetree.t.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace fringetree; 6 | 7 | TEST(TreeTest, TestGTest) { 8 | ASSERT_EQ(1, 1); 9 | } 10 | 11 | TEST(TreeTest, Breathing) { 12 | Leaf leaf; 13 | Branch branch; 14 | Tree t1{leaf}; 15 | Tree t2{branch}; 16 | 17 | int ltag = t1.tag(); 18 | int btag = t2.tag(); 19 | 20 | ASSERT_EQ(0, ltag); 21 | ASSERT_EQ(0, btag); 22 | 23 | } 24 | 25 | TEST(TreeTest, makeLeaf) { 26 | using Tree = Tree; 27 | std::shared_ptr p; 28 | auto p2 = Tree::leaf(1); 29 | 30 | ASSERT_EQ(1, p2->tag()); 31 | ASSERT_EQ(tag(p2), p2->tag()); 32 | } 33 | 34 | TEST(TreeTest, makeBranch) { 35 | using Tree = Tree; 36 | auto l1 = Tree::leaf(1); 37 | auto l2 = Tree::leaf(2); 38 | auto b1 = Tree::branch(l1, l2); 39 | ASSERT_EQ(2, b1->tag()); 40 | ASSERT_EQ(tag(b1), b1->tag()); 41 | 42 | } 43 | 44 | 45 | TEST(TreeTest, breadth) { 46 | using Tree = Tree; 47 | auto t = Tree::branch( 48 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 49 | Tree::leaf(3) 50 | ); 51 | 52 | auto i = breadth(t); 53 | ASSERT_EQ(3, i); 54 | 55 | auto empty = Tree::empty(); 56 | ASSERT_EQ(0, breadth(empty)); 57 | 58 | auto t2 = Tree::branch( 59 | Tree::branch(Tree::empty(), Tree::leaf(1)), 60 | Tree::branch(Tree::leaf(2), Tree::empty()) 61 | ); 62 | ASSERT_EQ(2, breadth(t2)); 63 | } 64 | 65 | TEST(TreeTest, depth) { 66 | using Tree = Tree; 67 | auto t = Tree::branch( 68 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 69 | Tree::leaf(3) 70 | ); 71 | 72 | auto i = depth(t); 73 | ASSERT_EQ(3, i); 74 | 75 | auto empty = Tree::empty(); 76 | ASSERT_EQ(0, depth(empty)); 77 | 78 | auto t2 = Tree::branch( 79 | Tree::branch(Tree::empty(), Tree::leaf(1)), 80 | Tree::branch(Tree::leaf(2), Tree::empty()) 81 | ); 82 | ASSERT_EQ(3, depth(t2)); 83 | } 84 | 85 | TEST(TreeTest, flatten) { 86 | using Tree = Tree; 87 | auto t = Tree::branch( 88 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 89 | Tree::leaf(3) 90 | ); 91 | 92 | std::vector expected1 = {1, 2, 3}; 93 | auto i = flatten(t); 94 | ASSERT_EQ(expected1, i); 95 | 96 | std::vector expected2 = {}; 97 | auto empty = Tree::empty(); 98 | ASSERT_EQ(expected2, flatten(empty)); 99 | 100 | std::vector expected3 = {1, 2}; 101 | auto t2 = Tree::branch( 102 | Tree::branch(Tree::empty(), Tree::leaf(1)), 103 | Tree::branch(Tree::leaf(2), Tree::empty()) 104 | ); 105 | ASSERT_EQ(expected3, flatten(t2)); 106 | } 107 | 108 | TEST(TreeTest, prepend) { 109 | using Tree = Tree; 110 | auto t = Tree::branch( 111 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 112 | Tree::leaf(3) 113 | ); 114 | 115 | auto t_ = prepend(0, t); 116 | 117 | std::vector expected1 = {0, 1, 2, 3}; 118 | auto i = flatten(t_); 119 | ASSERT_EQ(expected1, i); 120 | 121 | std::vector expected2 = {0}; 122 | auto empty = Tree::empty(); 123 | auto empty_ = prepend(0, empty); 124 | ASSERT_EQ(expected2, flatten(empty_)); 125 | 126 | std::vector expected3 = {0, 1, 2}; 127 | auto t3 = Tree::branch( 128 | Tree::branch(Tree::empty(), Tree::leaf(1)), 129 | Tree::branch(Tree::leaf(2), Tree::empty()) 130 | ); 131 | auto t3_ = prepend(0, t3); 132 | ASSERT_EQ(expected3, flatten(t3_)); 133 | 134 | 135 | auto l_ = prepend(0, Tree::leaf(1)); 136 | ASSERT_EQ(std::vector({0,1}), flatten(l_)); 137 | } 138 | 139 | TEST(TreeTest, append) { 140 | using Tree = Tree; 141 | auto t = Tree::branch( 142 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 143 | Tree::leaf(3) 144 | ); 145 | 146 | auto t_ = append(0, t); 147 | 148 | std::vector expected1 = {1, 2, 3, 0}; 149 | auto i = flatten(t_); 150 | ASSERT_EQ(expected1, i); 151 | 152 | std::vector expected2 = {0}; 153 | auto empty = Tree::empty(); 154 | auto empty_ = append(0, empty); 155 | ASSERT_EQ(expected2, flatten(empty_)); 156 | 157 | std::vector expected3 = {1, 2, 0}; 158 | auto t3 = Tree::branch( 159 | Tree::branch(Tree::empty(), Tree::leaf(1)), 160 | Tree::branch(Tree::leaf(2), Tree::empty()) 161 | ); 162 | auto t3_ = append(0, t3); 163 | ASSERT_EQ(expected3, flatten(t3_)); 164 | 165 | 166 | auto l_ = append(0, Tree::leaf(1)); 167 | ASSERT_EQ(std::vector({1,0}), flatten(l_)); 168 | } 169 | 170 | TEST(TreeTest, leftView) { 171 | using Tree = Tree; 172 | auto t = Tree::branch( 173 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 174 | Tree::leaf(3) 175 | ); 176 | 177 | auto vl = view_l(t); 178 | ASSERT_EQ(vl.isView(), true); 179 | ASSERT_EQ(vl.value(), 1); 180 | 181 | std::vector expected1 = {2, 3}; 182 | auto i = flatten(vl.tree()); 183 | ASSERT_EQ(expected1, i); 184 | 185 | auto empty = Tree::empty(); 186 | auto vl_empty = view_l(empty); 187 | ASSERT_EQ(vl_empty.isView(), false); 188 | ASSERT_EQ(vl_empty.isNil(), true); 189 | 190 | std::vector expected3 = {1, 2, 0}; 191 | auto t3 = Tree::branch( 192 | Tree::branch(Tree::empty(), Tree::leaf(1)), 193 | Tree::branch(Tree::leaf(2), Tree::empty()) 194 | ); 195 | auto vl3 = view_l(t3); 196 | ASSERT_EQ(vl3.isView(), true); 197 | ASSERT_EQ(vl3.value(), 1); 198 | 199 | auto l_ = Tree::leaf(7); 200 | auto vl4 = view_l(l_); 201 | ASSERT_EQ(vl4.isView(), true); 202 | ASSERT_EQ(vl4.value(), 7); 203 | ASSERT_EQ(vl4.tree()->isEmpty(), true); 204 | 205 | auto left = Tree::branch( 206 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 207 | Tree::leaf(3) 208 | ); 209 | auto v_left = view_l(left); 210 | ASSERT_EQ(v_left.isView(), true); 211 | auto v_v_left = view_l(v_left.tree()); 212 | ASSERT_EQ(v_v_left.isView(), true); 213 | ASSERT_EQ(v_v_left.value(), 2); 214 | 215 | std::vector expected4 = {3}; 216 | auto flat = flatten(v_v_left.tree()); 217 | ASSERT_EQ(expected4, flat); 218 | 219 | } 220 | 221 | TEST(TreeTest, rightView) { 222 | using Tree = Tree; 223 | auto t = Tree::branch( 224 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 225 | Tree::leaf(3) 226 | ); 227 | 228 | auto vr = view_r(t); 229 | ASSERT_EQ(vr.isView(), true); 230 | ASSERT_EQ(vr.value(), 3); 231 | 232 | std::vector expected1 = {1, 2}; 233 | auto i = flatten(vr.tree()); 234 | ASSERT_EQ(expected1, i); 235 | 236 | auto empty = Tree::empty(); 237 | auto vr_empty = view_r(empty); 238 | ASSERT_EQ(vr_empty.isView(), false); 239 | ASSERT_EQ(vr_empty.isNil(), true); 240 | 241 | std::vector expected3 = {1, 2, 0}; 242 | auto t3 = Tree::branch( 243 | Tree::branch(Tree::empty(), Tree::leaf(1)), 244 | Tree::branch(Tree::leaf(2), Tree::empty()) 245 | ); 246 | auto vr3 = view_r(t3); 247 | ASSERT_EQ(vr3.isView(), true); 248 | ASSERT_EQ(vr3.value(), 2); 249 | 250 | auto l_ = Tree::leaf(7); 251 | auto vr4 = view_r(l_); 252 | ASSERT_EQ(vr4.isView(), true); 253 | ASSERT_EQ(vr4.value(), 7); 254 | ASSERT_EQ(vr4.tree()->isEmpty(), true); 255 | } 256 | 257 | TEST(TreeTest, listOps) { 258 | using Tree = Tree; 259 | auto t = Tree::branch( 260 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 261 | Tree::leaf(3) 262 | ); 263 | 264 | ASSERT_EQ(head(t), 1); 265 | ASSERT_EQ(last(t), 3); 266 | 267 | std::vector expected1 = {2, 3}; 268 | ASSERT_EQ(expected1, flatten(tail(t))); 269 | 270 | std::vector expected2 = {1, 2}; 271 | ASSERT_EQ(expected2, flatten(init(t))); 272 | 273 | auto t3 = Tree::branch( 274 | Tree::branch(Tree::empty(), Tree::leaf(1)), 275 | Tree::branch(Tree::leaf(2), Tree::empty()) 276 | ); 277 | 278 | ASSERT_EQ(head(t3), 1); 279 | ASSERT_EQ(last(t3), 2); 280 | ASSERT_EQ(std::vector{2}, flatten(tail(t3))); 281 | ASSERT_EQ(std::vector{1}, flatten(init(t3))); 282 | 283 | auto l = Tree::leaf(7); 284 | ASSERT_EQ(head(l), 7); 285 | ASSERT_EQ(last(l), 7); 286 | ASSERT_EQ(std::vector{}, flatten(tail(l))); 287 | ASSERT_EQ(std::vector{}, flatten(init(l))); 288 | 289 | ASSERT_EQ(is_empty(l), false); 290 | EXPECT_EQ(is_empty(t3), false); 291 | EXPECT_EQ(is_empty(t), false); 292 | EXPECT_EQ(is_empty(Tree::empty()), true); 293 | 294 | } 295 | 296 | TEST(TreeTest, concat) { 297 | using Tree = Tree; 298 | auto left = Tree::branch( 299 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 300 | Tree::leaf(3) 301 | ); 302 | 303 | auto right = Tree::branch( 304 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 305 | Tree::leaf(3) 306 | ); 307 | 308 | auto c = concat(left, right); 309 | auto i = flatten(c); 310 | 311 | std::vector expected1 = {1, 2, 3, 1, 2, 3}; 312 | ASSERT_EQ(expected1, i); 313 | 314 | } 315 | 316 | TEST(TreeTest, measure) { 317 | using Tree = Tree; 318 | auto leaf1 = Tree::leaf(1); 319 | auto leaf2 = Tree::leaf(2); 320 | auto leaf3 = Tree::leaf(3); 321 | auto branch1 = Tree::branch(leaf1, leaf2); 322 | 323 | auto tree = Tree::branch( 324 | branch1, 325 | leaf3 326 | ); 327 | 328 | ASSERT_EQ(1, measure(leaf1)); 329 | ASSERT_EQ(1, measure(leaf2)); 330 | ASSERT_EQ(1, measure(leaf3)); 331 | ASSERT_EQ(2, measure(branch1)); 332 | ASSERT_EQ(3, measure(tree)); 333 | } 334 | -------------------------------------------------------------------------------- /cppnow/fringetree/main.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | import ; 3 | 4 | import smd.fringetree; 5 | 6 | int main(int /*argc*/, char** /*argv*/) 7 | { 8 | using namespace fringetree; 9 | 10 | using Tree = Tree; 11 | auto t = Tree::branch( 12 | Tree::branch(Tree::leaf(1), Tree::leaf(2)), 13 | Tree::leaf(3) 14 | ); 15 | 16 | // auto t1 = prepend(0, t); 17 | // auto t2 = append(4, t1); 18 | 19 | // // printer(std::cout, t_); 20 | 21 | // std::cout << "digraph G {\n"; 22 | // printer_ p(std::cout); 23 | // t->visit(p); 24 | // t1->visit(p); 25 | // t2->visit(p); 26 | // std::cout << "}\n"; 27 | 28 | // // auto left = Tree::branch( 29 | // // Tree::branch(Tree::leaf(1), Tree::leaf(2)), 30 | // // Tree::leaf(3) 31 | // // ); 32 | 33 | // // auto right = Tree::branch( 34 | // // Tree::branch(Tree::leaf(1), Tree::leaf(2)), 35 | // // Tree::leaf(3) 36 | // // ); 37 | 38 | // // auto c = concat(left, right); 39 | // // printer_ p2(std::cout); 40 | // // std::cout << "digraph G {\n"; 41 | // // left->visit(p2); 42 | // // right->visit(p2); 43 | // // c->visit(p2); 44 | // // std::cout << "}\n"; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /cppnow/fringetree/prepend.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | import smd.fringetree; 3 | 4 | #include 5 | 6 | int main(int /*argc*/, char** /*argv*/) 7 | { 8 | using namespace fringetree; 9 | 10 | using Tree = Tree; 11 | auto list = Tree::empty(); 12 | auto l1 = prepend(0, list); 13 | auto l2 = prepend(1, l1); 14 | auto l3 = prepend(2, l2); 15 | auto l4 = prepend(3, l3); 16 | auto l5 = prepend(4, l4); 17 | 18 | std::cout << "digraph G {\n"; 19 | printer_ p2(std::cout); 20 | list->visit(p2); 21 | l1->visit(p2); 22 | l2->visit(p2); 23 | l3->visit(p2); 24 | l4->visit(p2); 25 | l5->visit(p2); 26 | std::cout << "}\n"; 27 | } 28 | -------------------------------------------------------------------------------- /cppnow/modulating-a-component.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:2 p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Writing a C++ 20 Module 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2021-01-20 Wed> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | C++Now Proposal 36 | Proposal submissions due February 14 37 | Conference May 2, 2021 - May 7, 2021 38 | * Abstract 39 | This talk will walk through creating a C++ 20 module interface and the implementation of a simple data structure, a functional tree. This will cover how to control export of types and inline code, hiding an implementation, and making sure that necessary un-exported definitions are still reachable. 40 | 41 | * IPWG :noexport: 42 | 43 | ** Will any client data be used? 44 | No 45 | 46 | ** Will any proprietary data be published? 47 | No 48 | 49 | 50 | ** Will the publication expose information about our internal operations, practices, policies or security? 51 | No 52 | 53 | 54 | ** Will the publication give away any critical competitive advantage? 55 | No 56 | 57 | 58 | ** Will the publication reveal any product functionality that hasn’t yet been released? 59 | No 60 | 61 | 62 | ** Will the publication paint Bloomberg or its technology in a negative light? 63 | No 64 | 65 | 66 | ** Will the publication disparage another company and/or paint it in a negative light? 67 | No 68 | 69 | 70 | ** Will any code be published? Will the publication mention any code which has not been published? 71 | Yes. The code will be de novo for the talk, but is implemented in terms of std library components. 72 | 73 | 74 | ** Will any proprietary data be used? 75 | No 76 | 77 | 78 | ** Will the publication reveal confidential or proprietary information belonging to or pertaining to our vendors, partners, licensors, etc.? 79 | No 80 | 81 | 82 | ** Will the publication mention (in any form) any of Bloomberg's vendors or partners, or any commercial products? 83 | No 84 | 85 | 86 | ** Will any software not originating at Bloomberg be used? 87 | No 88 | 89 | 90 | ** Will any data not originating at Bloomberg be used? 91 | No 92 | 93 | 94 | * Overview of C++ 20 Modules 95 | ** Not packages - Hygene 96 | ** Module Units 97 | ** Exports 98 | ** Imports 99 | ** Private Module Fragment 100 | ** Instantiation Context 101 | ** Reachability 102 | * The component fringetree to be modulated 103 | ** Pure persistent functional tree 104 | ** Uses std::variant<>, std::shared_ptr<>, and visitors 105 | ** Exposes function objects as interface 106 | ** Is an experimental TOY 107 | * Considerations for a module 108 | ** Not new decisions, but more control 109 | ** What to export 110 | ** What NOT to export 111 | ** Exporting code for inlining 112 | ** Organization is not exposed to customers 113 | * Code 114 | ** Primary module interface 115 | *** Note that modules compose 116 | ** Module implementation unit(s) 117 | ** Module partitions to decompose large modules 118 | *** Access to names with module linkage 119 | ** Private Fragment 120 | ** The C++ Standard tries to avoid Policy 121 | * Building modules 122 | ** Your build system will not survive contact 123 | ** Must build in DAG order 124 | ** Back to the future: `makedeps` 125 | ** Packaging modules is an open question 126 | ** CMI are fragile - plan on delivering source 127 | -------------------------------------------------------------------------------- /cppnow/module-hw/Makefile: -------------------------------------------------------------------------------- 1 | main : main.o hello.o 2 | g++ -o main main.o hello.o 3 | 4 | main.o : main.cpp gcm.cache/smd.hello.gcm 5 | g++ -fPIC -fmodules-ts -std=c++20 -o main.o -c main.cpp 6 | 7 | hello.o: hello.cpp 8 | g++ -fPIC -fmodules-ts -std=c++20 -o hello.o -c hello.cpp 9 | 10 | gcm.cache/smd.hello.gcm: hello.o 11 | @test -f $@ || rm -f $< 12 | @test -f $@ || $(MAKE) $< 13 | 14 | clean: 15 | rm hello.o main.o gcm.cache/smd.hello.gcm 16 | 17 | clean-gcm: 18 | rm gcm.cache/smd.hello.gcm 19 | 20 | test: 21 | ./main 22 | 23 | all: main 24 | -------------------------------------------------------------------------------- /cppnow/module-hw/hello.cpp: -------------------------------------------------------------------------------- 1 | // hello.cpp 2 | module; 3 | import ; 4 | import ; 5 | 6 | export module smd.hello; 7 | 8 | export namespace hello { 9 | void hello(std::string_view name) 10 | { 11 | std::cout << "Hello, " << name << "! \n"; 12 | } 13 | } // namespace hello 14 | -------------------------------------------------------------------------------- /cppnow/module-hw/main.cpp: -------------------------------------------------------------------------------- 1 | // main.cxx 2 | 3 | import smd.hello; 4 | 5 | int main() 6 | { 7 | hello::hello("Steve"); 8 | } 9 | -------------------------------------------------------------------------------- /cppnow/t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow/t2.png -------------------------------------------------------------------------------- /cppnow23/.clang-format: -------------------------------------------------------------------------------- 1 | AccessModifierOffset: -2 2 | AlignAfterOpenBracket: Align 3 | AlignConsecutiveAssignments: true 4 | AlignConsecutiveDeclarations: true 5 | AlignEscapedNewlines: Left 6 | AlignOperands: true 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: All 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AlwaysBreakAfterDefinitionReturnType: None 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: false 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BinPackArguments: false 19 | BinPackParameters: false 20 | BraceWrapping: 21 | AfterClass: false 22 | AfterControlStatement: false 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterObjCDeclaration: false 27 | AfterStruct: false 28 | AfterUnion: false 29 | AfterExternBlock: false 30 | BeforeCatch: false 31 | BeforeElse: false 32 | IndentBraces: false 33 | SplitEmptyFunction: true 34 | SplitEmptyRecord: true 35 | SplitEmptyNamespace: true 36 | BreakBeforeBinaryOperators: None 37 | BreakBeforeBraces: Custom 38 | BreakBeforeInheritanceComma: false 39 | BreakBeforeTernaryOperators: true 40 | BreakConstructorInitializersBeforeComma: false 41 | BreakConstructorInitializers: BeforeColon 42 | BreakAfterJavaFieldAnnotations: false 43 | BreakStringLiterals: true 44 | ColumnLimit: 50 45 | CommentPragmas: '^ IWYU pragma:' 46 | CompactNamespaces: false 47 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 48 | ConstructorInitializerIndentWidth: 4 49 | ContinuationIndentWidth: 4 50 | Cpp11BracedListStyle: true 51 | DerivePointerAlignment: false 52 | DisableFormat: false 53 | ExperimentalAutoDetectBinPacking: false 54 | FixNamespaceComments: true 55 | ForEachMacros: 56 | - foreach 57 | - Q_FOREACH 58 | - BOOST_FOREACH 59 | IncludeBlocks: Preserve 60 | IncludeCategories: 61 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 62 | Priority: 2 63 | - Regex: '^(<|"(gtest|isl|json)/)' 64 | Priority: 3 65 | - Regex: '.*' 66 | Priority: 1 67 | IncludeIsMainRegex: '$' 68 | IndentCaseLabels: false 69 | IndentPPDirectives: None 70 | IndentWidth: 2 71 | IndentWrappedFunctionNames: false 72 | JavaScriptQuotes: Leave 73 | JavaScriptWrapImports: true 74 | KeepEmptyLinesAtTheStartOfBlocks: true 75 | MacroBlockBegin: '' 76 | MacroBlockEnd: '' 77 | MaxEmptyLinesToKeep: 1 78 | NamespaceIndentation: None 79 | ObjCBinPackProtocolList: Auto 80 | ObjCBlockIndentWidth: 4 81 | ObjCSpaceAfterProperty: false 82 | ObjCSpaceBeforeProtocolList: true 83 | PenaltyBreakAssignment: 2 84 | PenaltyBreakBeforeFirstCallParameter: 19 85 | PenaltyBreakComment: 300 86 | PenaltyBreakFirstLessLess: 120 87 | PenaltyBreakString: 1000 88 | PenaltyBreakTemplateDeclaration: 10 89 | PenaltyExcessCharacter: 1000000 90 | PenaltyReturnTypeOnItsOwnLine: 60 91 | PointerAlignment: Left 92 | ReflowComments: true 93 | SortIncludes: false 94 | SortUsingDeclarations: true 95 | SpaceAfterCStyleCast: false 96 | SpaceAfterTemplateKeyword: true 97 | SpaceBeforeAssignmentOperators: true 98 | SpaceBeforeCtorInitializerColon: true 99 | SpaceBeforeInheritanceColon: true 100 | SpaceBeforeParens: ControlStatements 101 | SpaceBeforeRangeBasedForLoopColon: true 102 | SpaceInEmptyParentheses: false 103 | SpacesBeforeTrailingComments: 1 104 | SpacesInAngles: false 105 | SpacesInContainerLiterals: true 106 | SpacesInCStyleCastParentheses: false 107 | SpacesInParentheses: false 108 | SpacesInSquareBrackets: false 109 | Standard: Auto 110 | TabWidth: 8 111 | UseTab: Never 112 | 113 | --- 114 | Language: Cpp 115 | 116 | --- 117 | Language: ObjC 118 | 119 | ... 120 | -------------------------------------------------------------------------------- /cppnow23/async_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow23/async_title.png -------------------------------------------------------------------------------- /cppnow23/footer.css: -------------------------------------------------------------------------------- 1 | .reveal .slides .slide-footer { 2 | position: absolute; 3 | bottom: -10em; 4 | left: 0; 5 | font-size: 0.25em; 6 | } 7 | 8 | footer 9 | { 10 | position: absolute; 11 | bottom: 0; 12 | height: 3rem; 13 | 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | 18 | /* 19 | * Use Flexbox to put the footer at the bottom of the screen if the content doesn't 20 | * push it to the bottom. 21 | */ 22 | 23 | /* Add a little margin on the left to the index */ 24 | body.index 25 | { 26 | margin-left: 2em; 27 | display: flex; 28 | flex-direction: column; 29 | } 30 | 31 | .index div.content 32 | { 33 | flex: 1 0 auto; 34 | } 35 | 36 | .index div.footer 37 | { 38 | flex-shrink: 0; 39 | } 40 | 41 | 42 | /* Copyright text in footer */ 43 | div.copyright 44 | { 45 | font-family: 'Arial Narrow', Arial, sans-serif; 46 | font-size: 0.5em; 47 | 48 | padding-bottom: 0.5em; 49 | 50 | text-align: start; 51 | } 52 | 53 | 54 | img.footerlogo 55 | { 56 | width: 50rem; 57 | } 58 | -------------------------------------------------------------------------------- /cppnow23/images/just.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow23/images/just.png -------------------------------------------------------------------------------- /cppnow23/images/let_value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow23/images/let_value.png -------------------------------------------------------------------------------- /cppnow23/images/sender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow23/images/sender.png -------------------------------------------------------------------------------- /cppnow23/images/then.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steve-downey/papers/30a6ec791f92e956e5fdf7eda83df21e0f8b8dbf/cppnow23/images/then.png -------------------------------------------------------------------------------- /cppnow23/my_theme.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Based on 3 | * Solarized Light theme for reveal.js. 4 | * Author: Achim Staebler 5 | */ 6 | @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700,400italic,700italic); 7 | @import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic); 8 | @import url(https://fonts.googleapis.com/css?family=Noto+Sans:400,700,400italic,700italic); 9 | /** 10 | * Solarized colors by Ethan Schoonover 11 | */ 12 | html * { 13 | color-profile: sRGB; 14 | rendering-intent: auto; 15 | } 16 | 17 | /********************************************* 18 | * GLOBAL STYLES 19 | *********************************************/ 20 | :root { 21 | --r-background-color: #fbf7f0; 22 | --r-main-font: Source Sans Pro, sans-serif; 23 | --r-main-font-size: 40px; 24 | --r-main-color: #000000; 25 | --r-block-margin: 20px; 26 | --r-heading-margin: 0 0 20px 0; 27 | --r-heading-font: Source Sans Pro, sans-serif; 28 | --r-heading-color: #000000; 29 | --r-heading-line-height: 1.2; 30 | --r-heading-letter-spacing: normal; 31 | --r-heading-text-transform: uppercase; 32 | --r-heading-text-shadow: none; 33 | --r-heading-font-weight: bold; 34 | --r-heading1-text-shadow: none; 35 | --r-heading1-size: 3.77em; 36 | --r-heading2-size: 2.11em; 37 | --r-heading3-size: 1.55em; 38 | --r-heading4-size: 1em; 39 | --r-code-font: Source Code Pro, monospace; 40 | --r-link-color: #3548cf; 41 | --r-link-color-dark: #1a6091; 42 | --r-link-color-hover: #78b9e6; 43 | --r-selection-background-color: #d33682; 44 | --r-selection-color: #fff; 45 | } 46 | 47 | .reveal-viewport { 48 | background: #fdf6e3; 49 | background-color: var(--r-background-color); 50 | } 51 | 52 | .reveal { 53 | font-family: var(--r-main-font); 54 | font-size: var(--r-main-font-size); 55 | font-weight: normal; 56 | color: var(--r-main-color); 57 | } 58 | 59 | .reveal ::selection { 60 | color: var(--r-selection-color); 61 | background: var(--r-selection-background-color); 62 | text-shadow: none; 63 | } 64 | 65 | .reveal ::-moz-selection { 66 | color: var(--r-selection-color); 67 | background: var(--r-selection-background-color); 68 | text-shadow: none; 69 | } 70 | 71 | .reveal .slides section, 72 | .reveal .slides section > section { 73 | line-height: 1.3; 74 | font-weight: inherit; 75 | } 76 | 77 | /********************************************* 78 | * HEADERS 79 | *********************************************/ 80 | .reveal h1, 81 | .reveal h2, 82 | .reveal h3, 83 | .reveal h4, 84 | .reveal h5, 85 | .reveal h6 { 86 | margin: var(--r-heading-margin); 87 | color: var(--r-heading-color); 88 | font-family: var(--r-heading-font); 89 | font-weight: var(--r-heading-font-weight); 90 | line-height: var(--r-heading-line-height); 91 | letter-spacing: var(--r-heading-letter-spacing); 92 | text-transform: var(--r-heading-text-transform); 93 | text-shadow: var(--r-heading-text-shadow); 94 | word-wrap: break-word; 95 | } 96 | 97 | .reveal h1 { 98 | font-size: var(--r-heading1-size); 99 | } 100 | 101 | .reveal h2 { 102 | font-size: var(--r-heading2-size); 103 | } 104 | 105 | .reveal h3 { 106 | font-size: var(--r-heading3-size); 107 | } 108 | 109 | .reveal h4 { 110 | font-size: var(--r-heading4-size); 111 | } 112 | 113 | .reveal h1 { 114 | text-shadow: var(--r-heading1-text-shadow); 115 | } 116 | 117 | /********************************************* 118 | * OTHER 119 | *********************************************/ 120 | .reveal p { 121 | margin: var(--r-block-margin) 0; 122 | line-height: 1.3; 123 | } 124 | 125 | /* Remove trailing margins after titles */ 126 | .reveal h1:last-child, 127 | .reveal h2:last-child, 128 | .reveal h3:last-child, 129 | .reveal h4:last-child, 130 | .reveal h5:last-child, 131 | .reveal h6:last-child { 132 | margin-bottom: 0; 133 | } 134 | 135 | /* Ensure certain elements are never larger than the slide itself */ 136 | .reveal img, 137 | .reveal video, 138 | .reveal iframe { 139 | max-width: 95%; 140 | max-height: 95%; 141 | } 142 | 143 | .reveal strong, 144 | .reveal b { 145 | font-weight: bold; 146 | } 147 | 148 | .reveal em { 149 | font-style: italic; 150 | } 151 | 152 | .reveal ol, 153 | .reveal dl, 154 | .reveal ul { 155 | display: inline-block; 156 | text-align: left; 157 | margin: 0 0 0 1em; 158 | } 159 | 160 | .reveal ol { 161 | list-style-type: decimal; 162 | } 163 | 164 | .reveal ul { 165 | list-style-type: disc; 166 | } 167 | 168 | .reveal ul ul { 169 | list-style-type: square; 170 | } 171 | 172 | .reveal ul ul ul { 173 | list-style-type: circle; 174 | } 175 | 176 | .reveal ul ul, 177 | .reveal ul ol, 178 | .reveal ol ol, 179 | .reveal ol ul { 180 | display: block; 181 | margin-left: 40px; 182 | } 183 | 184 | .reveal dt { 185 | font-weight: bold; 186 | } 187 | 188 | .reveal dd { 189 | margin-left: 40px; 190 | } 191 | 192 | .reveal blockquote { 193 | display: block; 194 | position: relative; 195 | width: 70%; 196 | margin: var(--r-block-margin) auto; 197 | padding: 5px; 198 | font-style: italic; 199 | background: rgba(255, 255, 255, 0.05); 200 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); 201 | } 202 | 203 | .reveal blockquote p:first-child, 204 | .reveal blockquote p:last-child { 205 | display: inline-block; 206 | } 207 | 208 | .reveal q { 209 | font-style: italic; 210 | } 211 | 212 | .reveal pre { 213 | display: block; 214 | position: relative; 215 | width: 90%; 216 | margin: var(--r-block-margin) auto; 217 | text-align: left; 218 | font-size: 0.55em; 219 | font-family: var(--r-code-font); 220 | line-height: 1.2em; 221 | word-wrap: break-word; 222 | box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); 223 | } 224 | 225 | .reveal code { 226 | font-family: var(--r-code-font); 227 | text-transform: none; 228 | tab-size: 2; 229 | } 230 | 231 | .reveal pre code { 232 | display: block; 233 | padding: 5px; 234 | overflow: auto; 235 | max-height: 400px; 236 | word-wrap: normal; 237 | } 238 | 239 | .reveal .code-wrapper { 240 | white-space: normal; 241 | } 242 | 243 | .reveal .code-wrapper code { 244 | white-space: pre; 245 | } 246 | 247 | .reveal table { 248 | margin: auto; 249 | border-collapse: collapse; 250 | border-spacing: 0; 251 | } 252 | 253 | .reveal table th { 254 | font-weight: bold; 255 | } 256 | 257 | .reveal table th, 258 | .reveal table td { 259 | text-align: left; 260 | padding: 0.2em 0.5em 0.2em 0.5em; 261 | border-bottom: 1px solid; 262 | } 263 | 264 | .reveal table th[align=center], 265 | .reveal table td[align=center] { 266 | text-align: center; 267 | } 268 | 269 | .reveal table th[align=right], 270 | .reveal table td[align=right] { 271 | text-align: right; 272 | } 273 | 274 | .reveal table tbody tr:last-child th, 275 | .reveal table tbody tr:last-child td { 276 | border-bottom: none; 277 | } 278 | 279 | .reveal sup { 280 | vertical-align: super; 281 | font-size: smaller; 282 | } 283 | 284 | .reveal sub { 285 | vertical-align: sub; 286 | font-size: smaller; 287 | } 288 | 289 | .reveal small { 290 | display: inline-block; 291 | font-size: 0.6em; 292 | line-height: 1.2em; 293 | vertical-align: top; 294 | } 295 | 296 | .reveal small * { 297 | vertical-align: top; 298 | } 299 | 300 | .reveal img { 301 | margin: var(--r-block-margin) 0; 302 | } 303 | 304 | /********************************************* 305 | * LINKS 306 | *********************************************/ 307 | .reveal a { 308 | color: var(--r-link-color); 309 | text-decoration: none; 310 | transition: color 0.15s ease; 311 | } 312 | 313 | .reveal a:hover { 314 | color: var(--r-link-color-hover); 315 | text-shadow: none; 316 | border: none; 317 | } 318 | 319 | .reveal .roll span:after { 320 | color: #fff; 321 | background: var(--r-link-color-dark); 322 | } 323 | 324 | /********************************************* 325 | * Frame helper 326 | *********************************************/ 327 | .reveal .r-frame { 328 | border: 4px solid var(--r-main-color); 329 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 330 | } 331 | 332 | .reveal a .r-frame { 333 | transition: all 0.15s linear; 334 | } 335 | 336 | .reveal a:hover .r-frame { 337 | border-color: var(--r-link-color); 338 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); 339 | } 340 | 341 | /********************************************* 342 | * NAVIGATION CONTROLS 343 | *********************************************/ 344 | .reveal .controls { 345 | color: var(--r-link-color); 346 | } 347 | 348 | /********************************************* 349 | * PROGRESS BAR 350 | *********************************************/ 351 | .reveal .progress { 352 | background: rgba(0, 0, 0, 0.2); 353 | color: var(--r-link-color); 354 | } 355 | 356 | /********************************************* 357 | * PRINT BACKGROUND 358 | *********************************************/ 359 | @media print { 360 | .backgrounds { 361 | background-color: var(--r-background-color); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /empty-product-ranges.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:2 p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Empty Product for certain Views 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2022-02-06 Sun> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | 36 | - Document number: P2540R1 37 | - Date: {{{date(%Y-%m-%d)}}} 38 | - Author: Steve Downey , 39 | - Audience: SG9, LEWG 40 | 41 | #+BEGIN_ABSTRACT 42 | Abstract: This paper argues that the Cartesian product of no ranges should be a single empty tuple, which is the identity element for Cartesian products. Other product-like views, however, should not automatically have their identity be the result, and in particular for ~zip~, as it would introduce unsound inconsistencies. 43 | #+END_ABSTRACT 44 | 45 | 46 | 47 | * Motivation 48 | A natural extension of a product of two things is to a product of $n$ things, that is from $P = A \times B$ to $P = \prod_{i=1}^n a_i = a_1 \cdots a_n$, where the $\prod$ symbol stands for a repeated product, the same way that $\sum$ stands for a repeated sum. 49 | For $n=1$, the expansion immediately suggests that $P=a_1$, but the $n=0$ case requires more care. 50 | From the general rule that $P_n a_{n+1}=P_{n+1}$, we have that $P_0 a_1=a_1$, so $P_0$ is the identity for the product. 51 | This convention simplifies induction arguments and sometimes improves consistency with other well defined operations. 52 | For example, having $0^{0} = 1$, just as $n^{0} = 1$ for all non-zero numbers, greatly simplifies Taylor series notation. 53 | 54 | Also note that we are assuming up to isomorphism for types, and in particular that $(a, b, c)$ is isomorphic to $((a, b), c)$, and $(a, (b, c))$, and further that the unit type $()$ does not contribute, so that $((), a) \equiv (a) \equiv (a, ())$. That is there exists a simple and mechanical bijective mapping, one-to-one and onto, between the types. 55 | 56 | Making the empty product the identity element also puts ~fold0~ on a sounder footing. We don't have to supply an identity element because the base case gives it to us automatically. 57 | 58 | The Cartesian product can also be viewed as the union of all relations between sets. 59 | Any subset of the Cartesian product is a relation among the sets. 60 | For any number of sets, there are always the trivial relations of $\top$ (every combination is in the relation) and $\bot$ (the relation is empty). 61 | With zero sets, those are the only two relations, since there is no input variation on which the value might depend. 62 | Accordingly, the Cartesian product of zero sets must have exactly one element (which is the empty tuple $()$) so as to have exactly the empty set and the whole set as relations. 63 | 64 | The most general definition of product comes from Category Theory, of course, where it is well studied. And an important result is that for a Category, such as sets, there is one universal operation that is the product. This should make us suspicious of extending the empty product \equiv identity rule to other operations. 65 | 66 | In particular, ~zip~ has the property that it is the inner join of the indexed sets, and is the main diagonal of the Cartesian product. However, the identity element for ~zip~ is ~repeat(tuple<>)~, the infinite range of repeated empty tuples. If we allowed ~zip~ of an empty range of ranges to be its identity element, we would be introducing an inconsistency into the system, where two different formulations of notionally the same thing produces different answers. That would be bad. 67 | 68 | 69 | * Proposal 70 | Specify that the Cartesian product of an empty range of ranges is a range of one element, which is the empty tuple, ~std::tuple<>~. The type ~std::tuple<>~ is a monostate type, consisting of one element. 71 | This design should *not* be extended to zip. If it were to be defined, the zip of an empty range of ranges should be the diagonal of the Cartesian product, but this is not actually useful, since that is annihilating for ~zip~. It should be left undefined, as most operations on empty ranges are. 72 | 73 | 74 | * Wording 75 | Wording is relative to p2374r3 76 | 77 | ** Overview [range.cartesian.overview] 78 | ~cartesian_product_view~ presents a view with a value type that represents the cartesian product of the adapted ranges. 79 | 80 | The name ~views::cartesian_product~ denotes a customization point object. Given a pack of subexpressions ~Es...~, the expression ~views::cartesian_product(Es...)~ is expression-equivalent to 81 | 82 | - [[delete:][*decay-copy*(views::empty>)]][[insert:][views::single(tuple())]] if Es is an empty pack, 83 | - otherwise, cartesian_product_view...>(Es...). 84 | 85 | 86 | 87 | * References 88 | 89 | Reflector Discussion: [isocpp-lib-ext] zip and cartesian_product base case 90 | https://lists.isocpp.org/lib-ext/2022/01/22023.php 91 | 92 | Twitter: https://twitter.com/sdowney/status/1482469504248598532 and ff 93 | 94 | Empty product - Wikipedia: https://en.wikipedia.org/wiki/Empty_product 95 | 96 | [P2374R3] Sy Brand, Michał Dominiak. 2021-12-13. views::cartesian_product 97 | https://wg21.link/p2374r3 98 | 99 | # Local Variables: 100 | # org-html-htmlize-output-type: inline-css 101 | # End: 102 | 103 | # LocalWords: Downey cardinality 104 | -------------------------------------------------------------------------------- /ewgi-20191418.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:t todo:t |:t 5 | #+TITLE: ewgi-20191418 6 | #+DATE: <2019-02-18 Mon> 7 | #+AUTHOR: Steve Downey 8 | #+EMAIL: sdowney@sdowney.org 9 | #+LANGUAGE: en 10 | #+SELECT_TAGS: export 11 | #+EXCLUDE_TAGS: noexport 12 | #+CREATOR: Emacs 26.1.91 (Org mode 9.2.1) 13 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:auto html-preamble:t 14 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 15 | #+HTML_DOCTYPE: xhtml-strict 16 | #+HTML_CONTAINER: div 17 | #+DESCRIPTION: 18 | #+KEYWORDS: 19 | #+HTML_LINK_HOME: 20 | #+HTML_LINK_UP: 21 | #+HTML_MATHJAX: 22 | #+HTML_HEAD: 23 | #+HTML_HEAD_EXTRA: 24 | #+SUBTITLE: 25 | #+INFOJS_OPT: 26 | #+CREATOR:
Emacs 26.1.91 (Org mode 9.2.1) 27 | #+LATEX_HEADER: 28 | 29 | <2019-02-18 Mon> 30 | 31 | 32 | P1170 : Overload sets as function parameters 33 | 34 | std::overload_set is magic 35 | -------------------------------------------------------------------------------- /humans-bad-components.md: -------------------------------------------------------------------------------- 1 |
2 | Abstract: Humans are necessary for all useful systems, but nonetheless make terrible System components. It is important to keep in mind when designing, constructing and maintaining systems that the System will attempt to use people in ways that may range from ineffective to unpleasant or hostile, or there may be unplanned and unintended consequences for the people using or interacting with the System. Understanding that Systems are chaotic, emergent and fractal is key for building Systems that humans can both live with and within. As engineers we have an ethical duty to consider how the systems we build will use the humans using our systems. 3 | 4 |
5 | 6 | System (noun): A set of things working together as parts of a mechanism or an interconnecting network; a complex whole. In particular, a set of things working together as parts of a mechanism or an interconnecting network. 7 | 8 | Systems aren't new, but automation and advances in computation have made building increasingly larger systems increasingly feasible. Outsourcing the adminsitration of systems to computers can make systems cheaper, more reliable and more efficient. All of those can occasionally be problems instead of benefits, as we will see. 9 | 10 | Two initial points as background for the discussion to follow: 11 | 12 | # We make systems for things we are not good at 13 | 14 | We build systems to compensate for things humans don't do well enough, fast enough or reliably enough. We rarely create systems for things we naturally do well. We don't generally create systems to help us breath. We frequently create systems to help us organize ourselves. Because the system's design goal is to help humans do things they are not good at, humans often find systems uncomfortable, particularly when they have no choice about adopting or using the system. 15 | 16 | 17 | # The System has its own goals 18 | 19 | Systems will exhibit behaviors and goals other than the ones they were designed for. A usual primary goal is the system's continued existence and expansion, because without that, systems are replaced or consumed by other systems that do have that goal. Budget systems, nominally put in place to make sure company resources are spent in line with company goals, often end up not doing that at all. Instead, they reflect the status of the people or groups involved; capital allocations are given to high prestige groups rather than to groups that could make better use of funding. This is often taken for granted as part of the political system of an organization, even if everyone agrees that the process *should* run as stated. Some will even claim that the system is actually doing what its stated purpose is, when it manifestly is not. This is generally true. 20 | 21 | 22 | # Parkinson's first law: Systems grow 23 | 24 | C. Northcote Parkinson observed 1that the staffing of the British Navy continued to grow after World War II, even though the actual number of ships declined. While he attributed much of it to human nature in a bureaucracy, it was later observed to be true for almost all systems. Existing systems will be given wider scopes, additional functions, and generally be added to, or they will be consumed and replaced by other systems that have those system goals. James Werner Zawinksi (aka jwz) coined the *Law of Software Envelopment*: "Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can." 2 25 | 26 | 27 | # Gall's observation: Systems Fail, always and constantly 28 | 29 | Complex systems are usually in a failure mode. Working systems will compensate for that. When something fails visibly, it is often the result of 5 or 6 overlapping failures. What is not often recognized is that, at any given time, 2 or 3 parts of the system have failed, and the overall system has worked around the problem. When investigating a bug, it is not uncommon to find code that quite literally never worked. Fixing that code then causes failures, where the rest of the system was working around the defect. Human users of a system take into account the peculiarities of a system and will avoid problems, sometimes long after the problem is gone, and they will resist changes to their patterns even when they may be an overall improvement. 3 30 | 31 | 32 | # System Design: Systems run better when designed to run downhill 33 | 34 | Pulling generally works better than pushing. Take into account how humans behave. If you are trying to effect change with a system, you want the forces your system produces to move people in ways they will continue to move. Pushing uphill often leads to rolling back and being in a worse position that when the system was put in place. Pushing developers to write tests doesn't work as well as changing to a test-driven developement system, where programmers are rewarded quickly by succeeding at the game of making tests pass. However, it's often some work to move from one locally stable point - a local minima - to a new, and better, stable point. You have to get over a small hill before getting to the downhill part. 35 | 36 | 37 | # Efficient Systems are Dangerous, Loose systems last longer and work better 38 | 39 | Efficient systems, with little slack, will fail much more catestrophically than loose systems do. Calendaring software often efficiently books meetings and rooms with no slack. This results in back-to-back-to-back meetings in far apart locations. As a result, enough participants are late that all of the efficiency is lost. The system actually works against itself. Sometimes there are "solutions" proposed involving punishing the participants in various ways, leading to further efficiency problems. Postel's Law, "Be conservative in what you do, be liberal in what you accept from others" (RFC 793)4 is a maxim about making sure there is looseness in a system. The coupling between components is forgiving of error and strives to not stress weaker links in the system. 40 | 41 | 42 | # Programming is a Human activity. Account for the Programmers 43 | 44 | Since systems always continue growing, they are never complete. A class of humans often ignored in the system are the programmers who continue to fix, maintain, debug, and extend the system. The needs of programmers are even ignored by other programmers. We do things to ourselves that we would never accept on behalf of users of our systems. System deployment instructions will be on a web page with 16 steps, 3 of which no longer apply, and one of which may be destructive, but insiders will nonetheless say the process is simple. Being somewhat proud of the number of people affected by an outage, or the frequency of overnight problems, and using that as a proxy for the importance of the sysytem, and neglecting to actually fix the underlying issues causing the outages. Development builds that require more than one- or two-word commands. Tests that are never run, don't work, and may never have worked beyond the first developer's desk. Extreme difficulty in bringing up a full system in an observable and debuggable state so that production problems can be reproduced. Code in the system that no one understands anymore and lives in fear of disturbing. 45 | 46 | The entire development process is a system that lives within the larger system being provided. It mush be recognized that problems in the development system are problems for the system as a whole, and it is not selfish for programmers to insist that their system is important. 47 | 48 |
49 | Audience Takeaways: The audience will have a better understanding of how Systems tend to grow and behave outside of our control or design. With greater awareness, they will now be in a position to counteract those tendencies whenever possible and necessary. Don't take the System for granted and be prepared to work to change it. Try to avoid what Dan Luu called the "normalization of deviance"5, accepting signals that there is a problem with the system as normal, even, or especially, if you know why the deviation from normal was done. Maintain awareness of the people you are affecting with your systems. 50 | 51 |
52 | 53 | ## Footnotes 54 | 55 | 1 Parkinson, Cyril Northcote (19 November 1955), ["Parkinson's Law"](http://www.economist.com/businessfinance/management/displaystory.cfm?story_id=14116121), The Economist. 56 | 57 | 2 [Law of Software Envelopment](https://www.jwz.org/hacks) 58 | 59 | 3 Gall, John. The Systems Bible: The Beginner's Guide to Systems Large and Small (Third Edition of SYSTEMANTICS), General Systemantics Press/Liberty, 2003. ISBN 0-9618251-7-0. 60 | 61 | 4 [TRANSMISSION CONTROL PROTOCOL](https://tools.ietf.org/html/rfc793) 62 | 63 | 5 [Dan Luu, Normalization of Deviance](https://danluu.com/wat/) 64 | -------------------------------------------------------------------------------- /humans-bad-components.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Human Beings are not good System Components 6 | #+DATE: <2018-10-07 Sun> 7 | #+AUTHOR: Steve Downey 8 | #+EMAIL: sdowney2@bloomberg.net 9 | #+LANGUAGE: en 10 | #+SELECT_TAGS: export 11 | #+EXCLUDE_TAGS: noexport 12 | #+CREATOR: Emacs 26.1 (Org mode 9.1.14) 13 | #+LATEX_CLASS: report 14 | #+LATEX_CLASS_OPTIONS: 15 | #+LATEX_HEADER: 16 | #+LATEX_HEADER_EXTRA: 17 | #+DESCRIPTION: 18 | #+KEYWORDS: 19 | #+SUBTITLE: 20 | #+LATEX_COMPILER: pdflatex 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:auto html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | #+CREATOR: Emacs 26.1 (Org mode 9.1.14) 35 | #+LATEX_HEADER: 36 | #+STARTUP: showeverything 37 | 38 | Abstract: Humans are necessary for all useful systems, but nonetheless make terrible system components. It is important in designing, constructing, and maintaining systems to keep in mind that the System will attempt to use people in ways that may range from ineffective to unpleasant or hostile, or with unplanned and unintended consequences to the people using or interacting with the System. Understanding that Systems are chaotic, emergent, and fractal, is key for building Systems that humans can live with and within. 39 | 40 | System n. : A set of things working together as parts of a mechanism or an interconnecting network; a complex whole. In particular a set of things working together as parts of a mechanism or an interconnecting network. 41 | 42 | Systems aren't new, but automation and advances in computation have made building larger and larger systems increasingly feasible. Outsourcing adminsitration of systems to computers can make systems cheaper, more reliable, and more efficient. All of those can occasionally be problems instead of benefit, as we will see. 43 | 44 | Humans are necessary for all useful systems, but nonetheless make terrible system components. It is important in designing, constructing, and maintaining systems to keep in mind that the System will attempt to use people in ways that may range from ineffective to unpleasant or hostile, or with unplanned and unintended consequences to the people using or interacting with the System. Understanding that Systems are chaotic, emergent, and fractal, is key for building Systems that humans can live with and within. As engineers we have an ethical duty to consider how the systems we build will use the humans using our systems. 45 | 46 | Two initial points as background for the discussion to follow: 47 | 48 | * We make systems for things we are not good at 49 | We build systems to compensate for things human being don't do well enough; either not fast enough or not reliably enough. We rarely create systems for things we naturally do well. We don't generally create systems to help us breath. We frequently create systems to help us organize ourselves. Because the system's design goal is to make humans do things they are not good at, humans often find systems uncomfortable, particularly when they have no choice about adoption or use of a system. 50 | 51 | * The System has its own goals 52 | Systems will exhibit behaviors and goals other than the ones they were designed for. A primary goal is usually the systems continued existence and expansion, because systems without that are replaced or consumed by systems that do have that as a goal. Budget systems, nominally put in place to make sure company resources are spent in line with company goals, often end up not doing that at all, and instead reflect status of the peopls or groups involved. Capitol allocations are given to high prestige groups rather than to groups that could make better use of funding, and this is often taken for granted as part of the political system of an organization, even if everyone agrees that the process should be as stated. Some will even claim that the system is actually doing what is stated purpose is, when it manifestly is not. This is true generally. 53 | 54 | * Parkinson's first law: Systems grow 55 | C.Northcote Parkinson observed [fn:5]that the staffing of the British Navy continued to grow after WWII even though the actual number of ships declined. Although he attributed much of it to human nature in a bureaucracy, it has later been observer to be true for almost all systems. Existing systems will be given wider scopes, additional functions, and generally be added to, or they will be consumed and replaced by other systems with those system goals. J.W.Zawinksi coined the Law of Software Envelopment: "Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can." [fn:3] 56 | 57 | * Gall's observation: Systems Fail, always and constantly 58 | Complex systems are usually in a failure mode. Working systems will compensate for that. When something fails visibly, it is often the result of 5 or 6 overlapping failures. What is not often recognized is that at any given time 2 or 3 parts of the system have failed, and the overall system has worked around the problem. When investigating a bug, it is not uncommon to find code that quite literally never worked. Fixing that code then causes failures, where the rest of the system was working around the defect. Human users of a system take into account the peculiarities of a system and will avoid problems, sometimes long after the problem is gone, and they will resist changes to their patterns even when they may be an overall improvement. [fn:4] 59 | 60 | * System Design: Systems run better when designed to run downhill 61 | Pulling generally works better than pushing. Take into account how human beings behave. If you are trying to effect change with a system, you want the forces your system produces to move people in ways they will continue to move. Pushing up hill often leads to rolling back and being in a worse position that when the system was put in place. Pushing developers to write tests works less well than changing to a test-driven developement system, where programmers are rewarded quickly by succeeding at the game of making tests pass. However, it's often some work to move from one locally stable point, a local minima, to a new, and better, stable point. You have to get over a small hill before getting to the downhill part. 62 | 63 | * Efficient Systems are Dangerous, Loose systems last longer and work better 64 | Efficient systems, with little slack, will fail much more catestrophically than loose systems do. Calendaring software often efficiently books meetings and rooms with no slack. This results in back-to-back-to-back meetings in widely separated locations leading to enough participants being late that all of the efficiency is lost. The system actually works against itself. Sometimes there are "solutions" proposed involving punishing the participants in various ways, leading to further efficiency problems. 65 | Postel's Law, "Be conservative in what you do, be liberal in what you accept from others." (RFC 793)[fn:2] is a maxim about making sure there is loosness in a system. The coupling between components is forgiving of error, and strives to not stress weaker links in the system. 66 | 67 | * Programming is a Human activity. Account for the Programmers 68 | Systems, since they continue to grow, are never complete. A class of humans often ignored in the system are the programmers continuing to fix, maintain, debug, and extend the system. The needs of programmers are even ignored by programmers. We do things to ourselves that we would never accept on behalf of users of our systems. System deployment instructions will be on a web page with 16 steps, 3 of which no longer apply, and one of which may be destructive, but nonetheless insiders will say the process is simple. Being somewhat proud of the number of people affected by an outage, or the frequency of overnight problems, and using that as a proxy for the importance of the sysytem, and neglecting to actually fix the underlying issues causing outages. Development builds that require more than a one or two word command. Tests that are never run, don't work, and may never have worked beyond the first developers desk. Extreme difficulty in bringing up a full system in an observable and debuggable state so that production problems can be reproduced. Code in the system that no one understands anymore and lives in fear of disturbing. 69 | 70 | The entire development process is a system that lives within the larger system being provided. It mush be recognized that problems in the development system are problems for the system as a whole, and it is not selfish for programmers to insist that their system is important. 71 | 72 | #+BEGIN_ABSTRACT 73 | Audience Takeaways: The audience will have a better understanding of how Systems tend to grow and behave outside of our control or design, and with greater awareness, be in a position to counter-act those tendencies when possible and necessary. Don't take the System for granted and be prepared to work to change it. Try to avoid what Dan Luu called "normalization of deviance"[fn:1], accepting as normal signals that there is a problem with the system, even, or especially, if you know why the deviation from normal was done. Maintain awareness of the people you are affecting with your system. 74 | #+END_ABSTRACT 75 | 76 | * Footnotes 77 | 78 | [fn:5] Parkinson, Cyril Northcote (19 November 1955), [[http://www.economist.com/businessfinance/management/displaystory.cfm?story_id=14116121]["Parkinson's Law"]], The Economist. 79 | 80 | [fn:4] Gall, John. The Systems Bible: The Beginner's Guide to Systems Large and Small (Third Edition of SYSTEMANTICS), General Systemantics Press/Liberty, 2003. ISBN 0-9618251-7-0. 81 | 82 | [fn:3] [[https://www.jwz.org/hacks][Law of Software Envelopment]] 83 | 84 | [fn:2] [[https://tools.ietf.org/html/rfc793][TRANSMISSION CONTROL PROTOCOL]] 85 | 86 | [fn:1] [[https://danluu.com/wat/][Dan Luu, Normalization of Deviance]] 87 | 88 | 89 | # Local Variables: 90 | # org-html-htmlize-output-type: inline-css 91 | # End: 92 | -------------------------------------------------------------------------------- /lewg-monday-morning.org: -------------------------------------------------------------------------------- 1 | * LEWG Morning 2 | ** SPan 3 | *** Should be span be regular 4 | 5 | Forward to LWG - no objections 6 | 7 | *** Usability Enhancments for Span 8 | 9 | No objections 10 | 11 | 12 | ** Constexpr (all presented by Louis): 13 | 14 | *** P0784 Standard containers and constexpr — presented by Louis Dionne 15 | Paper will be updated, doesn't have to come back 16 | *** P1251 A more constexpr bitset — presented by Louis Dionne 17 | Slight change, links this to the prior paper. 18 | 19 | *** P0533 constexpr for and — presented by Louis Dionne 20 | 21 | 22 | 23 | ** Approve a name for a magic library call: 24 | 25 | *** P0595 std::is_constant_evaluated() — presented by Richard Smith (small) 26 | 27 | Bikeshedding a new header for is_constant_evaluated 28 | 29 | 30 | 31 | ** Clarify a past decision: 32 | 33 | *** P0340 Making std::underlying_type SFINAE-friendly — presented by Titus Winters 34 | 35 | * EWG Monday afternoon 36 | 37 | ** p1141r1 Yet another approach for constrained declarations 38 | Terse notation wins, except for the very tersest 39 | 40 | ** P1199R0 A simple proposal for unifying generic and object-oriented programming 41 | An interesting approach to converting Class auto& to a concept match 42 | 43 | ** P1168R0 How to make Terse Notation soar with Class Template Argument Deduction 44 | 45 | CTAD 46 | 47 | 48 | * LEWGI - after break Monday (called for particpants) 49 | 50 | ** p1223R - backwards iteration 51 | if and not versions are contentious 52 | 53 | ** p1310r0 Unifying the many ways to compare 54 | 55 | ** p1317 Remove return type deduction in std::apply 56 | everyone agrees that the problem is real, and awful, but bandwidth for 20 is low 57 | 58 | ** P1318R0 Tuple application traits 59 | 60 | ** p1201 Variant direct comparisons 61 | tue 62 | -------------------------------------------------------------------------------- /lewg-wednesday.org: -------------------------------------------------------------------------------- 1 | * Ranges Fixes 2 | 3 | 4 | Was annoying about deprecation 5 | 6 | * Rangify new algs 7 | 8 | clamp? 9 | 10 | 11 | * view::maybe 12 | 13 | good encouragment 14 | 15 | 16 | * Break 17 | -------------------------------------------------------------------------------- /local-class-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Allow Templates in Local Classes 3 | document: D1988R1 4 | date: today 5 | audience: 6 | - EWG 7 | author: 8 | - name: Steve Downey 9 | email: , 10 | toc: false 11 | --- 12 | 13 | # Abstract 14 | Local classes should be permitted to have member templates. 15 | 16 | # Before / After Table 17 | 18 | ::: cmptable 19 | 20 | ### Before 21 | ```C++ 22 | // Extracted From LLVM test case temp.mem/p2.cpp 23 | void fun() { 24 | struct foo { 25 | template struct bar {}; // Error 26 | template void baz() {} // Error 27 | template using corge = int; // Error 28 | }; 29 | } 30 | ``` 31 | 32 | ### After 33 | ```C++ 34 | // Extracted From LLVM test case temp.mem/p2.cpp 35 | void fun() { 36 | struct foo { 37 | template struct bar {}; // Allowed 38 | template void baz() {} // Allowed 39 | template using corge = int; // Allowed 40 | }; 41 | } 42 | 43 | 44 | ``` 45 | ::: 46 | 47 | # Implementation Experience For C++98 48 | 49 | Implemented in clang by deleting the check for template inside local class. 50 | 51 | ```diff 52 | diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp 53 | index 5633582d679..d155bf8b5e4 100644 54 | --- a/clang/lib/Sema/SemaTemplate.cpp 55 | +++ b/clang/lib/Sema/SemaTemplate.cpp 56 | @@ -7385,12 +7385,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { 57 | if (CXXRecordDecl *RD = dyn_cast(Ctx)) { 58 | // C++ [temp.mem]p2: 59 | // A local class shall not have member templates. 60 | - if (RD->isLocalClass()) 61 | - return Diag(TemplateParams->getTemplateLoc(), 62 | - diag::err_template_inside_local_class) 63 | - << TemplateParams->getSourceRange(); 64 | - else 65 | - return false; 66 | + return false; 67 | } 68 | } 69 | 70 | ``` 71 | 72 | Built a stage2 bootstrap of llvm, including libc++, which succeeded. 73 | ```sh 74 | CXX=clang++-8 CC=clang-8 cmake -DCLANG_ENABLE_BOOTSTRAP=On \ 75 | -DCLANG_BOOTSTRAP_PASSTHROUGH=\ 76 | "CMAKE_INSTALL_PREFIX;CMAKE_BUILD_TYPE;LLVM_USE_LINKER;LLVM_PARALLEL_LINK_JOBS;LLVM_ENABLE_PROJECTS" \ 77 | -DCMAKE_INSTALL_PREFIX=~/install/llvm-localclass/ -DLLVM_ENABLE_LIBCXX=yes \ 78 | -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=yes -DLLVM_USE_LINKER=lld \ 79 | -DLLVM_PARALLEL_LINK_JOBS=1 \ 80 | -DLLVM_ENABLE_PROJECTS=\ 81 | "clang;clang-tools-extra;compiler-rt;debuginfo-tests;libcxx;libcxxabi;libunwind;lld;lldb;llvm" \ 82 | -G Ninja ../llvm-project/llvm/ 83 | ``` 84 | The test suite produced one new set of errors, the tests checking that templates not be declared inside of a local class. 85 | 86 | error: 'error' diagnostics expected but not seen: 87 | File /temp/temp.decls/temp.mem/p2.cpp Line 8: templates cannot be declared inside of a local class 88 | File /temp/temp.decls/temp.mem/p2.cpp Line 9: templates cannot be declared inside of a local class 89 | File /temp/temp.decls/temp.mem/p2.cpp Line 10: templates cannot be declared inside of a local class 90 | File /temp/temp.decls/temp.mem/p2.cpp Line 11: templates cannot be declared inside of a local class 91 | File /temp/temp.decls/temp.mem/p2.cpp Line 12: templates cannot be declared inside of a local class 92 | 5 errors generated. 93 | 94 | 95 | # Why C++ 98 96 | In C++98 there is no way for a local class to escape the scope in which it is declared. (Un)Fortunately in C++11 we allowed the `auto` keyword and the deduction of the return type of a function. 97 | 98 | What this means for templates in local classes is that the instantiation point may be outside the scope that the class is declared in. This leads to complications. 99 | 100 | If the local class is returned from such a function, and the member template is used, the context defining the member, in existing implementations is lost. 101 | 102 | ~~~C++ 103 | template auto f(T t) { 104 | struct X { 105 | template void g() { 106 | decltype(t) x = 123; } 107 | }; 108 | return X(); 109 | } 110 | 111 | void h() { 112 | f(nullptr).g(); 113 | } 114 | ~~~ 115 | 116 | With the patch above, clang will ICE. The corresponding lambda expression is diagnosed as an error. 117 | 118 | ~~~C++ 119 | template 120 | auto f(T t) { 121 | auto y = [](U u) { decltype(t) x = 123;}; 122 | return y; 123 | } 124 | 125 | void h1() { auto k = f(nullptr);}; 126 | ~~~ 127 | 128 | clang reports: 129 | 130 | ~~~ 131 | :3:48: error: cannot initialize a variable of type 'decltype(t)' (aka 'nullptr_t') with an rvalue of type 'int' 132 | auto y = [](U u) { decltype(t) x = 123;}; 133 | ^ ~~~ 134 | :7:22: note: in instantiation of function template specialization 'f' requested here 135 | void h1() { auto k = f(nullptr);}; 136 | ^ 137 | 1 error generated. 138 | Compiler returned: 1 139 | ~~~ 140 | 141 | [Compiler Explorer](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAM1QDsCBlZAQwBtMQBGAFlICsupVs1qhkAUgBMAISnTSAZ0ztkBPHUqZa6AMKpWAVwC2tEAGYAbKS3oAMnlqYAcsYBGmYiADspAA6oFQnVaPUMTQX9AtTp7Rxcjd09ORWVMVWCGAmZiAlDjU0sUlWjaTOyCWOc3D29FLJy88OSFeoqHKoSazgBKRVQDYmQOAHICTCNfYTGAanEzHQIAT18tZiNMaYAVOexxAAYAQWYDImmqCE3pgm7Zr1lD6cfp49PF2bMAEVmAVllvj7mC2Wq3W0wAqjsIGDpgYbuI7tMsMhWEsVhBrtMAB7vL6cSRmOayLwAsz3A5PabETAEAa0aaLQn7A7wgGHJkAN1QeHQ0wQnAgcIRL1Q0wA1jizhBaAZWKxfARiN1GcTCbNDgB6dWc7m8yQC27SZ4nEXiuZfc7S2XyxWq0UQHrKkmG4a9VggYbfYakUzDPZe1DunRyOTTBT9QYbKRmThegjuv3dXqikDcTgAOgsmaz2azPjdw24Xp9ftIAeGXoUID2pDjvpdpDgsBgiBQdBoxCMIiG5EoaAmeHYxErsD7vgHHgAkugUMJRAB9BUGWii0vy4KV4YAWk3LXQZokMjkkmY9Ygo/HxCnIGAClozF8CgQqAIq5KG%2B3u/3wZkx5dvUw%2BBEMQ3KCLOwBXgesgyEIeCuMOAquu6nrevG/qBm2JCdrQQzTOyeCYAA7h40wQLghAkLM%2BI9NMkjqpwJa1gmvQIJgzBYJ4AqkMmZgABxpjxAmCUJAkAJxCO6hakEYIDfNWxZoeWihVjWqG9I2UDNhASDnoOPZnqg/aDjOIjAAuxBLiuVADmMQ6UK4qGkK4DjZIs7oxqQfbrPQADytCsK5dakFgWHAOwDn4FS6TspgG4lpgmJpCcIzuQ4Yz5iWrCwcQLl6FgbmxsB0nDDGvQ0PQTBsBwPD8KBJkoN%2B8iZXB8C9Kga50O%2BO4EHunyQUeJ59AMQxcIhHpFg5ZaYjxFibhY3DTMiJkkYuy43KRgEUVGyTTHohnEVtNxBoeMixqpzGsexlCjZJ0myShgVlhWymMaemnaQZY66RQ%2Bl7Z4N53g%2BT4vlZKIeJWED2YFTl3sQAXuZ5WgEL5/nheMJlhYFEVpGo0WxV68WJWM%2BXkPQygOU12Ww7lyUFXgRUlaQZWMCwYXVQIkhCHVfXQU18Gte1tCdZ%2BvUNb%2Bg0RiN4ljfdJaTdNs3zcAyDIMt5mrSRZFAZR0akDtH0XtrkiHQ1p11ompAsWxNScdxZhpmYDuO07ju8PmN0yXJE3uk91YvebyaSHx3wO9wIkWF4ZiSHskgWJw3xS2Y40Pd7Klmw2mlvSA/QEL4Jx6TpXTWBtSSM3QzOVVwvAEdlvj5aNyHyaW7pbdMBGEAgWLy3NC1garFndKbTEWxd1tJiAkiSGmE/TzPM9mFL7t3Y3j1Kb7qnp/AWlZycucvt9BeeBzAHkSXTMVazVc13XUsN17wxRpIrft53M3d0rKvomrooD6nQ%2BW5dnE3Zelup7ZOilKxrzNmPSOaZvheC8LHbgZgvAiT2DxUOPEE5J1linP2Y9vh8WdkQx2Vh8ySGAVwPYoCcGKTwVLchMsFKDz/KQaKQ5ggpiAA%3D%3D%3D) 142 | 143 | Interestingly, there is some divergence in detecting the error. GCC doesn't unless k is invoked: 144 | 145 | ~~~C++ 146 | void h2() { auto k = f(nullptr); k(1);}; 147 | ~~~ 148 | 149 | ~~~ 150 | : In instantiation of 'f(T) [with T = std::nullptr_t]:: [with U = int]': 151 | :8:37: required from here 152 | :3:52: error: cannot convert 'int' to 'std::nullptr_t' in initialization 153 | | auto y = [](U u) { decltype(t) x = 123;}; 154 | | ^~~ 155 | | | 156 | | int 157 | Compiler returned: 1 158 | ~~~ 159 | [Compiler Explorer](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAM1QDsCBlZAQwBtMQBGAFlICsupVs1qhkAUgBMAISnTSAZ0ztkBPHUqZa6AMKpWAVwC2tQVvQAZPLUwA5YwCNMxEAA5SAB1QLC62nsMTQS8fNTorG3sjJxd3JRUw2gYCZmICAONTTkVlTFU/ZNSCCLtHZzdFFLSMoOyFKuLrUujy1wBKRVQDYmQOAHICTCMPYUGAanEAZh0CAE8PLWYjTDGAFSnscQAGAEFmAyIxqghVsYI2iYB2WV2xu7H9w9mJyYARCYBWWQ/XqZn5xbLMYAVQ2EGBYwMF3E1zGWGQrDmCwg5zGAA8Xu9OJJJlNZJdfpMbjt7mNiJgCN1aGNZnjtjsYb9dvSAG6oPDoMYITgQaGwx6oMYAa0xRwgtAMrFYHgIxDadIJeImuzZHK5kl5V2kDwOgpFU3exwlUplcqVQognHlRMZSr6HVYID6Hz6pFMfS2rtQTp0cjkYwUXR6Kykk04roITs9bQ6QpA3E4ADoAGyptPptOXIRO7iu92e0jevquhQgLakSMe%2B2kOCwGCIFB0GjEIwiXrkShoYZ4djEUuwLseHvOACS6BQwlEAH1ZQZaELCzK/KW%2BgBaVf1dAGiQyOSSZjViCD4fEMcgYAKWjMDwKBCoAiLxIr9eb7d%2BmT7%2B0dTD4IjEDmCJOwBnjusgyEIeAOP2vIOk6LpulGXo%2Bk2JCtrQvRjCyeCYAA7s4YwQLghAkBMOJWmMkgAPScAWlbRh0CCYMwWAuLypBxpMriJq4PG8XxPEAJzZn0uakEYIAfOW%2BZIcWihlhWiEdLWUD1hASDHr2HZHqg3a9hOIjADOxBzguVA9oMfaUA4iGkA41ipLMTrhqQXbLPQADytCsI5VakFgaHAOwNn4OS%2BQspgK4FpgaJ5Ac/TOdYgyOr5rCQcQDl6FgTkRv%2B4l9OGHQ0PQTBsBwPD8IBBkoO%2B8ipVB8AdKgS50M%2BG4EFubygXuB45AkfiaNoNRZKQ5glFEMTBN4vh0ENk2hH4Y1lC4dS5PkdCFNU%2BiZII8R5IkG2NJES07Q0s11A0i0tMtHSBt0vRcLBzp5jZRZoq4yarsm3BjAiBkEbO84XIRv4kaG2RjHoun4WDFy%2BruMgRopDFMSxlCPaJ4mSQhvlFiW8l0YeqnqTpQ6aRQ2lQy4F5Xjed4PmZiLOKWEDWb5dlXsQPnOa5WgEJ53nBUMBlBb5IV7Xg4WRa60WxYM2XkPQyg2XV6Wc5l8U5XgeUFaQRWMCwQXlQIkhCFVXXgXV0GNc1tCta%2BnU1Z%2BvXixoEDmGdI3aJdE3ZCE03%2BFttSeFNiTe%2BUK19etp2B8Nu1rUkF1NON4eVEUHv1EUYfXZ0d1lY98HSYWTpvR9X1jMAyDIP9xmAwRRF/qRYakBDJMno3kiwzViNVjGpCMcx5RsRxkyJpMY/jxP4%2B8MlGMSVJL1Onj5YE73caSFxHxj9wAnJpckySFskjJpwHzCZMz044vCk9zWqlEyAXQEB4BxaRpKc/sRy263Q%2BulVwvA4XSh4bK%2BcL4FiLGDMYOFCAIHRO9T631fqiGriZNo3d6J9xRoPWMIBJCSETHgwhRCiGTGErPLGhdcZyWXopW%2B8A1IPwOM/B85M34uBNh/P8gg9YlUNgAoBIDhIFwXn0UMkgoEwLgaXb6Fcq4ohrkKNB18MH91RmxGerpMbz0vrJUsNCe44P3omD4lxLjH24JMS4AktiuG3u4ZK59sbgKvivHBHwuKT08ePZMwlJCaK4FsbRzjZKuN8WAmS6CvykHCn2fq3AgA%3D%3D) 160 | 161 | I believe that clang is being too aggressive in instatiation of the `operator()` of the lambda, but I have not constructed an example that errors on otherwise well-formed code. 162 | 163 | # Modules and Reachability 164 | The problem of unnamable types whose members might be templates is similar to that of types in modules that are not exported but are present in interfaces that are. 165 | 166 | ~~~C++ 167 | export module M; 168 | struct X {}; 169 | 170 | export { 171 | X func(){return X{};} 172 | } 173 | ~~~ 174 | The name X is unavailable outside the module, but the function `func` is. `auto x = funct();` is valid code. 175 | 176 | This suggests we could leverage Reachability in order to provide meaning to local classes outside their declarative region. 177 | From [module.reach](http://eel.is/c++draft/module.reach) 178 | 179 | >[3]{.pnum} A declaration D is reachable if, for any point P in the instantiation context ([module.context]), 180 | > 181 | >[3.1]{.pnum} D appears prior to P in the same translation unit, or 182 | > 183 | >[3.2]{.pnum} D is not discarded ([module.global.frag]), appears in a translation unit that is reachable from P, and either does not appear within a private-module-fragment or appears in a private-module-fragment of the module containing P. 184 | > 185 | >[ Note: Whether a declaration is exported has no bearing on whether it is reachable. — end note ] 186 | 187 | 188 | The language already requires that the declaration of D, the local class, appear before any use of it, because of the existing rules for `auto`. 189 | 190 | [module.global.frag](http://eel.is/c++draft/module#global.frag) provides 191 | 192 | > [4]{.pnum} A declaration D in a global module fragment of a module unit is discarded if D is not decl-reachable from any top-level-declaration in the top-level-declaration-seq of the translation unit. [ Note: A discarded declaration is neither reachable nor visible to name lookup outside the module unit, nor in template instantiations whose points of instantiation ([temp.point]) are outside the module unit, even when the instantiation context ([module.context]) includes the module unit. — end note ] 193 | 194 | If we extend decl-reachable to include local classes that are made available via the return type of its declaring function, the defintion of the local class would be _reachable_ for purposes of instantiating its member functions. 195 | 196 | I do not know if this is viable in any sense as an implementation, but it seems to be a viable direction in terms of the standard. 197 | 198 | # Wording 199 | 200 | >[temp.mem.2]{.pnum} [A local class of non-closure type shall not have member 201 | >templates.]{.rm} Access control rules apply to member template names. A 202 | >destructor shall not be a member template. A non-template member function 203 | >([dcl.fct]) with a given name and type and a member function template of the 204 | >same name, which could be used to generate a specialization of the same type, 205 | >can both be declared in a class. When both exist, a use of that name and type 206 | >refers to the non-template member unless an explicit template argument list is 207 | >supplied. 208 | 209 | I have not figured out how to word decl-reachable yet. 210 | -------------------------------------------------------------------------------- /manylinux.org: -------------------------------------------------------------------------------- 1 | #+options: ':nil 2 | #+options: *:t 3 | #+options: -:t 4 | #+options: ::t 5 | #+options: <:t 6 | #+options: H:8 7 | #+options: \n:nil 8 | #+options: ^:nil 9 | #+options: arch:headline 10 | #+options: author:t 11 | #+options: broken-links:nil 12 | #+options: c:nil 13 | #+options: creator:nil 14 | #+options: d:(not "LOGBOOK") 15 | #+options: date:t 16 | #+options: e:t 17 | #+options: email:nil 18 | #+options: expand-links:t 19 | #+options: f:t 20 | #+options: inline:t 21 | #+options: num:t 22 | #+options: p:nil 23 | #+options: pri:nil 24 | #+options: prop:nil 25 | #+options: stat:t 26 | #+options: tags:t 27 | #+options: tasks:t 28 | #+options: tex:t 29 | #+options: timestamp:t 30 | #+options: title:t 31 | #+options: toc:t 32 | #+options: todo:t 33 | #+options: |:t 34 | #+options: html-link-use-abs-url:nil 35 | #+options: html-postamble:nil 36 | #+options: html-preamble:t 37 | #+options: html-scripts:t 38 | #+options: html-style:t 39 | #+options: html5-fancy:nil 40 | #+options: tex:t 41 | 42 | #+title: C++ Runtimes and ~manylinux~ 43 | #+date: <2025-05-19 Mon> 44 | #+author: Steve Downey 45 | #+email: sdowney2@bloomberg.net 46 | #+language: en 47 | #+select_tags: export 48 | #+exclude_tags: noexport 49 | #+cite_export: 50 | 51 | #+html_doctype: xhtml-strict 52 | #+html_container: div 53 | #+html_content_class: content 54 | #+description: 55 | #+keywords: 56 | #+html_link_home: 57 | #+html_link_up: 58 | #+html_mathjax: 59 | #+html_equation_reference_format: \eqref{%s} 60 | #+html_head: 61 | #+html_head_extra: 62 | #+subtitle: 63 | #+infojs_opt: 64 | #+latex_header: 65 | 66 | * Maintaining Deployment Compatibility 67 | One of the key features of the Red Hat Toolset products is their guarantee with respect to being able to deploy to unpatched RHEL machines. Bloomberg relies on this. We do not coordinate our software deployment with the patch levels of the target machines, nor do we check minor or major OS versions. We rely on being able to run the same binary on RHEL7 and 8, and expect to do so for RHEL9. 68 | 69 | We also rely on being able to use binary wheels from PyPI. The [[https://peps.python.org/pep-0599/][PEP-0599]] and [[https://peps.python.org/pep-0600/][PEP-0600]] Python Enhancement Proposals define profiles of system libraries and the API versions they provide to allow a binary python extension module to be deployed across a wide variety of glibc derived Linux distributions. 70 | 71 | It turns out that the tools used by the Python Package Index and the Python Packaging Authority derive ultimately from the same guarantees that Red Hat is providing for Red Hat Enterprise Linux. They reference CentOS as the source, but at the time, CentOS mirrored as exactly as possible the software shipped as part of Enterprise Linux. 72 | 73 | PyPA also provides tools to machine check the compatibility of binaries against the definitions. Many of these tools are in the package [[https://pypi.org/project/auditwheel/][auditwheel]], which also provides tools for rewriting shared objects to make public dependencies private. 74 | 75 | | manylinux | RHEL | 76 | |----------------+-------| 77 | | manylinux_2_17 | RHEL7 | 78 | | manylinux_2_28 | RHEL8 | 79 | | manylinux_2_34 | RHEL9 | 80 | 81 | 82 | * Key Runtime Library API 83 | - CXXABI :: [[https://itanium-cxx-abi.github.io/cxx-abi/abi.html][Itanium ABI]] 84 | The APIs used by the C++ language itself. For example ~longjmp_unwind~. 85 | #+begin_quote 86 | The objective of a full ABI is to allow arbitrary mixing of object files produced by conforming implementations, by fully specifying the binary interface of application programs. We do not fully achieve this objective. 87 | #+end_quote 88 | 89 | - GCC :: gcc runtime support in libgcc_s.so 90 | Includes CXXABI functions. 91 | 92 | - GLIBC :: C runtime and kernel interface. May be tightly coupled with OS. The parts are provided by more than one shared object, also. Partial list: libc, libm, libpthread 93 | 94 | - GLIBCXX :: libstdc++.so 95 | Support and implementation of the C++ standard library. 96 | 97 | - ZLIB :: Compression library 98 | Widely used. Bloomberg generally prefers the static version we have in dpkg. 99 | 100 | * Risks 101 | ** GLIBC 102 | As long as we compile within an image that has the expected host versions of the libraries, the risk is low. 103 | ** ZLIB 104 | We have a zlib in dpkg, and static linking means we should not have runtime issues. It may be an issue for binary wheels. 105 | ** GCC and GLIBCXX 106 | There are open risks here. We need to understand what steps Red Hat is undertaking to make sure that the unpatched system versions of the libraries from downlevel compilers can support executables built by later compilers. Both libraries provide versioned symbols for current compilers, which would be unavailable for earlier versions. 107 | GCC supports linking both libstdc++ and libgcc_s with specific command line switches ~-static-libgcc~ and ~-static-libstdc++~. 108 | 109 | * Opportunities 110 | We should consider adapting the technology in ~auditwheel~ to confirm our software distributions to production. We have seen accidental use of system shared objects available in our RHEL7 images. Fortunately these are usually upwards compatible libraries, and have been harmless, instead of causing immediate errors. 111 | -------------------------------------------------------------------------------- /networking-polls.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Building C++ Reliably 6 | #+DATE: <2018-10-07 Sun> 7 | #+AUTHOR: Steve Downey 8 | #+EMAIL: sdowney2@bloomberg.net 9 | #+LANGUAGE: en 10 | #+SELECT_TAGS: export 11 | #+EXCLUDE_TAGS: noexport 12 | #+CREATOR: Emacs 26.1 (Org mode 9.1.14) 13 | #+LATEX_CLASS: report 14 | #+LATEX_CLASS_OPTIONS: 15 | #+LATEX_HEADER: 16 | #+LATEX_HEADER_EXTRA: 17 | #+DESCRIPTION: 18 | #+KEYWORDS: 19 | #+SUBTITLE: 20 | #+LATEX_COMPILER: pdflatex 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:auto html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | #+CREATOR: Emacs 26.1 (Org mode 9.1.14) 35 | #+LATEX_HEADER: 36 | #+STARTUP: showeverything 37 | 38 | #+BEGIN_ABSTRACT 39 | Positions on C++ committee polling asynchronous programming 40 | #+END_ABSTRACT 41 | 42 | * My votes and the outcomes of direction polls on Async programming in C++ 43 | 44 | 45 | 46 | * Summary 47 | 2021-10-04 LEWG/SG1 Networking/Executors Polls 48 | Please read the following papers for context on these polls: 49 | 50 | https://isocpp.org/files/papers/P2300R2.html - `std::execution` 51 | https://isocpp.org/files/papers/P2444R0.pdf - The Asio asynchronous model 52 | https://isocpp.org/files/papers/P2464R0.html - Ruminations on networking and executors 53 | https://isocpp.org/files/papers/P2469R0.pdf - Response to P2464: The Networking TS is baked, P2300 Sender/Receiver is not 54 | https://wg21.link/P2195R2 - Electronic Polling Procedures 55 | 56 | 57 | * Poll 1: The Networking TS/Asio async model (P2444) is a good basis for most asynchronous use cases, including networking, parallelism, and GPUs 58 | ** My position: Network TS: SA 59 | 60 | While there is an existence proof of Networking TS/Asio working for networking, I do not believe it's a good basis for general parallelism, concurrency, or GPUs. 61 | The sender/receiver model is equivalent to continuation passing where continuations can be composed via the contexts/decorators that model the sender concept, and separating the concerns of writing application functions and transforming the functions into continuation passing style. This is a sound and well understood model for computation, including async computation. 62 | 63 | ** Results 64 | 65 | | Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against | 66 | | 5 | 10 | 6 | 14 | 18 | 67 | Weak Consensus Against 68 | What this means: LEWG won't be pursuing P2444 as a general async model. 69 | 70 | * Poll 2: The sender/receiver model (P2300) is a good basis for most asynchronous use cases, including networking, parallelism, and GPUs. 71 | ** My position: S/R SF 72 | 73 | While I would have little qualm in referring someone to Asio or the NetTS flavor of the library, as it clearly works, I do not believe that it provides a sound composable vocabulary for the standard library. I do not have confidence that I could compose two independent 'third-party' libraries using these tools, or third party components with my own code. 74 | 75 | ** Results 76 | 77 | 78 | | Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against | 79 | | 24 | 16 | 3 | 6 | 3 | 80 | Consensus in Favor 81 | 82 | * Poll 3: Stop pursuing the Networking TS/Asio design as the C++ Standard Library's answer for networking. 83 | ** My position: Net TS progress: WA 84 | 85 | 86 | I certainly do not want to spend any more time seeing if the Network TS design can be refactored or extended to support other use cases, and any further work should be solely focused on wording that reflects the design as is. 87 | 88 | I am not concerned about singularity or purity of the standard library. We have several different models of IO and of text formatting. 89 | 90 | ** Results 91 | 92 | | Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against | 93 | | 13 | 13 | 8 | 6 | 10 | 94 | No Consensus 95 | 96 | * Poll 4: Networking in the C++ Standard Library should be based on the sender/receiver model (P2300). 97 | ** My position: S/R Networking: WF 98 | 99 | Only weakly in favor because if the standard library does not provide S/R networking, I am confident I could write networking that interoperated with the standard library algorithms, senders, receivers, and schedulers. I would prefer, of course, not to have to. 100 | 101 | ** Results 102 | 103 | | Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against | 104 | | 17 | 11 | 10 | 4 | 6 | 105 | Weak consensus in Favor 106 | 107 | * Poll 5: It is acceptable to ship socket-based networking in the C++ Standard Library that does not support secure sockets (TLS/DTLS). 108 | ** My position: TLS not required: WF 109 | 110 | TLS has not been API stable enough in the past to require it in the standard library. I do not want to be in an API or ABI argument with my compiler vendor to fix a security problem. 111 | 112 | S/R gives enough separation of concerns that independent libraries can be integrated into the model without vendors having to do that in core. 113 | Asio also has enough separation to provide external support for TLS, and boost.ssl shows that the SSL management interfaces can be externalized. 114 | 115 | ** Results 116 | | Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against | 117 | | 9 | 13 | 5 | 6 | 13 | 118 | No Consensus 119 | -------------------------------------------------------------------------------- /new-basic-characters.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Add @, $, and ` to the basic character set" 3 | document: P2558R2 4 | date: today 5 | audience: 6 | - SG16 7 | - SG22 8 | - EWG 9 | author: 10 | - name: Steve Downey 11 | email: 12 | toc: true 13 | toc-depth: 2 14 | --- 15 | 16 | # Abstract 17 | WG14, the C Standardization committee, is adopting [@CN2701] for C23. 18 | 19 | This will add 20 | 21 | | Code point | Glyph | Name | 22 | |------------|-------|---------------| 23 | | U+0024 | $ | DOLLAR SIGN | 24 | | U+0040 | @ | COMMERCIAL AT | 25 | | U+0060 | ` | GRAVE ACCENT | 26 | 27 | 28 | to the basic source character set. 29 | 30 | C++ should adopt the same characters for C++26. 31 | 32 | # Motivation 33 | These characters are available in all encoded character sets in common use and everyone assumes that they are available, using them freely in source text. The primary change would be that these characters become available for syntactic purposes. Although using $ in identifiers is a common extension, they were not added to the identifier set in C, and this paper does not propose adding them either. Nor were trigraphs added in C for these characters, and this paper does not propose additional trigraphs or digraphs be added. 34 | 35 | The translation model for C makes adding these to their basic source character set, the encoded set for source code before translation, much more compelling. These characters being already in the translation character set as single byte characters makes this less important for C++. Nonetheless, it would be useful to make these available for language purposes as the more conservative C language has agreed there are no functional impediments to their use. 36 | 37 | Corentin Jabot discusses the usage in other programming languages extensively in [@P2342R0], _For a Few Punctuators More_, q.v. 38 | 39 | While it would be possible to add these characters to the grammar of C++ without adding them to the basic character set, that would violate the contract that the basic character set is sufficient for writing C and C++. Digraphs and trigraphs are concessions to ease of keyboarding. It is assumed that the characters represented by those means are available. 40 | 41 | # Implications and Consequences 42 | 43 | Because this proposal is not making these characters available for syntactic purposes, the changes are limited to how these characters encoded today, or are represented in source. 44 | 45 | ## Universal Character Names 46 | Adding these characters to the basic source character set implies that they can no longer be spelled as universal character names outside of literals. An example of such a construct: 47 | ```C++ 48 | #include 49 | 50 | #define STR(x) #x 51 | 52 | int main() 53 | { 54 | printf("%s", STR(\u0060)); // U+0060 is ` GRAVE ACCENT 55 | } 56 | ``` 57 | This is currently rejected by GCC 'error: universal character \u0060 is not valid in an identifier', although this seems to be a bug, and the code is accepted by clang and msvc. 58 | 59 | ## Literal Encoding 60 | Adding these characters to the basic character set means these will have to be encoded in a single byte, with positive value when used as a `char`. This is true for all POSIX encoded character sets, as @, $, and ` are part of the portable character set. This also implies they are available in all POSIX locales, and in particular the "POSIX" locale, which is equivalent to the "C" locale. [@POSIX] 61 | See [6. Character Set](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html "6. Character Set") 62 | 63 | ## Runtime Encoding 64 | A locale that does not provide for these characters would be non-conforming. Interpreting the literal encoding in any encoded character set, including the "C" LC_CTYPE character set if it does not match the literal encoding, is already at best unspecified. Substitution ciphers are apparently conforming, although misleading. There is a long history of interpreting the Yen sign, ¥, as a path separator on Windows exactly because of these encoding aliasing issues. 65 | 66 | POSIX, which has the ultimate definition of locales and how they work, defines the [Portable Character Set](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html) that are required to be encoded. They are not invariant, and may appear in different locations in different encodings. 67 | 68 | IBM defines a portable EBCDIC set to conform with the X/Open portable character set. However, it is documented to contain Accent Acute, which is not part of the portable set defined by X/Open or POSIX. Examining EBCDIC code pages, I did not find any that did not encode U0060. $ and @ are included in the EBCDIC [portable character set](https://www.ibm.com/docs/en/i/7.1?topic=sets-portable-character-set). 69 | 70 | ## Source Encoding and Representation 71 | There is a rule that characters in the basic character set may not be expressed as UCNs, unless inside a character or string literal. For C there are issues for characters in comments. This is not the case for C++. In non-comment contexts, these characters are currently not allowed in portable source outside of strings and character literals, so the spelling of the character is irrelevant, so other than the stringification example above, this seems unlikely to break real world code. 72 | 73 | For extensions that allow, for example, $ in identifiers, no one outside of compiler test suites, is likely to use a UCN to spell that. 74 | 75 | C++ places no constraints on source encoding. The closest we have is the in-flight requirement that implementations that accept files be required to accept UTF-8, and UTF-8 encodes these characters. 76 | 77 | ## Raw String Literals 78 | The new characters would be allowed in the raw delimiters, as there seems no reason to exclude them. The current list of exclusions is because white space, parentheses, and back slash could cause parsing ambiguity in the paired delimiter strings. 79 | 80 | ## Header names 81 | The grammar productions for header names uses the translation character set. It is conditionally supported with implementation defined semantics if `\\` is allowed, from which we can infer that universal character names are conditionally supported. If anyone was using UCNs to represent the new characters in a header, implementations could continue to interpret them, despite the rule of UCNs not being a valid representation of characters in the basic character set. 82 | 83 | Footnote 14 from [lex.header] 84 | 85 | > Thus, a sequence of characters that resembles an escape sequence can result in an error, be interpreted as the character corresponding to the escape sequence, or have a completely different meaning, depending on the implementation. 86 | 87 | 88 | 89 | # Wording 90 | 91 | These changes are relative to [@N4901] “Working Draft, Standard for Programming Language C++” 92 | 93 | Modify [lex.charset] as follows: 94 | 95 | > [2]{.pnum} The basic character set is a subset of the translation character set, consisting of [96]{.rm}[99]{.add} characters as specified in Table 1. 96 | 97 | Modify [tab:lex.charset.basic] with the following additions: 98 | 99 | ~~~ 100 | U+0009 CHARACTER TABULATION 101 | U+000B LINE TABULATION 102 | U+000C FORM FEED 103 | U+0020 SPACE 104 | U+000A LINE FEED new-line 105 | U+0021 EXCLAMATION MARK ! 106 | U+0022 QUOTATION MARK " 107 | U+0023 NUMBER SIGN # 108 | ~~~ 109 | ::: add 110 | ~~~ 111 | U+0024 DOLLAR SIGN $ 112 | ~~~ 113 | ::: 114 | ~~~ 115 | U+0025 PERCENT SIGN % 116 | U+0026 AMPERSAND & 117 | U+0027 APOSTROPHE ' 118 | U+0028 LEFT PARENTHESIS ( 119 | U+0029 RIGHT PARENTHESIS ) 120 | U+002A ASTERISK * 121 | U+002B PLUS SIGN + 122 | U+002C COMMA , 123 | U+002D HYPHEN-MINUS - 124 | U+002E FULL STOP . 125 | U+002F SOLIDUS / 126 | U+0030 .. U+0039 DIGIT ZERO .. NINE 0 1 2 3 4 5 6 7 8 9 127 | U+003A COLON : 128 | U+003B SEMICOLON ; 129 | U+003C LESS-THAN SIGN < 130 | U+003D EQUALS SIGN = 131 | U+003E GREATER-THAN SIGN > 132 | U+003F QUESTION MARK ? 133 | ~~~ 134 | ::: add 135 | ~~~ 136 | U+0040 COMMERCIAL AT @ 137 | ~~~ 138 | ::: 139 | ~~~ 140 | U+0041 .. U+005A LATIN CAPITAL LETTER A .. Z A B C D E F G H I J K L M 141 | N O P Q R S T U V W X Y Z 142 | U+005B LEFT SQUARE BRACKET [ 143 | U+005C REVERSE SOLIDUS \ 144 | U+005D RIGHT SQUARE BRACKET ] 145 | U+005E CIRCUMFLEX ACCENT ^ 146 | U+005F LOW LINE _ 147 | ~~~ 148 | ::: add 149 | ~~~ 150 | U+0060 GRAVE ACCENT ` 151 | ~~~ 152 | ::: 153 | ~~~ 154 | U+0061 .. U+007A LATIN SMALL LETTER A .. Z a b c d e f g h i j k l m 155 | n o p q r s t u v w x y z 156 | U+007B LEFT CURLY BRACKET { 157 | U+007C VERTICAL LINE | 158 | U+007D RIGHT CURLY BRACKET } 159 | U+007E TILDE ~ 160 | ~~~ 161 | 162 | 163 | --- 164 | references: 165 | - id: CN2701 166 | citation-label: N2701 167 | title: "@ and $ in source and execution character set" 168 | author: 169 | - family: Krause 170 | given: Philipp Klaus 171 | URL: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2701.htm 172 | 173 | - id: POSIX 174 | citation-label: POSIX 175 | title: "The Open Group Base Specifications Issue 7, 2018 edition" 176 | author: 177 | - family: IEEE and The Open Group 178 | URL: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/contents.html 179 | 180 | --- 181 | -------------------------------------------------------------------------------- /notes.org: -------------------------------------------------------------------------------- 1 | 2 | For SG15 - issues around extern "C++" {import stuff} 3 | For SG15 - issues around extern "C++" {#include "stuff"} 4 | 5 | SG16 - round trip of localized output should be possible in the cases that non-localized is round-trippable 6 | 7 | 8 | POSIX allows positional parameters 9 | https://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html 10 | C99 did not, current C does and POSIX defers to it. 11 | 12 | 13 | Ranges and IO: Where is the interlock for C and C++ io (iostreams vs cout) 14 | -------------------------------------------------------------------------------- /numerics-notes.org: -------------------------------------------------------------------------------- 1 | mixin with a lambda via override hack 2 | -------------------------------------------------------------------------------- /pmr-stacktrace.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Add a `pmr` alias for `std::stacktrace`" 3 | document: P2301R1 4 | date: today 5 | audience: LEWG, LWG 6 | author: 7 | - name: Steve Downey 8 | email: , 9 | toc: false 10 | --- 11 | 12 | 13 | Abstract: This paper proposes to add an alias in the `pmr` namespace defaulting the allocator used by the `std::basic_stacktrace` template to `pmr::allocator`. No changes to the api of `std::stacktrace` are necessary. 14 | 15 | # Changes 16 | ## Changes since R0 17 | 18 | Removed unneeded "std::" in the pmr alias. 19 | ``` 20 | namespace pmr { 21 | using stacktrace = @[`std::`]{.rm}@basic_stacktrace>; 22 | } 23 | ``` 24 | 25 | Expanded Motivation. 26 | 27 | # Before / After Table 28 | 29 | ::: tonytable 30 | 31 | ### Before 32 | ```C++ 33 | char buffer[1024]; 34 | 35 | std::pmr::monotonic_buffer_resource pool{ 36 | std::data(buffer), std::size(buffer)}; 37 | 38 | std::basic_stacktrace< 39 | std::pmr::polymorphic_allocator> 40 | trace{&pool}; 41 | ``` 42 | 43 | ### After 44 | ```C++ 45 | char buffer[1024]; 46 | 47 | std::pmr::monotonic_buffer_resource pool{ 48 | std::data(buffer), std::size(buffer)}; 49 | 50 | std::pmr::stacktrace trace{&pool}; 51 | ``` 52 | 53 | ::: 54 | 55 | # Motivation 56 | 57 | The type `std::basic_stacktrace` is a class template with an allocator type parameter, the allocator is fixed to be `std::allocator` in the `std::stacktrace` alias, and it models _AllocatorAwareContainer_. All of the work to enable a pmr using type has been done, except for actually specifying the existence of the template alias `std::pmr::stacktrace` with a `polymorphic_allocator`. 58 | 59 | In general a template should have an alias in the `pmr` namespace when the primary template supports the allocator model and the allocator template parameter is defaulted to be `std::allocator`. Providing the `pmr` alias is a convenience for changing the default. 60 | 61 | Not having the pmr alias makes `std::stacktrace` inconsistent with the other types that support using a `polymorphic_allocator`. Programmers that wish to use types supporting polymorphic memory resources should expect to find those types having a pmr alias that changes the default. Although the burden is often low for writing such an alias, it is not zero. 62 | 63 | In addition, writing into a fixed contiguous buffer can improve performance allowing this facilty to be used safely in more contexts. 64 | 65 | # Proposed Wording 66 | 67 | Modify __[stacktrace.syn]{.sref}__ as indicated 68 | 69 | ``` 70 | namespace std { 71 | // [stacktrace.entry], class stacktrace_­entry 72 | class stacktrace_entry; 73 | 74 | // [stacktrace.basic], class template basic_­stacktrace 75 | template 76 | class basic_stacktrace; 77 | 78 | // basic_­stacktrace typedef names 79 | using stacktrace = basic_stacktrace>; 80 | 81 | // [stacktrace.basic.nonmem], non-member functions 82 | template 83 | void swap(basic_stacktrace& a, basic_stacktrace& b) 84 | noexcept(noexcept(a.swap(b))); 85 | 86 | string to_string(const stacktrace_entry& f); 87 | 88 | template 89 | string to_string(const basic_stacktrace& st); 90 | 91 | template 92 | basic_ostream& 93 | operator<<(basic_ostream& os, const stacktrace_entry& f); 94 | 95 | template 96 | basic_ostream& 97 | operator<<(basic_ostream& os, const basic_stacktrace& st); 98 | 99 | @@[`namespace pmr {`]{.add}@@ 100 | @@[`using stacktrace = basic_stacktrace>;`]{.add}@@ 101 | @@[`}`]{.add}@@ 102 | 103 | // [stacktrace.basic.hash], hash support 104 | template struct hash; 105 | template<> struct hash; 106 | template struct hash>; 107 | } 108 | ``` 109 | [Compiler Explorer Link](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAM1QDsCBlZAQwBtMQBGAFlICsupVs1qhkAUgBMAISnTSAZ0ztkBPHUqZa6AMKpWAVwC2tQVvQAZPLUwA5YwCNMxEAFYAbKQAOqBYXW0eoYmgj5%2BanRWNvZGTi4eisqYqgEMBMzEBEHGppyJKhG0aRkEUXaOzm6eCumZ2SF5NSVlMXFVAJSKqAbEyBwA5FIAzNbIhlgA1OJDOkaYRiQAntPY4gAMAILDo%2BOYUzNzC8SLAPrEmArdvZgr61ubd7TMcwpezH0TNehTAOyymxMJgB6IFTVzSJrIADWBGI70wADotLDlq4ACKkCZjZgKBSfdLQ2Hwk7iHSScQbNHI453QHY3H494wuF9E7U5ZDf73DaAkFgiEE5nwhEOHF4CTozH0vEEeZeYSyiaivzIElkiloyFCvq0iayozy5iy6Y6aUTDasVioFhEYi3AGArHCBnK8UnLVEnWcu66vmu1Wk8mUj0svYERZeTBYKgTJ4vXUGPyiRmE0P7NFKsWqkPwk1sK02kgmnOs9m3Iarb0PB188TgkuI/0I2h0Q51jGxugAWkOcQmVAMtBSdAUuv1huNMzNFoLRqLFd1gIAbqg8N8FAB3ZheCD%2B92Cz03GYz61zu0LyTuCbMTF7hsmk%2BF8%2BrS9K9qLx0tzAADz6XgIEBfr%2BmD/hAzAIpu267u0MHTFyuo1MQ1jAHqqD7khogQGgtA1Cm2qYGy9A0q%2BVDvlW3KAuOCpHqazp4o%2BZ72jyjqIchqHochWEjgQmYqvuTKHg%2BlqnratyvjUZHwQ6VFGjRZrIAgGQACpSnRepwoQo4Lg6gJ7r4sKYM8JoKcpmJEppYnuB%2BgKoJGcKiTMJq7lmJz6ecRlTopxAqepzAWReV6%2BFK3F4YehEolIV6kXBPrSXK1HGWpJneapOIyhpBAKKlDIMQ5qw6bxbpuYZRjGV5PnmZllnWRMtnOIxjkzM5fHFR5prlWZGVaS%2BgVZViIV3geoZCbOeWRfikmxcxcYXG8HxeEYxC/FyjoTImbENum%2BLoCAICDQJw0zD4rCLEcXgIG6%2BYifOOgNuFNILo9K2/GiU2%2BqCdYCgdwpNopCgIO2mJ/QgnwGF4PiZGO8WyYlaUTEpKz4sQBiqBMwMxXFBoJY12BIyjPHozMd1lk9UNYzDU5qbl8644h%2BNoziAMzPtqa5sewlPuWlbwT8r3Vhs1g8U4NDnBA7TLXcyVKgYVBUM4n2cGskjcO2GPcl8u0LS4IALC2RC0G6Dgy3LxBnBcVzzag%2BjiH8H4ayA6BGswu7G84nTbbtfgAF6YC7stuzbr3kXc9ss/hJp2wQO0gFrmv6KdJDnZdHMNbdUee0NxIk5W%2BXMZRw225ePjW7zauB1NgvXlQsrEGLEubFLRv%2B3a4KK8rqvB5s9uxzrdCoPrhuu6b5yXD0lsl89gL2476R%2Byb7v297vtN/P5edxs3eLRn30fIJhfuMXrBrzzaL9J0rAgP0rj9KQpj9GsN%2BoJfOhyHInwW3swycDfBCXw/MGkChCAIYQwEQgPARAyBngL79G4DfO%2BD9SBP36DfBQIA1ikF/vfM%2BpA4CwCQGgA0eB2BkAoFxIhJCUDCFECcWEg4oSkCoMQmuaDdx/xvg4awGRFiX2/qQQhcx6AAHlaAnXYaQLARgRDAHYOI/A5wUhLguOIn8yQDCyl4TfQWyhxGsDwA4OExw9BYE0ZgpCRhNGdBoPQJgbAOA8H4IIahYhX4yCEPotBkBOi2UKGg/oXYuxfGmGiCQMg5CSEQUoAoARNDaHqLkUg5gWgVBcHkMI/g6DxNCL4DJtBkmxEqI0JIw4ii1CyPoHIggonJEKMUTI%2BS2iNDKVkppzRrDlAKakzoo9rhcHPpfa%2Bt9xHIO/AADncF2dw3AnTSImBAOhtAoTiwgLgQgJApiSCGHkCYegKHOA2Vs8WL8wkyB/uwgBQCQFgMgTckB0DL5wKGdgpBl9UHoMwec3BMBEAgG6AQLw6jyCUEIV4YhhTEn4FtIIaxjAWCyIcRuOEXhLFCAGfA4Zl8v4TA3IQEGYyJlTJmcmeZyNFntDOdgi5wDQG3Nuai2B6LnnILeRgrB/9%2Bn9EkIyxBzKPmUs6Eo4gfgNDcCAA) 110 | -------------------------------------------------------------------------------- /sd2018-tuesday.org: -------------------------------------------------------------------------------- 1 | * Modules 2 | 3 | ** Anonymous namespaces in modules, why? 4 | 5 | ** Skepticism of legacy header units 6 | 7 | ** Constraints based on what compilers can do, and have done 8 | 9 | 10 | * Module keyword 11 | 12 | arguing about deprecation - 13 | 14 | 15 | * BREAK 16 | 17 | 18 | * Pre-lunch 19 | 20 | ** Partitions 21 | ** More Partitions 22 | 23 | ** More about legacy headers 24 | XOPEN and UNICODE poster children 25 | 26 | 27 | 28 | * After Lunch 29 | 30 | ** global fragment is needed 31 | -------------------------------------------------------------------------------- /sg16-notes.org: -------------------------------------------------------------------------------- 1 | P1108R4 2 | Start 4:15 3 | Peter Brett: 4 | No http header which determines encoding, please provide a method of specifying encoding 5 | Hal Finkel 6 | Briefy touched on in telecon 7 | Data Might not be text 8 | Interest in providing mime-type 9 | Not sure if it is implemental to provide encoding unless part of mime type 10 | Zach: 11 | Might be reasonable to just require UTF-8 12 | Hal: 13 | All strings now u8strings 14 | Only "Window Title" might be complicated, u8string can be handled by implementation 15 | 16 | No Polls 17 | 18 | End 4:25 19 | 20 | Discussion on what to discuss 21 | -------------------------------------------------------------------------------- /sg16-review-rubric.md: -------------------------------------------------------------------------------- 1 | - Document number: P1253R0 2 | - Date: 2019-01-21 3 | - Author: Steve Downey 4 | [sdowney2@bloomberg.net](mailto:sdowney2@bloomberg.net) 5 | - Audience: SG16, LEWG, LEWGI, EWG, EWGI, WG21 6 | 7 |
8 | Abstract: Guidelines for when a WG21 proposal should be reviewed by 9 | SG16, the text and Unicode study group. 10 | 11 |
12 | 13 | 14 | # Introduction 15 | 16 | This paper provides some guidelines for when WG21 papers should be forwarded to study group 16 for review. The focus of study group 16 is text processing, with a specific focus on Unicode. Study group 16 will also review papers for issues with text encoding, text formatting, and IO. 17 | 18 | 19 | # Unicode Facilities 20 | 21 | Any proposal that implements a general purpose Unicode text type, a view on Unicode text, or implements any of the Unicode standard facilities or algorithms should of course be forwarded to SG16. SG16 is currently reviewing proposals for std::text and std::text\\\_view, so anything with those names should also be sent to SG16. 22 | 23 | Any proposal that mentions Unicode may be sent for review, if just to get clarification of what is meant in context. We currently live in a multi-character set and encoding world, and in general it is difficult to require or specify that general text follows a particular encoding. If existing external standards, such as XML or JSON, require Unicode or a particular encoding, following those standards doesn't need particular review from SG16. 24 | 25 | Using existing language and library facilities does not require review. For example, using std::string, std::string\\\_view, etc. An exception would be using char16\\\_t, char32\\\_t, or char8\\\_t, but only because those imply, or should imply, Unicode text. 26 | 27 | 28 | # Char{8,16,32}\_t overloads or specializations 29 | 30 | Any specific overload or specialization using the types char16\\\_t, char32\\\_t, or char8\\\_t should be reviewed by Study Group 16. They are intended for Unicode text processing, and are therefor within the remit of SG16. 31 | 32 | If the types are merely mentioned because they are trivial types, and there is no specialized behavior because of the type, SG16 does not need to review. 33 | 34 | 35 | # Text Encoding 36 | 37 | Any proposal that transcodes text from host, source, execution, or other text encoding, to any of the Unicode text encodings, such as UTF-8, should be sent to Study Group 16. Any proposal that states that text is encoded in a particular specified encoding, such as UTF-18, or CP-1252, should be sent to Study Group 16, where the group can make recommendations about avoiding that, and the unfortunate reality of supported systems where this can not be done. 38 | 39 | Any proposals for controlling or changing source or execution encoding should be sent to Study Group 16. 40 | 41 | Proposals merely asserting that text is in the execution encoding or translated from the source encoding as currently specified do not need review. 42 | 43 | Study Group 16 would like to be made aware of proposals using Unicode encoded literals, but in general would not need to review them. 44 | 45 | The assumption that char, signed char, and unsigned char, are in the execution encoding has turned out in practice to be fraught. It may be appropriate to treat data from external sources as having an unknown encoding, rather than the unspecified execution encoding. New facilities may need to provide mechanisms for explicitly specifing the encoding of text. 46 | 47 | 48 | # Formatting 49 | 50 | Study Group has already been involved in reviewing std::fmt, and will continue as Unicode facilities are added. 51 | 52 | 53 | # Locales 54 | 55 | A proposal that uses `std::locale` should be referred to Study Group 16. It is the view of Study Group 16 that large parts of std::locale range from unportable to broken in practice. SG16 may be able to provide expertise and experience on correct use of locales. 56 | 57 | Providing alternatives is an area of active research, and any new uses of `std::locale` are of interest. 58 | 59 | 60 | # IO 61 | 62 | New text input and output proposals should be referred to Study Group 16 to the extent that they expect to deal with text encoding, or want to require a particular encoding. Recent examples include command line arguments, environment, and debugging data. 63 | 64 | Using existing input/output facilities, such as iostreams or C-style IO does not require review. 65 | 66 | 67 | # Text containers and string builders 68 | 69 | New text containers should be sent to Study Group 16 for review, to make sure they can be aligned with Unicode facilities. In particular, there are concerns around breaking encodings by slicing codepoints when operating by code unit, as well as slicing grapheme clusters. String builders may have similar issues, and should also be referred to SG16. 70 | 71 | 72 | # File names 73 | 74 | File names present particular challenges, in both host and execution environments. Even using `std::filesystem::path` may present issues if it is expected that the name is displayable. Display names may not roundtrip properly to what the OS APIs require. This is an area of research for Study Group 16, so papers should be referred to SG16. 75 | -------------------------------------------------------------------------------- /sg16-review-rubric.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: SG16 Guidelines for Review of Proposals 6 | #+AUTHOR: Steve Downey 7 | #+EMAIL: sdowney2@bloomberg.net, sdowney@gmail.com 8 | #+LANGUAGE: en 9 | #+SELECT_TAGS: export 10 | #+EXCLUDE_TAGS: noexport 11 | #+LATEX_CLASS: article 12 | #+LATEX_CLASS_OPTIONS: 13 | #+LATEX_HEADER: 14 | #+LATEX_HEADER_EXTRA: 15 | #+DESCRIPTION: 16 | #+KEYWORDS: 17 | #+SUBTITLE: 18 | #+LATEX_COMPILER: pdflatex 19 | #+DATE: <2018-11-26 Mon> 20 | #+STARTUP: showall 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+SUBTITLE: 33 | #+INFOJS_OPT: 34 | 35 | - Document number: DnnnnR0 36 | - Date: 2019-01-08 37 | - Author: Steve Downey 38 | [[mailto:sdowney2@bloomberg.net][sdowney2@bloomberg.net]] 39 | - Audience: SG16, LEWG, LEWGI, EWG, EWGI, WG21 40 | 41 | #+BEGIN_ABSTRACT 42 | Abstract: Guidelines for when a WG21 proposal should be reviewed by 43 | SG16, the text and Unicode study group. 44 | #+END_ABSTRACT 45 | 46 | * Introduction 47 | :PROPERTIES: 48 | :CUSTOM_ID: introduction 49 | :END: 50 | 51 | This paper provides some guidelines for when WG21 papers should be forwarded to study group 16 for review. The focus of study group 16 is text processing, with a specific focus on Unicode. Study group 16 will also review papers for issues with text encoding, text formatting, and IO. 52 | 53 | * Unicode Facilities 54 | :PROPERTIES: 55 | :CUSTOM_ID: unicode-facilities 56 | :END: 57 | 58 | Any proposal that implements a general purpose Unicode text type, a view on Unicode text, or implements any of the Unicode standard facilities or algorithms should of course be forwarded to SG16. SG16 is currently reviewing proposals for std::text and std::text\_view, so anything with those names should also be sent to SG16. 59 | 60 | Any proposal that mentions Unicode may be sent for review, if just to get clarification of what is meant in context. We currently live in a multi-character set and encoding world, and in general it is difficult to require or specify that general text follows a particular encoding. If existing external standards, such as XML or JSON, require Unicode or a particular encoding, following those standards doesn't need particular review from SG16. 61 | 62 | Using existing language and library facilities does not require review. For example, using std::string, std::string\_view, etc. An exception would be using char16\_t, char32\_t, or char8\_t, but only because those imply, or should imply, Unicode text. 63 | 64 | * Char{8,16,32}_t overloads or specializations 65 | :PROPERTIES: 66 | :CUSTOM_ID: charN_t 67 | :END: 68 | Any specific overload or specialization using the types char16\_t, char32\_t, or char8\_t should be reviewed by Study Group 16. They are intended for Unicode text processing, and are therefor within the remit of SG16. 69 | 70 | If the types are merely mentioned because they are trivial types, and there is no specialized behavior because of the type, SG16 does not need to review. 71 | 72 | * Text Encoding 73 | :PROPERTIES: 74 | :CUSTOM_ID: text-encoding 75 | :END: 76 | 77 | Any proposal that transcodes text from host, source, execution, or other text encoding, to any of the Unicode text encodings, such as UTF-8, should be sent to Study Group 16. Any proposal that states that text is encoded in a particular specified encoding, such as UTF-18, or CP-1252, should be sent to Study Group 16, where the group can make recommendations about avoiding that, and the unfortunate reality of supported systems where this can not be done. 78 | 79 | Any proposals for controlling or changing source or execution encoding should be sent to Study Group 16. 80 | 81 | Proposals merely asserting that text is in the execution encoding or translated from the source encoding as currently specified do not need review. 82 | 83 | Study Group 16 would like to be made aware of proposals using Unicode encoded literals, but in general would not need to review them. 84 | 85 | The assumption that char, signed char, and unsigned char, are in the execution encoding has turned out in practice to be fraught. It may be appropriate to treat data from external sources as having an unknown encoding, rather than the unspecified execution encoding. New facilities may need to provide mechanisms for explicitly specifing the encoding of text. 86 | 87 | * Locales 88 | A proposal that uses ~std::locale~ should be referred to Study Group 16. It is the view of Study Group 16 that large parts of std::locale range from unportable to broken in practice. SG16 may be able to provide expertise and experience on correct use of locales. 89 | 90 | Providing alternatives is an area of active research, and any new uses of ~std::locale~ are of interest. 91 | 92 | * Formatting 93 | :PROPERTIES: 94 | :CUSTOM_ID: formatting 95 | :END: 96 | 97 | Study Group has already been involved in reviewing std::fmt, and will continue as Unicode faciliities are added. 98 | 99 | * IO 100 | :PROPERTIES: 101 | :CUSTOM_ID: io 102 | :END: 103 | 104 | New text input and output proposals should be referred to Study Group 16 to the extent that they expect to deal with text encoding, or want to require a particular encoding. Recent examples include command line arguments, environment, and debugging data. 105 | 106 | Using existing input/output facilities, such as iostreams or C-style IO does not require review. 107 | 108 | * Text containers and string builders 109 | New text containers should be sent to Study Group 16 for review, to make sure they can be aligned with Unicode facilities. In particular, there are concerns around breaking encodings by slicing codepoints when operating by code unit, as well as slicing grapheme clusters. String builders may have similar issues, and should also be referred to SG16. 110 | 111 | * File names 112 | File names present particular challenges, in both host and execution environments. Even using ~std::filesystem::path~ may present issues if it is expected that the name is displayable. Display names may not roundtrip properly to what the OS APIs require. This is an area of research for Study Group 16, so papers should be referred to SG16. 113 | -------------------------------------------------------------------------------- /unicode-strawman.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline author:nil 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:nil e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Unicode Strawman 6 | #+DATE: <2019-02-21 Thu> 7 | #+AUTHOR: Steve Downey 8 | #+EMAIL: sdowney@sdowney.org 9 | #+LANGUAGE: en 10 | #+SELECT_TAGS: export 11 | #+EXCLUDE_TAGS: noexport 12 | #+CREATOR: Emacs 26.1.91 (Org mode 9.2.1) 13 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:auto html-preamble:t 14 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 15 | #+HTML_DOCTYPE: xhtml-strict 16 | #+HTML_CONTAINER: div 17 | #+DESCRIPTION: 18 | #+KEYWORDS: 19 | #+HTML_LINK_HOME: 20 | #+HTML_LINK_UP: 21 | #+HTML_MATHJAX: 22 | #+HTML_HEAD: 23 | #+HTML_HEAD_EXTRA: 24 | #+SUBTITLE: 25 | #+INFOJS_OPT: 26 | #+CREATOR: Emacs 26.1.91 (Org mode 9.2.1) 27 | #+LATEX_HEADER: 28 | #+STARTUP: showall 29 | 30 | 31 | * A C++ 20 Range API for Unicode Text (for C++23) 32 | 33 | A unicode codepoint is always modeled as a char32_t. Because I don't like typedefs, there is no ~codepoint_t~. 34 | 35 | Customization point objects ~codepoint~ and ~grapheme~ whose default behavior is to treat the View that they are given as a sequence of UTF-8 and produce Views over char32_t codepoints, and Views over Views of char32_t codepoints, ~codepoint_view~ and ~grapheme_view~. Draconian error handling, producing nothing if the underlying data is not well formed. There may be _other_ transcoding objects providing replacements or callbacks for error handling. 36 | 37 | A Concept, ~UnicodeText~, which requires that ~codepoint(T const& t)~ and ~grapheme(T const& t)~ are well formed. 38 | 39 | Concepts ~CodepointView~ and ~GraphemeView~, which syntactically require that a type is View of char32_t and View of View of char32_t respectively, but have the additional semantic requirement of being ranges of codepoints and grapheme clusters. 40 | 41 | Unicode algorithms take Concepts of either UnicodeText or the Concept they require, and the second is producible from the first. 42 | 43 | std::text will model UnicodeText. 44 | 45 | std::text does not model Range. Access to code units is via ~text::data()~, codepoints via ~text::codepoint()~, EGCs via ~text::grapheme()~. 46 | -------------------------------------------------------------------------------- /view-maybe-lewgi.org: -------------------------------------------------------------------------------- 1 | #+TITLE: View::maybe 2 | #+DATE: <2019-02-14 Thu> 3 | #+AUTHOR: Steve Downey 4 | #+EMAIL: sdowney@sdowney.org 5 | #+LANGUAGE: en 6 | #+SELECT_TAGS: export 7 | #+EXCLUDE_TAGS: noexport 8 | #+CREATOR: Emacs 26.1.91 (Org mode 9.2.1) 9 | 10 | #+STARTUP: showall 11 | #+OPTIONS: reveal_center:nil reveal_progress:t reveal_history:nil reveal_control:t 12 | #+OPTIONS: reveal_rolling_links:t reveal_keyboard:t reveal_overview:t num:nil 13 | #+OPTIONS: reveal_width:1400 reveal_height:1000 14 | #+OPTIONS: toc:1 15 | #+REVEAL_MARGIN: 0.1 16 | #+REVEAL_MIN_SCALE: 0.5 17 | #+REVEAL_MAX_SCALE: 2.5 18 | #+REVEAL_TRANS: cube 19 | #+REVEAL_THEME: moon 20 | #+REVEAL_HLEVEL: 2 21 | 22 | #+REVEAL_MATHJAX_URL: https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML 23 | #+REVEAL_HIGHLIGHT_CSS: %r/lib/css/zenburn.css 24 | #+REVEAL_PLUGINS: (markdown notes) 25 | 26 | * The motivation. 27 | 28 | In writing range transformation pipelines it is useful to be able to lift a nullable value into a view that is either empty or contains the value held by the nullable. 29 | 30 | The adapter view::single fills a similar purpose for non-nullable values, lifting a single value into a view, and view::empty provides a range of no values of a given type. 31 | 32 | A view::maybe adaptor also allows nullable values to be treated as ranges when it is otherwise undesirable to make them containers, for example std::optional. 33 | 34 | ** Example 1 35 | #+begin_src C++ 36 | std::vector> v{ 37 | std::optional{42}, 38 | std::optional{}, 39 | std::optional{6 * 9}}; 40 | 41 | auto r = view::join(view::transform(v, view::maybe)); 42 | 43 | for (auto i : r) { 44 | std::cout << i; // prints 42 and 42^H^H 56 45 | } 46 | #+end_src 47 | 48 | ** Example 2 49 | #+begin_src C++ 50 | std::optional o{7}; 51 | for (auto&& i : view::maybe(o)) { 52 | i = 9; 53 | std::cout << "i=" << i << " prints 9\n"; 54 | } 55 | std::cout << "o=" << *o << " prints 9\n"; 56 | 57 | auto oe = std::optional{}; 58 | for (int i : view::maybe(oe)) 59 | std::cout << "i=" << i << '\n'; // does not print 60 | #+end_src 61 | 62 | * The basics of the design. 63 | Depending on if the underlying nullable is a temporary or not, the view either captures a copy of the nullable object in a ~semiregular-box~ or holds a pointer to the underlying object. In either case, if the nullable object is empty, ~data()~ returns nullptr, otherwise the address of the value. 64 | 65 | The view interface function ~size()~ returns 0 or 1, and ~begin()~ and ~end()~ have natural definitions in terms of ~data()~ and ~size()~. 66 | 67 | ** ~view::maybe~ 68 | #+begin_src C++ 69 | struct __maybe_fn { 70 | template > 71 | requires ranges::Constructible && 72 | ranges::CopyConstructible 73 | constexpr safe_maybe_view operator()(T&& t) 74 | const noexcept(std::is_nothrow_constructible_v) { 75 | return safe_maybe_view{std::move(t)}; // Safe copy 76 | } 77 | 78 | template 79 | constexpr ref_maybe_view operator()(T& t) 80 | const noexcept { 81 | return ref_maybe_view{t}; // Refer to t 82 | } 83 | }; 84 | inline constexpr __maybe_fn maybe{}; 85 | #+end_src 86 | 87 | ** ~safe_maybe_view~ 88 | Some details removed 89 | #+begin_src C++ 90 | template 91 | requires ranges::CopyConstructible 92 | class safe_maybe_view 93 | : public ranges::view_interface> { 94 | private: 95 | using T = remove_reference_t>; 96 | 97 | ranges::detail::semiregular_box value_; 98 | 99 | public: 100 | constexpr safe_maybe_view() = default; 101 | 102 | constexpr explicit safe_maybe_view(Maybe&& maybe) 103 | noexcept(is_nothrow_move_constructible_v) 104 | : value_(move(maybe)) {} 105 | 106 | constexpr T* begin() noexcept { return data(); } 107 | constexpr T* end() noexcept { return data() + size(); } 108 | 109 | constexpr ptrdiff_t size() const noexcept { return bool(value_.get()); } 110 | 111 | constexpr T* data() noexcept { 112 | Maybe& m = value_.get(); 113 | return m ? addressof(*m) : nullptr; 114 | } 115 | }; 116 | #+end_src 117 | 118 | ** ~ref_maybe_view~ 119 | Some details removed 120 | #+begin_src C++ 121 | template 122 | class ref_maybe_view 123 | : public std::experimental::ranges::view_interface> { 124 | using T = std::remove_reference_t>; 125 | 126 | Maybe* value_ = nullptr; 127 | 128 | public: 129 | constexpr ref_maybe_view() = default; 130 | constexpr explicit ref_maybe_view(Maybe& maybe) noexcept 131 | : value_(std::addressof(maybe)) {} 132 | 133 | constexpr T* begin() noexcept { return data(); } 134 | constexpr T* end() noexcept { return data() + size(); } 135 | 136 | constexpr std::ptrdiff_t size() const noexcept { return bool(*value_); } 137 | 138 | constexpr T* data() noexcept { 139 | return *value_ ? std::addressof(**value_) : nullptr; 140 | } 141 | }; 142 | #+end_src 143 | ** Concept Nullable 144 | Leaving out equality preserving requirements 145 | #+begin_src C++ 146 | template 147 | concept bool Nullable = 148 | std::is_object_v && 149 | requires(T& t, const T& ct) { 150 | bool(ct); 151 | *t; 152 | *ct; 153 | }; 154 | #+end_src 155 | 156 | * The history of your proposal within WG21. 157 | Presented R0 at San Diego 158 | 159 | "Not Small" 160 | 161 | Encouraged to make it small. 162 | 163 | Internally to Bloomberg got assurances that our nullable type would be made to conform with the std nullable protocol. 164 | 165 | * Important changes from previous revisions. 166 | Removed all customization points. 167 | 168 | Now defined purely in terms of the, non-normative, Nullable Concept. 169 | 170 | A Nullalble is Contextually Bool and Dereferenceable. 171 | 172 | Considered Readable, instead of dereferenceable, but that pulls in expensive traits. 173 | 174 | * Previous polls and guidance. 175 | Discussed in San Diego: 176 | http://wiki.edg.com/bin/view/Wg21sandiego2018/P1255 177 | 178 | ** encourage future work - find a solution to visiting one-or-more optionals 179 | | SF | F | N | A | SA | 180 | | 6 | 7 | 5 | 1 | 0 | 181 | 182 | ** like the Maybe concept (contextually convertible to bool not by decay, dereferencable to object type) 183 | 184 | | SF | F | N | A | SA | 185 | | 2 | 12 | 1 | 1 | 0 | 186 | 187 | ** prefer view::maybe vs. begin()/end() for optional<> / Maybe 188 | | SV | V | N | O | SO | 189 | | 6 | 7 | 3 | 2 | 0 | 190 | 191 | * Your intended ship vehicle 192 | Ideally C++20, failing that, C++23 and get it into experimental/ in range libraries. 193 | 194 | * Relevant prior art and existing best practice. 195 | Similar facilities in wide use in functional languages, for lifting an Optional type into List. 196 | 197 | A simplified version used in Eric Niebler's [[http://ericniebler.com/2018/12/05/standard-ranges/][Pythagorian Triples, Revisited]] 198 | #+begin_src C++ 199 | // maybe_view defines a view over zero or one 200 | // objects. 201 | template 202 | struct maybe_view : view_interface> { 203 | maybe_view() = default; 204 | maybe_view(T t) : data_(std::move(t)) { 205 | } 206 | T const *begin() const noexcept { 207 | return data_ ? &*data_ : nullptr; 208 | } 209 | T const *end() const noexcept { 210 | return data_ ? &*data_ + 1 : nullptr; 211 | } 212 | private: 213 | optional data_{}; 214 | }; 215 | #+end_src 216 | 217 | * Implementation and usage experience. 218 | Implementation available at https://github.com/steve-downey/view_maybe which depends on cmcstl2. 219 | 220 | https://github.com/steve-downey/view_maybe/blob/master/src/view_maybe/view_maybe.h 221 | 222 | There will be a PR for CMCSTL2 soon. There was red tape involved. 223 | 224 | This tends to be written, poorly, by many people implementing range style code. 225 | -------------------------------------------------------------------------------- /why-modules.org: -------------------------------------------------------------------------------- 1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t 2 | #+OPTIONS: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t 3 | #+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t 4 | #+OPTIONS: tasks:t tex:t timestamp:t title:t toc:nil todo:t |:t 5 | #+TITLE: Why Modules? 6 | #+SUBTITLE: It's not about build time. 7 | #+DATE: <2024-02-01 Thu> 8 | #+AUTHOR: Steve Downey 9 | #+EMAIL: sdowney2@bloomberg.net 10 | #+LANGUAGE: en 11 | #+SELECT_TAGS: export 12 | #+EXCLUDE_TAGS: noexport 13 | #+LATEX_CLASS: report 14 | #+LATEX_CLASS_OPTIONS: 15 | #+LATEX_HEADER: 16 | #+LATEX_HEADER_EXTRA: 17 | #+DESCRIPTION: 18 | #+KEYWORDS: 19 | #+SUBTITLE: 20 | #+LATEX_COMPILER: pdflatex 21 | #+OPTIONS: html-link-use-abs-url:nil html-postamble:nil html-preamble:t 22 | #+OPTIONS: html-scripts:t html-style:t html5-fancy:nil tex:t 23 | #+HTML_DOCTYPE: xhtml-strict 24 | #+HTML_CONTAINER: div 25 | #+DESCRIPTION: 26 | #+KEYWORDS: 27 | #+HTML_LINK_HOME: 28 | #+HTML_LINK_UP: 29 | #+HTML_MATHJAX: 30 | #+HTML_HEAD: 31 | #+HTML_HEAD_EXTRA: 32 | #+INFOJS_OPT: 33 | #+CREATOR: 34 | #+LATEX_HEADER: 35 | #+STARTUP: showeverything 36 | 37 | * Why Modules 38 | 39 | Abstract: C++ Named Modules are not about build optimization, although that was an important design consideration. Modules are about controlling visibility and access to names and definitions at a fine-grained level. 40 | 41 | This talk will show how to use the various features of modules and the kinds of module units to provide access to the features of your library while hiding the details you don't want clients to depend on. The talk will also cover some of the limitations and how clients may still end up depending on your details in ways that constrain your ability to maintain ABI compatibility. 42 | 43 | Topics and Preliminary Outline 44 | * Module Syntax and Semantics 45 | ** Module units 46 | ** Module "Purviews" 47 | ** Export 48 | ** Import 49 | ** Global Module Fragment 50 | ** Private Module Fragment 51 | ** Instantiation Context 52 | ** Reachability 53 | 54 | * Organizing your Module 55 | ** Dependency Cycles Are Forbidden 56 | ** Single File Unit 57 | ** Module Partitions 58 | ** Implementation Partitions 59 | ** `export import` : sub-modules 60 | 61 | * Planning ahead 62 | ** Do you care about ABI or API? 63 | ** What do you want to hide 64 | ** `inline` means inline 65 | ** Module Attachment and Mangling 66 | 67 | * Testing Modules 68 | ** Public Interface 69 | ** Test Implementation Units 70 | 71 | # Local Variables: 72 | # org-html-htmlize-output-type: inline-css 73 | # End: 74 | --------------------------------------------------------------------------------