text: //===--- StructMetadataVisitor.h - CRTP for struct metadata ------*- 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
  //
  //===----------------------------------------------------------------------===//
  //
  // A CRTP class useful for laying out struct metadata.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef POLARPHP_IRGEN_INTERNAL_STRUCTMETADATALAYOUT_H
  #define POLARPHP_IRGEN_INTERNAL_STRUCTMETADATALAYOUT_H
  
  #include "polarphp/irgen/internal/NominalMetadataVisitor.h"
  
  namespace polar::irgen {
  
  /// A CRTP class for laying out struct metadata.
  ///
  /// This produces an object corresponding to the StructMetadata type.
  /// It does not itself doing anything special for metadata templates.
  template<class Impl>
  class StructMetadataVisitor
     : public NominalMetadataVisitor<Impl> {
     using super = NominalMetadataVisitor<Impl>;
  
  protected:
     using super::IGM;
     using super::asImpl;
  
     /// The struct.
     StructDecl *const Target;
  
     StructMetadataVisitor(IRGenModule &IGM, StructDecl *target)
        : super(IGM), Target(target) {}
  
  public:
     void layout() {
        // Metadata header.
        super::layout();
  
        // StructMetadata header.
        asImpl().addNominalTypeDescriptor();
  
        // Everything after this is type-specific.
        asImpl().noteStartOfTypeSpecificMembers();
  
        // Generic arguments.
        // This must always be the first piece of trailing data.
        asImpl().addGenericFields(Target);
  
        // Struct field offsets.
        asImpl().noteStartOfFieldOffsets();
        for (VarDecl *prop : Target->getStoredProperties())
           asImpl().addFieldOffset(prop);
  
        asImpl().noteEndOfFieldOffsets();
     }
  
     // Note the start of the field offset vector.
     void noteStartOfFieldOffsets() {}
  
     // Note the end of the field offset vector.
     void noteEndOfFieldOffsets() {}
  };
  
  /// An "implementation" of StructMetadataVisitor that just scans through
  /// the metadata layout, maintaining the offset of the next field.
  template<class Impl>
  class StructMetadataScanner : public StructMetadataVisitor<Impl> {
     using super = StructMetadataVisitor<Impl>;
  
  protected:
     Size NextOffset = Size(0);
  
     StructMetadataScanner(IRGenModule &IGM, StructDecl *target)
        : super(IGM, target) {}
  
  public:
     void addMetadataFlags() { addPointer(); }
  
     void addValueWitnessTable() { addPointer(); }
  
     void addNominalTypeDescriptor() { addPointer(); }
  
     void addFieldOffset(VarDecl *) { addInt32(); }
  
     void addGenericArgument() { addPointer(); }
  
     void addGenericWitnessTable() { addPointer(); }
  
     void noteStartOfTypeSpecificMembers() {}
  
     void noteEndOfFieldOffsets() {
        NextOffset = NextOffset.roundUpToAlignment(super::IGM.getPointerAlignment());
     }
  
  private:
     void addPointer() {
        NextOffset += super::IGM.getPointerSize();
     }
  
     void addInt32() { NextOffset += Size(4); }
  };
  
  } // polar::irgen
  
  #endif // POLARPHP_IRGEN_INTERNAL_STRUCTMETADATALAYOUT_H
  