counting, null by default, shallowly copyable, reassignable, and slow.
* `OwningPointer<>`: A nullable pointer with ownership, better suited
for use with forward-defined types than `std::unique_ptr<>` is.
-Null by default, not copyable, reassignable.
-Does not have means for allocating data, and inconveniently requires
+Null by default, optionally copyable, reassignable.
+Does not have direct means for allocating data, and inconveniently requires
the definition of an external destructor.
* `Indirection<>`: A non-nullable pointer with ownership and
optional deep copy semantics; reassignable.
| `&r` | no | n/a | no | no | shallowly | yes |
| `unique_ptr<>` | yes | yes | yes | yes | no | no |
| `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
-| `OwningPointer<>` | yes | yes | yes | yes | no | yes |
+| `OwningPointer<>` | yes | yes | yes | yes | optionally deeply | yes |
| `Indirection<>` | no | n/a | yes | yes | optionally deeply | no |
| `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
// A variant of Indirection suitable for use with forward-referenced types.
// These are nullable pointers, not references. Allocation is not available,
-// and a single externalized destructor must be defined.
+// and a single externalized destructor must be defined. Copyable if an
+// external copy constructor and operator= are implemented.
template<typename A> class OwningPointer {
public:
using element_type = A;
OwningPointer(OwningPointer &&that) : p_{that.release()} {}
explicit OwningPointer(std::unique_ptr<A> &&that) : p_{that.release()} {}
explicit OwningPointer(A *&&p) : p_{p} { p = nullptr; }
- ~OwningPointer();
OwningPointer &operator=(OwningPointer &&that) {
reset(that.release());
return *this;
}
+ // Must be externally defined; see the macro below.
+ ~OwningPointer();
+
+ // Must be externally defined if copying is needed.
+ OwningPointer(const A &);
+ OwningPointer(const OwningPointer &);
+ OwningPointer &operator=(const A &);
+ OwningPointer &operator=(const OwningPointer &);
+
A &operator*() { return *p_; }
const A &operator*() const { return *p_; }
A *operator->() { return p_; }
private:
A *p_{nullptr};
};
+
+// Mandatory instantiation and definition -- put somewhere, not in a namespace
+#define DEFINE_OWNING_POINTER_DESTRUCTOR(A) \
+ namespace Fortran::common { \
+ template class OwningPointer<A>; \
+ template<> OwningPointer<A>::~OwningPointer() { \
+ delete p_; \
+ p_ = nullptr; \
+ } \
+ }
+
+// Optional definitions
+#define DEFINE_OWNING_POINTER_COPY_CONSTRUCTORS(A) \
+ namespace Fortran::common { \
+ template<> \
+ OwningPointer<A>::OwningPointer(const A &that) : p_{new A(that)} {} \
+ template<> \
+ OwningPointer<A>::OwningPointer(const OwningPointer<A> &that) \
+ : p_{that.p_ ? new A(*that.p_) : nullptr} {} \
+ }
+#define DEFINE_OWNING_POINTER_COPY_ASSIGNMENTS(A) \
+ namespace Fortran::common { \
+ template<> OwningPointer<A> &OwningPointer<A>::operator=(const A &that) { \
+ delete p_; \
+ p_ = new A(that); \
+ return *this; \
+ } \
+ template<> \
+ OwningPointer<A> &OwningPointer<A>::operator=( \
+ const OwningPointer<A> &that) { \
+ delete p_; \
+ p_ = that.p_ ? new A(*that.p_) : nullptr; \
+ return *this; \
+ } \
+ }
}
#endif // FORTRAN_COMMON_INDIRECTION_H_
}
}
-namespace Fortran::common {
-template class OwningPointer<evaluate::characteristics::Procedure>;
-template<>
-OwningPointer<evaluate::characteristics::Procedure>::~OwningPointer() {
- delete p_;
- p_ = nullptr;
-}
-}
+// Define OwningPointer special member functions
+DEFINE_OWNING_POINTER_DESTRUCTOR(evaluate::characteristics::Procedure)
+DEFINE_OWNING_POINTER_COPY_CONSTRUCTORS(evaluate::characteristics::Procedure)
+DEFINE_OWNING_POINTER_COPY_ASSIGNMENTS(evaluate::characteristics::Procedure)
#ifndef FORTRAN_EVALUATE_CHARACTERISTICS_H_
#define FORTRAN_EVALUATE_CHARACTERISTICS_H_
+#include "common.h"
#include "expression.h"
#include "type.h"
#include "../common/Fortran.h"
struct DummyDataObject {
ENUM_CLASS(Attr, AssumedRank, Optional, Allocatable, Asynchronous, Contiguous,
Value, Volatile, Polymorphic, Pointer, Target)
+ DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyDataObject)
DynamicType type;
std::vector<std::optional<Expr<SubscriptInteger>>> shape;
std::vector<Expr<SubscriptInteger>> coshape;
// 15.3.2.3
struct DummyProcedure {
ENUM_CLASS(Attr, Pointer, Optional)
+ DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyProcedure)
common::OwningPointer<Procedure> explicitProcedure;
common::EnumSet<Attr, 32> attrs;
bool operator==(const DummyProcedure &) const;
struct FunctionResult {
ENUM_CLASS(
Attr, Polymorphic, Allocatable, Pointer, Contiguous, ProcedurePointer)
+ DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(FunctionResult)
DynamicType type;
int rank{0};
common::EnumSet<Attr, 32> attrs;
// 15.3.1
struct Procedure {
ENUM_CLASS(Attr, Pure, Elemental, Bind_C)
+ Procedure() {}
+ DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Procedure)
std::optional<FunctionResult> functionResult; // absent means subroutine
std::vector<DummyArgument> dummyArguments;
common::EnumSet<Attr, 32> attrs;
// 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.
-namespace Fortran::common {
-template class OwningPointer<evaluate::GenericExprWrapper>;
-template<> OwningPointer<evaluate::GenericExprWrapper>::~OwningPointer() {
- delete p_;
- p_ = nullptr;
-}
-}
+DEFINE_OWNING_POINTER_DESTRUCTOR(evaluate::GenericExprWrapper)