2019-02-27 20:12:16 +01:00
|
|
|
// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
2018-05-01 21:50:34 +02:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2018-06-18 20:03:43 +02:00
|
|
|
#ifndef FORTRAN_COMMON_INDIRECTION_H_
|
|
|
|
#define FORTRAN_COMMON_INDIRECTION_H_
|
2018-01-30 20:51:44 +01:00
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
// Define a smart pointer class template that is rather like
|
|
|
|
// non-nullable std::unique_ptr<>. Indirection<> is, like a C++ reference
|
|
|
|
// type, restricted to be non-null when constructed or assigned.
|
|
|
|
// Indirection<> optionally supports copy construction and copy assignment.
|
|
|
|
//
|
|
|
|
// To use Indirection<> with forward-referenced types, add
|
|
|
|
// extern template class Fortran::common::Indirection<FORWARD_TYPE>;
|
|
|
|
// outside any namespace in a header before use, and
|
|
|
|
// template class Fortran::common::Indirection<FORWARD_TYPE>;
|
|
|
|
// in one C++ source file later where a definition of the type is visible.
|
2018-01-30 20:51:44 +01:00
|
|
|
|
2019-04-12 01:12:10 +02:00
|
|
|
#include "idioms.h"
|
2018-09-07 19:33:32 +02:00
|
|
|
#include <memory>
|
2018-07-10 01:23:12 +02:00
|
|
|
#include <type_traits>
|
2018-01-30 20:51:44 +01:00
|
|
|
#include <utility>
|
|
|
|
|
2018-06-18 20:03:43 +02:00
|
|
|
namespace Fortran::common {
|
2018-01-30 20:51:44 +01:00
|
|
|
|
2018-07-10 01:23:12 +02:00
|
|
|
// The default case does not support (deep) copy construction and assignment.
|
|
|
|
template<typename A, bool COPY = false> class Indirection {
|
|
|
|
public:
|
|
|
|
using element_type = A;
|
|
|
|
Indirection() = delete;
|
|
|
|
Indirection(A *&&p) : p_{p} {
|
|
|
|
CHECK(p_ && "assigning null pointer to Indirection");
|
|
|
|
p = nullptr;
|
|
|
|
}
|
|
|
|
Indirection(A &&x) : p_{new A(std::move(x))} {}
|
|
|
|
Indirection(Indirection &&that) : p_{that.p_} {
|
|
|
|
CHECK(p_ && "move construction of Indirection from null Indirection");
|
|
|
|
that.p_ = nullptr;
|
|
|
|
}
|
|
|
|
~Indirection() {
|
|
|
|
delete p_;
|
|
|
|
p_ = nullptr;
|
|
|
|
}
|
|
|
|
Indirection &operator=(Indirection &&that) {
|
|
|
|
CHECK(that.p_ && "move assignment of null Indirection to Indirection");
|
2018-07-11 02:11:12 +02:00
|
|
|
auto tmp{p_};
|
2018-07-10 01:23:12 +02:00
|
|
|
p_ = that.p_;
|
|
|
|
that.p_ = tmp;
|
|
|
|
return *this;
|
|
|
|
}
|
2019-03-04 22:42:00 +01:00
|
|
|
|
|
|
|
A &value() { return *p_; }
|
|
|
|
const A &value() const { return *p_; }
|
2018-07-10 01:23:12 +02:00
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
bool operator==(const A &that) const { return *p_ == that; }
|
2019-01-04 23:05:53 +01:00
|
|
|
bool operator==(const Indirection &that) const { return *p_ == *that.p_; }
|
|
|
|
|
2019-04-09 22:29:40 +02:00
|
|
|
template<typename... ARGS>
|
|
|
|
static common::IfNoLvalue<Indirection, ARGS...> Make(ARGS &&... args) {
|
2019-04-08 21:29:11 +02:00
|
|
|
return {new A(std::move(args)...)};
|
2018-07-10 01:23:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
A *p_{nullptr};
|
|
|
|
};
|
|
|
|
|
|
|
|
// Variant with copy construction and assignment
|
|
|
|
template<typename A> class Indirection<A, true> {
|
2018-02-05 21:54:36 +01:00
|
|
|
public:
|
2018-01-30 20:51:44 +01:00
|
|
|
using element_type = A;
|
2019-03-05 00:15:08 +01:00
|
|
|
|
2018-01-30 20:51:44 +01:00
|
|
|
Indirection() = delete;
|
|
|
|
Indirection(A *&&p) : p_{p} {
|
|
|
|
CHECK(p_ && "assigning null pointer to Indirection");
|
|
|
|
p = nullptr;
|
|
|
|
}
|
2018-06-19 23:16:01 +02:00
|
|
|
Indirection(const A &x) : p_{new A(x)} {}
|
2018-07-07 00:12:33 +02:00
|
|
|
Indirection(A &&x) : p_{new A(std::move(x))} {}
|
|
|
|
Indirection(const Indirection &that) {
|
|
|
|
CHECK(that.p_ && "copy construction of Indirection from null Indirection");
|
|
|
|
p_ = new A(*that.p_);
|
|
|
|
}
|
2018-06-19 23:16:01 +02:00
|
|
|
Indirection(Indirection &&that) : p_{that.p_} {
|
|
|
|
CHECK(p_ && "move construction of Indirection from null Indirection");
|
2018-01-30 20:51:44 +01:00
|
|
|
that.p_ = nullptr;
|
|
|
|
}
|
|
|
|
~Indirection() {
|
|
|
|
delete p_;
|
|
|
|
p_ = nullptr;
|
|
|
|
}
|
2018-07-07 00:12:33 +02:00
|
|
|
Indirection &operator=(const Indirection &that) {
|
|
|
|
CHECK(that.p_ && "copy assignment of Indirection from null Indirection");
|
|
|
|
*p_ = *that.p_;
|
|
|
|
return *this;
|
|
|
|
}
|
2018-01-30 20:51:44 +01:00
|
|
|
Indirection &operator=(Indirection &&that) {
|
2018-06-19 23:16:01 +02:00
|
|
|
CHECK(that.p_ && "move assignment of null Indirection to Indirection");
|
2018-07-11 02:11:12 +02:00
|
|
|
auto tmp{p_};
|
2018-01-30 20:51:44 +01:00
|
|
|
p_ = that.p_;
|
|
|
|
that.p_ = tmp;
|
|
|
|
return *this;
|
|
|
|
}
|
2019-03-04 22:42:00 +01:00
|
|
|
|
|
|
|
A &value() { return *p_; }
|
|
|
|
const A &value() const { return *p_; }
|
2018-02-05 23:29:26 +01:00
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
bool operator==(const A &that) const { return *p_ == that; }
|
2019-01-04 23:05:53 +01:00
|
|
|
bool operator==(const Indirection &that) const { return *p_ == *that.p_; }
|
|
|
|
|
2019-04-09 22:29:40 +02:00
|
|
|
template<typename... ARGS>
|
|
|
|
static common::IfNoLvalue<Indirection, ARGS...> Make(ARGS &&... args) {
|
2019-04-08 21:29:11 +02:00
|
|
|
return {new A(std::move(args)...)};
|
2018-07-07 00:12:33 +02:00
|
|
|
}
|
|
|
|
|
2018-02-05 21:54:36 +01:00
|
|
|
private:
|
2018-01-30 20:51:44 +01:00
|
|
|
A *p_{nullptr};
|
|
|
|
};
|
2018-07-07 00:12:33 +02:00
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
template<typename A> using CopyableIndirection = Indirection<A, true>;
|
2018-09-07 19:33:32 +02:00
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
// For use with std::unique_ptr<> when declaring owning pointers to
|
|
|
|
// forward-referenced types, here's a minimal custom deleter that avoids
|
|
|
|
// some of the drama with std::default_delete<>. Invoke DEFINE_DELETER()
|
|
|
|
// later in exactly one C++ source file where a complete definition of the
|
|
|
|
// type is visible. Be advised, std::unique_ptr<> does not have copy
|
|
|
|
// semantics; if you need ownership, copy semantics, and nullability,
|
|
|
|
// std::optional<CopyableIndirection<>> works.
|
|
|
|
template<typename A> class Deleter {
|
2019-03-05 00:15:08 +01:00
|
|
|
public:
|
2019-03-20 19:38:45 +01:00
|
|
|
void operator()(A *) const;
|
2018-09-07 19:33:32 +02:00
|
|
|
};
|
2019-03-05 00:15:08 +01:00
|
|
|
}
|
2019-03-20 19:38:45 +01:00
|
|
|
#define DEFINE_DELETER(A) \
|
|
|
|
template<> void Fortran::common::Deleter<A>::operator()(A *p) const { \
|
|
|
|
delete p; \
|
2019-03-04 20:23:50 +01:00
|
|
|
}
|
2018-06-18 20:03:43 +02:00
|
|
|
#endif // FORTRAN_COMMON_INDIRECTION_H_
|