// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "constant.h" #include "expression.h" #include "type.h" #include "../parser/characters.h" #include namespace Fortran::evaluate { template ConstantBase::~ConstantBase() {} static void ShapeAsFortran( std::ostream &o, const std::vector &shape) { if (shape.size() > 1) { o << ",shape="; char ch{'['}; for (auto dim : shape) { o << ch << dim; ch = ','; } o << "])"; } } template std::ostream &ConstantBase::AsFortran(std::ostream &o) const { if (Rank() > 1) { o << "reshape("; } if (Rank() > 0) { o << '[' << GetType().AsFortran() << "::"; } bool first{true}; for (const auto &value : values_) { if (first) { first = false; } else { o << ','; } if constexpr (Result::category == TypeCategory::Integer) { o << value.SignedDecimal() << '_' << Result::kind; } else if constexpr (Result::category == TypeCategory::Real || Result::category == TypeCategory::Complex) { value.AsFortran(o, Result::kind); } else if constexpr (Result::category == TypeCategory::Character) { o << Result::kind << '_' << parser::QuoteCharacterLiteral(value); } else if constexpr (Result::category == TypeCategory::Logical) { if (value.IsTrue()) { o << ".true."; } else { o << ".false."; } o << '_' << Result::kind; } else { StructureConstructor{AsConstant().derivedTypeSpec(), value}.AsFortran(o); } } if (Rank() > 0) { o << ']'; } ShapeAsFortran(o, shape_); return o; } static std::int64_t SubscriptsToOffset(const std::vector &index, const std::vector &shape) { CHECK(index.size() == shape.size()); std::int64_t stride{1}, offset{0}; int dim{0}; for (std::int64_t j : index) { std::int64_t bound{shape[dim++]}; CHECK(j >= 1 && j <= bound); offset += stride * (j - 1); stride *= bound; } return offset; } template auto ConstantBase::At( const std::vector &index) const -> ScalarValue { return values_.at(SubscriptsToOffset(index, shape_)); } static Constant ShapeAsConstant( const std::vector &shape) { using IntType = Scalar; std::vector result; for (std::int64_t dim : shape) { result.emplace_back(dim); } return {std::move(result), std::vector{static_cast(shape.size())}}; } template Constant ConstantBase::SHAPE() const { return ShapeAsConstant(shape_); } // Constant specializations template Constant>::Constant(const ScalarValue &str) : values_{str}, length_{static_cast(values_.size())} {} template Constant>::Constant(ScalarValue &&str) : values_{std::move(str)}, length_{ static_cast(values_.size())} {} template Constant>::Constant(std::int64_t len, std::vector &&strings, std::vector &&dims) : length_{len}, shape_{std::move(dims)} { values_.assign(strings.size() * length_, static_cast(' ')); std::int64_t at{0}; for (const auto &str : strings) { auto strLen{static_cast(str.size())}; if (strLen > length_) { values_.replace(at, length_, str.substr(0, length_)); } else { values_.replace(at, strLen, str); } at += length_; } CHECK(at == static_cast(values_.size())); } template Constant>::~Constant() {} static std::int64_t ShapeElements(const std::vector &shape) { std::int64_t elements{1}; for (auto dim : shape) { elements *= dim; } return elements; } template bool Constant>::empty() const { return size() == 0; } template std::size_t Constant>::size() const { if (length_ == 0) { return ShapeElements(shape_); } else { return static_cast(values_.size()) / length_; } } template auto Constant>::At( const std::vector &index) const -> ScalarValue { auto offset{SubscriptsToOffset(index, shape_)}; return values_.substr(offset, length_); } template Constant Constant>::SHAPE() const { return ShapeAsConstant(shape_); } template std::ostream &Constant>::AsFortran( std::ostream &o) const { if (Rank() > 1) { o << "reshape("; } if (Rank() > 0) { o << '[' << GetType().AsFortran(std::to_string(length_)) << "::"; } auto total{static_cast(size())}; for (std::int64_t j{0}; j < total; ++j) { ScalarValue value{values_.substr(j * length_, length_)}; if (j > 0) { o << ','; } else if (Rank() == 0) { o << Result::kind << '_'; } o << parser::QuoteCharacterLiteral(value); } if (Rank() > 0) { o << ']'; } ShapeAsFortran(o, shape_); return o; } // Constant specialization Constant::Constant(const StructureConstructor &x) : Base{x.values()}, derivedTypeSpec_{&x.derivedTypeSpec()} {} Constant::Constant(StructureConstructor &&x) : Base{std::move(x.values())}, derivedTypeSpec_{&x.derivedTypeSpec()} {} Constant::Constant(const semantics::DerivedTypeSpec &spec, std::vector &&x, std::vector &&s) : Base{std::move(x), std::move(s)}, derivedTypeSpec_{&spec} {} static std::vector GetValues( std::vector &&x) { std::vector result; for (auto &&structure : std::move(x)) { result.emplace_back(std::move(structure.values())); } return result; } Constant::Constant(const semantics::DerivedTypeSpec &spec, std::vector &&x, std::vector &&s) : Base{GetValues(std::move(x)), std::move(s)}, derivedTypeSpec_{&spec} {} FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase) template class ConstantBase; FOR_EACH_INTRINSIC_KIND(template class Constant) }