mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Visual Studio objects with the following: ``` AST/AnyRequest.h(243): error: C2580: 'swift::AnyRequest::AnyRequest(const swift::AnyRequest &)': multiple versions of a defaulted special member functions are not allowed AST/AnyRequest(243): warning C4521: 'swift::AnyRequest': multiple copy constructors specified ``` Remove the non-const implementation, the default'ed definition should be sufficient. Additionally, remove the nonsense const move constructor.
285 lines
8.8 KiB
C++
285 lines
8.8 KiB
C++
//===--- AnyRequest.h - Requests Instances ----------------------*- 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 AnyRequest class, which describes a stored request.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_ANYREQUEST_H
|
|
#define SWIFT_AST_ANYREQUEST_H
|
|
|
|
#include "swift/Basic/TypeID.h"
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
#include "llvm/ADT/Hashing.h"
|
|
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
|
#include <string>
|
|
|
|
namespace llvm {
|
|
class raw_ostream;
|
|
}
|
|
|
|
namespace swift {
|
|
|
|
using llvm::hash_code;
|
|
using llvm::hash_value;
|
|
|
|
class DiagnosticEngine;
|
|
|
|
/// Stores a request (for the \c Evaluator class) of any kind.
|
|
///
|
|
/// Requests must be value types and provide the following API to be stored in
|
|
/// an \c AnyRequest instance:
|
|
///
|
|
/// - Copy constructor
|
|
/// - Equality operator (==)
|
|
/// - Hashing support (hash_value)
|
|
/// - TypeID support (see swift/Basic/TypeID.h)
|
|
/// - Display support (free function):
|
|
/// void simple_display(llvm::raw_ostream &, const T &);
|
|
/// - Cycle diagnostics operations:
|
|
/// void diagnoseCycle(DiagnosticEngine &diags) const;
|
|
/// void noteCycleStep(DiagnosticEngine &diags) const;
|
|
///
|
|
class AnyRequest {
|
|
friend llvm::DenseMapInfo<swift::AnyRequest>;
|
|
|
|
static hash_code hashForHolder(uint64_t typeID, hash_code requestHash) {
|
|
return hash_combine(hash_value(typeID), requestHash);
|
|
}
|
|
|
|
/// Abstract base class used to hold the specific request kind.
|
|
class HolderBase : public llvm::RefCountedBase<HolderBase> {
|
|
public:
|
|
/// The type ID of the request being stored.
|
|
const uint64_t typeID;
|
|
|
|
/// Hash value for the request itself.
|
|
const hash_code hash;
|
|
|
|
protected:
|
|
/// Initialize base with type ID and hash code.
|
|
HolderBase(uint64_t typeID, hash_code hash)
|
|
: typeID(typeID), hash(AnyRequest::hashForHolder(typeID, hash)) { }
|
|
|
|
public:
|
|
virtual ~HolderBase();
|
|
|
|
/// Determine whether this request is equivalent to the \c other
|
|
/// request.
|
|
virtual bool equals(const HolderBase &other) const = 0;
|
|
|
|
/// Display.
|
|
virtual void display(llvm::raw_ostream &out) const = 0;
|
|
|
|
/// Diagnose a cycle detected for this request.
|
|
virtual void diagnoseCycle(DiagnosticEngine &diags) const = 0;
|
|
|
|
/// Note that this request is part of a cycle.
|
|
virtual void noteCycleStep(DiagnosticEngine &diags) const = 0;
|
|
};
|
|
|
|
/// Holds a value that can be used as a request input/output.
|
|
template<typename Request>
|
|
class Holder final : public HolderBase {
|
|
public:
|
|
const Request request;
|
|
|
|
Holder(const Request &request)
|
|
: HolderBase(TypeID<Request>::value, hash_value(request)),
|
|
request(request) { }
|
|
|
|
Holder(Request &&request)
|
|
: HolderBase(TypeID<Request>::value, hash_value(request)),
|
|
request(std::move(request)) { }
|
|
|
|
virtual ~Holder() { }
|
|
|
|
/// Determine whether this request is equivalent to another.
|
|
///
|
|
/// The caller guarantees that the typeIDs are the same.
|
|
virtual bool equals(const HolderBase &other) const override {
|
|
assert(typeID == other.typeID && "Caller should match typeIDs");
|
|
return request == static_cast<const Holder<Request> &>(other).request;
|
|
}
|
|
|
|
/// Display.
|
|
virtual void display(llvm::raw_ostream &out) const override {
|
|
simple_display(out, request);
|
|
}
|
|
|
|
/// Diagnose a cycle detected for this request.
|
|
virtual void diagnoseCycle(DiagnosticEngine &diags) const override {
|
|
request.diagnoseCycle(diags);
|
|
}
|
|
|
|
/// Note that this request is part of a cycle.
|
|
virtual void noteCycleStep(DiagnosticEngine &diags) const override {
|
|
request.noteCycleStep(diags);
|
|
}
|
|
};
|
|
|
|
/// FIXME: Inefficient. Use the low bits.
|
|
enum class StorageKind {
|
|
Normal,
|
|
Empty,
|
|
Tombstone,
|
|
} storageKind = StorageKind::Normal;
|
|
|
|
/// The data stored in this value.
|
|
llvm::IntrusiveRefCntPtr<HolderBase> stored;
|
|
|
|
AnyRequest(StorageKind storageKind) : storageKind(storageKind) {
|
|
assert(storageKind != StorageKind::Normal);
|
|
}
|
|
|
|
public:
|
|
AnyRequest(const AnyRequest &other) = default;
|
|
AnyRequest &operator=(const AnyRequest &other) = default;
|
|
|
|
AnyRequest(AnyRequest &&other)
|
|
: storageKind(other.storageKind), stored(std::move(other.stored)) {
|
|
other.storageKind = StorageKind::Empty;
|
|
}
|
|
|
|
AnyRequest &operator=(AnyRequest &&other) {
|
|
storageKind = other.storageKind;
|
|
stored = std::move(other.stored);
|
|
other.storageKind = StorageKind::Empty;
|
|
other.stored = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
// Create a local template typename `ValueType` in the template specialization
|
|
// so that we can refer to it in the SFINAE condition as well as the body of
|
|
// the template itself. The SFINAE condition allows us to remove this
|
|
// constructor from candidacy when evaluating explicit construction with an
|
|
// instance of `AnyRequest`. If we do not do so, we will find ourselves with
|
|
// ambiguity with this constructor and the defined move constructor above.
|
|
/// Construct a new instance with the given value.
|
|
template <typename T,
|
|
typename ValueType = typename std::remove_cv<
|
|
typename std::remove_reference<T>::type>::type,
|
|
typename = typename std::enable_if<
|
|
!std::is_same<ValueType, AnyRequest>::value>::type>
|
|
explicit AnyRequest(T &&value) : storageKind(StorageKind::Normal) {
|
|
stored = llvm::IntrusiveRefCntPtr<HolderBase>(
|
|
new Holder<ValueType>(std::forward<T>(value)));
|
|
}
|
|
|
|
/// Cast to a specific (known) type.
|
|
template<typename Request>
|
|
const Request &castTo() const {
|
|
assert(stored->typeID == TypeID<Request>::value && "wrong type in cast");
|
|
return static_cast<const Holder<Request> *>(stored.get())->request;
|
|
}
|
|
|
|
/// Try casting to a specific (known) type, returning \c nullptr on
|
|
/// failure.
|
|
template<typename Request>
|
|
const Request *getAs() const {
|
|
if (stored->typeID != TypeID<Request>::value)
|
|
return nullptr;
|
|
|
|
return &static_cast<const Holder<Request> *>(stored.get())->request;
|
|
}
|
|
|
|
/// Diagnose a cycle detected for this request.
|
|
void diagnoseCycle(DiagnosticEngine &diags) const {
|
|
stored->diagnoseCycle(diags);
|
|
}
|
|
|
|
/// Note that this request is part of a cycle.
|
|
void noteCycleStep(DiagnosticEngine &diags) const {
|
|
stored->noteCycleStep(diags);
|
|
}
|
|
|
|
/// Compare two instances for equality.
|
|
friend bool operator==(const AnyRequest &lhs, const AnyRequest &rhs) {
|
|
if (lhs.storageKind != rhs.storageKind) {
|
|
return false;
|
|
}
|
|
|
|
if (lhs.storageKind != StorageKind::Normal)
|
|
return true;
|
|
|
|
if (lhs.stored->typeID != rhs.stored->typeID)
|
|
return false;
|
|
|
|
return lhs.stored->equals(*rhs.stored);
|
|
}
|
|
|
|
friend bool operator!=(const AnyRequest &lhs, const AnyRequest &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
friend hash_code hash_value(const AnyRequest &any) {
|
|
if (any.storageKind != StorageKind::Normal)
|
|
return 1;
|
|
|
|
return any.stored->hash;
|
|
}
|
|
|
|
friend void simple_display(llvm::raw_ostream &out, const AnyRequest &any) {
|
|
any.stored->display(out);
|
|
}
|
|
|
|
/// Return the result of calling simple_display as a string.
|
|
std::string getAsString() const;
|
|
|
|
static AnyRequest getEmptyKey() {
|
|
return AnyRequest(StorageKind::Empty);
|
|
}
|
|
|
|
static AnyRequest getTombstoneKey() {
|
|
return AnyRequest(StorageKind::Tombstone);
|
|
}
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
template<>
|
|
struct DenseMapInfo<swift::AnyRequest> {
|
|
static inline swift::AnyRequest getEmptyKey() {
|
|
return swift::AnyRequest::getEmptyKey();
|
|
}
|
|
static inline swift::AnyRequest getTombstoneKey() {
|
|
return swift::AnyRequest::getTombstoneKey();
|
|
}
|
|
static unsigned getHashValue(const swift::AnyRequest &request) {
|
|
return hash_value(request);
|
|
}
|
|
template <typename Request>
|
|
static unsigned getHashValue(const Request &request) {
|
|
return swift::AnyRequest::hashForHolder(swift::TypeID<Request>::value,
|
|
hash_value(request));
|
|
}
|
|
static bool isEqual(const swift::AnyRequest &lhs,
|
|
const swift::AnyRequest &rhs) {
|
|
return lhs == rhs;
|
|
}
|
|
template <typename Request>
|
|
static bool isEqual(const Request &lhs,
|
|
const swift::AnyRequest &rhs) {
|
|
if (rhs == getEmptyKey() || rhs == getTombstoneKey())
|
|
return false;
|
|
const Request *rhsRequest = rhs.getAs<Request>();
|
|
if (!rhsRequest)
|
|
return false;
|
|
return lhs == *rhsRequest;
|
|
}
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif // SWIFT_AST_ANYREQUEST_H
|