1+ #ifndef IFT_ENCODER_CONDITION_TO_GLYPHS_INDEX_H_
2+ #define IFT_ENCODER_CONDITION_TO_GLYPHS_INDEX_H_
3+
4+ #include < optional>
5+
6+ #include " absl/container/btree_map.h"
7+ #include " ift/encoder/activation_condition.h"
8+ #include " ift/encoder/types.h"
9+
10+ namespace ift ::encoder {
11+
12+ // Stores a mapping from ActivationCondition to a set of glyphs.
13+ //
14+ // Also maintains the reverse mapping indices.
15+ class ConditionToGlyphsIndex {
16+ public:
17+ std::optional<ActivationCondition> Invalidate (glyph_id_t gid) {
18+ auto it = glyph_to_condition_.find (gid);
19+ if (it == glyph_to_condition_.end ()) {
20+ return std::nullopt ;
21+ }
22+
23+ ActivationCondition condition = it->second ;
24+
25+ auto & glyphs = conditions_and_glyphs_.at (condition);
26+ glyphs.erase (gid);
27+ glyph_to_condition_.erase (gid);
28+
29+ if (glyphs.empty ()) {
30+ Remove (condition);
31+ }
32+ return condition;
33+ }
34+
35+ void Remove (ActivationCondition condition) {
36+ auto it = conditions_and_glyphs_.find (condition);
37+ if (it == conditions_and_glyphs_.end ()) {
38+ return ;
39+ }
40+
41+ for (glyph_id_t gid : it->second ) {
42+ glyph_to_condition_.erase (gid);
43+ }
44+
45+ conditions_and_glyphs_.erase (it);
46+
47+ for (segment_index_t s : condition.TriggeringSegments ()) {
48+ auto it = triggering_segment_to_conditions_.find (s);
49+ if (it != triggering_segment_to_conditions_.end ()) {
50+ it->second .erase (condition);
51+ if (it->second .empty ()) {
52+ triggering_segment_to_conditions_.erase (it);
53+ }
54+ }
55+ }
56+ }
57+
58+ absl::Status Union (ActivationCondition condition, common::GlyphSet glyphs) {
59+ conditions_and_glyphs_[condition].union_set (glyphs);
60+
61+ for (segment_index_t s : condition.TriggeringSegments ()) {
62+ triggering_segment_to_conditions_[s].insert (condition);
63+ }
64+
65+ for (glyph_id_t gid : glyphs) {
66+ auto [it, did_insert] =
67+ glyph_to_condition_.insert (std::pair (gid, condition));
68+ if (!did_insert && it->second != condition) {
69+ return absl::InternalError (
70+ " glyph_to_condition mapping does not match existing one." );
71+ }
72+ }
73+
74+ return absl::OkStatus ();
75+ }
76+
77+ absl::Status Add (ActivationCondition condition, common::GlyphSet glyphs) {
78+ const auto & [new_value_it, did_insert] =
79+ conditions_and_glyphs_.insert (std::pair (condition, glyphs));
80+
81+ if (!did_insert) {
82+ // If there's an existing value it must match what we're trying to add
83+ if (!new_value_it->second .is_subset_of (glyphs)) {
84+ return absl::InternalError (absl::StrCat (
85+ " Trying to add a condition and glyph mapping (" ,
86+ condition.ToString (), " => " , glyphs.ToString (),
87+ " ) which "
88+ " would override an existing mapping (" ,
89+ new_value_it->first .ToString (), " => " ,
90+ new_value_it->second .ToString (), " ) to a different value." ));
91+ }
92+
93+ // We allow overrides that only increase the glyph set.
94+ glyphs.subtract (new_value_it->second );
95+ new_value_it->second .union_set (glyphs);
96+ } else {
97+ for (segment_index_t s : condition.TriggeringSegments ()) {
98+ triggering_segment_to_conditions_[s].insert (new_value_it->first );
99+ }
100+ }
101+
102+ for (glyph_id_t gid : glyphs) {
103+ bool did_insert =
104+ glyph_to_condition_.insert (std::pair (gid, new_value_it->first ))
105+ .second ;
106+ if (!did_insert) {
107+ return absl::InternalError (
108+ " Unexpected existing glyph to condition mapping." );
109+ }
110+ }
111+
112+ return absl::OkStatus ();
113+ }
114+
115+ const absl::btree_map<ActivationCondition, common::GlyphSet>&
116+ ConditionsAndGlyphs () const {
117+ return conditions_and_glyphs_;
118+ }
119+
120+ const absl::flat_hash_map<glyph_id_t , ActivationCondition>& GlyphToCondition ()
121+ const {
122+ return glyph_to_condition_;
123+ }
124+
125+ const absl::flat_hash_map<segment_index_t ,
126+ absl::btree_set<ActivationCondition>>&
127+ TriggeringSegmentToConditions () const {
128+ return triggering_segment_to_conditions_;
129+ }
130+
131+ bool operator ==(const ConditionToGlyphsIndex& other) const {
132+ return conditions_and_glyphs_ == other.conditions_and_glyphs_ &&
133+ glyph_to_condition_ == other.glyph_to_condition_ &&
134+ triggering_segment_to_conditions_ ==
135+ other.triggering_segment_to_conditions_ ;
136+ }
137+
138+ private:
139+ absl::btree_map<ActivationCondition, common::GlyphSet> conditions_and_glyphs_;
140+ absl::flat_hash_map<glyph_id_t , ActivationCondition> glyph_to_condition_;
141+ absl::flat_hash_map<segment_index_t , absl::btree_set<ActivationCondition>>
142+ triggering_segment_to_conditions_;
143+ };
144+
145+ } // namespace ift::encoder
146+
147+ #endif // IFT_ENCODER_CONDITION_TO_GLYPHS_INDEX_H_
0 commit comments