|  | @@ -27,7 +27,7 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map* map,
 | 
	
		
			
				|  |  |                                   size_t initial_capacity) {
 | 
	
		
			
				|  |  | -  GPR_ASSERT(initial_capacity > 1);
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(initial_capacity > 1);
 | 
	
		
			
				|  |  |    map->keys =
 | 
	
		
			
				|  |  |        static_cast<uint32_t*>(gpr_malloc(sizeof(uint32_t) * initial_capacity));
 | 
	
		
			
				|  |  |    map->values =
 | 
	
	
		
			
				|  | @@ -63,9 +63,17 @@ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map* map, uint32_t key,
 | 
	
		
			
				|  |  |    uint32_t* keys = map->keys;
 | 
	
		
			
				|  |  |    void** values = map->values;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  // The first assertion ensures that the table is monotonically increasing.
 | 
	
		
			
				|  |  |    GPR_ASSERT(count == 0 || keys[count - 1] < key);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(value);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(grpc_chttp2_stream_map_find(map, key) == nullptr);
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(value);
 | 
	
		
			
				|  |  | +  // Asserting that the key is not already in the map can be a debug assertion.
 | 
	
		
			
				|  |  | +  // Why: we're already checking that the map elements are monotonically
 | 
	
		
			
				|  |  | +  // increasing. If we re-add a key, i.e. if the key is already present, then
 | 
	
		
			
				|  |  | +  // either it is the most recently added key in the map (in which case the
 | 
	
		
			
				|  |  | +  // first assertion fails due to key == last_key) or there is a more recently
 | 
	
		
			
				|  |  | +  // added (larger) key at the end of the map: in which case the first assertion
 | 
	
		
			
				|  |  | +  // still fails due to key < last_key.
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(grpc_chttp2_stream_map_find(map, key) == nullptr);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (count == capacity) {
 | 
	
		
			
				|  |  |      if (map->free > capacity / 4) {
 | 
	
	
		
			
				|  | @@ -74,7 +82,7 @@ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map* map, uint32_t key,
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        /* resize when less than 25% of the table is free, because compaction
 | 
	
		
			
				|  |  |           won't help much */
 | 
	
		
			
				|  |  | -      map->capacity = capacity = 3 * capacity / 2;
 | 
	
		
			
				|  |  | +      map->capacity = capacity = 2 * capacity;
 | 
	
		
			
				|  |  |        map->keys = keys = static_cast<uint32_t*>(
 | 
	
		
			
				|  |  |            gpr_realloc(keys, capacity * sizeof(uint32_t)));
 | 
	
		
			
				|  |  |        map->values = values =
 | 
	
	
		
			
				|  | @@ -87,6 +95,7 @@ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map* map, uint32_t key,
 | 
	
		
			
				|  |  |    map->count = count + 1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +template <bool strict_find>
 | 
	
		
			
				|  |  |  static void** find(grpc_chttp2_stream_map* map, uint32_t key) {
 | 
	
		
			
				|  |  |    size_t min_idx = 0;
 | 
	
		
			
				|  |  |    size_t max_idx = map->count;
 | 
	
	
		
			
				|  | @@ -95,7 +104,8 @@ static void** find(grpc_chttp2_stream_map* map, uint32_t key) {
 | 
	
		
			
				|  |  |    void** values = map->values;
 | 
	
		
			
				|  |  |    uint32_t mid_key;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (max_idx == 0) return nullptr;
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(!strict_find || max_idx > 0);
 | 
	
		
			
				|  |  | +  if (!strict_find && max_idx == 0) return nullptr;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    while (min_idx < max_idx) {
 | 
	
		
			
				|  |  |      /* find the midpoint, avoiding overflow */
 | 
	
	
		
			
				|  | @@ -112,28 +122,28 @@ static void** find(grpc_chttp2_stream_map* map, uint32_t key) {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(!strict_find);
 | 
	
		
			
				|  |  |    return nullptr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void* grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map* map, uint32_t key) {
 | 
	
		
			
				|  |  | -  void** pvalue = find(map, key);
 | 
	
		
			
				|  |  | -  void* out = nullptr;
 | 
	
		
			
				|  |  | -  if (pvalue != nullptr) {
 | 
	
		
			
				|  |  | -    out = *pvalue;
 | 
	
		
			
				|  |  | -    *pvalue = nullptr;
 | 
	
		
			
				|  |  | -    map->free += (out != nullptr);
 | 
	
		
			
				|  |  | -    /* recognize complete emptyness and ensure we can skip
 | 
	
		
			
				|  |  | -     * defragmentation later */
 | 
	
		
			
				|  |  | -    if (map->free == map->count) {
 | 
	
		
			
				|  |  | -      map->free = map->count = 0;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    GPR_ASSERT(grpc_chttp2_stream_map_find(map, key) == nullptr);
 | 
	
		
			
				|  |  | +  void** pvalue = find<true>(map, key);
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(pvalue != nullptr);
 | 
	
		
			
				|  |  | +  void* out = *pvalue;
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(out != nullptr);
 | 
	
		
			
				|  |  | +  *pvalue = nullptr;
 | 
	
		
			
				|  |  | +  map->free++;
 | 
	
		
			
				|  |  | +  /* recognize complete emptyness and ensure we can skip
 | 
	
		
			
				|  |  | +     defragmentation later */
 | 
	
		
			
				|  |  | +  if (map->free == map->count) {
 | 
	
		
			
				|  |  | +    map->free = map->count = 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  GPR_DEBUG_ASSERT(grpc_chttp2_stream_map_find(map, key) == nullptr);
 | 
	
		
			
				|  |  |    return out;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void* grpc_chttp2_stream_map_find(grpc_chttp2_stream_map* map, uint32_t key) {
 | 
	
		
			
				|  |  | -  void** pvalue = find(map, key);
 | 
	
		
			
				|  |  | +  void** pvalue = find<false>(map, key);
 | 
	
		
			
				|  |  |    return pvalue != nullptr ? *pvalue : nullptr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |