#ifndef FORTRAN_IDIOMS_H_ #define FORTRAN_IDIOMS_H_ // Defines anything that might ever be useful in more than one source file // or that is too weird or too specific to the host C++ compiler to be // exposed elsewhere. #ifndef __cplusplus #error this is a C++ program #endif #if __cplusplus < 201703L #error this is a C++17 program #endif #if defined __GNUC__ && __GNUC__ < 7 #error G++ >= 7.0 is required #endif #include #include #include #include #include #include // Avoid a deduction bug in GNU 7.1.0 headers by forcing the answer. // TODO: better resolution namespace std { template struct is_trivially_copy_constructible> : false_type {}; template struct is_trivially_copy_constructible>> : false_type {}; } // namespace std using namespace std::string_literals; // enable "this is a std::string"s namespace Fortran { // Helper templates for combining a list of lambdas into an anonymous // struct for use with std::visit() on a std::variant<> sum type. // E.g.: std::visit(visitors{ // [&](const UnaryExpr &x) { ... }, // [&](const BinaryExpr &x) { ... }, // ... // }, structure.unionMember); template struct visitors : LAMBDAS... { using LAMBDAS::operator()...; }; template visitors(LAMBDAS... x)->visitors; // Calls std::fprintf(stderr, ...), then abort(). [[noreturn]] void die(const char *, ...); // Treat operator! as if it were a Boolean context, i.e. like if() and ? :, // when its operand is std::optional<>. template bool operator!(const std::optional &x) { return !x.has_value(); } } // namespace Fortran // For switch statements without default: labels. #define CRASH_NO_CASE die("no case at " __FILE__ "(%d)", __LINE__) // For cheap assertions that should be applied in production. #define CHECK(x) \ ((x) || (die("CHECK(" #x ") failed at " __FILE__ "(%d)", __LINE__), false)) // To make error messages more informative, wrap some type information // around a false compile-time value, e.g. // static_assert(BadType::value, "no case for type"); template struct BadType : std::false_type {}; // Formatting namespace Fortran { template std::ostream &operator<<(std::ostream &o, const std::optional &x) { if (x.has_value()) { return o << x.value(); } return o << "()"; } template std::ostream &operator<<(std::ostream &o, const std::list &xs) { if (xs.empty()) { return o << "[]"; } char marker{'['}; for (const auto &x : xs) { o << marker << x; marker = ' '; } return o << ']'; } template typename std::enable_if, std::ostream &>::type formatTuple(std::ostream &o, const T &x) { return o << C << std::get(x) << '}'; } template typename std::enable_if, std::ostream &>::type formatTuple(std::ostream &o, const T &x) { return formatTuple(o << C << std::get(x), x); } template std::ostream &operator<<(std::ostream &o, const std::tuple &xs) { return formatTuple<0, '{'>(o, xs); } template std::ostream &operator<<(std::ostream &o, const std::variant &x) { return std::visit( [&o](const auto &y) -> std::ostream & { return o << y; }, x); } } // namespace Fortran #endif // FORTRAN_IDIOMS_H_