forked from OSchip/llvm-project
[flang] new refactored Fold
Original-commit: flang-compiler/f18@061868fd85 Reviewed-on: https://github.com/flang-compiler/f18/pull/219 Tree-same-pre-rewrite: false
This commit is contained in:
parent
43a0a63441
commit
d6ea6af7c4
|
@ -144,7 +144,8 @@ template<typename A> class Expr;
|
|||
|
||||
// Classes that support a Fold(FoldingContext &) member function have the
|
||||
// IsFoldableTrait.
|
||||
CLASS_TRAIT(IsFoldableTrait)
|
||||
CLASS_TRAIT(IsFoldableTrait) // TODO pmk rm
|
||||
|
||||
struct FoldingContext {
|
||||
explicit FoldingContext(const parser::ContextualMessages &m,
|
||||
Rounding round = defaultRounding, bool flush = false)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "expression.h"
|
||||
#include "common.h"
|
||||
#include "fold.h"
|
||||
#include "int-power.h"
|
||||
#include "tools.h"
|
||||
#include "variable.h"
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../lib/common/template.h"
|
||||
#include "../lib/parser/char-block.h"
|
||||
#include "../lib/parser/message.h"
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
@ -158,12 +159,10 @@ public:
|
|||
int Rank() const {
|
||||
int rank{left().Rank()};
|
||||
if constexpr (operands > 1) {
|
||||
int rightRank{right().Rank()};
|
||||
if (rightRank > rank) {
|
||||
rank = rightRank;
|
||||
}
|
||||
return std::max(rank, right().Rank());
|
||||
} else {
|
||||
return rank;
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
@ -570,6 +569,9 @@ FOR_EACH_REAL_KIND(extern template struct Relational)
|
|||
FOR_EACH_CHARACTER_KIND(extern template struct Relational)
|
||||
extern template struct Relational<SomeType>;
|
||||
|
||||
// Logical expressions of a kind bigger than LogicalResult
|
||||
// do not include Relational<> operations as possibilities
|
||||
// since their results are always LogicalResult (kind=1).
|
||||
template<int KIND>
|
||||
class Expr<Type<TypeCategory::Logical, KIND>>
|
||||
: public ExpressionBase<Type<TypeCategory::Logical, KIND>> {
|
||||
|
@ -581,14 +583,15 @@ public:
|
|||
explicit Expr(bool x) : u{Constant<Result>{x}} {}
|
||||
|
||||
private:
|
||||
using Operations =
|
||||
std::variant<Convert<Result, TypeCategory::Logical>, Parentheses<Result>,
|
||||
Not<KIND>, LogicalOperation<KIND>, Relational<SomeType>>;
|
||||
using Operations = std::variant<Convert<Result, TypeCategory::Logical>,
|
||||
Parentheses<Result>, Not<KIND>, LogicalOperation<KIND>>;
|
||||
using Relations = std::conditional_t<KIND == LogicalResult::kind,
|
||||
std::variant<Relational<SomeType>>, std::variant<>>;
|
||||
using Others =
|
||||
std::variant<Constant<Result>, Designator<Result>, FunctionRef<Result>>;
|
||||
|
||||
public:
|
||||
common::CombineVariants<Operations, Others> u;
|
||||
common::CombineVariants<Operations, Relations, Others> u;
|
||||
};
|
||||
|
||||
FOR_EACH_LOGICAL_KIND(extern template class Expr)
|
||||
|
@ -607,7 +610,7 @@ public:
|
|||
|
||||
// Note that Expr<SomeDerived> does not inherit from ExpressionBase
|
||||
// since Constant<SomeDerived> and Scalar<SomeDerived> are not defined
|
||||
// for derived types..
|
||||
// for derived types.
|
||||
template<> class Expr<SomeDerived> {
|
||||
public:
|
||||
using Result = SomeDerived;
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
// Copyright (c) 2018, 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.
|
||||
|
||||
#ifndef FORTRAN_EVALUATE_FOLD_H_
|
||||
#define FORTRAN_EVALUATE_FOLD_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "expression.h"
|
||||
#include "int-power.h"
|
||||
#include "tools.h"
|
||||
#include "type.h"
|
||||
#include "../common/indirection.h"
|
||||
#include "../parser/message.h"
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
using namespace Fortran::parser::literals;
|
||||
|
||||
// The result of Fold() is always packaged as an Expr<>.
|
||||
// This allows Fold() to replace an operation with a constant or
|
||||
// a canonicalized expression.
|
||||
// When the operand is an Expr<A>, the result has the same type.
|
||||
|
||||
// Base cases
|
||||
template<typename A> Expr<ResultType<A>> Fold(FoldingContext &, A &&x) {
|
||||
return Expr<ResultType<A>>{std::move(x)};
|
||||
}
|
||||
|
||||
template<typename A> Expr<A> Fold(FoldingContext &context, Expr<A> &&expr) {
|
||||
static_assert(A::isSpecificIntrinsicType);
|
||||
return std::visit([&](auto &&x) -> Expr<A> { return Fold(context, std::move(x)); }, std::move(expr.u));
|
||||
}
|
||||
|
||||
template<TypeCategory CAT>
|
||||
Expr<SomeKind<CAT>>
|
||||
Fold(FoldingContext &context, Expr<SomeKind<CAT>> &&expr) {
|
||||
return std::visit([&](auto &&x) -> Expr<SomeKind<CAT>> {
|
||||
if constexpr (CAT == TypeCategory::Derived) {
|
||||
return Fold(context, std::move(x));
|
||||
} else {
|
||||
return Expr<SomeKind<CAT>>{Fold(context, std::move(x))};
|
||||
}
|
||||
}, std::move(expr.u));
|
||||
}
|
||||
|
||||
template<> inline Expr<SomeType> Fold(FoldingContext &context, Expr<SomeType> &&expr) {
|
||||
return std::visit([&](auto &&x) -> Expr<SomeType> {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, BOZLiteralConstant>) {
|
||||
return std::move(expr);
|
||||
} else {
|
||||
return Expr<SomeType>{Fold(context, std::move(x))};
|
||||
}
|
||||
}, std::move(expr.u));
|
||||
}
|
||||
|
||||
// Unary operations
|
||||
|
||||
template<typename TO, TypeCategory FROMCAT> Expr<TO> Fold(FoldingContext &context, Convert<TO, FROMCAT> &&convert) {
|
||||
return std::visit([&](auto &kindExpr) -> Expr<TO> {
|
||||
kindExpr = Fold(context, std::move(kindExpr));
|
||||
using Operand = ResultType<decltype(kindExpr)>;
|
||||
if (const auto *c{std::get_if<Constant<Operand>>(&kindExpr.u)}) {
|
||||
if constexpr (TO::category == TypeCategory::Integer) {
|
||||
if constexpr (Operand::category == TypeCategory::Integer) {
|
||||
auto converted{Scalar<TO>::ConvertSigned(c->value)};
|
||||
if (converted.overflow) {
|
||||
context.messages.Say("INTEGER(%d) to INTEGER(%d) conversion overflowed"_en_US, Operand::kind, TO::kind);
|
||||
}
|
||||
return Expr<TO>{Constant<TO>{std::move(converted.value)}};
|
||||
} else if constexpr (Operand::category == TypeCategory::Real) {
|
||||
auto converted{c->value.template ToInteger<Scalar<TO>>()};
|
||||
if (converted.flags.test(RealFlag::InvalidArgument)) {
|
||||
context.messages.Say(
|
||||
"REAL(%d) to INTEGER(%d) conversion: invalid argument"_en_US, Operand::kind, TO::kind);
|
||||
} else if (converted.flags.test(RealFlag::Overflow)) {
|
||||
context.messages.Say(
|
||||
"REAL(%d) to INTEGER(%d) conversion overflowed"_en_US, Operand::kind, TO::kind);
|
||||
}
|
||||
return Expr<TO>{Constant<TO>{std::move(converted.value)}};
|
||||
}
|
||||
} else if constexpr (TO::category == TypeCategory::Real) {
|
||||
if constexpr (Operand::category == TypeCategory::Integer) {
|
||||
auto converted{Scalar<TO>::FromInteger(c->value)};
|
||||
if (!converted.flags.empty()) {
|
||||
char buffer[64];
|
||||
std::snprintf(buffer, sizeof buffer, "INTEGER(%d) to REAL(%d) conversion", Operand::kind, TO::kind);
|
||||
RealFlagWarnings(context, converted.flags, buffer);
|
||||
}
|
||||
return Expr<TO>{Constant<TO>{std::move(converted.value)}};
|
||||
} else if constexpr (Operand::category == TypeCategory::Real) {
|
||||
auto converted{Scalar<TO>::Convert(c->value)};
|
||||
if (!converted.flags.empty()) {
|
||||
char buffer[64];
|
||||
std::snprintf(buffer, sizeof buffer, "REAL(%d) to REAL(%d) conversion", Operand::kind, TO::kind);
|
||||
RealFlagWarnings(context, converted.flags, buffer);
|
||||
}
|
||||
return Expr<TO>{Constant<TO>{std::move(converted.value)}};
|
||||
}
|
||||
} else if constexpr (TO::category == TypeCategory::Logical &&
|
||||
Operand::category == TypeCategory::Logical) {
|
||||
return Expr<TO>{Constant<TO>{c->value.IsTrue()}};
|
||||
}
|
||||
}
|
||||
return Expr<TO>{std::move(convert)};
|
||||
}, convert.left().u);
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Negate<T> &&x) {
|
||||
auto &operand{x.left()};
|
||||
operand = Fold(context, std::move(operand));
|
||||
if (const auto *c{std::get_if<Constant<T>>(&operand.u)}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
auto negated{c->value.Negate()};
|
||||
if (negated.overflow) {
|
||||
context.messages.Say("INTEGER(%d) negation overflowed"_en_US, T::kind);
|
||||
}
|
||||
return Expr<T>{Constant<T>{std::move(negated.value)}};
|
||||
} else {
|
||||
return Expr<T>{Constant<T>{c->value.Negate()}}; // REAL & COMPLEX negation: no exceptions possible
|
||||
}
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
template<int KIND> Expr<Type<TypeCategory::Real, KIND>> Fold(FoldingContext &context, ComplexComponent<KIND> &&x) {
|
||||
using Operand = Type<TypeCategory::Complex, KIND>;
|
||||
using Part = Type<TypeCategory::Real, KIND>;
|
||||
auto &operand{x.left()};
|
||||
operand = Fold(context, std::move(operand));
|
||||
if (const auto *z{std::get_if<Constant<Operand>>(&operand.u)}) {
|
||||
if (x.isImaginaryPart) {
|
||||
return Expr<Part>{Constant<Part>{z->value.AIMAG()}};
|
||||
} else {
|
||||
return Expr<Part>{Constant<Part>{z->value.REAL()}};
|
||||
}
|
||||
}
|
||||
return Expr<Part>{std::move(x)};
|
||||
}
|
||||
|
||||
template<int KIND> Expr<Type<TypeCategory::Logical, KIND>> Fold(FoldingContext &context, Not<KIND> &&x) {
|
||||
using Ty = Type<TypeCategory::Logical, KIND>;
|
||||
auto &operand{x.left()};
|
||||
operand = Fold(context, std::move(operand));
|
||||
if (const auto *c{std::get_if<Constant<Ty>>(&operand.u)}) {
|
||||
return Expr<Ty>{Constant<Ty>{c->value.IsTrue()}};
|
||||
}
|
||||
return Expr<Ty>{x};
|
||||
}
|
||||
|
||||
// Binary (dyadic) operations
|
||||
|
||||
template<typename T1, typename T2> std::optional<std::pair<Scalar<T1>, Scalar<T2>>>
|
||||
FoldOperands(FoldingContext &context, Expr<T1> &x, Expr<T2> &y) {
|
||||
x = Fold(context, std::move(x));
|
||||
y = Fold(context, std::move(y));
|
||||
if (const auto *xc{std::get_if<Constant<T1>>(&x.u)}) {
|
||||
if (const auto *yc{std::get_if<Constant<T2>>(&y.u)}) {
|
||||
return {std::make_pair(xc->value, yc->value)};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Add<T> &&x) {
|
||||
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
auto sum{folded->first.AddSigned(folded->second)};
|
||||
if (sum.overflow) {
|
||||
context.messages.Say("INTEGER(%d) addition overflowed"_en_US, T::kind);
|
||||
}
|
||||
return Expr<T>{Constant<T>{sum.value}};
|
||||
} else {
|
||||
auto sum{folded->first.Add(folded->second, context.rounding)};
|
||||
RealFlagWarnings(context, sum.flags, "addition");
|
||||
return Expr<T>{Constant<T>{sum.value}};
|
||||
}
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Subtract<T> &&x) {
|
||||
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
auto difference{folded->first.SubtractSigned(folded->second)};
|
||||
if (difference.overflow) {
|
||||
context.messages.Say("INTEGER(%d) subtraction overflowed"_en_US, T::kind);
|
||||
}
|
||||
return Expr<T>{Constant<T>{difference.value}};
|
||||
} else {
|
||||
auto difference{folded->first.Subtract(folded->second, context.rounding)};
|
||||
RealFlagWarnings(context, difference.flags, "subtraction");
|
||||
return Expr<T>{Constant<T>{difference.value}};
|
||||
}
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Multiply<T> &&x) {
|
||||
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
auto product{folded->first.MultiplySigned(folded->second)};
|
||||
if (product.SignedMultiplicationOverflowed()) {
|
||||
context.messages.Say("INTEGER(%d) multiplication overflowed"_en_US, T::kind);
|
||||
}
|
||||
return Expr<T>{Constant<T>{product.lower}};
|
||||
} else {
|
||||
auto product{folded->first.Multiply(folded->second, context.rounding)};
|
||||
RealFlagWarnings(context, product.flags, "multiplication");
|
||||
return Expr<T>{Constant<T>{product.value}};
|
||||
}
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Divide<T> &&x) {
|
||||
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
auto quotAndRem{folded->first.DivideSigned(folded->second)};
|
||||
if (quotAndRem.divisionByZero) {
|
||||
context.messages.Say("INTEGER(%d) division by zero"_en_US, T::kind);
|
||||
}
|
||||
if (quotAndRem.overflow) {
|
||||
context.messages.Say("INTEGER(%d) division overflowed"_en_US, T::kind);
|
||||
}
|
||||
return Expr<T>{Constant<T>{quotAndRem.quotient}};
|
||||
} else {
|
||||
auto quotient{folded->first.Divide(folded->second, context.rounding)};
|
||||
RealFlagWarnings(context, quotient.flags, "division");
|
||||
return Expr<T>{Constant<T>{quotient.value}};
|
||||
}
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Power<T> &&x) {
|
||||
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
auto power{folded->first.Power(folded->second)};
|
||||
if (power.divisionByZero) {
|
||||
context.messages.Say("INTEGER(%d) zero to negative power"_en_US, T::kind);
|
||||
} else if (power.overflow) {
|
||||
context.messages.Say("INTEGER(%d) power overflowed"_en_US, T::kind);
|
||||
} else if (power.zeroToZero) {
|
||||
context.messages.Say("INTEGER(%d) 0**0 is not defined"_en_US, T::kind);
|
||||
}
|
||||
return Expr<T>{Constant<T>{power.power}};
|
||||
} else {
|
||||
// TODO: real & complex power with non-integral exponent
|
||||
}
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, RealToIntPower<T> &&x) {
|
||||
return std::visit([&](auto &y) -> Expr<T> {
|
||||
if (auto folded{FoldOperands(context, x.left(), y)}) {
|
||||
auto power{evaluate::IntPower(folded->first, folded->second)};
|
||||
RealFlagWarnings(context, power.flags, "power with INTEGER exponent");
|
||||
return Expr<T>{Constant<T>{power.value}};
|
||||
} else {
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
}, x.right().u);
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Fold(FoldingContext &context, Extremum<T> &&x) {
|
||||
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
|
||||
if constexpr (T::category == TypeCategory::Integer) {
|
||||
if (folded->first.CompareSigned(folded->second) == x.ordering) {
|
||||
return Expr<T>{Constant<T>{folded->first}};
|
||||
}
|
||||
} else if constexpr (T::category == TypeCategory::Real) {
|
||||
if (folded->first.IsNotANumber() || (folded->first.Compare(folded->second) == Relation::Less) == (x.ordering == Ordering::Less)) {
|
||||
return Expr<T>{Constant<T>{folded->first}};
|
||||
}
|
||||
} else {
|
||||
if (x.ordering == Compare(folded->first, folded->second)) {
|
||||
return Expr<T>{Constant<T>{folded->first}};
|
||||
}
|
||||
}
|
||||
return Expr<T>{Constant<T>{folded->second}};
|
||||
}
|
||||
return Expr<T>{std::move(x)};
|
||||
}
|
||||
|
||||
}
|
||||
#endif // FORTRAN_EVALUATE_FOLD_H_
|
|
@ -40,23 +40,41 @@ SourceFile::~SourceFile() { Close(); }
|
|||
|
||||
static std::vector<std::size_t> FindLineStarts(
|
||||
const char *source, std::size_t bytes) {
|
||||
if (bytes == 0) {
|
||||
return {};
|
||||
}
|
||||
CHECK(source[bytes - 1] == '\n' && "missing ultimate newline");
|
||||
std::vector<std::size_t> result;
|
||||
std::size_t at{0};
|
||||
do {
|
||||
result.push_back(at);
|
||||
const void *vp{static_cast<const void *>(&source[at])};
|
||||
const void *vnl{std::memchr(vp, '\n', bytes - at)};
|
||||
const char *nl{static_cast<const char *>(vnl)};
|
||||
at = nl + 1 - source;
|
||||
} while (at < bytes);
|
||||
result.shrink_to_fit();
|
||||
if (bytes > 0) {
|
||||
CHECK(source[bytes - 1] == '\n' && "missing ultimate newline");
|
||||
std::size_t at{0};
|
||||
do {
|
||||
result.push_back(at);
|
||||
const void *vp{static_cast<const void *>(&source[at])};
|
||||
const void *vnl{std::memchr(vp, '\n', bytes - at)};
|
||||
const char *nl{static_cast<const char *>(vnl)};
|
||||
at = nl + 1 - source;
|
||||
} while (at < bytes);
|
||||
result.shrink_to_fit();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SourceFile::RecordLineStarts() {
|
||||
lineStart_ = FindLineStarts(content_, bytes_);
|
||||
}
|
||||
|
||||
// Cut down the contiguous content of a source file to skip
|
||||
// things like byte order marks.
|
||||
void SourceFile::IdentifyPayload() {
|
||||
content_ = address_;
|
||||
bytes_ = size_;
|
||||
if (content_ != nullptr) {
|
||||
if (bytes_ >= 3 && content_[0] == 0xef && content_[1] == 0xbb &&
|
||||
content_[2] == 0xbf) {
|
||||
// UTF-8 encoding of Unicode byte order mark (BOM)
|
||||
content_ += 3;
|
||||
bytes_ -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string DirectoryName(std::string path) {
|
||||
auto lastSlash{path.rfind("/")};
|
||||
return lastSlash == std::string::npos ? path : path.substr(0, lastSlash);
|
||||
|
@ -136,24 +154,28 @@ bool SourceFile::ReadFile(std::string errorPath, std::stringstream *error) {
|
|||
// Don't bother with small ones. This also helps keep the number
|
||||
// of open file descriptors from getting out of hand.
|
||||
if (useMMap && S_ISREG(statbuf.st_mode)) {
|
||||
bytes_ = static_cast<std::size_t>(statbuf.st_size);
|
||||
if (bytes_ >= minMapFileBytes &&
|
||||
size_ = static_cast<std::size_t>(statbuf.st_size);
|
||||
if (size_ >= minMapFileBytes &&
|
||||
openFileDescriptors <= maxMapOpenFileDescriptors) {
|
||||
void *vp = mmap(0, bytes_, PROT_READ, MAP_SHARED, fileDescriptor_, 0);
|
||||
void *vp = mmap(0, size_, PROT_READ, MAP_SHARED, fileDescriptor_, 0);
|
||||
if (vp != MAP_FAILED) {
|
||||
content_ = static_cast<const char *>(const_cast<const void *>(vp));
|
||||
if (content_[bytes_ - 1] == '\n' &&
|
||||
std::memchr(vp, '\r', bytes_) == nullptr) {
|
||||
address_ = static_cast<const char *>(const_cast<const void *>(vp));
|
||||
IdentifyPayload();
|
||||
if (bytes_ > 0 && content_[bytes_ - 1] == '\n' &&
|
||||
std::memchr(static_cast<const void *>(content_), '\r', bytes_) ==
|
||||
nullptr) {
|
||||
isMemoryMapped_ = true;
|
||||
lineStart_ = FindLineStarts(content_, bytes_);
|
||||
RecordLineStarts();
|
||||
return true;
|
||||
}
|
||||
// The file needs to have its line endings normalized to simple
|
||||
// newlines. Remap it for a private rewrite in place.
|
||||
vp = mmap(vp, bytes_, PROT_READ | PROT_WRITE, MAP_PRIVATE,
|
||||
fileDescriptor_, 0);
|
||||
vp = mmap(
|
||||
vp, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileDescriptor_, 0);
|
||||
if (vp != MAP_FAILED) {
|
||||
auto mutableContent{static_cast<char *>(vp)};
|
||||
address_ = static_cast<const char *>(const_cast<const void *>(vp));
|
||||
IdentifyPayload();
|
||||
auto mutableContent{const_cast<char *>(content_)};
|
||||
bytes_ = RemoveCarriageReturns(mutableContent, bytes_);
|
||||
if (bytes_ > 0) {
|
||||
if (mutableContent[bytes_ - 1] == '\n' ||
|
||||
|
@ -166,13 +188,14 @@ bool SourceFile::ReadFile(std::string errorPath, std::stringstream *error) {
|
|||
CHECK(isNowReadOnly);
|
||||
content_ = mutableContent;
|
||||
isMemoryMapped_ = true;
|
||||
lineStart_ = FindLineStarts(content_, bytes_);
|
||||
RecordLineStarts();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
munmap(vp, bytes_);
|
||||
content_ = nullptr;
|
||||
munmap(vp, size_);
|
||||
address_ = content_ = nullptr;
|
||||
size_ = bytes_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,30 +222,31 @@ bool SourceFile::ReadFile(std::string errorPath, std::stringstream *error) {
|
|||
--openFileDescriptors;
|
||||
}
|
||||
fileDescriptor_ = -1;
|
||||
bytes_ = buffer.size();
|
||||
if (bytes_ == 0) {
|
||||
if (buffer.size() == 0) {
|
||||
// empty file
|
||||
content_ = nullptr;
|
||||
address_ = content_ = nullptr;
|
||||
size_ = bytes_ = 0;
|
||||
} else {
|
||||
normalized_ = buffer.MarshalNormalized();
|
||||
content_ = normalized_.data();
|
||||
bytes_ = normalized_.size();
|
||||
lineStart_ = FindLineStarts(content_, bytes_);
|
||||
address_ = normalized_.data();
|
||||
size_ = normalized_.size();
|
||||
IdentifyPayload();
|
||||
RecordLineStarts();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SourceFile::Close() {
|
||||
if (useMMap && isMemoryMapped_) {
|
||||
munmap(reinterpret_cast<void *>(const_cast<char *>(content_)), bytes_);
|
||||
munmap(reinterpret_cast<void *>(const_cast<char *>(address_)), size_);
|
||||
isMemoryMapped_ = false;
|
||||
} else if (!normalized_.empty()) {
|
||||
normalized_.clear();
|
||||
} else if (content_ != nullptr) {
|
||||
delete[] content_;
|
||||
} else if (address_ != nullptr) {
|
||||
delete[] address_;
|
||||
}
|
||||
content_ = nullptr;
|
||||
bytes_ = 0;
|
||||
address_ = content_ = nullptr;
|
||||
size_ = bytes_ = 0;
|
||||
if (fileDescriptor_ > 0) {
|
||||
close(fileDescriptor_);
|
||||
--openFileDescriptors;
|
||||
|
|
|
@ -50,11 +50,15 @@ public:
|
|||
|
||||
private:
|
||||
bool ReadFile(std::string errorPath, std::stringstream *error);
|
||||
void IdentifyPayload();
|
||||
void RecordLineStarts();
|
||||
|
||||
std::string path_;
|
||||
int fileDescriptor_{-1};
|
||||
bool isMemoryMapped_{false};
|
||||
const char *content_{nullptr};
|
||||
const char *address_{nullptr}; // raw content
|
||||
std::size_t size_{0};
|
||||
const char *content_{nullptr}; // usable content
|
||||
std::size_t bytes_{0};
|
||||
std::vector<std::size_t> lineStart_;
|
||||
std::string normalized_;
|
||||
|
|
Loading…
Reference in New Issue