1#!/usr/bin/env python3 2 3# Copyright 2015 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import collections 18import hashlib 19import itertools 20import os 21import re 22import subprocess 23import sys 24 25import perfection 26 27# Configuration: a list of either strings or 2-tuples of strings. 28# A single string represents a static grpc_mdstr. 29# A 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will 30# also be created). 31# The list of 2-tuples must begin with the static hpack table elements as 32# defined by RFC 7541 and be in the same order because of an hpack encoding 33# performance optimization that relies on this. If you want to change this, then 34# you must change the implementation of the encoding optimization as well. 35 36CONFIG = [ 37 # metadata strings 38 'host', 39 'grpc-timeout', 40 'grpc-internal-encoding-request', 41 'grpc-internal-stream-encoding-request', 42 'grpc-payload-bin', 43 ':path', 44 'grpc-encoding', 45 'grpc-accept-encoding', 46 'user-agent', 47 ':authority', 48 'grpc-message', 49 'grpc-status', 50 'grpc-server-stats-bin', 51 'grpc-tags-bin', 52 'grpc-trace-bin', 53 'grpc-previous-rpc-attempts', 54 'grpc-retry-pushback-ms', 55 '1', 56 '2', 57 '3', 58 '4', 59 '', 60 'x-endpoint-load-metrics-bin', 61 # channel arg keys 62 'grpc.wait_for_ready', 63 'grpc.timeout', 64 'grpc.max_request_message_bytes', 65 'grpc.max_response_message_bytes', 66 # well known method names 67 '/grpc.lb.v1.LoadBalancer/BalanceLoad', 68 '/envoy.service.load_stats.v2.LoadReportingService/StreamLoadStats', 69 '/envoy.service.load_stats.v3.LoadReportingService/StreamLoadStats', 70 '/grpc.health.v1.Health/Watch', 71 '/envoy.service.discovery.v2.AggregatedDiscoveryService/StreamAggregatedResources', 72 '/envoy.service.discovery.v3.AggregatedDiscoveryService/StreamAggregatedResources', 73 # compression algorithm names 74 'deflate', 75 'gzip', 76 'stream/gzip', 77 # te: trailers strings 78 'te', 79 'trailers', 80 # metadata elements 81 # begin hpack static elements 82 (':authority', ''), 83 (':method', 'GET'), 84 (':method', 'POST'), 85 (':path', '/'), 86 (':path', '/index.html'), 87 (':scheme', 'http'), 88 (':scheme', 'https'), 89 (':status', '200'), 90 (':status', '204'), 91 (':status', '206'), 92 (':status', '304'), 93 (':status', '400'), 94 (':status', '404'), 95 (':status', '500'), 96 ('accept-charset', ''), 97 ('accept-encoding', 'gzip, deflate'), 98 ('accept-language', ''), 99 ('accept-ranges', ''), 100 ('accept', ''), 101 ('access-control-allow-origin', ''), 102 ('age', ''), 103 ('allow', ''), 104 ('authorization', ''), 105 ('cache-control', ''), 106 ('content-disposition', ''), 107 ('content-encoding', ''), 108 ('content-language', ''), 109 ('content-length', ''), 110 ('content-location', ''), 111 ('content-range', ''), 112 ('content-type', ''), 113 ('cookie', ''), 114 ('date', ''), 115 ('etag', ''), 116 ('expect', ''), 117 ('expires', ''), 118 ('from', ''), 119 ('host', ''), 120 ('if-match', ''), 121 ('if-modified-since', ''), 122 ('if-none-match', ''), 123 ('if-range', ''), 124 ('if-unmodified-since', ''), 125 ('last-modified', ''), 126 ('link', ''), 127 ('location', ''), 128 ('max-forwards', ''), 129 ('proxy-authenticate', ''), 130 ('proxy-authorization', ''), 131 ('range', ''), 132 ('referer', ''), 133 ('refresh', ''), 134 ('retry-after', ''), 135 ('server', ''), 136 ('set-cookie', ''), 137 ('strict-transport-security', ''), 138 ('transfer-encoding', ''), 139 ('user-agent', ''), 140 ('vary', ''), 141 ('via', ''), 142 ('www-authenticate', ''), 143 # end hpack static elements 144 ('grpc-status', '0'), 145 ('grpc-status', '1'), 146 ('grpc-status', '2'), 147 ('grpc-encoding', 'identity'), 148 ('grpc-encoding', 'gzip'), 149 ('grpc-encoding', 'deflate'), 150 ('content-type', 'application/grpc'), 151 (':scheme', 'grpc'), 152 (':method', 'PUT'), 153 ('accept-encoding', ''), 154 ('content-encoding', 'identity'), 155 ('content-encoding', 'gzip'), 156 ('lb-cost-bin', ''), 157] 158 159# All entries here are ignored when counting non-default initial metadata that 160# prevents the chttp2 server from sending a Trailers-Only response. 161METADATA_BATCH_CALLOUTS = [ 162 ':path', 163 ':method', 164 ':status', 165 ':authority', 166 ':scheme', 167 'grpc-message', 168 'grpc-status', 169 'grpc-payload-bin', 170 'grpc-encoding', 171 'grpc-accept-encoding', 172 'grpc-server-stats-bin', 173 'grpc-tags-bin', 174 'grpc-trace-bin', 175 'content-type', 176 'content-encoding', 177 'accept-encoding', 178 'grpc-internal-encoding-request', 179 'grpc-internal-stream-encoding-request', 180 'user-agent', 181 'host', 182 'grpc-previous-rpc-attempts', 183 'grpc-retry-pushback-ms', 184 'x-endpoint-load-metrics-bin', 185] 186 187COMPRESSION_ALGORITHMS = [ 188 'identity', 189 'deflate', 190 'gzip', 191] 192 193STREAM_COMPRESSION_ALGORITHMS = [ 194 'identity', 195 'gzip', 196] 197 198 199# utility: mangle the name of a config 200def mangle(elem, name=None): 201 xl = { 202 '-': '_', 203 ':': '', 204 '/': 'slash', 205 '.': 'dot', 206 ',': 'comma', 207 ' ': '_', 208 } 209 210 def m0(x): 211 if not x: 212 return 'empty' 213 r = '' 214 for c in x: 215 put = xl.get(c, c.lower()) 216 if not put: 217 continue 218 last_is_underscore = r[-1] == '_' if r else True 219 if last_is_underscore and put == '_': 220 continue 221 elif len(put) > 1: 222 if not last_is_underscore: 223 r += '_' 224 r += put 225 r += '_' 226 else: 227 r += put 228 if r[-1] == '_': 229 r = r[:-1] 230 return r 231 232 def n(default, name=name): 233 if name is None: 234 return 'grpc_%s_' % default 235 if name == '': 236 return '' 237 return 'grpc_%s_' % name 238 239 if isinstance(elem, tuple): 240 return '%s%s_%s' % (n('mdelem'), m0(elem[0]), m0(elem[1])) 241 else: 242 return '%s%s' % (n('mdstr'), m0(elem)) 243 244 245# utility: generate some hash value for a string 246def fake_hash(elem): 247 return hashlib.md5(elem).hexdigest()[0:8] 248 249 250# utility: print a big comment block into a set of files 251def put_banner(files, banner): 252 for f in files: 253 print('/*', file=f) 254 for line in banner: 255 print(' * %s' % line, file=f) 256 print(' */', file=f) 257 print('', file=f) 258 259 260# build a list of all the strings we need 261all_strs = list() 262all_elems = list() 263static_userdata = {} 264# put metadata batch callouts first, to make the check of if a static metadata 265# string is a callout trivial 266for elem in METADATA_BATCH_CALLOUTS: 267 if elem not in all_strs: 268 all_strs.append(elem) 269for elem in CONFIG: 270 if isinstance(elem, tuple): 271 if elem[0] not in all_strs: 272 all_strs.append(elem[0]) 273 if elem[1] not in all_strs: 274 all_strs.append(elem[1]) 275 if elem not in all_elems: 276 all_elems.append(elem) 277 else: 278 if elem not in all_strs: 279 all_strs.append(elem) 280compression_elems = [] 281for mask in range(1, 1 << len(COMPRESSION_ALGORITHMS)): 282 val = ','.join(COMPRESSION_ALGORITHMS[alg] 283 for alg in range(0, len(COMPRESSION_ALGORITHMS)) 284 if (1 << alg) & mask) 285 elem = ('grpc-accept-encoding', val) 286 if val not in all_strs: 287 all_strs.append(val) 288 if elem not in all_elems: 289 all_elems.append(elem) 290 compression_elems.append(elem) 291 static_userdata[elem] = 1 + (mask | 1) 292stream_compression_elems = [] 293for mask in range(1, 1 << len(STREAM_COMPRESSION_ALGORITHMS)): 294 val = ','.join(STREAM_COMPRESSION_ALGORITHMS[alg] 295 for alg in range(0, len(STREAM_COMPRESSION_ALGORITHMS)) 296 if (1 << alg) & mask) 297 elem = ('accept-encoding', val) 298 if val not in all_strs: 299 all_strs.append(val) 300 if elem not in all_elems: 301 all_elems.append(elem) 302 stream_compression_elems.append(elem) 303 static_userdata[elem] = 1 + (mask | 1) 304 305# output configuration 306args = sys.argv[1:] 307MD_H = None 308MD_C = None 309STR_H = None 310STR_C = None 311D = None 312if args: 313 if 'md_header' in args: 314 MD_H = sys.stdout 315 else: 316 MD_H = open('/dev/null', 'w') 317 if 'md_source' in args: 318 MD_C = sys.stdout 319 else: 320 MD_C = open('/dev/null', 'w') 321 if 'str_header' in args: 322 STR_H = sys.stdout 323 else: 324 STR_H = open('/dev/null', 'w') 325 if 'str_source' in args: 326 STR_C = sys.stdout 327 else: 328 STR_C = open('/dev/null', 'w') 329 if 'dictionary' in args: 330 D = sys.stdout 331 else: 332 D = open('/dev/null', 'w') 333else: 334 MD_H = open( 335 os.path.join(os.path.dirname(sys.argv[0]), 336 '../../../src/core/lib/transport/static_metadata.h'), 'w') 337 MD_C = open( 338 os.path.join(os.path.dirname(sys.argv[0]), 339 '../../../src/core/lib/transport/static_metadata.cc'), 'w') 340 STR_H = open( 341 os.path.join(os.path.dirname(sys.argv[0]), 342 '../../../src/core/lib/slice/static_slice.h'), 'w') 343 STR_C = open( 344 os.path.join(os.path.dirname(sys.argv[0]), 345 '../../../src/core/lib/slice/static_slice.cc'), 'w') 346 D = open( 347 os.path.join(os.path.dirname(sys.argv[0]), 348 '../../../test/core/end2end/fuzzers/hpack.dictionary'), 349 'w') 350 351# copy-paste copyright notice from this file 352with open(sys.argv[0]) as my_source: 353 copyright = [] 354 for line in my_source: 355 if line[0] != '#': 356 break 357 for line in my_source: 358 if line[0] == '#': 359 copyright.append(line) 360 break 361 for line in my_source: 362 if line[0] != '#': 363 break 364 copyright.append(line) 365 put_banner([MD_H, MD_C, STR_H, STR_C], 366 [line[2:].rstrip() for line in copyright]) 367 368hex_bytes = [ord(c) for c in 'abcdefABCDEF0123456789'] 369 370 371def esc_dict(line): 372 out = "\"" 373 for c in line: 374 if 32 <= c < 127: 375 if c != ord('"'): 376 out += chr(c) 377 else: 378 out += "\\\"" 379 else: 380 out += '\\x%02X' % c 381 return out + "\"" 382 383 384put_banner([MD_H, MD_C, STR_H, STR_C], """WARNING: Auto-generated code. 385 386To make changes to this file, change 387tools/codegen/core/gen_static_metadata.py, and then re-run it. 388 389See metadata.h for an explanation of the interface here, and metadata.cc for 390an explanation of what's going on. 391""".splitlines()) 392 393print('#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H', file=MD_H) 394print('#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H', file=MD_H) 395print('', file=MD_H) 396print('#include <grpc/support/port_platform.h>', file=MD_H) 397print('', file=MD_H) 398print('#include <cstdint>', file=MD_H) 399print('', file=MD_H) 400print('#include "src/core/lib/transport/metadata.h"', file=MD_H) 401print('#include "src/core/lib/slice/static_slice.h"', file=MD_H) 402print('', file=MD_H) 403print('#ifndef GRPC_CORE_LIB_SLICE_STATIC_SLICE_H', file=STR_H) 404print('#define GRPC_CORE_LIB_SLICE_STATIC_SLICE_H', file=STR_H) 405print('', file=STR_H) 406print('#include <grpc/support/port_platform.h>', file=STR_H) 407print('', file=STR_H) 408print('#include <cstdint>', file=STR_H) 409print('#include <type_traits>', file=STR_H) 410print('#include "src/core/lib/slice/slice_utils.h"', file=STR_H) 411print('#include "src/core/lib/slice/slice_refcount_base.h"', file=STR_H) 412print('', file=STR_H) 413print('#include <grpc/support/port_platform.h>', file=MD_C) 414print('', file=MD_C) 415print('#include "src/core/lib/transport/static_metadata.h"', file=MD_C) 416print('', file=MD_C) 417print('#include "src/core/lib/slice/slice_internal.h"', file=MD_C) 418print('', file=MD_C) 419print('#include <grpc/support/port_platform.h>', file=STR_C) 420print('', file=STR_C) 421print('#include "src/core/lib/slice/static_slice.h"', file=STR_C) 422print('', file=STR_C) 423 424str_ofs = 0 425id2strofs = {} 426for i, elem in enumerate(all_strs): 427 id2strofs[i] = str_ofs 428 str_ofs += len(elem) 429 430 431def slice_def_for_ctx(i): 432 return ( 433 'grpc_core::StaticMetadataSlice(&g_static_metadata_slice_refcounts[%d].base, %d, g_static_metadata_bytes+%d)' 434 ) % (i, len(all_strs[i]), id2strofs[i]) 435 436 437def slice_def(i): 438 return ( 439 'grpc_core::StaticMetadataSlice(&g_static_metadata_slice_refcounts[%d].base, %d, g_static_metadata_bytes+%d)' 440 ) % (i, len(all_strs[i]), id2strofs[i]) 441 442 443def str_idx(s): 444 for i, s2 in enumerate(all_strs): 445 if s == s2: 446 return i 447 448 449# validate configuration 450for elem in METADATA_BATCH_CALLOUTS: 451 assert elem in all_strs 452static_slice_dest_assert = ( 453 'static_assert(std::is_trivially_destructible' + 454 '<grpc_core::StaticMetadataSlice>::value, ' 455 '"grpc_core::StaticMetadataSlice must be trivially destructible.");') 456print(static_slice_dest_assert, file=STR_H) 457print('#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs), file=STR_H) 458for i, elem in enumerate(all_strs): 459 print('/* "%s" */' % elem, file=STR_H) 460 print('#define %s (::grpc_core::g_static_metadata_slice_table[%d])' % 461 (mangle(elem).upper(), i), 462 file=STR_H) 463print('', file=STR_H) 464print('namespace grpc_core {', file=STR_C) 465print('', 466 'const uint8_t g_static_metadata_bytes[] = {%s};' % 467 (','.join('%d' % ord(c) for c in ''.join(all_strs))), 468 file=STR_C) 469print('', file=STR_C) 470print(''' 471namespace grpc_core { 472extern StaticSliceRefcount g_static_metadata_slice_refcounts[GRPC_STATIC_MDSTR_COUNT]; 473extern const StaticMetadataSlice g_static_metadata_slice_table[GRPC_STATIC_MDSTR_COUNT]; 474extern const uint8_t g_static_metadata_bytes[]; 475} 476''', 477 file=STR_H) 478print('grpc_slice_refcount grpc_core::StaticSliceRefcount::kStaticSubRefcount;', 479 file=STR_C) 480print(''' 481StaticSliceRefcount 482 g_static_metadata_slice_refcounts[GRPC_STATIC_MDSTR_COUNT] = { 483''', 484 file=STR_C) 485for i, elem in enumerate(all_strs): 486 print(' StaticSliceRefcount(%d), ' % i, file=STR_C) 487print('};', file=STR_C) # static slice refcounts 488print('', file=STR_C) 489print(''' 490 const StaticMetadataSlice 491 g_static_metadata_slice_table[GRPC_STATIC_MDSTR_COUNT] = { 492''', 493 file=STR_C) 494for i, elem in enumerate(all_strs): 495 print(slice_def_for_ctx(i) + ',', file=STR_C) 496print('};', file=STR_C) # static slices 497print('namespace grpc_core {', file=MD_C) 498print('StaticMetadata g_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {', 499 file=MD_C) 500for idx, (a, b) in enumerate(all_elems): 501 print('StaticMetadata(%s,%s, %d),' % 502 (slice_def_for_ctx(str_idx(a)), slice_def_for_ctx(str_idx(b)), idx), 503 file=MD_C) 504print('};', file=MD_C) # static_mdelem_table 505print((''' 506/* Warning: the core static metadata currently operates under the soft constraint 507that the first GRPC_CHTTP2_LAST_STATIC_ENTRY (61) entries must contain 508metadata specified by the http2 hpack standard. The CHTTP2 transport reads the 509core metadata with this assumption in mind. If the order of the core static 510metadata is to be changed, then the CHTTP2 transport must be changed as well to 511stop relying on the core metadata. */ 512'''), 513 file=MD_C) 514print(('grpc_mdelem ' 515 'g_static_mdelem_manifested[GRPC_STATIC_MDELEM_COUNT] = {'), 516 file=MD_C) 517print('// clang-format off', file=MD_C) 518static_mds = [] 519for i, elem in enumerate(all_elems): 520 md_name = mangle(elem).upper() 521 md_human_readable = '"%s": "%s"' % elem 522 md_spec = ' /* %s: \n %s */\n' % (md_name, md_human_readable) 523 md_spec += ' GRPC_MAKE_MDELEM(\n' 524 md_spec += ((' &g_static_mdelem_table[%d].data(),\n' % i) + 525 ' GRPC_MDELEM_STORAGE_STATIC)') 526 static_mds.append(md_spec) 527print(',\n'.join(static_mds), file=MD_C) 528print('// clang-format on', file=MD_C) 529print(('};'), file=MD_C) # static_mdelem_manifested 530print('}', file=MD_C) # namespace grpc_core 531print('}', file=STR_C) # namespace grpc_core 532 533print('', file=MD_C) 534print('#define GRPC_IS_STATIC_METADATA_STRING(slice) \\', file=STR_H) 535print((' ((slice).refcount != NULL && (slice).refcount->GetType() == ' 536 'grpc_slice_refcount::Type::STATIC)'), 537 file=STR_H) 538print('', file=STR_H) 539print('', file=STR_C) 540print('#define GRPC_STATIC_METADATA_INDEX(static_slice) \\', file=STR_H) 541print( 542 '(reinterpret_cast<grpc_core::StaticSliceRefcount*>((static_slice).refcount)->index)', 543 file=STR_H) 544print('', file=STR_H) 545 546print('# hpack fuzzing dictionary', file=D) 547for i, elem in enumerate(all_strs): 548 print('%s' % (esc_dict([len(elem)] + [ord(c) for c in elem])), file=D) 549for i, elem in enumerate(all_elems): 550 print('%s' % (esc_dict([0, len(elem[0])] + [ord(c) for c in elem[0]] + 551 [len(elem[1])] + [ord(c) for c in elem[1]])), 552 file=D) 553 554print('#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems), file=MD_H) 555print(''' 556namespace grpc_core { 557extern StaticMetadata g_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; 558extern grpc_mdelem g_static_mdelem_manifested[GRPC_STATIC_MDELEM_COUNT]; 559} 560''', 561 file=MD_H) 562print(('extern uintptr_t ' 563 'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];'), 564 file=MD_H) 565 566for i, elem in enumerate(all_elems): 567 md_name = mangle(elem).upper() 568 print('/* "%s": "%s" */' % elem, file=MD_H) 569 print(('#define %s (::grpc_core::g_static_mdelem_manifested[%d])' % 570 (md_name, i)), 571 file=MD_H) 572print('', file=MD_H) 573 574print(('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] ' 575 '= {'), 576 file=MD_C) 577print(' %s' % 578 ','.join('%d' % static_userdata.get(elem, 0) for elem in all_elems), 579 file=MD_C) 580print('};', file=MD_C) 581print('', file=MD_C) 582 583 584def md_idx(m): 585 for i, m2 in enumerate(all_elems): 586 if m == m2: 587 return i 588 589 590def offset_trials(mink): 591 yield 0 592 for i in range(1, 100): 593 for mul in [-1, 1]: 594 yield mul * i 595 596 597def perfect_hash(keys, name): 598 p = perfection.hash_parameters(keys) 599 600 def f(i, p=p): 601 i += p.offset 602 x = i % p.t 603 y = i // p.t 604 return x + p.r[y] 605 606 return { 607 'PHASHNKEYS': 608 len(p.slots), 609 'pyfunc': 610 f, 611 'code': 612 """ 613static const int8_t %(name)s_r[] = {%(r)s}; 614static uint32_t %(name)s_phash(uint32_t i) { 615 i %(offset_sign)s= %(offset)d; 616 uint32_t x = i %% %(t)d; 617 uint32_t y = i / %(t)d; 618 uint32_t h = x; 619 if (y < GPR_ARRAY_SIZE(%(name)s_r)) { 620 uint32_t delta = static_cast<uint32_t>(%(name)s_r[y]); 621 h += delta; 622 } 623 return h; 624} 625 """ % { 626 'name': name, 627 'r': ','.join('%d' % (r if r is not None else 0) for r in p.r), 628 't': p.t, 629 'offset': abs(p.offset), 630 'offset_sign': '+' if p.offset > 0 else '-' 631 } 632 } 633 634 635elem_keys = [ 636 str_idx(elem[0]) * len(all_strs) + str_idx(elem[1]) for elem in all_elems 637] 638elem_hash = perfect_hash(elem_keys, 'elems') 639print(elem_hash['code'], file=MD_C) 640 641keys = [0] * int(elem_hash['PHASHNKEYS']) 642idxs = [255] * int(elem_hash['PHASHNKEYS']) 643for i, k in enumerate(elem_keys): 644 h = elem_hash['pyfunc'](k) 645 assert keys[h] == 0 646 keys[h] = k 647 idxs[h] = i 648print('static const uint16_t elem_keys[] = {%s};' % 649 ','.join('%d' % k for k in keys), 650 file=MD_C) 651print('static const uint8_t elem_idxs[] = {%s};' % 652 ','.join('%d' % i for i in idxs), 653 file=MD_C) 654print('', file=MD_C) 655 656print( 657 'grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);', 658 file=MD_H) 659print( 660 'grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) {', 661 file=MD_C) 662print(' if (a == -1 || b == -1) return GRPC_MDNULL;', file=MD_C) 663print(' uint32_t k = static_cast<uint32_t>(a * %d + b);' % len(all_strs), 664 file=MD_C) 665print(' uint32_t h = elems_phash(k);', file=MD_C) 666print( 667 ' return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && elem_idxs[h] != 255 ? GRPC_MAKE_MDELEM(&grpc_core::g_static_mdelem_table[elem_idxs[h]].data(), GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;', 668 file=MD_C) 669print('}', file=MD_C) 670print('', file=MD_C) 671 672print('typedef enum {', file=MD_H) 673for elem in METADATA_BATCH_CALLOUTS: 674 print(' %s,' % mangle(elem, 'batch').upper(), file=MD_H) 675print(' GRPC_BATCH_CALLOUTS_COUNT', file=MD_H) 676print('} grpc_metadata_batch_callouts_index;', file=MD_H) 677print('', file=MD_H) 678print('typedef union {', file=MD_H) 679print(' struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];', 680 file=MD_H) 681print(' struct {', file=MD_H) 682for elem in METADATA_BATCH_CALLOUTS: 683 print(' struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower(), 684 file=MD_H) 685print(' } named;', file=MD_H) 686print('} grpc_metadata_batch_callouts;', file=MD_H) 687print('', file=MD_H) 688 689batch_idx_of_hdr = '#define GRPC_BATCH_INDEX_OF(slice) \\' 690static_slice = 'GRPC_IS_STATIC_METADATA_STRING((slice))' 691slice_to_slice_ref = '(slice).refcount' 692static_slice_ref_type = 'grpc_core::StaticSliceRefcount*' 693slice_ref_as_static = ('reinterpret_cast<' + static_slice_ref_type + '>(' + 694 slice_to_slice_ref + ')') 695slice_ref_idx = slice_ref_as_static + '->index' 696batch_idx_type = 'grpc_metadata_batch_callouts_index' 697slice_ref_idx_to_batch_idx = ('static_cast<' + batch_idx_type + '>(' + 698 slice_ref_idx + ')') 699batch_invalid_idx = 'GRPC_BATCH_CALLOUTS_COUNT' 700batch_invalid_u32 = 'static_cast<uint32_t>(' + batch_invalid_idx + ')' 701# Assemble GRPC_BATCH_INDEX_OF(slice) macro as a join for ease of reading. 702batch_idx_of_pieces = [ 703 batch_idx_of_hdr, '\n', '(', static_slice, '&&', slice_ref_idx, '<=', 704 batch_invalid_u32, '?', slice_ref_idx_to_batch_idx, ':', batch_invalid_idx, 705 ')' 706] 707print(''.join(batch_idx_of_pieces), file=MD_H) 708print('', file=MD_H) 709 710print('extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % 711 (1 << len(COMPRESSION_ALGORITHMS)), 712 file=MD_H) 713print('const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % 714 (1 << len(COMPRESSION_ALGORITHMS)), 715 file=MD_C) 716print('0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems), 717 file=MD_C) 718print('};', file=MD_C) 719print('', file=MD_C) 720 721print( 722 '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_core::g_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]].data(), GRPC_MDELEM_STORAGE_STATIC))', 723 file=MD_H) 724print('', file=MD_H) 725 726print('extern const uint8_t grpc_static_accept_stream_encoding_metadata[%d];' % 727 (1 << len(STREAM_COMPRESSION_ALGORITHMS)), 728 file=MD_H) 729print('const uint8_t grpc_static_accept_stream_encoding_metadata[%d] = {' % 730 (1 << len(STREAM_COMPRESSION_ALGORITHMS)), 731 file=MD_C) 732print('0,%s' % 733 ','.join('%d' % md_idx(elem) for elem in stream_compression_elems), 734 file=MD_C) 735print('};', file=MD_C) 736 737print( 738 '#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_core::g_static_mdelem_table[grpc_static_accept_stream_encoding_metadata[(algs)]].data(), GRPC_MDELEM_STORAGE_STATIC))', 739 file=MD_H) 740 741print('#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */', file=MD_H) 742print('#endif /* GRPC_CORE_LIB_SLICE_STATIC_SLICE_H */', file=STR_H) 743 744MD_H.close() 745MD_C.close() 746STR_H.close() 747STR_C.close() 748