Make search for function with given name O(1).

This operation is done in multiple places and currently it is O(N), where N is the total number of items in the IR.

PiperOrigin-RevId: 513510823
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index 859b644..e7fd18e 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -106,12 +106,25 @@
             namespace_id_to_number_of_reopened_namespaces.insert(canonical_id, current_count + 1);
         });
 
+    let mut function_name_to_functions = HashMap::<UnqualifiedIdentifier, Vec<Rc<Func>>>::new();
+    flat_ir
+        .items
+        .iter()
+        .filter_map(|item| match item {
+            Item::Func(func) => Some(func),
+            _ => None,
+        })
+        .for_each(|f| {
+            function_name_to_functions.entry(f.name.clone()).or_default().push(f.clone());
+        });
+
     Ok(IR {
         flat_ir,
         item_id_to_item_idx,
         lifetimes,
         namespace_id_to_number_of_reopened_namespaces,
         reopened_namespace_id_to_idx,
+        function_name_to_functions,
     })
 }
 
@@ -769,6 +782,7 @@
     lifetimes: HashMap<LifetimeId, LifetimeName>,
     namespace_id_to_number_of_reopened_namespaces: HashMap<ItemId, usize>,
     reopened_namespace_id_to_idx: HashMap<ItemId, usize>,
+    function_name_to_functions: HashMap<UnqualifiedIdentifier, Vec<Rc<Func>>>,
 }
 
 impl IR {
@@ -924,6 +938,13 @@
     pub fn crate_root_path(&self) -> Option<Rc<str>> {
         self.flat_ir.crate_root_path.clone()
     }
+
+    pub fn get_functions_by_name(
+        &self,
+        function_name: &UnqualifiedIdentifier,
+    ) -> impl Iterator<Item = &Rc<Func>> {
+        self.function_name_to_functions.get(function_name).map_or([].iter(), |v| v.iter())
+    }
 }
 
 #[cfg(test)]
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index ebe975d..6831f19 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -1160,12 +1160,8 @@
     expected_param_types: Vec<RsTypeKind>,
 ) -> Option<(Ident, ImplKind)> {
     db.ir()
-        // TODO(jeanpierreda): make this O(1) using a hash table lookup.
-        .functions()
-        .filter(|function| {
-            function.name == expected_function_name
-                && generate_func(db, (*function).clone()).ok().flatten().is_some()
-        })
+        .get_functions_by_name(&expected_function_name)
+        .filter(|function| generate_func(db, (*function).clone()).ok().flatten().is_some())
         .find_map(|function| {
             let mut function_param_types = function
                 .params
@@ -1189,12 +1185,10 @@
     should_derive_clone(&record)
         || db
             .ir()
-            // TODO(jeanpierreda): make this O(1) using a hash table lookup.
-            .functions()
+            .get_functions_by_name(&UnqualifiedIdentifier::Constructor)
             .filter(|function| {
-                function.name == UnqualifiedIdentifier::Constructor
                 // __this is always the first parameter of constructors
-                && function.params.len() == 2
+                function.params.len() == 2
             })
             .any(|function| {
                 let mut function_param_types = function
@@ -7041,12 +7035,12 @@
         let ir = ir_from_cc("struct Class {};").unwrap();
 
         let destructor =
-            ir.functions().find(|f| f.name == UnqualifiedIdentifier::Destructor).unwrap();
+            ir.get_functions_by_name(&UnqualifiedIdentifier::Destructor).next().unwrap();
         assert_eq!(thunk_ident(destructor), make_rs_ident("__rust_thunk___ZN5ClassD1Ev"));
 
         let default_constructor = ir
-            .functions()
-            .find(|f| f.name == UnqualifiedIdentifier::Constructor && f.params.len() == 1)
+            .get_functions_by_name(&UnqualifiedIdentifier::Constructor)
+            .find(|f| f.params.len() == 1)
             .unwrap();
         assert_eq!(thunk_ident(default_constructor), make_rs_ident("__rust_thunk___ZN5ClassC1Ev"));
     }