[flang] Avoid std::shared_ptr<> in favor of reference counting.

Original-commit: flang-compiler/f18@116c9881c9
Reviewed-on: https://github.com/flang-compiler/f18/pull/59
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-04-17 10:28:25 -07:00
parent f595462ea8
commit 84ebba9e53
5 changed files with 130 additions and 128 deletions

View File

@ -79,7 +79,7 @@ public:
constexpr BacktrackingParser(const A &parser) : parser_{parser} {} constexpr BacktrackingParser(const A &parser) : parser_{parser} {}
std::optional<resultType> Parse(ParseState *state) const { std::optional<resultType> Parse(ParseState *state) const {
Messages messages{std::move(state->messages())}; Messages messages{std::move(state->messages())};
MessageContext context{state->context()}; Message::Context context{state->context()};
ParseState backtrack{*state}; ParseState backtrack{*state};
std::optional<resultType> result{parser_.Parse(state)}; std::optional<resultType> result{parser_.Parse(state)};
if (result.has_value()) { if (result.has_value()) {
@ -89,7 +89,7 @@ public:
} else { } else {
state->swap(backtrack); state->swap(backtrack);
state->messages().swap(messages); state->messages().swap(messages);
state->set_context(context); state->set_context(std::move(context));
} }
return result; return result;
} }
@ -239,75 +239,46 @@ public:
constexpr AlternativeParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {} constexpr AlternativeParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {}
std::optional<resultType> Parse(ParseState *state) const { std::optional<resultType> Parse(ParseState *state) const {
Messages messages{std::move(state->messages())}; Messages messages{std::move(state->messages())};
MessageContext context{state->context()}; Message::Context context{state->context()};
ParseState backtrack{*state}; ParseState backtrack{*state};
int depth{state->alternativeDepth()};
bool deferred{state->deferMessages()};
if (!deferred) {
if (depth == 0 && state->messages().empty()) {
CHECK(!state->blockedMessages());
state->set_deferMessages(true);
}
}
state->set_alternativeDepth(depth + 1);
if (std::optional<resultType> ax{pa_.Parse(state)}) { if (std::optional<resultType> ax{pa_.Parse(state)}) {
if (!deferred && state->blockedMessages()) { // preserve any new messages
// We deferred messages but now we need them. Regenerate. messages.Annex(state->messages());
state->swap(backtrack); state->messages().swap(messages);
state->messages().swap(messages);
state->set_context(context);
return pa_.Parse(state);
}
state->set_alternativeDepth(depth)
.set_deferMessages(deferred)
.set_context(context)
.messages().Annex(messages);
return ax; return ax;
} }
ParseState backtrack2{backtrack}; #if 0 // needed below if "tied" messages are to be saved
auto start = backtrack.GetLocation();
#endif
ParseState paState{std::move(*state)};
state->swap(backtrack); state->swap(backtrack);
if (!deferred) { state->set_context(std::move(context));
if (depth == 0 && state->messages().empty()) {
CHECK(!state->blockedMessages());
state->set_deferMessages(true);
}
}
state->set_alternativeDepth(depth + 1);
if (std::optional<resultType> bx{pb_.Parse(state)}) { if (std::optional<resultType> bx{pb_.Parse(state)}) {
if (!deferred && state->blockedMessages()) { // preserve any new messages
state->swap(backtrack2); messages.Annex(state->messages());
state->messages().swap(messages); state->messages().swap(messages);
state->set_context(context);
return pb_.Parse(state);
}
state->set_alternativeDepth(depth)
.set_deferMessages(deferred)
.set_context(context)
.messages().Annex(messages);
return bx; return bx;
} }
// Both alternatives failed. Retain the state (and messages) from the // Both alternatives failed. Retain the state (and messages) from the
// alternative parse that went the furthest. // alternative parse that went the furthest.
if (backtrack.GetLocation() >= state->GetLocation()) { auto paEnd = paState.GetLocation();
if (!deferred && backtrack.blockedMessages()) { auto pbEnd = state->GetLocation();
state->swap(backtrack2); if (paEnd > pbEnd) {
state->messages().swap(messages); messages.Annex(paState.messages());
state->set_context(context); state->swap(paState);
return pa_.Parse(state); } else if (paEnd < pbEnd) {
} messages.Annex(state->messages());
state->swap(backtrack);
} else { } else {
if (!deferred && state->blockedMessages()) { // It's a tie.
state->swap(backtrack2); messages.Annex(paState.messages());
state->messages().swap(messages); #if 0
state->set_context(context); if (paEnd > start) {
return pb_.Parse(state); // Both parsers consumed text; retain messages from both.
messages.Annex(state->messages());
} }
#endif
} }
state->set_alternativeDepth(depth) state->messages().swap(messages);
.set_deferMessages(deferred)
.set_context(context)
.messages().Annex(messages);
return {}; return {};
} }
@ -342,7 +313,7 @@ public:
constexpr RecoveryParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {} constexpr RecoveryParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {}
std::optional<resultType> Parse(ParseState *state) const { std::optional<resultType> Parse(ParseState *state) const {
Messages messages{std::move(state->messages())}; Messages messages{std::move(state->messages())};
MessageContext context{state->context()}; Message::Context context{state->context()};
ParseState backtrack{*state}; ParseState backtrack{*state};
std::optional<resultType> ax{pa_.Parse(state)}; std::optional<resultType> ax{pa_.Parse(state)};
messages.Annex(state->messages()); messages.Annex(state->messages());
@ -351,7 +322,7 @@ public:
return ax; return ax;
} }
state->swap(backtrack); state->swap(backtrack);
state->set_context(context); state->set_context(std::move(context));
std::optional<resultType> bx{pb_.Parse(state)}; std::optional<resultType> bx{pb_.Parse(state)};
state->messages().swap(messages); state->messages().swap(messages);
if (bx.has_value()) { if (bx.has_value()) {

View File

@ -16,10 +16,6 @@ template<typename A> class Indirection {
public: public:
using element_type = A; using element_type = A;
Indirection() = delete; Indirection() = delete;
Indirection(A *&p) : p_{p} {
CHECK(p_ && "assigning null pointer to Indirection");
p = nullptr;
}
Indirection(A *&&p) : p_{p} { Indirection(A *&&p) : p_{p} {
CHECK(p_ && "assigning null pointer to Indirection"); CHECK(p_ && "assigning null pointer to Indirection");
p = nullptr; p = nullptr;

View File

@ -6,9 +6,9 @@
#include "idioms.h" #include "idioms.h"
#include "provenance.h" #include "provenance.h"
#include "reference-counted.h"
#include <cstddef> #include <cstddef>
#include <forward_list> #include <forward_list>
#include <memory>
#include <optional> #include <optional>
#include <ostream> #include <ostream>
#include <string> #include <string>
@ -80,34 +80,31 @@ private:
std::size_t bytes_{1}; std::size_t bytes_{1};
}; };
class Message;
using MessageContext = std::shared_ptr<Message>;
class Message { class Message : public ReferenceCounted<Message> {
public: public:
using Context = CountedReference<Message>;
Message() {} Message() {}
Message(const Message &) = default;
Message(Message &&) = default; Message(Message &&) = default;
Message &operator=(const Message &that) = default;
Message &operator=(Message &&that) = default; Message &operator=(Message &&that) = default;
// TODO: Change these to cover ranges of provenance // TODO: Change these to cover ranges of provenance
Message(Provenance p, MessageFixedText t, MessageContext c = nullptr) Message(Provenance p, MessageFixedText t, Message *c = nullptr)
: provenance_{p}, text_{t}, context_{c}, isFatal_{t.isFatal()} {} : provenance_{p}, text_{t}, context_{c}, isFatal_{t.isFatal()} {}
Message(Provenance p, MessageFormattedText &&s, MessageContext c = nullptr) Message(Provenance p, MessageFormattedText &&s, Message *c = nullptr)
: provenance_{p}, string_{s.MoveString()}, context_{c}, isFatal_{ : provenance_{p}, string_{s.MoveString()}, context_{c},
s.isFatal()} {} isFatal_{s.isFatal()} {}
Message(Provenance p, MessageExpectedText t, MessageContext c = nullptr) Message(Provenance p, MessageExpectedText t, Message *c = nullptr)
: provenance_{p}, text_{t.AsMessageFixedText()}, : provenance_{p}, text_{t.AsMessageFixedText()},
isExpectedText_{true}, context_{c}, isFatal_{true} {} isExpectedText_{true}, context_{c}, isFatal_{true} {}
Message(const char *csl, MessageFixedText t, MessageContext c = nullptr) Message(const char *csl, MessageFixedText t, Message *c = nullptr)
: cookedSourceLocation_{csl}, text_{t}, context_{c}, isFatal_{t.isFatal()} { : cookedSourceLocation_{csl}, text_{t}, context_{c}, isFatal_{t.isFatal()} {}
} Message(const char *csl, MessageFormattedText &&s, Message *c = nullptr)
Message(const char *csl, MessageFormattedText &&s, MessageContext c = nullptr)
: cookedSourceLocation_{csl}, string_{s.MoveString()}, context_{c}, : cookedSourceLocation_{csl}, string_{s.MoveString()}, context_{c},
isFatal_{s.isFatal()} {} isFatal_{s.isFatal()} {}
Message(const char *csl, MessageExpectedText t, MessageContext c = nullptr) Message(const char *csl, MessageExpectedText t, Message *c = nullptr)
: cookedSourceLocation_{csl}, text_{t.AsMessageFixedText()}, : cookedSourceLocation_{csl}, text_{t.AsMessageFixedText()},
isExpectedText_{true}, context_{c}, isFatal_{true} {} isExpectedText_{true}, context_{c}, isFatal_{true} {}
@ -123,20 +120,24 @@ public:
Provenance provenance() const { return provenance_; } Provenance provenance() const { return provenance_; }
const char *cookedSourceLocation() const { return cookedSourceLocation_; } const char *cookedSourceLocation() const { return cookedSourceLocation_; }
MessageContext context() const { return context_; } Context context() const { return context_; }
bool isFatal() const { return isFatal_; } bool isFatal() const { return isFatal_; }
Provenance Emit( Provenance Emit(
std::ostream &, const CookedSource &, bool echoSourceLine = true) const; std::ostream &, const CookedSource &, bool echoSourceLine = true) const;
void TakeReference() { ++refCount_; }
void DropReference() { if (--refCount_ == 0) { delete this; } }
private: private:
Provenance provenance_; Provenance provenance_;
const char *cookedSourceLocation_{nullptr}; const char *cookedSourceLocation_{nullptr};
MessageFixedText text_; MessageFixedText text_;
bool isExpectedText_{false}; // implies "expected '%s'"_err_en_US bool isExpectedText_{false}; // implies "expected '%s'"_err_en_US
std::string string_; std::string string_;
MessageContext context_; Context context_;
bool isFatal_{false}; bool isFatal_{false};
int refCount_{0};
}; };
class Messages { class Messages {

View File

@ -35,10 +35,7 @@ public:
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_}, warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_}, warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_}, anyErrorRecovery_{that.anyErrorRecovery_},
anyConformanceViolation_{that.anyConformanceViolation_}, anyConformanceViolation_{that.anyConformanceViolation_} {}
alternativeDepth_{that.alternativeDepth_},
deferMessages_{that.deferMessages_}, blockedMessages_{
that.blockedMessages_} {}
ParseState(ParseState &&that) ParseState(ParseState &&that)
: p_{that.p_}, limit_{that.limit_}, messages_{std::move(that.messages_)}, : p_{that.p_}, limit_{that.limit_}, messages_{std::move(that.messages_)},
context_{std::move(that.context_)}, userState_{that.userState_}, context_{std::move(that.context_)}, userState_{that.userState_},
@ -47,10 +44,7 @@ public:
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_}, warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_}, warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_}, anyErrorRecovery_{that.anyErrorRecovery_},
anyConformanceViolation_{that.anyConformanceViolation_}, anyConformanceViolation_{that.anyConformanceViolation_} {}
alternativeDepth_{that.alternativeDepth_},
deferMessages_{that.deferMessages_}, blockedMessages_{
that.blockedMessages_} {}
ParseState &operator=(ParseState &&that) { ParseState &operator=(ParseState &&that) {
swap(that); swap(that);
return *this; return *this;
@ -75,11 +69,15 @@ public:
UserState *userState() const { return userState_; } UserState *userState() const { return userState_; }
void set_userState(UserState *u) { userState_ = u; } void set_userState(UserState *u) { userState_ = u; }
MessageContext context() const { return context_; } Message::Context context() const { return context_; }
ParseState &set_context(MessageContext c) { ParseState &set_context(const Message::Context &c) {
context_ = c; context_ = c;
return *this; return *this;
} }
ParseState &set_context(Message::Context &&c) {
context_ = std::move(c);
return *this;
}
bool inFixedForm() const { return inFixedForm_; } bool inFixedForm() const { return inFixedForm_; }
ParseState &set_inFixedForm(bool yes) { ParseState &set_inFixedForm(bool yes) {
@ -111,25 +109,10 @@ public:
return *this; return *this;
} }
int alternativeDepth() const { return alternativeDepth_; }
ParseState &set_alternativeDepth(int d) {
alternativeDepth_ = d;
return *this;
}
bool deferMessages() const { return deferMessages_; }
ParseState &set_deferMessages(bool yes) {
deferMessages_ = yes;
return *this;
}
bool blockedMessages() const { return blockedMessages_; }
const char *GetLocation() const { return p_; } const char *GetLocation() const { return p_; }
MessageContext &PushContext(MessageFixedText text) { void PushContext(MessageFixedText text) {
context_ = std::make_shared<Message>(p_, text, context_); context_ = Message::Context{new Message{p_, text, context_.get()}};
return context_;
} }
void PopContext() { void PopContext() {
@ -143,25 +126,13 @@ public:
void Say(MessageExpectedText &&t) { return Say(p_, std::move(t)); } void Say(MessageExpectedText &&t) { return Say(p_, std::move(t)); }
void Say(const char *at, MessageFixedText t) { void Say(const char *at, MessageFixedText t) {
if (deferMessages_) { messages_.Put(Message{at, t, context_.get()});
blockedMessages_ = true;
} else {
messages_.Put(Message{at, t, context_});
}
} }
void Say(const char *at, MessageFormattedText &&t) { void Say(const char *at, MessageFormattedText &&t) {
if (deferMessages_) { messages_.Put(Message{at, std::move(t), context_.get()});
blockedMessages_ = true;
} else {
messages_.Put(Message{at, std::move(t), context_});
}
} }
void Say(const char *at, MessageExpectedText &&t) { void Say(const char *at, MessageExpectedText &&t) {
if (deferMessages_) { messages_.Put(Message{at, std::move(t), context_.get()});
blockedMessages_ = true;
} else {
messages_.Put(Message{at, std::move(t), context_});
}
} }
bool IsAtEnd() const { return p_ >= limit_; } bool IsAtEnd() const { return p_ >= limit_; }
@ -197,7 +168,7 @@ private:
// Accumulated messages and current nested context. // Accumulated messages and current nested context.
Messages messages_; Messages messages_;
MessageContext context_; Message::Context context_;
UserState *userState_{nullptr}; UserState *userState_{nullptr};
@ -208,9 +179,6 @@ private:
bool warnOnDeprecatedUsage_{false}; bool warnOnDeprecatedUsage_{false};
bool anyErrorRecovery_{false}; bool anyErrorRecovery_{false};
bool anyConformanceViolation_{false}; bool anyConformanceViolation_{false};
int alternativeDepth_{0};
bool deferMessages_{false};
bool blockedMessages_{false};
// NOTE: Any additions or modifications to these data members must also be // NOTE: Any additions or modifications to these data members must also be
// reflected in the copy and move constructors defined at the top of this // reflected in the copy and move constructors defined at the top of this
// class definition! // class definition!

View File

@ -0,0 +1,66 @@
#ifndef FORTRAN_PARSER_REFERENCE_COUNTED_H_
#define FORTRAN_PARSER_REFERENCE_COUNTED_H_
// A template class of smart pointers to objects with their own
// reference counting object lifetimes that's lighter weight
// than std::shared_ptr<>. Not thread-safe.
namespace Fortran {
namespace parser {
template<typename A> class ReferenceCounted {
public:
ReferenceCounted() {}
void TakeReference() { ++references_; }
void DropReference() {
if (--references_ == 0) {
delete static_cast<A*>(this);
}
}
private:
int references_{0};
};
template<typename A> class CountedReference {
public:
using type = A;
CountedReference() {}
CountedReference(type *m) : p_{m} { Take(); }
CountedReference(const CountedReference &c) : p_{c.p_} { Take(); }
CountedReference(CountedReference &&c) : p_{c.p_} { c.p_ = nullptr; }
CountedReference &operator=(const CountedReference &c) {
Drop();
p_ = c.p_;
Take();
return *this;
}
CountedReference &operator=(CountedReference &&c) {
Drop();
p_ = c.p_;
c.p_ = nullptr;
return *this;
}
~CountedReference() { Drop(); }
operator bool() const { return p_ != nullptr; }
type *get() const { return p_; }
type &operator*() const { return *p_; }
type *operator->() const { return p_; }
private:
void Take() {
if (p_) {
p_->TakeReference();
}
}
void Drop() {
if (p_) {
p_->DropReference();
p_ = nullptr;
}
}
type *p_{nullptr};
};
} // namespace parser
} // namespace Fortran
#endif // FORTRAN_PARSER_REFERENCE_COUNTED_H_