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
32namespace aapt {
33
34struct Span {
35  std::string name;
36  uint32_t first_char;
37  uint32_t last_char;
38};
39
40struct StyleString {
41  std::string str;
42  std::vector<Span> spans;
43};
44
45class 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;
59    Context(uint32_t p, const ConfigDescription& c) : priority(p), config(c) {}
60    explicit Context(uint32_t p) : priority(p) {}
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
231inline size_t StringPool::size() const { return strings_.size(); }
232
233inline StringPool::const_iterator begin(const StringPool& pool) {
234  return pool.strings_.begin();
235}
236
237inline 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