// 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 "shape.h" #include "type.h" #include namespace Fortran::evaluate { std::size_t TotalElementCount(const ConstantSubscripts &shape) { std::size_t size{1}; for (auto dim : shape) { CHECK(dim >= 0); size *= dim; } return size; } bool IncrementSubscripts( ConstantSubscripts &indices, const ConstantSubscripts &shape) { int rank{GetRank(shape)}; CHECK(GetRank(indices) == rank); for (int j{0}; j < rank; ++j) { CHECK(indices[j] >= 1); if (++indices[j] <= shape[j]) { return true; } else { CHECK(indices[j] == shape[j] + 1); indices[j] = 1; } } return false; // all done } template ConstantBase::ConstantBase( std::vector &&x, ConstantSubscripts &&dims, Result res) : result_{res}, values_(std::move(x)), shape_(std::move(dims)) { CHECK(size() == TotalElementCount(shape_)); } template ConstantBase::~ConstantBase() {} template bool ConstantBase::operator==(const ConstantBase &that) const { return shape_ == that.shape_ && values_ == that.values_; } static ConstantSubscript SubscriptsToOffset( const ConstantSubscripts &index, const ConstantSubscripts &shape) { CHECK(GetRank(index) == GetRank(shape)); ConstantSubscript stride{1}, offset{0}; int dim{0}; for (auto j : index) { auto bound{shape[dim++]}; CHECK(j >= 1 && j <= bound); offset += stride * (j - 1); stride *= bound; } return offset; } template Constant ConstantBase::SHAPE() const { return AsConstantShape(shape_); } template auto ConstantBase::Reshape( const ConstantSubscripts &dims) const -> std::vector { std::size_t n{TotalElementCount(dims)}; CHECK(!empty() || n == 0); std::vector elements; auto iter{values().cbegin()}; while (n-- > 0) { elements.push_back(*iter); if (++iter == values().cend()) { iter = values().cbegin(); } } return elements; } template auto Constant::At(const ConstantSubscripts &index) const -> Element { return Base::values_.at(SubscriptsToOffset(index, Base::shape_)); } template auto Constant::Reshape(ConstantSubscripts &&dims) const -> Constant { return {Base::Reshape(dims), std::move(dims)}; } // Constant specializations template Constant>::Constant( const Scalar &str) : values_{str}, length_{static_cast(values_.size())} {} template Constant>::Constant(Scalar &&str) : values_{std::move(str)}, length_{static_cast( values_.size())} {} template Constant>::Constant(ConstantSubscript len, std::vector> &&strings, ConstantSubscripts &&dims) : length_{len}, shape_{std::move(dims)} { CHECK(strings.size() == TotalElementCount(shape_)); values_.assign(strings.size() * length_, static_cast::value_type>(' ')); ConstantSubscript 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() {} template bool Constant>::empty() const { return size() == 0; } template std::size_t Constant>::size() const { if (length_ == 0) { return TotalElementCount(shape_); } else { return static_cast(values_.size()) / length_; } } template auto Constant>::At( const ConstantSubscripts &index) const -> Scalar { auto offset{SubscriptsToOffset(index, shape_)}; return values_.substr(offset * length_, length_); } template auto Constant>::Reshape( ConstantSubscripts &&dims) const -> Constant { std::size_t n{TotalElementCount(dims)}; CHECK(!empty() || n == 0); std::vector elements; ConstantSubscript at{0}, limit{static_cast(values_.size())}; while (n-- > 0) { elements.push_back(values_.substr(at, length_)); at += length_; if (at == limit) { // subtle: at > limit somehow? substr() will catch it at = 0; } } return {length_, std::move(elements), std::move(dims)}; } template Constant Constant>::SHAPE() const { return AsConstantShape(shape_); } // Constant specialization Constant::Constant(const StructureConstructor &x) : Base{x.values(), Result{x.derivedTypeSpec()}} {} Constant::Constant(StructureConstructor &&x) : Base{std::move(x.values()), Result{x.derivedTypeSpec()}} {} Constant::Constant(const semantics::DerivedTypeSpec &spec, std::vector &&x, ConstantSubscripts &&s) : Base{std::move(x), std::move(s), Result{spec}} {} static std::vector AcquireValues( 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, ConstantSubscripts &&s) : Base{AcquireValues(std::move(x)), std::move(s), Result{spec}} {} std::optional Constant::GetScalarValue() const { if (shape_.empty()) { return StructureConstructor{result().derivedTypeSpec(), values_.at(0)}; } else { return std::nullopt; } } StructureConstructor Constant::At( const ConstantSubscripts &index) const { return {result().derivedTypeSpec(), values_.at(SubscriptsToOffset(index, shape_))}; } auto Constant::Reshape(ConstantSubscripts &&dims) const -> Constant { return {result().derivedTypeSpec(), Base::Reshape(dims), std::move(dims)}; } INSTANTIATE_CONSTANT_TEMPLATES }