-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathModulesAtScale-p0841r0.html
324 lines (233 loc) · 22.4 KB
/
ModulesAtScale-p0841r0.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>ModulesAtScale</title>
<style type="text/css">
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
</style>
</head>
<body>
<h1 id="toc_0">Modules at scale</h1>
<p><em>Document number: P0841R0</em>
</br>
<em>Audience: EWG</em>
</br>
<em><a href="mailto:[email protected]">Bruno Cardoso Lopes</a>,
<a href="mailto:[email protected]">Adrian Prantl</a>,
<a href="mailto:[email protected]">Duncan P. N. Exon Smith</a></em>
</br>
<em>2017-10-16</em></p>
<hr>
<p>This paper discusses Apple's experience with modules on its software ecosystem and how the current state of the <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> lacks the necessary expressiveness to reflect Apple's requirements.</p>
<h2 id="toc_1">Background</h2>
<p>Apple currently uses <a href="https://clang.llvm.org/docs/Modules.html">Clang Modules</a>, a <em>Modules</em> design and implementation that's specific to clang and contains support for different C-based languages; C, Objective-C, Objective-C++ and C++. The intent of this paper is not to sell <em>Clang Modules</em> but to provide insights based on the current requirements of Apple's libraries. Ideally we would like to incorporate changes into the <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> that would allow Apple to support C++ Modules in its shipping library interface.</p>
<h2 id="toc_2">Modules at Apple</h2>
<p>Clang's modules implementation predates the <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> and was first introduced in 2012. Since then Apple has been shipping modularized library interfaces (headers) in its SDKs, enabled the use of modules by default for all new macOS/iOS projects, and facilitated the widespread use of modules by third-party libraries on Apple platforms. We also support modules internally for hundreds of internal projects.</p>
<p>The majority of these projects are written in Objective-C or Objective-C++, and although not strictly C++, they export C++ or C++-compatible interfaces, which are consumed by internal or external C++ projects; Clang and Webkit are examples of such projects.</p>
<h3 id="toc_3">Interoperability through modules</h3>
<p>The <em>Swift</em> language supports interoperation with C and Objective-C, which relies on Modules for bridging the languages. Apple's developer tools provide transparent generation of modules for C and Objective-C libraries, meaning that the majority of Swift developers targeting Apple's platforms indirectly use Modules, because:</p>
<ul>
<li>Swift access to Apple APIs is done through the C and Objective-C headers coming from SDKs.</li>
<li>The primary way to access third party library APIs written in C and Objective-C in Swift is through a modular interface.</li>
</ul>
<h2 id="toc_4">Header Modules</h2>
<p>To better explain Apple's use of <em>Clang Modules</em> in <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> terms, Apple ships and provides customers the equivalent of the <em>module interface unit</em> part of a library, meaning that Apple provides one module for each library, where the exported content comes from a set of headers. The set of headers in a library is entirely described in one module, which may or may not contain associated submodules.</p>
<p>Different libraries in Apple's SDKs contain dependencies between each other. Apple's SDK is almost entirely modularized bottom-up, meaning that the relationship between all library dependencies is a chain of module imports and few non-modular includes. This allows customers to consume modules at almost every single point where a header from the SDK is used.</p>
<p>Modularization of headers are described in a special textual file (<em>modulemap</em>) that maps headers to <em>modules</em> and <em>submodules</em>. Clang performs a module import transparently: parsing a <code>#include</code> directive triggers a module import if a <em>modulemap</em> is found for the header.</p>
<p>Export control is done at module granularity level, for each module one can specify if the entire module, a few selected submodules or nothing at all is exported - see Clang Modules <a href="https://clang.llvm.org/docs/Modules.html">documentation</a> for details.</p>
<p>For instance, two possible ways of mapping are:</p>
<ol>
<li>A main header (<em>umbrella header</em>) that includes all other headers that are part of the library interface. Each header in the umbrella is automatically assigned to a submodule.</li>
<li>The explicit list of headers that are part of the module, with possible inline declaration of submodules and their sub-sequential explicit list of headers or an umbrella header.</li>
</ol>
<p>To illustrate, take library <code>Foo</code> with umbrella header <code>Foo.h</code>, including <code>FooA.h</code> and <code>FooB.h</code> headers. This corresponds to module <code>Foo</code> with submodules <code>Foo.FooA</code> and <code>Foo.FooB</code>.</p>
<p>In order to properly modularize bottom-up, Apple ships <em>modulemaps</em> in its standard C++ library (libcxx) and C library (Darwin's <code>PATH_TO_SDK/usr/include</code>). </p>
<h3 id="toc_5">Problems with the current form of Modules TS</h3>
<p>The <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS (10.7.2)</a> states that there can only be one <em>module interface unit</em> file in a module:</p>
<blockquote>
<p>A module interface unit is a module unit whose module-declaration contains the export keyword; any other module unit is a module implementation unit. A named module shall contain exactly one module interface unit.</p>
</blockquote>
<p>This is a showstopper for us, because as mentioned in the previous section, Apple's libraries consists of one or more headers, where any of them can contribute content to be exported in the final module. Additionally, the headers are shared among other supported C-based languages, and we strongly believe it's a reasonable model to continue shipping.</p>
<p>Similar concerns have been mentioned before, see the <em>Module partitions</em> section from <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0273r0.pdf">P0273R0</a>.</p>
<h2 id="toc_6">Macros</h2>
<p>Given that Apple library interfaces support different C-based languages, we rely on macros in order to correctly gather availability information, heterogeneous platform support and to reason on top of features. Because Apple's SDK is entirely modularized, these macros are available for consumption at any library interface level, being critical in Apple's chain of module imports.</p>
<p>For example, as one can see in <code>LinearAlgebra/base.h</code> shipped with the SDK in macOS 10.13, the header use macros to control availability information for a library:</p>
<div><pre><code class="language-cpp">/* Define abstractions for a number of attributes that we wish to be able to
concisely attach to functions in the LinearAlgebra library. */
#define LA_AVAILABILITY __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
...
#define LA_FUNCTION OS_EXPORT OS_NOTHROW
#define LA_CONST OS_CONST</code></pre></div>
<p>Note that <code>__MAC_10_10</code> is available through another module that provides macros from <code>Availability.h</code>. Apple's customers depend on macros with modules like these.</p>
<h3 id="toc_7">Problems with the lack of Macros in Modules TS</h3>
<p>The <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> lacks support for macros. According to Section 3.2 in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0142r0.pdf">p0142r0</a>:</p>
<blockquote>
<p>... because the preprocessor is largely independent of the core language, it is impossible for a tool to understand (even grammatically) source code in header files without knowing the set of macros and configurations that a source file including the header file will activate. It is regrettably far too easy and far too common to under-appreciate how much macros are (and have been) stifling development of semantics-aware programming tools and how much of drag they constitute for C++, compared to alternatives...</p>
</blockquote>
<p>Using Modules as a way to break away from macros seems fair but we believe a transition path is necessary, since no support for macros blocks Apple's path to adopting C++ Modules. Additionally, concerns from others were already outlined in <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0273r1.pdf">P0273R1</a>.</p>
<p>We propose support for macros with the intent of helping with migration. To achieve it, we suggest adding extra syntax that:</p>
<ul>
<li>Adds on top of existing <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> syntax.</li>
<li>Can easily be later deprecated and removed, without polluting the reserved keyword namespace.</li>
</ul>
<h3 id="toc_8">Proposed macros syntax</h3>
<p>To export macros defined in a module, we propose augmenting the <em>module-declaration</em> in a <em>module interface unit</em> with a submodule-like specification:</p>
<div><pre><code class="language-cpp">export module M; // declare module M
...
export module M.__macros; // M export all macros</code></pre></div>
<p>In the code snippet above, all macros in <code>M</code>'s <em>module interface unit</em> are exported. To select macros to export, a macro identifier can be explicitly specified with <code>export module M.__macros.<MACRO_NAME></code> as if accessing a reserved submodule:</p>
<div><pre><code class="language-cpp">export module M.__macros.INFINITY; // M exports macro INFINITY
...
export module M.__macros.HUGE_VAL; // M exports macro HUGE_VAL</code></pre></div>
<p>On the module consumer side, a similar mechanism is used. To import the complete set of macros exported by module <code>M</code>:</p>
<div><pre><code class="language-cpp">import M.__macros; // import all macros exported in module M</code></pre></div>
<p>Similarly, for importing specific known macros from module <code>M</code>:</p>
<div><pre><code class="language-cpp">import M.__macros.INFINITY; // import macro INFINITY from module M
import M.__macros.HUGE_VAL; // import macro HUGE_VAL from module M</code></pre></div>
<p>Note that exporting all macros in module <code>M</code> doesn't by default make the macros visible to importers of <code>M</code>. Importers must explicitly <code>import M._macros</code> or <code>import M._macros.<MACRO_NAME></code> to make macros defined in <code>M</code> visible. This enforces judicious use of macros in a modular world.</p>
<p>The use of <code>import</code> for macros is only allowed <em>after</em> a <em>module-declaration</em> in the same file. Likewise <code>export</code> is only valid after a <em>module-import-declaration</em> in the same file.</p>
<p>Representing macros with syntactic sugar allows for deprecation of the mechanism later on, without pollution of the top-level reserved keyword space.</p>
<h2 id="toc_9">The <code>module</code> keyword</h2>
<p>It is not clear in the <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a> whether <code>module</code> is an always reserved or context-sensitive reserved keyword. </p>
<p>Apple has been shipping for several years a kernel extension interface in C++, where the identifier <code>module</code> is used to name members describing a kernel module, as one example in <code>/usr/include/mach/host_priv.h</code>:</p>
<div><pre><code class="language-cpp">...
kern_return_t kmod_create
(
host_priv_t host_priv,
vm_address_t info,
kmod_t *module
);</code></pre></div>
<p>For instance, some versions of Clang would <a href="https://bugs.llvm.org/show_bug.cgi?id=33801">complain</a> and error out when including the code above because of the keyword conflict in Clang's implementation of the <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/n4681.pdf">Modules TS</a>.</p>
<p>We propose that <code>module</code> becomes a context-sensitive reserved keyword allowing existing libraries and and interfaces to continue using it in contexts where no semantic conflict with modules is possible.</p>
<script type="text/javascript">
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e){var t=n.util.type(e);switch(t){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=n.util.clone(e[r]));return a;case"Array":return e.map&&e.map(function(e){return n.util.clone(e)})}return e}},languages:{extend:function(e,t){var a=n.util.clone(n.languages[e]);for(var r in t)a[r]=t[r];return a},insertBefore:function(e,t,a,r){r=r||n.languages;var l=r[e];if(2==arguments.length){a=arguments[1];for(var i in a)a.hasOwnProperty(i)&&(l[i]=a[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,t,a,r){r=r||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],a||l),"Object"!==n.util.type(e[l])||r[n.util.objId(e[l])]?"Array"!==n.util.type(e[l])||r[n.util.objId(e[l])]||(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,r)):(r[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,r)))}},plugins:{},highlightAll:function(e,t){var a={callback:t,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var r,l=a.elements||document.querySelectorAll(a.selector),i=0;r=l[i++];)n.highlightElement(r,e===!0,a.callback)},highlightElement:function(t,a,r){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1],i=n.languages[l]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(!s||!i)return n.hooks.run("complete",u),void 0;if(n.hooks.run("before-highlight",u),a&&_self.Worker){var c=new Worker(n.filename);c.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},c.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(t),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},highlight:function(e,t,r){var l=n.tokenize(e,t);return a.stringify(n.util.encode(l),r)},tokenize:function(e,t){var a=n.Token,r=[e],l=t.rest;if(l){for(var i in l)t[i]=l[i];delete t.rest}e:for(var i in t)if(t.hasOwnProperty(i)&&t[i]){var o=t[i];o="Array"===n.util.type(o)?o:[o];for(var s=0;s<o.length;++s){var u=o[s],c=u.inside,g=!!u.lookbehind,h=!!u.greedy,f=0,d=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var m=r[p];if(r.length>e.length)break e;if(!(m instanceof a)){u.lastIndex=0;var y=u.exec(m),v=1;if(!y&&h&&p!=r.length-1){var b=r[p+1].matchedStr||r[p+1],k=m+b;if(p<r.length-2&&(k+=r[p+2].matchedStr||r[p+2]),u.lastIndex=0,y=u.exec(k),!y)continue;var w=y.index+(g?y[1].length:0);if(w>=m.length)continue;var _=y.index+y[0].length,P=m.length+b.length;if(v=3,P>=_){if(r[p+1].greedy)continue;v=2,k=k.slice(0,P)}m=k}if(y){g&&(f=y[1].length);var w=y.index+f,y=y[0].slice(f),_=w+y.length,S=m.slice(0,w),O=m.slice(_),j=[p,v];S&&j.push(S);var A=new a(i,c?n.tokenize(y,c):y,d,y,h);j.push(A),O&&j.push(O),Array.prototype.splice.apply(r,j)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.matchedStr=a||null,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var l={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,l=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",n.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
</script>
<script type="text/javascript">
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
</script>
<script type="text/javascript">
Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(define|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|stdin|stdout|stderr)\b/}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"];
</script>
<script type="text/javascript">
Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),Prism.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}});
</script>
</body>
</html>