1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef DEVICE_VR_ANDROID_ARCORE_ADDRESS_TO_ID_MAP_H_
6 #define DEVICE_VR_ANDROID_ARCORE_ADDRESS_TO_ID_MAP_H_
7 
8 #include "base/check.h"
9 #include "base/optional.h"
10 #include "base/stl_util.h"
11 
12 #include <unordered_map>
13 
14 namespace device {
15 
16 // Wrapper class used to generate an Id for a given address. Allows looking up
17 // the Id for an address at a later time, or removing the mapping when desired.
18 // Ids generated will be monotonically increasing from 1, and are suitable to
19 // be passed over mojo. The Ids should be directly exposable from blink if
20 // desired.
21 // Note that IdType must be constructable from a uint64_t, and should most often
22 // be a util::IdTypeU64 type.
23 template <typename IdType>
24 class AddressToIdMap {
25  public:
26   // Helper struct to provide a cleaner return interface than a std::pair for
27   // CreateOrGetId.
28   struct CreateOrGetIdResult {
29     // The found or newly created Id corresponding to the supplied address.
30     IdType id;
31 
32     // Whether or not the above Id was newly created (true), or found (false).
33     bool created;
34 
CreateOrGetIdResultCreateOrGetIdResult35     CreateOrGetIdResult(IdType id, bool created) : id(id), created(created) {}
36   };
37 
38   // Retrieves or creates an id for the corresponding address.
CreateOrGetId(void * address)39   CreateOrGetIdResult CreateOrGetId(void* address) {
40     auto it = address_to_id_.find(address);
41     if (it != address_to_id_.end()) {
42       return {it->second, false};
43     }
44 
45     CHECK(next_id_ != std::numeric_limits<uint64_t>::max())
46         << "preventing ID overflow";
47 
48     uint64_t current_id = next_id_;
49     next_id_++;
50     address_to_id_.emplace(address, current_id);
51 
52     return {IdType(current_id), true};
53   }
54 
55   // Gets the id for the corresponding address, if it's available.
GetId(void * address)56   base::Optional<IdType> GetId(void* address) const {
57     auto it = address_to_id_.find(address);
58     if (it == address_to_id_.end()) {
59       return base::nullopt;
60     }
61 
62     return it->second;
63   }
64 
65   // Used to "erase" a particular id->address mapping, such that lookup methods
66   // for the given address will fail. This will result in a new id being
67   // generated if the address is passed into CreateOrGetId.
68   template <class Predicate>
EraseIf(Predicate pred)69   size_t EraseIf(Predicate pred) {
70     return base::EraseIf(address_to_id_, pred);
71   }
72 
73  private:
74   // The HashMaps used in blink do not allow Ids that evaluate to 0. Thus, we
75   // start generating Ids from 1, so that the first IdType does not cause any
76   // issues in blink.
77   uint64_t next_id_ = 1;
78   std::unordered_map<void*, IdType> address_to_id_;
79 };
80 
81 }  // namespace device
82 
83 #endif  // DEVICE_VR_ANDROID_ARCORE_ADDRESS_TO_ID_MAP_H_
84