1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef AAPT_STRING_POOL_H
18 #define AAPT_STRING_POOL_H
19 
20 #include <functional>
21 #include <memory>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25 
26 #include "android-base/macros.h"
27 #include "androidfw/StringPiece.h"
28 
29 #include "ConfigDescription.h"
30 #include "util/BigBuffer.h"
31 
32 namespace aapt {
33 
34 struct Span {
35   std::string name;
36   uint32_t first_char;
37   uint32_t last_char;
38 };
39 
40 struct StyleString {
41   std::string str;
42   std::vector<Span> spans;
43 };
44 
45 class StringPool {
46  public:
47   class Context {
48    public:
49     enum : uint32_t {
50       kStylePriority = 0u,
51       kHighPriority = 1u,
52       kNormalPriority = 0x7fffffffu,
53       kLowPriority = 0xffffffffu,
54     };
55     uint32_t priority = kNormalPriority;
56     ConfigDescription config;
57 
58     Context() = default;
Context(uint32_t p,const ConfigDescription & c)59     Context(uint32_t p, const ConfigDescription& c) : priority(p), config(c) {}
Context(uint32_t p)60     explicit Context(uint32_t p) : priority(p) {}
Context(const ConfigDescription & c)61     explicit Context(const ConfigDescription& c)
62         : priority(kNormalPriority), config(c) {}
63   };
64 
65   class Entry;
66 
67   class Ref {
68    public:
69     Ref();
70     Ref(const Ref&);
71     ~Ref();
72 
73     Ref& operator=(const Ref& rhs);
74     bool operator==(const Ref& rhs) const;
75     bool operator!=(const Ref& rhs) const;
76     const std::string* operator->() const;
77     const std::string& operator*() const;
78 
79     size_t index() const;
80     const Context& GetContext() const;
81 
82    private:
83     friend class StringPool;
84 
85     explicit Ref(Entry* entry);
86 
87     Entry* entry_;
88   };
89 
90   class StyleEntry;
91 
92   class StyleRef {
93    public:
94     StyleRef();
95     StyleRef(const StyleRef&);
96     ~StyleRef();
97 
98     StyleRef& operator=(const StyleRef& rhs);
99     bool operator==(const StyleRef& rhs) const;
100     bool operator!=(const StyleRef& rhs) const;
101     const StyleEntry* operator->() const;
102     const StyleEntry& operator*() const;
103 
104     size_t index() const;
105     const Context& GetContext() const;
106 
107    private:
108     friend class StringPool;
109 
110     explicit StyleRef(StyleEntry* entry);
111 
112     StyleEntry* entry_;
113   };
114 
115   class Entry {
116    public:
117     std::string value;
118     Context context;
119     size_t index;
120 
121    private:
122     friend class StringPool;
123     friend class Ref;
124 
125     int ref_;
126   };
127 
128   struct Span {
129     Ref name;
130     uint32_t first_char;
131     uint32_t last_char;
132   };
133 
134   class StyleEntry {
135    public:
136     Ref str;
137     std::vector<Span> spans;
138 
139    private:
140     friend class StringPool;
141     friend class StyleRef;
142 
143     int ref_;
144   };
145 
146   using const_iterator = std::vector<std::unique_ptr<Entry>>::const_iterator;
147 
148   static bool FlattenUtf8(BigBuffer* out, const StringPool& pool);
149   static bool FlattenUtf16(BigBuffer* out, const StringPool& pool);
150 
151   StringPool() = default;
152   StringPool(StringPool&&) = default;
153   StringPool& operator=(StringPool&&) = default;
154 
155   /**
156    * Adds a string to the pool, unless it already exists. Returns
157    * a reference to the string in the pool.
158    */
159   Ref MakeRef(const android::StringPiece& str);
160 
161   /**
162    * Adds a string to the pool, unless it already exists, with a context
163    * object that can be used when sorting the string pool. Returns
164    * a reference to the string in the pool.
165    */
166   Ref MakeRef(const android::StringPiece& str, const Context& context);
167 
168   /**
169    * Adds a style to the string pool and returns a reference to it.
170    */
171   StyleRef MakeRef(const StyleString& str);
172 
173   /**
174    * Adds a style to the string pool with a context object that
175    * can be used when sorting the string pool. Returns a reference
176    * to the style in the string pool.
177    */
178   StyleRef MakeRef(const StyleString& str, const Context& context);
179 
180   /**
181    * Adds a style from another string pool. Returns a reference to the
182    * style in the string pool.
183    */
184   StyleRef MakeRef(const StyleRef& ref);
185 
186   /**
187    * Moves pool into this one without coalescing strings. When this
188    * function returns, pool will be empty.
189    */
190   void Merge(StringPool&& pool);
191 
192   /**
193    * Returns the number of strings in the table.
194    */
195   inline size_t size() const;
196 
197   /**
198    * Reserves space for strings and styles as an optimization.
199    */
200   void HintWillAdd(size_t string_count, size_t style_count);
201 
202   /**
203    * Sorts the strings according to some comparison function.
204    */
205   void Sort(const std::function<bool(const Entry&, const Entry&)>& cmp);
206 
207   /**
208    * Removes any strings that have no references.
209    */
210   void Prune();
211 
212  private:
213   DISALLOW_COPY_AND_ASSIGN(StringPool);
214 
215   friend const_iterator begin(const StringPool& pool);
216   friend const_iterator end(const StringPool& pool);
217 
218   static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8);
219 
220   Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
221 
222   std::vector<std::unique_ptr<Entry>> strings_;
223   std::vector<std::unique_ptr<StyleEntry>> styles_;
224   std::unordered_multimap<android::StringPiece, Entry*> indexed_strings_;
225 };
226 
227 //
228 // Inline implementation
229 //
230 
size()231 inline size_t StringPool::size() const { return strings_.size(); }
232 
begin(const StringPool & pool)233 inline StringPool::const_iterator begin(const StringPool& pool) {
234   return pool.strings_.begin();
235 }
236 
end(const StringPool & pool)237 inline StringPool::const_iterator end(const StringPool& pool) {
238   return pool.strings_.end();
239 }
240 
241 }  // namespace aapt
242 
243 #endif  // AAPT_STRING_POOL_H
244