blob: 691c0ac4e195ab3d4ad94224df3e0d4708866573 [file] [log] [blame]
//===--- 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<typename PT1, typename PT2>
hash_code hash_value(const llvm::PointerUnion<PT1, PT2> &ptr) {
return hash_value(ptr.getOpaqueValue());
}
// FIXME: Belongs in LLVM itself
template<typename T>
hash_code hash_value(const llvm::Optional<T> &opt) {
if (!opt)
return 1;
return hash_value(*opt);
}
}
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<typename T>
class Holder final : public HolderBase {
public:
const T value;
Holder(T &&value)
: HolderBase(TypeID<T>::value),
value(std::move(value)) { }
Holder(const T &value) : HolderBase(TypeID<T>::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<const Holder<T> &>(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<HolderBase> stored;
public:
/// Construct a new instance with the given value.
template<typename T>
AnyValue(T&& value) {
using ValueType = typename std::remove_reference<T>::type;
stored.reset(new Holder<ValueType>(std::forward<T>(value)));
}
/// Cast to a specific (known) type.
template<typename T>
const T &castTo() const {
assert(stored->typeID == TypeID<T>::value);
return static_cast<const Holder<T> *>(stored.get())->value;
}
/// Try casting to a specific (known) type, returning \c nullptr on
/// failure.
template<typename T>
const T *getAs() const {
if (stored->typeID != TypeID<T>::value)
return nullptr;
return &static_cast<const Holder<T> *>(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<typename T>
bool operator==(const TinyPtrVector<T> &lhs, const TinyPtrVector<T> &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<typename T>
bool operator!=(const TinyPtrVector<T> &lhs, const TinyPtrVector<T> &rhs) {
return !(lhs == rhs);
}
template<typename T>
void simple_display(raw_ostream &out, const Optional<T> &opt) {
if (opt) {
simple_display(out, *opt);
} else {
out << "None";
}
}
} // end namespace llvm
#endif //