//===--- AnyValue.h - Any Value Existential ---------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the AnyValue class, which is used to store an // immutable value of any type. // //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_ANYVALUE_H #define SWIFT_BASIC_ANYVALUE_H #include "swift/Basic/SimpleDisplay.h" #include "swift/Basic/TypeID.h" #include "llvm/ADT/PointerUnion.h" // to define hash_value #include "llvm/ADT/TinyPtrVector.h" namespace llvm { // FIXME: Belongs in LLVM itself template hash_code hash_value(const llvm::PointerUnion &ptr) { return hash_value(ptr.getOpaqueValue()); } } namespace swift { /// Stores a value of any type that satisfies a small set of requirements. /// /// Requirements on the values stored within an AnyValue: /// /// - Copy constructor /// - Equality operator (==) /// - TypeID support (see swift/Basic/TypeID.h) /// - Display support (free function): /// void simple_display(llvm::raw_ostream &, const T &); class AnyValue { /// Abstract base class used to hold on to a value. class HolderBase { public: /// Type ID number. const uint64_t typeID; HolderBase() = delete; HolderBase(const HolderBase &) = delete; HolderBase(HolderBase &&) = delete; HolderBase &operator=(const HolderBase &) = delete; HolderBase &operator=(HolderBase &&) = delete; /// Initialize base with type ID. HolderBase(uint64_t typeID) : typeID(typeID) { } virtual ~HolderBase(); /// Determine whether this value is equivalent to another. /// /// The caller guarantees that the type IDs are the same. virtual bool equals(const HolderBase &other) const = 0; /// Display. virtual void display(llvm::raw_ostream &out) const = 0; }; /// Holds a value that can be used as a request input/output. template class Holder final : public HolderBase { public: const T value; Holder(T &&value) : HolderBase(TypeID::value), value(std::move(value)) { } Holder(const T &value) : HolderBase(TypeID::value), value(value) { } virtual ~Holder() { } /// Determine whether this value is equivalent to another. /// /// The caller guarantees that the type IDs are the same. virtual bool equals(const HolderBase &other) const override { assert(typeID == other.typeID && "Caller should match type IDs"); return value == static_cast &>(other).value; } /// Display. virtual void display(llvm::raw_ostream &out) const override { simple_display(out, value); } }; /// The data stored in this value. std::shared_ptr stored; public: /// Construct a new instance with the given value. template AnyValue(T&& value) { using ValueType = typename std::remove_reference::type; stored.reset(new Holder(std::forward(value))); } /// Cast to a specific (known) type. template const T &castTo() const { assert(stored->typeID == TypeID::value); return static_cast *>(stored.get())->value; } /// Try casting to a specific (known) type, returning \c nullptr on /// failure. template const T *getAs() const { if (stored->typeID != TypeID::value) return nullptr; return &static_cast *>(stored.get())->value; } /// Compare two instances for equality. friend bool operator==(const AnyValue &lhs, const AnyValue &rhs) { if (lhs.stored->typeID != rhs.stored->typeID) return false; return lhs.stored->equals(*rhs.stored); } friend bool operator!=(const AnyValue &lhs, const AnyValue &rhs) { return !(lhs == rhs); } friend void simple_display(llvm::raw_ostream &out, const AnyValue &value) { value.stored->display(out); } /// Return the result of calling simple_display as a string. std::string getAsString() const; }; } // end namespace swift namespace llvm { template bool operator==(const TinyPtrVector &lhs, const TinyPtrVector &rhs) { if (lhs.size() != rhs.size()) return false; for (unsigned i = 0, n = lhs.size(); i != n; ++i) { if (lhs[i] != rhs[i]) return false; } return true; } template bool operator!=(const TinyPtrVector &lhs, const TinyPtrVector &rhs) { return !(lhs == rhs); } template void simple_display(raw_ostream &out, const Optional &opt) { if (opt) { simple_display(out, *opt); } out << "None"; } } // end namespace llvm #endif //