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_VALUE_VISITOR_H
18#define AAPT_VALUE_VISITOR_H
19
20#include "ResourceValues.h"
21#include "ResourceTable.h"
22
23namespace aapt {
24
25/**
26 * Visits a value and invokes the appropriate method based on its type. Does not traverse
27 * into compound types. Use ValueVisitor for that.
28 */
29struct RawValueVisitor {
30    virtual ~RawValueVisitor() = default;
31
32    virtual void visitItem(Item* value) {}
33    virtual void visit(Reference* value) { visitItem(value); }
34    virtual void visit(RawString* value) { visitItem(value); }
35    virtual void visit(String* value) { visitItem(value); }
36    virtual void visit(StyledString* value) { visitItem(value); }
37    virtual void visit(FileReference* value) { visitItem(value); }
38    virtual void visit(Id* value) { visitItem(value); }
39    virtual void visit(BinaryPrimitive* value) { visitItem(value); }
40
41    virtual void visit(Attribute* value) {}
42    virtual void visit(Style* value) {}
43    virtual void visit(Array* value) {}
44    virtual void visit(Plural* value) {}
45    virtual void visit(Styleable* value) {}
46};
47
48#define DECL_VISIT_COMPOUND_VALUE(T) \
49    virtual void visit(T* value) { \
50        visitSubValues(value); \
51    }
52
53/**
54 * Visits values, and if they are compound values, visits the components as well.
55 */
56struct ValueVisitor : public RawValueVisitor {
57    // The compiler will think we're hiding an overload, when we actually intend
58    // to call into RawValueVisitor. This will expose the visit methods in the super
59    // class so the compiler knows we are trying to call them.
60    using RawValueVisitor::visit;
61
62    void visitSubValues(Attribute* attribute) {
63        for (Attribute::Symbol& symbol : attribute->symbols) {
64            visit(&symbol.symbol);
65        }
66    }
67
68    void visitSubValues(Style* style) {
69        if (style->parent) {
70            visit(&style->parent.value());
71        }
72
73        for (Style::Entry& entry : style->entries) {
74            visit(&entry.key);
75            entry.value->accept(this);
76        }
77    }
78
79    void visitSubValues(Array* array) {
80        for (std::unique_ptr<Item>& item : array->items) {
81            item->accept(this);
82        }
83    }
84
85    void visitSubValues(Plural* plural) {
86        for (std::unique_ptr<Item>& item : plural->values) {
87            if (item) {
88                item->accept(this);
89            }
90        }
91    }
92
93    void visitSubValues(Styleable* styleable) {
94        for (Reference& reference : styleable->entries) {
95            visit(&reference);
96        }
97    }
98
99    DECL_VISIT_COMPOUND_VALUE(Attribute);
100    DECL_VISIT_COMPOUND_VALUE(Style);
101    DECL_VISIT_COMPOUND_VALUE(Array);
102    DECL_VISIT_COMPOUND_VALUE(Plural);
103    DECL_VISIT_COMPOUND_VALUE(Styleable);
104};
105
106/**
107 * Do not use directly. Helper struct for dyn_cast.
108 */
109template <typename T>
110struct DynCastVisitor : public RawValueVisitor {
111    T* value = nullptr;
112
113    void visit(T* v) override {
114        value = v;
115    }
116};
117
118/**
119 * Specialization that checks if the value is an Item.
120 */
121template <>
122struct DynCastVisitor<Item> : public RawValueVisitor {
123    Item* value = nullptr;
124
125    void visitItem(Item* item) override {
126        value = item;
127    }
128};
129
130/**
131 * Returns a valid pointer to T if the Value is of subtype T.
132 * Otherwise, returns nullptr.
133 */
134template <typename T>
135T* valueCast(Value* value) {
136    if (!value) {
137        return nullptr;
138    }
139    DynCastVisitor<T> visitor;
140    value->accept(&visitor);
141    return visitor.value;
142}
143
144
145inline void visitAllValuesInPackage(ResourceTablePackage* pkg, RawValueVisitor* visitor) {
146    for (auto& type : pkg->types) {
147        for (auto& entry : type->entries) {
148            for (auto& configValue : entry->values) {
149                configValue->value->accept(visitor);
150            }
151        }
152    }
153}
154
155inline void visitAllValuesInTable(ResourceTable* table, RawValueVisitor* visitor) {
156    for (auto& pkg : table->packages) {
157        visitAllValuesInPackage(pkg.get(), visitor);
158    }
159}
160
161} // namespace aapt
162
163#endif // AAPT_VALUE_VISITOR_H
164