forked from OSchip/llvm-project
[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:
parent
f595462ea8
commit
84ebba9e53
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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!
|
||||||
|
|
|
@ -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_
|
Loading…
Reference in New Issue