#ifndef FORTRAN_RUNTIME_TYPE_INFO_H_
#define FORTRAN_RUNTIME_TYPE_INFO_H_
#include "terminator.h"
#include "flang/Common/Fortran.h"
#include "flang/Common/bit-population-count.h"
#include "flang/Common/optional.h"
#include "flang/Runtime/descriptor.h"
#include <cinttypes>
#include <memory>
namespace Fortran::runtime::typeInfo {
class DerivedType;
using ProcedurePointer = void (*)();
struct Binding {
ProcedurePointer proc;
StaticDescriptor<0> name;
};
class Value {
public:
enum class Genre : std::uint8_t {
Deferred = 1,
Explicit = 2,
LenParameter = 3
};
RT_API_ATTRS Genre genre() const { return genre_; }
RT_API_ATTRS Fortran::common::optional<TypeParameterValue> GetValue(
const Descriptor *) const;
private:
Genre genre_{Genre::Explicit};
TypeParameterValue value_{0};
};
class Component {
public:
enum class Genre : std::uint8_t {
Data = 1,
Pointer = 2,
Allocatable = 3,
Automatic = 4
};
RT_API_ATTRS const Descriptor &name() const { return name_.descriptor(); }
RT_API_ATTRS Genre genre() const { return genre_; }
RT_API_ATTRS TypeCategory category() const {
return static_cast<TypeCategory>(category_);
}
RT_API_ATTRS int kind() const { return kind_; }
RT_API_ATTRS int rank() const { return rank_; }
RT_API_ATTRS std::uint64_t offset() const { return offset_; }
RT_API_ATTRS const Value &characterLen() const { return characterLen_; }
RT_API_ATTRS const DerivedType *derivedType() const {
return derivedType_.descriptor().OffsetElement<const DerivedType>();
}
RT_API_ATTRS const Value *lenValue() const {
return lenValue_.descriptor().OffsetElement<const Value>();
}
RT_API_ATTRS const Value *bounds() const {
return bounds_.descriptor().OffsetElement<const Value>();
}
RT_API_ATTRS const char *initialization() const { return initialization_; }
RT_API_ATTRS std::size_t GetElementByteSize(const Descriptor &) const;
RT_API_ATTRS std::size_t GetElements(const Descriptor &) const;
RT_API_ATTRS std::size_t SizeInBytes(const Descriptor &) const;
RT_API_ATTRS void EstablishDescriptor(
Descriptor &, const Descriptor &container, Terminator &) const;
RT_API_ATTRS void CreatePointerDescriptor(Descriptor &,
const Descriptor &container, Terminator &,
const SubscriptValue * = nullptr) const;
FILE *Dump(FILE * = stdout) const;
private:
StaticDescriptor<0> name_;
Genre genre_{Genre::Data};
std::uint8_t category_;
std::uint8_t kind_{0};
std::uint8_t rank_{0};
std::uint64_t offset_{0};
Value characterLen_;
StaticDescriptor<0, true> derivedType_;
StaticDescriptor<1, true>
lenValue_;
StaticDescriptor<2, true>
bounds_;
const char *initialization_{nullptr};
};
struct ProcPtrComponent {
StaticDescriptor<0> name;
std::uint64_t offset{0};
ProcedurePointer procInitialization;
};
class SpecialBinding {
public:
enum class Which : std::uint8_t {
None = 0,
ScalarAssignment = 1,
ElementalAssignment = 2,
ReadFormatted = 3,
ReadUnformatted = 4,
WriteFormatted = 5,
WriteUnformatted = 6,
ElementalFinal = 7,
AssumedRankFinal = 8,
ScalarFinal = 9,
};
RT_API_ATTRS SpecialBinding(Which which, ProcedurePointer proc,
std::uint8_t isArgDescSet, std::uint8_t isTypeBound,
std::uint8_t isArgContiguousSet)
: which_{which}, isArgDescriptorSet_{isArgDescSet},
isTypeBound_{isTypeBound}, isArgContiguousSet_{isArgContiguousSet},
proc_{proc} {}
static constexpr RT_API_ATTRS Which RankFinal(int rank) {
return static_cast<Which>(static_cast<int>(Which::ScalarFinal) + rank);
}
RT_API_ATTRS Which which() const { return which_; }
RT_API_ATTRS bool IsArgDescriptor(int zeroBasedArg) const {
return (isArgDescriptorSet_ >> zeroBasedArg) & 1;
}
RT_API_ATTRS bool isTypeBound() const { return isTypeBound_; }
RT_API_ATTRS bool IsArgContiguous(int zeroBasedArg) const {
return (isArgContiguousSet_ >> zeroBasedArg) & 1;
}
template <typename PROC> RT_API_ATTRS PROC GetProc() const {
return reinterpret_cast<PROC>(proc_);
}
FILE *Dump(FILE *) const;
private:
Which which_{Which::None};
std::uint8_t isArgDescriptorSet_{0};
std::uint8_t isTypeBound_{0};
std::uint8_t isArgContiguousSet_{0};
ProcedurePointer proc_{nullptr};
};
class DerivedType {
public:
~DerivedType();
RT_API_ATTRS const Descriptor &binding() const {
return binding_.descriptor();
}
RT_API_ATTRS const Descriptor &name() const { return name_.descriptor(); }
RT_API_ATTRS std::uint64_t sizeInBytes() const { return sizeInBytes_; }
RT_API_ATTRS const Descriptor &uninstatiated() const {
return uninstantiated_.descriptor();
}
RT_API_ATTRS const Descriptor &kindParameter() const {
return kindParameter_.descriptor();
}
RT_API_ATTRS const Descriptor &lenParameterKind() const {
return lenParameterKind_.descriptor();
}
RT_API_ATTRS const Descriptor &component() const {
return component_.descriptor();
}
RT_API_ATTRS const Descriptor &procPtr() const {
return procPtr_.descriptor();
}
RT_API_ATTRS const Descriptor &special() const {
return special_.descriptor();
}
RT_API_ATTRS bool hasParent() const { return hasParent_; }
RT_API_ATTRS bool noInitializationNeeded() const {
return noInitializationNeeded_;
}
RT_API_ATTRS bool noDestructionNeeded() const { return noDestructionNeeded_; }
RT_API_ATTRS bool noFinalizationNeeded() const {
return noFinalizationNeeded_;
}
RT_API_ATTRS std::size_t LenParameters() const {
return lenParameterKind().Elements();
}
RT_API_ATTRS const DerivedType *GetParentType() const;
RT_API_ATTRS const Component *FindDataComponent(
const char *name, std::size_t nameLen) const;
RT_API_ATTRS const SpecialBinding *FindSpecialBinding(
SpecialBinding::Which which) const {
auto bitIndex{static_cast<std::uint32_t>(which)};
auto bit{std::uint32_t{1} << bitIndex};
if (specialBitSet_ & bit) {
int offset{common::BitPopulationCount(specialBitSet_ & (bit - 1))};
const auto *binding{
special_.descriptor().ZeroBasedIndexedElement<SpecialBinding>(
offset)};
INTERNAL_CHECK(binding && binding->which() == which);
return binding;
} else {
return nullptr;
}
}
FILE *Dump(FILE * = stdout) const;
private:
StaticDescriptor<1, true>
binding_;
StaticDescriptor<0> name_;
std::uint64_t sizeInBytes_{0};
StaticDescriptor<0, true> uninstantiated_;
StaticDescriptor<1> kindParameter_;
StaticDescriptor<1>
lenParameterKind_;
StaticDescriptor<1, true>
component_;
StaticDescriptor<1, true>
procPtr_;
StaticDescriptor<1, true>
special_;
std::uint32_t specialBitSet_{0};
bool hasParent_{false};
bool noInitializationNeeded_{false};
bool noDestructionNeeded_{false};
bool noFinalizationNeeded_{false};
};
}
#endif