1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #pragma once
4 
5 #include <fbjni/fbjni.h>
6 
7 #include <memory>
8 #include <unordered_map>
9 
10 namespace jni = facebook::jni;
11 
12 namespace expo {
13 
14 template <typename T>
hash_combine(std::size_t & seed,const T & v)15 inline void hash_combine(std::size_t& seed, const T& v)
16 {
17   std::hash<T> hasher;
18   // Reference from: https://github.com/boostorg/container_hash/blob/boost-1.76.0/include/boost/container_hash/hash.hpp
19   seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
20 }
21 
22 struct pairhash {
23   template <typename A, typename B>
operatorpairhash24   std::size_t operator()(const std::pair<A, B>& v) const {
25     std::size_t seed = 0;
26     hash_combine(seed, v.first);
27     hash_combine(seed, v.second);
28     return seed;
29   }
30 };
31 
32 using MethodHashMap = std::unordered_map<std::pair<std::string, std::string>, jmethodID, pairhash>;
33 
34 /**
35  * Singleton registry used to store references to often used Java classes.
36  */
37 class JavaReferencesCache {
38 public:
39   /**
40    * An entry in the Java class registry.
41    */
42   class CachedJClass {
43   public:
44     CachedJClass(jclass clazz, MethodHashMap methods);
45 
46     /**
47      * A bare reference to the class object.
48      */
49     jclass clazz;
50 
51     /**
52      * Returns a cached method id for provided method name and signature.
53      */
54     jmethodID getMethod(const std::string &name, const std::string &signature);
55 
56   private:
57     MethodHashMap methods;
58   };
59 
60   JavaReferencesCache(JavaReferencesCache const &) = delete;
61 
62   JavaReferencesCache &operator=(JavaReferencesCache const &) = delete;
63 
64   /**
65    * Gets a singleton instance
66    */
67   static std::shared_ptr<JavaReferencesCache> instance();
68 
69   /**
70    * Gets a cached Java class entry.
71    */
72   CachedJClass &getJClass(const std::string &className);
73 
74   /**
75    * Gets a cached Java class entry or loads it to the registry.
76    */
77   CachedJClass &getOrLoadJClass(JNIEnv *env, const std::string &className);
78 
79   /**
80    * Loads predefined set of Java classes and stores them
81    */
82   void loadJClasses(JNIEnv *env);
83 
84 private:
85   JavaReferencesCache() = default;
86 
87   std::unordered_map<std::string, CachedJClass> jClassRegistry;
88 
89   void loadJClass(
90     JNIEnv *env,
91     const std::string &name,
92     const std::vector<std::pair<std::string, std::string>> &methods
93   );
94 };
95 } // namespace expo
96