C++程序  |  211行  |  5.8 KB

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef AAPT_VALUE_VISITOR_H
#define AAPT_VALUE_VISITOR_H

#include "ResourceTable.h"
#include "ResourceValues.h"

namespace aapt {

// Visits a value and invokes the appropriate method based on its type.
// Does not traverse into compound types. Use ValueVisitor for that.
class ValueVisitor {
 public:
  virtual ~ValueVisitor() = default;

  virtual void VisitAny(Value* value) {}
  virtual void VisitItem(Item* value) { VisitAny(value); }
  virtual void Visit(Reference* value) { VisitItem(value); }
  virtual void Visit(RawString* value) { VisitItem(value); }
  virtual void Visit(String* value) { VisitItem(value); }
  virtual void Visit(StyledString* value) { VisitItem(value); }
  virtual void Visit(FileReference* value) { VisitItem(value); }
  virtual void Visit(Id* value) { VisitItem(value); }
  virtual void Visit(BinaryPrimitive* value) { VisitItem(value); }

  virtual void Visit(Attribute* value) { VisitAny(value); }
  virtual void Visit(Style* value) { VisitAny(value); }
  virtual void Visit(Array* value) { VisitAny(value); }
  virtual void Visit(Plural* value) { VisitAny(value); }
  virtual void Visit(Styleable* value) { VisitAny(value); }
};

// Const version of ValueVisitor.
class ConstValueVisitor {
 public:
  virtual ~ConstValueVisitor() = default;

  virtual void VisitAny(const Value* value) {
  }
  virtual void VisitItem(const Item* value) {
    VisitAny(value);
  }
  virtual void Visit(const Reference* value) {
    VisitItem(value);
  }
  virtual void Visit(const RawString* value) {
    VisitItem(value);
  }
  virtual void Visit(const String* value) {
    VisitItem(value);
  }
  virtual void Visit(const StyledString* value) {
    VisitItem(value);
  }
  virtual void Visit(const FileReference* value) {
    VisitItem(value);
  }
  virtual void Visit(const Id* value) {
    VisitItem(value);
  }
  virtual void Visit(const BinaryPrimitive* value) {
    VisitItem(value);
  }

  virtual void Visit(const Attribute* value) {
    VisitAny(value);
  }
  virtual void Visit(const Style* value) {
    VisitAny(value);
  }
  virtual void Visit(const Array* value) {
    VisitAny(value);
  }
  virtual void Visit(const Plural* value) {
    VisitAny(value);
  }
  virtual void Visit(const Styleable* value) {
    VisitAny(value);
  }
};

// NOLINT, do not add parentheses around T.
#define DECL_VISIT_COMPOUND_VALUE(T)                   \
  virtual void Visit(T* value) override { /* NOLINT */ \
    VisitSubValues(value);                             \
  }

// Visits values, and if they are compound values, descends into their components as well.
struct DescendingValueVisitor : public ValueVisitor {
  // The compiler will think we're hiding an overload, when we actually intend
  // to call into RawValueVisitor. This will expose the visit methods in the
  // super class so the compiler knows we are trying to call them.
  using ValueVisitor::Visit;

  void VisitSubValues(Attribute* attribute) {
    for (Attribute::Symbol& symbol : attribute->symbols) {
      Visit(&symbol.symbol);
    }
  }

  void VisitSubValues(Style* style) {
    if (style->parent) {
      Visit(&style->parent.value());
    }

    for (Style::Entry& entry : style->entries) {
      Visit(&entry.key);
      entry.value->Accept(this);
    }
  }

  void VisitSubValues(Array* array) {
    for (std::unique_ptr<Item>& item : array->elements) {
      item->Accept(this);
    }
  }

  void VisitSubValues(Plural* plural) {
    for (std::unique_ptr<Item>& item : plural->values) {
      if (item) {
        item->Accept(this);
      }
    }
  }

  void VisitSubValues(Styleable* styleable) {
    for (Reference& reference : styleable->entries) {
      Visit(&reference);
    }
  }

  DECL_VISIT_COMPOUND_VALUE(Attribute);
  DECL_VISIT_COMPOUND_VALUE(Style);
  DECL_VISIT_COMPOUND_VALUE(Array);
  DECL_VISIT_COMPOUND_VALUE(Plural);
  DECL_VISIT_COMPOUND_VALUE(Styleable);
};

// Do not use directly. Helper struct for dyn_cast.
template <typename T>
struct DynCastVisitor : public ConstValueVisitor {
  const T* value = nullptr;

  void Visit(const T* v) override {
    value = v;
  }
};

// Specialization that checks if the value is an Item.
template <>
struct DynCastVisitor<Item> : public ConstValueVisitor {
  const Item* value = nullptr;

  void VisitItem(const Item* item) override {
    value = item;
  }
};

// Returns a valid pointer to T if the value is an instance of T. Returns nullptr if value is
// nullptr of if value is not an instance of T.
template <typename T>
const T* ValueCast(const Value* value) {
  if (!value) {
    return nullptr;
  }
  DynCastVisitor<T> visitor;
  value->Accept(&visitor);
  return visitor.value;
}

// Non-const version of ValueCast.
template <typename T>
T* ValueCast(Value* value) {
  return const_cast<T*>(ValueCast<T>(static_cast<const Value*>(value)));
}

inline void VisitAllValuesInPackage(ResourceTablePackage* pkg, ValueVisitor* visitor) {
  for (auto& type : pkg->types) {
    for (auto& entry : type->entries) {
      for (auto& config_value : entry->values) {
        config_value->value->Accept(visitor);
      }
    }
  }
}

inline void VisitAllValuesInTable(ResourceTable* table, ValueVisitor* visitor) {
  for (auto& pkg : table->packages) {
    VisitAllValuesInPackage(pkg.get(), visitor);
  }
}

}  // namespace aapt

#endif  // AAPT_VALUE_VISITOR_H