Simplify batch callout index calculation
diff --git a/src/core/lib/transport/metadata_batch.c b/src/core/lib/transport/metadata_batch.c
index c41d28d..25cc65d 100644
--- a/src/core/lib/transport/metadata_batch.c
+++ b/src/core/lib/transport/metadata_batch.c
@@ -70,7 +70,7 @@
   for (grpc_linked_mdelem *l = batch->list.head; l != NULL; l = l->next) {
     grpc_slice key_interned = grpc_slice_intern(GRPC_MDKEY(l->md));
     grpc_metadata_batch_callouts_index callout_idx =
-        grpc_batch_index_of(key_interned);
+        GRPC_BATCH_INDEX_OF(key_interned);
     if (callout_idx != GRPC_BATCH_CALLOUTS_COUNT) {
       GPR_ASSERT(batch->idx.array[callout_idx] == l);
     }
@@ -115,22 +115,22 @@
 static grpc_error *maybe_link_callout(grpc_metadata_batch *batch,
                                       grpc_linked_mdelem *storage) {
   grpc_metadata_batch_callouts_index idx =
-      grpc_batch_index_of(GRPC_MDKEY(storage->md));
+      GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
   if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
     return GRPC_ERROR_NONE;
   }
-  if (batch->idx.array[idx] != NULL) {
-    return grpc_attach_md_to_error(
-        GRPC_ERROR_CREATE("Unallowed duplicate metadata"), storage->md);
+  if (batch->idx.array[idx] == NULL) {
+    batch->idx.array[idx] = storage;
+    return GRPC_ERROR_NONE;
   }
-  batch->idx.array[idx] = storage;
-  return GRPC_ERROR_NONE;
+  return grpc_attach_md_to_error(
+      GRPC_ERROR_CREATE("Unallowed duplicate metadata"), storage->md);
 }
 
 static void maybe_unlink_callout(grpc_metadata_batch *batch,
                                  grpc_linked_mdelem *storage) {
   grpc_metadata_batch_callouts_index idx =
-      grpc_batch_index_of(GRPC_MDKEY(storage->md));
+      GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
   if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
     return;
   }
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
index 588c098..abd5a91 100644
--- a/src/core/lib/transport/static_metadata.c
+++ b/src/core/lib/transport/static_metadata.c
@@ -807,39 +807,5 @@
      {.refcount = &grpc_static_metadata_refcounts[97],
       .data.refcounted = {g_bytes + 1010, 21}}},
 };
-#define BATCH_PHASHLEN 0x10
-#define BATCH_PHASHNKEYS 17
-#define BATCH_PHASHRANGE 32
-#define BATCH_PHASHSALT 0x9e3779b9
-
-static const uint8_t batch_tab[] = {
-    0, 13, 0, 13, 0, 13, 0, 13, 0, 13, 0, 15, 0, 13, 0, 23,
-};
-
-static uint32_t batch_phash(uint32_t val) {
-  val += (uint32_t)0;
-
-  uint32_t a, b, rsl;
-
-  b = (val & 0xf);
-  a = ((val << 27) >> 28);
-  rsl = (a ^ batch_tab[b]);
-  return rsl;
-}
-
-static const uint8_t batch_hash_to_idx[] = {
-    0,  2, 4, 6, 8, 10, 12, 14, 16, 9, 11, 13, 3, 1, 7, 5,
-    15, 0, 0, 0, 0, 0,  0,  0,  0,  0, 0,  0,  0, 0, 0, 0};
-
-grpc_metadata_batch_callouts_index grpc_batch_index_of(grpc_slice slice) {
-  if (!GRPC_IS_STATIC_METADATA_STRING(slice)) return GRPC_BATCH_CALLOUTS_COUNT;
-  uint32_t idx = (uint32_t)GRPC_STATIC_METADATA_INDEX(slice);
-  uint32_t hash = batch_phash(idx);
-  if (hash < GPR_ARRAY_SIZE(batch_hash_to_idx) &&
-      batch_hash_to_idx[hash] == idx)
-    return (grpc_metadata_batch_callouts_index)hash;
-  return GRPC_BATCH_CALLOUTS_COUNT;
-}
-
 const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  74, 75, 76,
                                                          77, 78, 79, 80};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index c9cceeb..e782a1f 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -507,22 +507,22 @@
 grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);
 typedef enum {
   GRPC_BATCH_PATH,
-  GRPC_BATCH_STATUS,
-  GRPC_BATCH_SCHEME,
-  GRPC_BATCH_GRPC_MESSAGE,
-  GRPC_BATCH_GRPC_PAYLOAD_BIN,
-  GRPC_BATCH_GRPC_ACCEPT_ENCODING,
-  GRPC_BATCH_GRPC_INTERNAL_ENCODING_REQUEST,
-  GRPC_BATCH_HOST,
-  GRPC_BATCH_LB_COST_BIN,
-  GRPC_BATCH_GRPC_ENCODING,
-  GRPC_BATCH_CONTENT_TYPE,
-  GRPC_BATCH_USER_AGENT,
-  GRPC_BATCH_AUTHORITY,
   GRPC_BATCH_METHOD,
-  GRPC_BATCH_GRPC_STATUS,
+  GRPC_BATCH_STATUS,
+  GRPC_BATCH_AUTHORITY,
+  GRPC_BATCH_SCHEME,
   GRPC_BATCH_TE,
+  GRPC_BATCH_GRPC_MESSAGE,
+  GRPC_BATCH_GRPC_STATUS,
+  GRPC_BATCH_GRPC_PAYLOAD_BIN,
+  GRPC_BATCH_GRPC_ENCODING,
+  GRPC_BATCH_GRPC_ACCEPT_ENCODING,
+  GRPC_BATCH_CONTENT_TYPE,
+  GRPC_BATCH_GRPC_INTERNAL_ENCODING_REQUEST,
+  GRPC_BATCH_USER_AGENT,
+  GRPC_BATCH_HOST,
   GRPC_BATCH_LB_TOKEN,
+  GRPC_BATCH_LB_COST_BIN,
   GRPC_BATCH_CALLOUTS_COUNT
 } grpc_metadata_batch_callouts_index;
 
@@ -530,26 +530,30 @@
   struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];
   struct {
     struct grpc_linked_mdelem *path;
-    struct grpc_linked_mdelem *status;
-    struct grpc_linked_mdelem *scheme;
-    struct grpc_linked_mdelem *grpc_message;
-    struct grpc_linked_mdelem *grpc_payload_bin;
-    struct grpc_linked_mdelem *grpc_accept_encoding;
-    struct grpc_linked_mdelem *grpc_internal_encoding_request;
-    struct grpc_linked_mdelem *host;
-    struct grpc_linked_mdelem *lb_cost_bin;
-    struct grpc_linked_mdelem *grpc_encoding;
-    struct grpc_linked_mdelem *content_type;
-    struct grpc_linked_mdelem *user_agent;
-    struct grpc_linked_mdelem *authority;
     struct grpc_linked_mdelem *method;
-    struct grpc_linked_mdelem *grpc_status;
+    struct grpc_linked_mdelem *status;
+    struct grpc_linked_mdelem *authority;
+    struct grpc_linked_mdelem *scheme;
     struct grpc_linked_mdelem *te;
+    struct grpc_linked_mdelem *grpc_message;
+    struct grpc_linked_mdelem *grpc_status;
+    struct grpc_linked_mdelem *grpc_payload_bin;
+    struct grpc_linked_mdelem *grpc_encoding;
+    struct grpc_linked_mdelem *grpc_accept_encoding;
+    struct grpc_linked_mdelem *content_type;
+    struct grpc_linked_mdelem *grpc_internal_encoding_request;
+    struct grpc_linked_mdelem *user_agent;
+    struct grpc_linked_mdelem *host;
     struct grpc_linked_mdelem *lb_token;
+    struct grpc_linked_mdelem *lb_cost_bin;
   } named;
 } grpc_metadata_batch_callouts;
 
-grpc_metadata_batch_callouts_index grpc_batch_index_of(grpc_slice slice);
+#define GRPC_BATCH_INDEX_OF(slice)                         \
+  (GRPC_IS_STATIC_METADATA_STRING((slice))                 \
+       ? GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, \
+                   GRPC_BATCH_CALLOUTS_COUNT)              \
+       : GRPC_BATCH_CALLOUTS_COUNT)
 
 extern const uint8_t grpc_static_accept_encoding_metadata[8];
 #define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs)                       \
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 7d363a9..bd05853 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -220,6 +220,8 @@
 all_strs = list()
 all_elems = list()
 static_userdata = {}
+# put metadata batch callouts first, to make the check of if a static metadata
+# string is a callout trivial
 for elem in METADATA_BATCH_CALLOUTS:
   if elem not in all_strs:
     all_strs.append(elem)
@@ -482,10 +484,7 @@
 print >>C, '};'
 
 print >>H, 'typedef enum {'
-batch_keys = [str_idx(s) for s in METADATA_BATCH_CALLOUTS]
-batch_hash = perfect_hash(batch_keys, 'batch')
-ordered_callouts = sorted((batch_hash['pyfunc'](str_idx(elem)), elem) for elem in METADATA_BATCH_CALLOUTS)
-for _, elem in ordered_callouts:
+for elem in METADATA_BATCH_CALLOUTS:
   print >>H, '  %s,' % mangle(elem, 'batch').upper()
 print >>H, '  GRPC_BATCH_CALLOUTS_COUNT'
 print >>H, '} grpc_metadata_batch_callouts_index;'
@@ -493,27 +492,14 @@
 print >>H, 'typedef union {'
 print >>H, '  struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];'
 print >>H, '  struct {'
-for _, elem in ordered_callouts:
+for elem in METADATA_BATCH_CALLOUTS:
   print >>H, '  struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower()
 print >>H, '  } named;'
 print >>H, '} grpc_metadata_batch_callouts;'
 print >>H
-print >>H, 'grpc_metadata_batch_callouts_index grpc_batch_index_of(grpc_slice slice);'
+print >>H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
+print >>H, '  (GRPC_IS_STATIC_METADATA_STRING((slice)) ? GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
 print >>H
-print >>C, batch_hash['code']
-batch_hash_to_idx = [0] * int(batch_hash['PHASHRANGE'])
-for i, elem in enumerate( METADATA_BATCH_CALLOUTS):
-  batch_hash_to_idx[batch_hash['pyfunc'](str_idx(elem))] = str_idx(elem)
-print >>C, 'static const uint8_t batch_hash_to_idx[] = {%s};' % ','.join('%d' % n for n in batch_hash_to_idx)
-print >>C
-print >>C, 'grpc_metadata_batch_callouts_index grpc_batch_index_of(grpc_slice slice) {'
-print >>C, '  if (!GRPC_IS_STATIC_METADATA_STRING(slice)) return GRPC_BATCH_CALLOUTS_COUNT;'
-print >>C, '  uint32_t idx = (uint32_t)GRPC_STATIC_METADATA_INDEX(slice);'
-print >>C, '  uint32_t hash = batch_phash(idx);'
-print >>C, '  if (hash < GPR_ARRAY_SIZE(batch_hash_to_idx) && batch_hash_to_idx[hash] == idx) return (grpc_metadata_batch_callouts_index)hash;'
-print >>C, '  return GRPC_BATCH_CALLOUTS_COUNT;'
-print >>C, '}'
-print >>C
 
 print >>H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (1 << len(COMPRESSION_ALGORITHMS))
 print >>C, 'const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % (1 << len(COMPRESSION_ALGORITHMS))