forked from OSchip/llvm-project
[flang] Add ForwardReference<> + documentation + clean-up
Original-commit: flang-compiler/f18@09e9501951 Reviewed-on: https://github.com/flang-compiler/f18/pull/314
This commit is contained in:
parent
752721d3a8
commit
c7cfc3f357
|
@ -199,12 +199,13 @@ for use with forward-defined types than `std::unique_ptr<>` is.
|
|||
Null by default, optionally copyable, reassignable.
|
||||
Does not have direct means for allocating data, and inconveniently requires
|
||||
the definition of an external destructor.
|
||||
* `OwningReference<>`: A non-nullable `OwningPointer<>`.
|
||||
* `Indirection<>`: A non-nullable pointer with ownership and
|
||||
optional deep copy semantics; reassignable.
|
||||
Often better than a reference (due to ownership) or `std::unique_ptr<>`
|
||||
(due to non-nullability and copyability).
|
||||
Can be wrapped in `std::optional<>` when nullability is required.
|
||||
* `ForwardReference<>`: A non-nullable `OwningPointer<>`, or a variant of
|
||||
`Indirection<>` that works with forward-declared content types; it's both.
|
||||
* `CountedReference<>`: A nullable pointer with shared ownership via
|
||||
reference counting, null by default, shallowly copyable, reassignable.
|
||||
Safe to use *only* when the data are private to just one
|
||||
|
@ -221,8 +222,8 @@ A feature matrix:
|
|||
| `unique_ptr<>` | yes | yes | yes | yes | no | no |
|
||||
| `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
|
||||
| `OwningPointer<>` | yes | yes | yes | yes | optionally deeply | yes |
|
||||
| `OwningReference<>` | no | yes | yes | yes | optionally deeply | yes |
|
||||
| `Indirection<>` | no | n/a | yes | yes | optionally deeply | no |
|
||||
| `ForwardReference<>` | no | n/a | yes | yes | optionally deeply | yes |
|
||||
| `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
|
||||
|
||||
### Overall design preferences
|
||||
|
|
|
@ -15,11 +15,20 @@
|
|||
#ifndef FORTRAN_COMMON_INDIRECTION_H_
|
||||
#define FORTRAN_COMMON_INDIRECTION_H_
|
||||
|
||||
// Defines a smart pointer class template that's rather like std::unique_ptr<>
|
||||
// but further restricted, like a C++ reference, to be non-null when constructed
|
||||
// or assigned. Users need not check whether these pointers are null.
|
||||
// Supports copy construction, too.
|
||||
// Intended to be as invisible as a reference, wherever possible.
|
||||
// Defines several smart pointer class templates that are rather like
|
||||
// std::unique_ptr<>.
|
||||
// - Indirection<> is, like a C++ reference type, restricted to be non-null
|
||||
// when constructed or assigned.
|
||||
// - OwningPointer<> is like a std::unique_ptr<> with an out-of-line destructor.
|
||||
// This makes it suitable for use with forward-declared content types
|
||||
// in a way that bare C pointers allow but std::unique_ptr<> cannot.
|
||||
// - ForwardReference<> is a kind of Indirection<> that, like OwningPointer<>,
|
||||
// accommodates the use of forward declarations.
|
||||
// Users of Indirection<> and ForwardReference<> need to check whether their
|
||||
// pointers are null. Like a C++ reference, they are meant to be as invisible
|
||||
// as possible.
|
||||
// All of these can optionally support copy construction
|
||||
// and copy assignment.
|
||||
|
||||
#include "../common/idioms.h"
|
||||
#include <memory>
|
||||
|
@ -61,6 +70,7 @@ public:
|
|||
A *operator->() { return p_; }
|
||||
const A *operator->() const { return p_; }
|
||||
|
||||
bool operator==(const A &x) const { return *p_ == x; }
|
||||
bool operator==(const Indirection &that) const { return *p_ == *that.p_; }
|
||||
|
||||
template<typename... ARGS> static Indirection Make(ARGS &&... args) {
|
||||
|
@ -75,6 +85,7 @@ private:
|
|||
template<typename A> class Indirection<A, true> {
|
||||
public:
|
||||
using element_type = A;
|
||||
|
||||
Indirection() = delete;
|
||||
Indirection(A *&&p) : p_{p} {
|
||||
CHECK(p_ && "assigning null pointer to Indirection");
|
||||
|
@ -114,6 +125,7 @@ public:
|
|||
A *operator->() { return p_; }
|
||||
const A *operator->() const { return p_; }
|
||||
|
||||
bool operator==(const A &x) const { return *p_ == x; }
|
||||
bool operator==(const Indirection &that) const { return *p_ == *that.p_; }
|
||||
|
||||
template<typename... ARGS> static Indirection Make(ARGS &&... args) {
|
||||
|
@ -133,15 +145,11 @@ public:
|
|||
using element_type = A;
|
||||
|
||||
OwningPointer() {}
|
||||
OwningPointer(OwningPointer &&that) : p_{that.release()} {}
|
||||
OwningPointer(OwningPointer &&that) : p_{that.p_} { that.p_ = nullptr; }
|
||||
explicit OwningPointer(std::unique_ptr<A> &&that) : p_{that.release()} {}
|
||||
explicit OwningPointer(A *&&p) : p_{p} { p = nullptr; }
|
||||
OwningPointer &operator=(OwningPointer &&that) {
|
||||
reset(that.release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Must be externally defined; see the macro below.
|
||||
// Must be externally defined; see DEFINE_OWNING_DESTRUCTOR below
|
||||
~OwningPointer();
|
||||
|
||||
// Must be externally defined if copying is needed.
|
||||
|
@ -150,6 +158,16 @@ public:
|
|||
OwningPointer &operator=(const A &);
|
||||
OwningPointer &operator=(const OwningPointer &);
|
||||
|
||||
OwningPointer &operator=(OwningPointer &&that) {
|
||||
auto tmp{p_};
|
||||
p_ = that.p_;
|
||||
that.p_ = tmp;
|
||||
return *this;
|
||||
}
|
||||
OwningPointer &operator=(A *&&p) {
|
||||
return *this = OwningPointer(std::move(p));
|
||||
}
|
||||
|
||||
A &operator*() { return *p_; }
|
||||
const A &operator*() const { return *p_; }
|
||||
A *operator->() { return p_; }
|
||||
|
@ -157,20 +175,7 @@ public:
|
|||
|
||||
A *get() const { return p_; }
|
||||
|
||||
A *release() {
|
||||
A *result{p_};
|
||||
p_ = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
void reset(A *p) {
|
||||
this->~OwningPointer();
|
||||
p_ = p;
|
||||
}
|
||||
|
||||
bool operator==(const A &x) const {
|
||||
return p_ != nullptr && (p_ == &x || *p_ == x);
|
||||
}
|
||||
bool operator==(const A &x) const { return p_ != nullptr && *p_ == x; }
|
||||
bool operator==(const OwningPointer &that) const {
|
||||
return (p_ == nullptr && that.p_ == nullptr) ||
|
||||
(that.p_ != nullptr && *this == *that.p_);
|
||||
|
@ -180,46 +185,101 @@ private:
|
|||
A *p_{nullptr};
|
||||
};
|
||||
|
||||
// ForwardReference can be viewed as either a non-nullable variant of
|
||||
// OwningPointer or as a variant of Indirection that accommodates use with
|
||||
// a forward-declared content type.
|
||||
template<typename A> class ForwardReference {
|
||||
public:
|
||||
using element_type = A;
|
||||
|
||||
explicit ForwardReference(std::unique_ptr<A> &&that) : p_{that.release()} {}
|
||||
explicit ForwardReference(A *&&p) : p_{p} {
|
||||
CHECK(p_ && "assigning null pointer to ForwardReference");
|
||||
p = nullptr;
|
||||
}
|
||||
ForwardReference(ForwardReference<A> &&that) : p_{that.p_} {
|
||||
CHECK(p_ &&
|
||||
"move construction of ForwardReference from null ForwardReference");
|
||||
that.p_ = nullptr;
|
||||
}
|
||||
|
||||
// Must be externally defined; see DEFINE_OWNING_DESTRUCTOR below
|
||||
~ForwardReference();
|
||||
|
||||
// Must be externally defined if copying is needed.
|
||||
ForwardReference(const A &);
|
||||
ForwardReference(const ForwardReference &);
|
||||
ForwardReference &operator=(const A &);
|
||||
ForwardReference &operator=(const ForwardReference &);
|
||||
|
||||
ForwardReference &operator=(ForwardReference &&that) {
|
||||
CHECK(that.p_ &&
|
||||
"move assignment of null ForwardReference to ForwardReference");
|
||||
auto tmp{p_};
|
||||
p_ = that.p_;
|
||||
that.p_ = tmp;
|
||||
return *this;
|
||||
}
|
||||
ForwardReference &operator=(A *&&p) {
|
||||
return *this = ForwardReference(std::move(p));
|
||||
}
|
||||
|
||||
A &operator*() { return *p_; }
|
||||
const A &operator*() const { return *p_; }
|
||||
A *operator->() { return p_; }
|
||||
const A *operator->() const { return p_; }
|
||||
|
||||
A &value() { return *p_; }
|
||||
const A &value() const { return *p_; }
|
||||
|
||||
bool operator==(const A &x) const { return *p_ == x; }
|
||||
bool operator==(const ForwardReference &that) const {
|
||||
return *p_ == *that.p_;
|
||||
}
|
||||
|
||||
private:
|
||||
A *p_{nullptr};
|
||||
};
|
||||
}
|
||||
|
||||
// Mandatory instantiation and definition -- put somewhere, not in a namespace
|
||||
#define DEFINE_OWNING_POINTER_DESTRUCTOR(A) \
|
||||
// CLASS here is OwningPointer or ForwardReference.
|
||||
#define DEFINE_OWNING_DESTRUCTOR(CLASS, A) \
|
||||
namespace Fortran::common { \
|
||||
template class OwningPointer<A>; \
|
||||
template<> OwningPointer<A>::~OwningPointer() { \
|
||||
template class CLASS<A>; \
|
||||
template<> CLASS<A>::~CLASS() { \
|
||||
delete p_; \
|
||||
p_ = nullptr; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional definitions
|
||||
#define DEFINE_OWNING_POINTER_COPY_CONSTRUCTORS(A) \
|
||||
// Optional definitions for OwningPointer and ForwardReference
|
||||
#define DEFINE_OWNING_COPY_CONSTRUCTORS(CLASS, A) \
|
||||
namespace Fortran::common { \
|
||||
template<> CLASS<A>::CLASS(const A &that) : p_{new A(that)} {} \
|
||||
template<> \
|
||||
OwningPointer<A>::OwningPointer(const A &that) : p_{new A(that)} {} \
|
||||
template<> \
|
||||
OwningPointer<A>::OwningPointer(const OwningPointer<A> &that) \
|
||||
CLASS<A>::CLASS(const CLASS<A> &that) \
|
||||
: p_{that.p_ ? new A(*that.p_) : nullptr} {} \
|
||||
}
|
||||
#define DEFINE_OWNING_POINTER_COPY_ASSIGNMENTS(A) \
|
||||
#define DEFINE_OWNING_COPY_ASSIGNMENTS(CLASS, A) \
|
||||
namespace Fortran::common { \
|
||||
template<> OwningPointer<A> &OwningPointer<A>::operator=(const A &that) { \
|
||||
template<> CLASS<A> &CLASS<A>::operator=(const A &that) { \
|
||||
delete p_; \
|
||||
p_ = new A(that); \
|
||||
return *this; \
|
||||
} \
|
||||
template<> \
|
||||
OwningPointer<A> &OwningPointer<A>::operator=( \
|
||||
const OwningPointer<A> &that) { \
|
||||
template<> CLASS<A> &CLASS<A>::operator=(const CLASS<A> &that) { \
|
||||
delete p_; \
|
||||
p_ = that.p_ ? new A(*that.p_) : nullptr; \
|
||||
return *this; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_OWNING_POINTER_COPY_FUNCTIONS(A) \
|
||||
DEFINE_OWNING_POINTER_COPY_CONSTRUCTORS(A) \
|
||||
DEFINE_OWNING_POINTER_COPY_ASSIGNMENTS(A)
|
||||
#define DEFINE_OWNING_POINTER_SPECIAL_FUNCTIONS(A) \
|
||||
DEFINE_OWNING_POINTER_DESTRUCTOR(A) \
|
||||
DEFINE_OWNING_POINTER_COPY_FUNCTIONS(A)
|
||||
}
|
||||
#define DEFINE_OWNING_COPY_FUNCTIONS(CLASS, A) \
|
||||
DEFINE_OWNING_COPY_CONSTRUCTORS(CLASS, A) \
|
||||
DEFINE_OWNING_COPY_ASSIGNMENTS(CLASS, A)
|
||||
#define DEFINE_OWNING_SPECIAL_FUNCTIONS(CLASS, A) \
|
||||
DEFINE_OWNING_DESTRUCTOR(CLASS, A) \
|
||||
DEFINE_OWNING_COPY_FUNCTIONS(CLASS, A)
|
||||
|
||||
#endif // FORTRAN_COMMON_INDIRECTION_H_
|
||||
|
|
|
@ -101,4 +101,5 @@ std::ostream &Procedure::Dump(std::ostream &o) const {
|
|||
}
|
||||
|
||||
// Define OwningPointer special member functions
|
||||
DEFINE_OWNING_POINTER_SPECIAL_FUNCTIONS(evaluate::characteristics::Procedure)
|
||||
DEFINE_OWNING_SPECIAL_FUNCTIONS(
|
||||
OwningPointer, evaluate::characteristics::Procedure)
|
||||
|
|
|
@ -321,4 +321,4 @@ FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor)
|
|||
// been embedded in the parse tree. This destructor appears here, where
|
||||
// definitions for all the necessary types are available, to obviate a
|
||||
// need to include lib/evaluate/*.h headers in the parser proper.
|
||||
DEFINE_OWNING_POINTER_SPECIAL_FUNCTIONS(evaluate::GenericExprWrapper)
|
||||
DEFINE_OWNING_SPECIAL_FUNCTIONS(OwningPointer, evaluate::GenericExprWrapper)
|
||||
|
|
|
@ -2032,8 +2032,7 @@ public:
|
|||
#if PMKDEBUG
|
||||
// checked->AsFortran(std::cout << "checked expression: ") << '\n';
|
||||
#endif
|
||||
expr.typedExpr.reset(
|
||||
new evaluate::GenericExprWrapper{std::move(*checked)});
|
||||
expr.typedExpr = new evaluate::GenericExprWrapper{std::move(*checked)};
|
||||
} else {
|
||||
#if PMKDEBUG
|
||||
std::cout << "TODO: expression analysis failed for this expression: ";
|
||||
|
|
Loading…
Reference in New Issue