//===--- GenSequential.h - IR generation for sequential types ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file provides some common code for emitting sequential types.
//  A sequential type is something like a tuple or a struct.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_IRGEN_GENSEQUENTIAL_H
#define SWIFT_IRGEN_GENSEQUENTIAL_H

#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "Explosion.h"
#include "GenEnum.h"
#include "LoadableTypeInfo.h"
#include "TypeInfo.h"
#include "StructLayout.h"

namespace swift {
namespace irgen {

template <class, class, class> class SequentialTypeBuilder;

/// A field of a sequential type.
template <class FieldImpl> class SequentialField {
  ElementLayout Layout;

  template <class, class, class> friend class SequentialTypeBuilder;

  /// Begin/End - the range of explosion indexes for this element
  unsigned Begin : 16;
  unsigned End : 16;

protected:
  explicit SequentialField(const TypeInfo &elementTI)
    : Layout(ElementLayout::getIncomplete(elementTI)) {}

  explicit SequentialField(const ElementLayout &layout,
                           unsigned begin, unsigned end)
    : Layout(layout), Begin(begin), End(end) {}

  const FieldImpl *asImpl() const {
    return static_cast<const FieldImpl*>(this);
  }
public:
  const TypeInfo &getTypeInfo() const { return Layout.getType(); }

  void completeFrom(const ElementLayout &layout) {
    Layout.completeFrom(layout);
  }

  bool isEmpty() const {
    return Layout.isEmpty();
  }

  IsPOD_t isPOD() const {
    return Layout.isPOD();
  }

  Address projectAddress(IRGenFunction &IGF, Address seq,
                         NonFixedOffsets offsets) const {
    return Layout.project(IGF, seq, offsets, "." + asImpl()->getFieldName());
  }
  
  ElementLayout::Kind getKind() const {
    return Layout.getKind();
  }
  
  Size getFixedByteOffset() const {
    return Layout.getByteOffset();
  }

  std::pair<unsigned, unsigned> getProjectionRange() const {
    return {Begin, End};
  }
};

/// A metaprogrammed TypeInfo implementation for sequential types.
template <class Impl, class Base, class FieldImpl_,
          bool IsLoadable = std::is_base_of<LoadableTypeInfo, Base>::value>
class SequentialTypeInfoImpl : public Base {
public:
  typedef FieldImpl_ FieldImpl;

private:
  const unsigned NumFields;

  const FieldImpl *getFieldsBuffer() const {
    return reinterpret_cast<const FieldImpl*>(static_cast<const Impl*>(this)+1);
  }
  FieldImpl *getFieldsBuffer() {
    return reinterpret_cast<FieldImpl*>(static_cast<Impl*>(this)+1);
  }

protected:
  const Impl &asImpl() const { return *static_cast<const Impl*>(this); }

  template <class... As> 
  SequentialTypeInfoImpl(ArrayRef<FieldImpl> fields, As&&...args)
      : Base(std::forward<As>(args)...), NumFields(fields.size()) {
    std::uninitialized_copy(fields.begin(), fields.end(),
                            getFieldsBuffer());
  }

public:
  /// Allocate and initialize a type info of this type.
  template <class... As>
  static Impl *create(ArrayRef<FieldImpl> fields, As &&...args) {
    void *buffer =
      ::operator new(sizeof(Impl) + fields.size() * sizeof(FieldImpl));
    return new(buffer) Impl(fields, std::forward<As>(args)...);
  }

  ArrayRef<FieldImpl> getFields() const {
    return ArrayRef<FieldImpl>(getFieldsBuffer(), NumFields);
  }

  /// The standard schema is just all the fields jumbled together.
  void getSchema(ExplosionSchema &schema) const override {
    for (auto &field : getFields()) {
      field.getTypeInfo().getSchema(schema);
    }
  }

  void assignWithCopy(IRGenFunction &IGF, Address dest,
                      Address src, SILType T) const override {
    auto offsets = asImpl().getNonFixedOffsets(IGF, T);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address destField = field.projectAddress(IGF, dest, offsets);
      Address srcField = field.projectAddress(IGF, src, offsets);
      field.getTypeInfo().assignWithCopy(IGF, destField, srcField,
                                         field.getType(IGF.IGM, T));
    }
  }

  void assignWithTake(IRGenFunction &IGF, Address dest,
                      Address src, SILType T) const override {
    auto offsets = asImpl().getNonFixedOffsets(IGF, T);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address destField = field.projectAddress(IGF, dest, offsets);
      Address srcField = field.projectAddress(IGF, src, offsets);
      field.getTypeInfo().assignWithTake(IGF, destField, srcField,
                                         field.getType(IGF.IGM, T));
    }
  }

  void initializeWithCopy(IRGenFunction &IGF,
                          Address dest, Address src,
                          SILType T) const override {
    // If we're POD, use the generic routine.
    if (this->isPOD(ResilienceScope::Component) &&
        isa<LoadableTypeInfo>(this)) {
      return cast<LoadableTypeInfo>(this)->
               LoadableTypeInfo::initializeWithCopy(IGF, dest, src, T);
    }

    auto offsets = asImpl().getNonFixedOffsets(IGF, T);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address destField = field.projectAddress(IGF, dest, offsets);
      Address srcField = field.projectAddress(IGF, src, offsets);
      field.getTypeInfo().initializeWithCopy(IGF, destField, srcField,
                                             field.getType(IGF.IGM, T));
    }
  }
  
  void initializeWithTake(IRGenFunction &IGF,
                          Address dest, Address src,
                          SILType T) const override {
    // If we're bitwise-takable, use memcpy.
    if (this->isBitwiseTakable(ResilienceScope::Component)) {
      IGF.Builder.CreateMemCpy(dest.getAddress(), src.getAddress(),
                 asImpl().Impl::getSize(IGF, T),
                 std::min(dest.getAlignment(), src.getAlignment()).getValue());
      return;
    }
    
    auto offsets = asImpl().getNonFixedOffsets(IGF, T);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;
      
      Address destField = field.projectAddress(IGF, dest, offsets);
      Address srcField = field.projectAddress(IGF, src, offsets);
      field.getTypeInfo().initializeWithTake(IGF, destField, srcField,
                                             field.getType(IGF.IGM, T));
    }
  }

  void destroy(IRGenFunction &IGF, Address addr, SILType T) const override {
    auto offsets = asImpl().getNonFixedOffsets(IGF, T);
    for (auto &field : getFields()) {
      if (field.isPOD()) continue;

      field.getTypeInfo().destroy(IGF, field.projectAddress(IGF, addr, offsets),
                                  field.getType(IGF.IGM, T));
    }
  }
};

template <class Impl, class Base, class FieldImpl_,
          bool IsLoadable = std::is_base_of<LoadableTypeInfo, Base>::value>
class SequentialTypeInfo;

/// An implementation of SequentialTypeInfo for non-loadable types. 
template <class Impl, class Base, class FieldImpl>
class SequentialTypeInfo<Impl, Base, FieldImpl, /*IsLoadable*/ false>
    : public SequentialTypeInfoImpl<Impl, Base, FieldImpl> {
  typedef SequentialTypeInfoImpl<Impl, Base, FieldImpl> super;
protected:
  template <class... As> 
  SequentialTypeInfo(As&&...args) : super(std::forward<As>(args)...) {}
};

/// An implementation of SequentialTypeInfo for loadable types. 
template <class Impl, class Base, class FieldImpl>
class SequentialTypeInfo<Impl, Base, FieldImpl, /*IsLoadable*/ true>
    : public SequentialTypeInfoImpl<Impl, Base, FieldImpl> {
  typedef SequentialTypeInfoImpl<Impl, Base, FieldImpl> super;

  unsigned ExplosionSize : 16;

protected:
  using super::asImpl;

  template <class... As> 
  SequentialTypeInfo(ArrayRef<FieldImpl> fields, unsigned explosionSize,
                     As &&...args)
    : super(fields, std::forward<As>(args)...),
      ExplosionSize(explosionSize) {}

private:
  template <void (LoadableTypeInfo::*Op)(IRGenFunction &IGF,
                                         Address addr,
                                         Explosion &out) const>
  void forAllFields(IRGenFunction &IGF, Address addr, Explosion &out) const {
    auto offsets = asImpl().getNonFixedOffsets(IGF);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address fieldAddr = field.projectAddress(IGF, addr, offsets);
      (cast<LoadableTypeInfo>(field.getTypeInfo()).*Op)(IGF, fieldAddr, out);
    }
  }

  template <void (LoadableTypeInfo::*Op)(IRGenFunction &IGF,
                                         Explosion &in,
                                         Address addr) const>
  void forAllFields(IRGenFunction &IGF, Explosion &in, Address addr) const {
    auto offsets = asImpl().getNonFixedOffsets(IGF);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address fieldAddr = field.projectAddress(IGF, addr, offsets);
      (cast<LoadableTypeInfo>(field.getTypeInfo()).*Op)(IGF, in, fieldAddr);
    }
  }

public:
  using super::getFields;

  void loadAsCopy(IRGenFunction &IGF, Address addr,
                  Explosion &out) const override {
    forAllFields<&LoadableTypeInfo::loadAsCopy>(IGF, addr, out);
  }

  void loadAsTake(IRGenFunction &IGF, Address addr,
                  Explosion &out) const override {
    forAllFields<&LoadableTypeInfo::loadAsTake>(IGF, addr, out);
  }
  
  void assign(IRGenFunction &IGF, Explosion &e, Address addr) const override {
    forAllFields<&LoadableTypeInfo::assign>(IGF, e, addr);
  }

  void initialize(IRGenFunction &IGF, Explosion &e,
                  Address addr) const override {
    forAllFields<&LoadableTypeInfo::initialize>(IGF, e, addr);
  }

  unsigned getExplosionSize() const override {
    return ExplosionSize;
  }

  void reexplode(IRGenFunction &IGF, Explosion &src,
                 Explosion &dest) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo()).reexplode(IGF, src, dest);
  }

  void copy(IRGenFunction &IGF, Explosion &src,
            Explosion &dest) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo()).copy(IGF, src, dest);
  }
      
  void consume(IRGenFunction &IGF, Explosion &src) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo()).consume(IGF, src);
  }

  void fixLifetime(IRGenFunction &IGF, Explosion &src) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo()).fixLifetime(IGF, src);
  }
  
  void packIntoEnumPayload(IRGenFunction &IGF,
                           EnumPayload &payload,
                           Explosion &src,
                           unsigned startOffset) const override {
    for (auto &field : getFields()) {
      if (field.getKind() != ElementLayout::Kind::Empty) {
        unsigned offset = field.getFixedByteOffset().getValueInBits()
          + startOffset;
        cast<LoadableTypeInfo>(field.getTypeInfo())
          .packIntoEnumPayload(IGF, payload, src, offset);
      }
    }
  }
  
  void unpackFromEnumPayload(IRGenFunction &IGF, const EnumPayload &payload,
                             Explosion &dest, unsigned startOffset)
                            const override {
    for (auto &field : getFields()) {
      if (field.getKind() != ElementLayout::Kind::Empty) {
        unsigned offset = field.getFixedByteOffset().getValueInBits()
          + startOffset;
        cast<LoadableTypeInfo>(field.getTypeInfo())
          .unpackFromEnumPayload(IGF, payload, dest, offset);
      }
    }
  }
};

/// A builder of sequential types.
///
/// Required for a full implementation:
///   TypeInfoImpl *construct(void *buffer, ArrayRef<ASTField> fields);
///   FieldImpl getFieldInfo(const ASTField &field, const TypeInfo &fieldTI);
///   Type getType(const ASTField &field);
///   void performLayout(ArrayRef<const TypeInfo *> fieldTypes);
///     - should call recordLayout with the layout
template <class BuilderImpl, class FieldImpl, class ASTField>
class SequentialTypeBuilder {
protected:
  IRGenModule &IGM;
  SequentialTypeBuilder(IRGenModule &IGM) : IGM(IGM) {}

  BuilderImpl *asImpl() { return static_cast<BuilderImpl*>(this); }

public:
  TypeInfo *layout(ArrayRef<ASTField> astFields) {
    SmallVector<FieldImpl, 8> fields;
    SmallVector<const TypeInfo *, 8> fieldTypesForLayout;
    fields.reserve(astFields.size());
    fieldTypesForLayout.reserve(astFields.size());

    bool loadable = true;

    unsigned explosionSize = 0;
    for (unsigned i : indices(astFields)) {
      auto &astField = astFields[i];
      // Compute the field's type info.
      auto &fieldTI = IGM.getTypeInfo(asImpl()->getType(astField));
      assert(fieldTI.isComplete());
      fieldTypesForLayout.push_back(&fieldTI);

      fields.push_back(FieldImpl(asImpl()->getFieldInfo(i, astField, fieldTI)));

      auto loadableFieldTI = dyn_cast<LoadableTypeInfo>(&fieldTI);
      if (!loadableFieldTI) {
        loadable = false;
        continue;
      }

      auto &fieldInfo = fields.back();
      fieldInfo.Begin = explosionSize;
      explosionSize += loadableFieldTI->getExplosionSize();
      fieldInfo.End = explosionSize;
    }

    // Perform layout and fill in the fields.
    StructLayout layout = asImpl()->performLayout(fieldTypesForLayout);
    for (unsigned i = 0, e = fields.size(); i != e; ++i) {
      fields[i].completeFrom(layout.getElements()[i]);
    }

    // Create the type info.
    if (loadable) {
      assert(layout.isFixedLayout());
      return asImpl()->createLoadable(fields, std::move(layout), explosionSize);
    } else if (layout.isFixedLayout()) {
      return asImpl()->createFixed(fields, std::move(layout));
    } else {
      return asImpl()->createNonFixed(fields, std::move(layout));
    }
  }  
};

} // end namespace irgen
} // end namespace swift

#endif
