//===--- ExistentialContainer.h -------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_RUNTIME_EXISTENTIALCONTAINER_H
#define SWIFT_RUNTIME_EXISTENTIALCONTAINER_H

#include "swift/Runtime/Metadata.h"

namespace swift {

/// The basic layout of an opaque (non-class-bounded) existential type.
template <typename Runtime>
struct TargetOpaqueExistentialContainer {
  TargetValueBuffer<Runtime> Buffer;
  ConstTargetMetadataPointer<Runtime, TargetMetadata> Type;

  const TargetWitnessTable<Runtime> **getWitnessTables() {
    return reinterpret_cast<const TargetWitnessTable<Runtime> **>(this + 1);
  }

  const TargetWitnessTable<Runtime> *const *getWitnessTables() const {
    return reinterpret_cast<const TargetWitnessTable<Runtime> *const *>(this +
                                                                        1);
  }

  void copyTypeInto(swift::TargetOpaqueExistentialContainer<Runtime> *dest,
                    unsigned numTables) const {
    dest->Type = Type;
    for (unsigned i = 0; i != numTables; ++i)
      dest->getWitnessTables()[i] = getWitnessTables()[i];
  }

  /// Return true if this opaque existential container contains a value that is
  /// stored inline in the container. Returns false if the value is stored out
  /// of line.
  bool isValueInline() const;

  /// Project out a pointer to the value stored in the container.
  ///
  /// *NOTE* If the container contains the value inline, then this will return a
  /// pointer inside the container itself. Otherwise, it will return a pointer
  /// to out of line memory.
  const OpaqueValue *projectValue() const;

  /// Cleans up an existential container instance whose value is uninitialized.
  void deinit();

#ifndef NDEBUG
  /// Verify invariants of the container.
  ///
  /// We verify that:
  ///
  /// 1. The container itself is in live memory.
  /// 2. If we have an out of line value, that the value is in live memory.
  ///
  /// The intention is that this is used in combination with ASAN or Guard
  /// Malloc to catch use-after-frees.
  void verify() const;

  /// Dump information about this specific box and its contents. Only intended
  /// for use in the debugger.
  [[deprecated("Only meant for use in the debugger")]] void dump() const;
#endif
};
using OpaqueExistentialContainer = TargetOpaqueExistentialContainer<InProcess>;

/// The basic layout of a class-bounded existential type.
template <typename ContainedValue>
struct ClassExistentialContainerImpl {
  ContainedValue Value;

  const WitnessTable **getWitnessTables() {
    return reinterpret_cast<const WitnessTable **>(this + 1);
  }
  const WitnessTable *const *getWitnessTables() const {
    return reinterpret_cast<const WitnessTable *const *>(this + 1);
  }

  void copyTypeInto(ClassExistentialContainerImpl *dest,
                    unsigned numTables) const {
    for (unsigned i = 0; i != numTables; ++i)
      dest->getWitnessTables()[i] = getWitnessTables()[i];
  }
};
using ClassExistentialContainer = ClassExistentialContainerImpl<void *>;
using WeakClassExistentialContainer =
    ClassExistentialContainerImpl<WeakReference>;
using UnownedClassExistentialContainer =
    ClassExistentialContainerImpl<UnownedReference>;

} // end swift namespace

#endif
