// Invoke CLASS_TRAIT(traitName) to define a trait, then put
// using traitName = std::true_type; (or false_type)
// into the appropriate class definitions. You can then use
-// typename std::enable_if<traitName<...>, ...>::type
+// typename std::enable_if_t<traitName<...>, ...>
// in template specialization definitions.
#define CLASS_TRAIT(T) \
namespace class_trait_ns_##T { \
template<typename A> \
constexpr bool has_trait{decltype(test<A>(nullptr))::value}; \
template<typename A> \
- constexpr typename std::enable_if<has_trait<A>, bool>::type \
- trait_value() { \
+ constexpr typename std::enable_if_t<has_trait<A>, bool> trait_value() { \
using U = typename A::T; \
return U::value; \
} \
template<typename A> \
- constexpr typename std::enable_if<!has_trait<A>, bool>::type \
- trait_value() { \
+ constexpr typename std::enable_if_t<!has_trait<A>, bool> trait_value() { \
return false; \
} \
} \
integer.cc
logical.cc
real.cc
- type.cc
)
target_link_libraries(FortranEvaluate
#define FORTRAN_EVALUATE_COMMON_H_
#include "../common/enum-set.h"
+#include "../common/idioms.h"
#include <cinttypes>
namespace Fortran::evaluate {
// Integers are always ordered; reals may not be.
-enum class Ordering { Less, Equal, Greater };
-enum class Relation { Less, Equal, Greater, Unordered };
+ENUM_CLASS(Ordering, Less, Equal, Greater)
+ENUM_CLASS(Relation, Less, Equal, Greater, Unordered)
static constexpr Ordering CompareUnsigned(std::uint64_t x, std::uint64_t y) {
if (x < y) {
}
}
-enum class RealFlag {
- Overflow,
- DivideByZero,
- InvalidArgument,
- Underflow,
- Inexact
-};
+ENUM_CLASS(
+ RealFlag, Overflow, DivideByZero, InvalidArgument, Underflow, Inexact)
using RealFlags = common::EnumSet<RealFlag, 5>;
RealFlags flags;
};
-enum class Rounding { TiesToEven, ToZero, Down, Up, TiesAwayFromZero };
+ENUM_CLASS(Rounding, TiesToEven, ToZero, Down, Up, TiesAwayFromZero)
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
constexpr bool IsHostLittleEndian{false};
#define FORTRAN_EVALUATE_EXPRESSION_H_
// Represent Fortran expressions in a type-safe manner.
-// Expressions are the sole owners of their constituents; there is no
+// Expressions are the sole owners of their constituents; i.e., there is no
// context-independent hash table or sharing of common subexpressions.
-// Both deep copy and move semantics are supported for expression construction.
+// Both deep copy and move semantics are supported for expression construction
+// and manipulation in place.
// TODO: variable and function references
+// TODO: elevate some intrinsics to operations
+// TODO: convenience wrappers for constructing conversions
#include "common.h"
#include "type.h"
struct AnyIntegerOrRealExpr;
// Helper base classes to manage subexpressions, which are known as data members
-// named 'x' and (for binary operations) 'y'.
+// named 'x' and, for binary operations, 'y'.
template<typename A> struct Unary {
Unary(const A &a) : x{std::make_unique<A>(a)} {}
Unary(std::unique_ptr<const A> &&a) : x{std::move(a)} {}
};
// Convenience functions and operator overloadings for expression construction.
+// These definitions are created with temporary helper macros to reduce
+// C++ boilerplate. All combinations of lvalue and rvalue references are
+// allowed for operands.
#define UNARY(FUNC, CONSTR) \
template<typename A> A FUNC(const A &x) { return {typename A::CONSTR{x}}; }
UNARY(Parentheses, Parentheses)
+++ /dev/null
-// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
-//
-// 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.
-
-#include "type.h"
-#include <string>
-
-namespace Fortran::evaluate {
-
-std::string CategoryName(Category c) {
- switch (c) {
- case Category::Integer: return "Integer";
- case Category::Real: return "Real";
- case Category::Complex: return "Complex";
- case Category::Logical: return "Logical";
- case Category::Character: return "Character";
- case Category::Derived: return "Derived";
- }
- return ""; // placate g++
-}
-} // namespace Fortran::evaluate
#include "integer.h"
#include "logical.h"
#include "real.h"
+#include "../common/idioms.h"
#include <string>
#include <variant>
namespace Fortran::evaluate {
-enum class Category { Integer, Real, Complex, Logical, Character, Derived };
-
-std::string CategoryName(Category);
+ENUM_CLASS(Category, Integer, Real, Complex, Logical, Character, Derived)
template<Category C, int KIND> struct TypeBase {
static constexpr Category category{C};
static constexpr int kind{KIND};
static constexpr bool hasLen{false};
static std::string Dump() {
- return CategoryName(category) + '(' + std::to_string(kind) + ')';
+ return EnumToString(category) + '(' + std::to_string(kind) + ')';
}
};
// With a single argument that is a parser with a usable value of
// type A, construct<T>(p) invokes T's explicit constructor T(A &&).
template<class T, typename PA>
-constexpr
- typename std::enable_if<std::is_same_v<Success, typename PA::resultType>,
- Construct01<T, PA>>::type
- construct(const PA &parser) {
+constexpr std::enable_if_t<std::is_same_v<Success, typename PA::resultType>,
+ Construct01<T, PA>>
+construct(const PA &parser) {
return Construct01<T, PA>{parser};
}
template<typename T, typename PA>
-constexpr
- typename std::enable_if<!std::is_same_v<Success, typename PA::resultType>,
- Construct1<T, PA>>::type
- construct(const PA &parser) {
+constexpr std::enable_if_t<!std::is_same_v<Success, typename PA::resultType>,
+ Construct1<T, PA>>
+construct(const PA &parser) {
return Construct1<T, PA>{parser};
}
// Default case for visitation of non-class data members and strings
template<typename A, typename V>
-typename std::enable_if<!std::is_class_v<A> ||
- std::is_same_v<std::string, A>>::type
-Walk(const A &x, V &visitor) {
+std::enable_if_t<!std::is_class_v<A> || std::is_same_v<std::string, A>> Walk(
+ const A &x, V &visitor) {
if (visitor.Pre(x)) {
visitor.Post(x);
}
}
template<typename A, typename M>
-typename std::enable_if<!std::is_class_v<A> ||
- std::is_same_v<std::string, A>>::type
-Walk(A &x, M &mutator) {
+std::enable_if_t<!std::is_class_v<A> || std::is_same_v<std::string, A>> Walk(
+ A &x, M &mutator) {
if (mutator.Pre(x)) {
mutator.Post(x);
}
// Trait-determined traversal of empty, tuple, union, and wrapper classes.
template<typename A, typename V>
-typename std::enable_if<EmptyTrait<A>>::type Walk(const A &x, V &visitor) {
+std::enable_if_t<EmptyTrait<A>> Walk(const A &x, V &visitor) {
if (visitor.Pre(x)) {
visitor.Post(x);
}
}
template<typename A, typename M>
-typename std::enable_if<EmptyTrait<A>>::type Walk(A &x, M &mutator) {
+std::enable_if_t<EmptyTrait<A>> Walk(A &x, M &mutator) {
if (mutator.Pre(x)) {
mutator.Post(x);
}
}
template<typename A, typename V>
-typename std::enable_if<TupleTrait<A>>::type Walk(const A &x, V &visitor) {
+std::enable_if_t<TupleTrait<A>> Walk(const A &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.t, visitor);
visitor.Post(x);
}
}
template<typename A, typename M>
-typename std::enable_if<TupleTrait<A>>::type Walk(A &x, M &mutator) {
+std::enable_if_t<TupleTrait<A>> Walk(A &x, M &mutator) {
if (mutator.Pre(x)) {
Walk(x.t, mutator);
mutator.Post(x);
}
template<typename A, typename V>
-typename std::enable_if<UnionTrait<A>>::type Walk(const A &x, V &visitor) {
+std::enable_if_t<UnionTrait<A>> Walk(const A &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.u, visitor);
visitor.Post(x);
}
}
template<typename A, typename M>
-typename std::enable_if<UnionTrait<A>>::type Walk(A &x, M &mutator) {
+std::enable_if_t<UnionTrait<A>> Walk(A &x, M &mutator) {
if (mutator.Pre(x)) {
Walk(x.u, mutator);
mutator.Post(x);
}
template<typename A, typename V>
-typename std::enable_if<WrapperTrait<A>>::type Walk(const A &x, V &visitor) {
+std::enable_if_t<WrapperTrait<A>> Walk(const A &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.v, visitor);
visitor.Post(x);
}
}
template<typename A, typename M>
-typename std::enable_if<WrapperTrait<A>>::type Walk(A &x, M &mutator) {
+std::enable_if_t<WrapperTrait<A>> Walk(A &x, M &mutator) {
if (mutator.Pre(x)) {
Walk(x.v, mutator);
mutator.Post(x);