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