[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/olivermaths/cppfront/main/include/cpp2util.h [Back]  [Original]

//  Copyright (c) Herb Sutter
//  SPDX-License-Identifier: CC-BY-NC-ND-4.0

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.


//===========================================================================
//  Cpp2 utilities:
//      Language support implementations
//      #include'd by generated Cpp1 code
//===========================================================================

#ifndef __CPP2_UTIL
#define __CPP2_UTIL

//  If this implementation doesn't support source_location yet, disable it
//  TODO: technically this test should have  included first, but GEFN
#if !defined(_MSC_VER) && !defined(__cpp_lib_source_location)
    #undef CPP2_USE_SOURCE_LOCATION
#endif

//  If the cppfront user requested -pure-cpp2, this will be set
//  and we should be using modules only
#ifdef CPP2_USE_MODULES

    //  If we have real modules, use those the best we can
    //  as implementations are still underway
    #ifdef __cpp_modules

        #ifndef _MSC_VER
            //  This is the ideal -- note that we just voted "import std;"
            //  into draft C++23 in late July 2022, so implementers haven't
            //  had time to catch up yet. As of this writing (September 2022)
            //  no compiler will take this path yet, but they're on the way...
            import std;
        #else // MSVC
            //  Note: When C++23 "import std;" is available, we will switch to that here
            //  In the meantime, this is what works on MSVC which is the only compiler
            //  I've been able to get access to that implements modules enough to demo
            //  (but we'll have more full-C++20 compilers soon!)
            import std.core;
            import std.regex;
            import std.filesystem;
            import std.memory;
            import std.threading;

            //  Suppress spurious MSVC modules warning
            #pragma warning(disable:5050)
        #endif

    //  Otherwise, "fake it till you make it"... include (nearly) all the
    //  standard headers, with a feature test #ifdef for each header that
    //  isn't yet supported by all of { VS 2022, g++-10, clang++-12 }
    //  ... this should approximate "import std;" on those compilers
    #else
        #include 
        #include 
        #ifdef __cpp_lib_coroutine
            #include 
        #endif
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #ifdef __cpp_lib_source_location
            #include 
        #endif
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #ifdef __cpp_lib_memory_resource
            #include 
        #endif
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #if __has_include()
            #include 
        #endif
        #include 
        #include 
        #ifdef __cpp_lib_format
            #include 
        #endif
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #include 
        #ifdef __cpp_lib_spanstream
            #include 
        #endif
        #include 
        #include 
        #ifdef __cpp_lib_syncstream
            #include 
        #endif
        #include 
        #include 
        #include 
        #ifdef __cpp_lib_barrier
            #include 
        #endif
        #include 
        #include 
        #ifdef __cpp_lib_latch
            #include 
        #endif
        #include 
        #ifdef __cpp_lib_semaphore
            #include 
        #endif
        #include 
        #ifdef __cpp_lib_jthread
            #include 
        #endif
        #include 
        #include 

        // libstdc++ currently has a dependency on linking TBB if  is
        // included, and TBB seems to be not automatically installed and linkable
        // on some GCC installations, so let's not pull in that little-used header
        // in our -pure-cpp2 "import std;" simulation mode... if you need this,
        // use mixed mode (not -pure-cpp2) and #include all the headers you need
        // including this one
        // 
        // #include 
    #endif

//  Otherwise, we're not in -pure-cpp2 and so just #include
//  what we need in this header to make this self-contained
#else
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 

    #if defined(CPP2_USE_SOURCE_LOCATION)
        #include 
    #endif
#endif


#define CPP2_TYPEOF(x)  std::remove_cvref_t
#define CPP2_FORWARD(x) std::forward(x)


namespace cpp2 {

//-----------------------------------------------------------------------
//
//  Convenience names for fundamental types
//
//  Note: De jure, some of these are optional per the C and C++ standards
//        De facto, all of these are supported in all implementations I know of
//
//-----------------------------------------------------------------------
//

//  Encouraged by default: Fixed-precision names
using i8        = std::int8_t        ;
using i16       = std::int16_t       ;
using i32       = std::int32_t       ;
using i64       = std::int64_t       ;
using u8        = std::uint8_t       ;
using u16       = std::uint16_t      ;
using u32       = std::uint32_t      ;
using u64       = std::uint64_t      ;

//  Rarely, when really needed for speed optimization: Fastest type with at least N bits
using i8_fast   = std::int_fast8_t   ;
using i16_fast  = std::int_fast16_t  ;
using i32_fast  = std::int_fast32_t  ;
using i64_fast  = std::int_fast64_t  ;
using u8_fast   = std::uint_fast8_t  ;
using u16_fast  = std::uint_fast16_t ;
using u32_fast  = std::uint_fast32_t ;
using u64_fast  = std::uint_fast64_t ;

//  Rarely, when really needed for space optimization: Smallest type with at least N bits
using i8_small  = std::int_least8_t  ;
using i16_small = std::int_least16_t ;
using i32_small = std::int_least32_t ;
using i64_small = std::int_least64_t ;
using u8_small  = std::uint_least8_t ;
using u16_small = std::uint_least16_t;
using u32_small = std::uint_least32_t;
using u64_small = std::uint_least64_t;

//  Discouraged: Variable precision names
//                short
using ushort    = unsigned short;
//                int
using ulong     = unsigned long;
//                long
using longlong  = long long;
using ulonglong = unsigned long long;
using longdouble = long double;

//  Strongly discouraged, for compatibility/interop only
using __schar   = signed char;      // normally use i8 instead
using __uchar   = unsigned char;    // normally use u8 instead


//-----------------------------------------------------------------------
//
//  contract_group
//
//-----------------------------------------------------------------------
//

#ifdef CPP2_USE_SOURCE_LOCATION
    #define CPP2_SOURCE_LOCATION_PARAM              , std::source_location where
    #define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , std::source_location where = std::source_location::current()
    #define CPP2_SOURCE_LOCATION_PARAM_SOLO         std::source_location where
    #define CPP2_SOURCE_LOCATION_ARG                , where
#else
    #define CPP2_SOURCE_LOCATION_PARAM
    #define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
    #define CPP2_SOURCE_LOCATION_PARAM_SOLO
    #define CPP2_SOURCE_LOCATION_ARG
#endif

//  For C++23: make this std::string_view and drop the macro
//      Before C++23 std::string_view was not guaranteed to be trivially copyable,
//      and so in will pass it by const& and really it should be by value
#define CPP2_MESSAGE_PARAM  char const*

class contract_group {
public:
    using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM);

    constexpr contract_group  (handler h = {})  : reporter(h) { }
    constexpr auto set_handler(handler h) -> handler;
    constexpr auto get_handler() const    -> handler { return reporter; }
    constexpr auto expects    (bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
                                          -> void { if (!b) reporter(msg CPP2_SOURCE_LOCATION_ARG); }
private:
    handler reporter;
};

[[noreturn]] inline auto report_and_terminate(std::string_view group, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) noexcept -> void {
    std::cerr
#ifdef CPP2_USE_SOURCE_LOCATION
         std::string {
    return "(customize me - no cpp2::to_string overload exists for this type)";
}

inline auto to_string(std::any const&) -> std::string {
    return "std::any";
}

template
inline auto to_string(T const& t) -> std::string
    requires requires { std::to_string(t); }
{
    return std::to_string(t);
}

inline auto to_string(char const* s) -> std::string
{
    return std::string{s};
}

inline auto to_string(std::string const& s) -> std::string const&
{
    return s;
}

template
inline auto to_string(T const& sv) -> std::string
    requires (std::is_convertible_v 
              && !std::is_convertible_v)
{
    return std::string{sv};
}

template 
inline auto to_string(std::variant const& v) -> std::string;

template < typename T, typename U>
inline auto to_string(std::pair const& p) -> std::string;

template < typename... Ts>
inline auto to_string(std::tuple const& t) -> std::string;

template
inline auto to_string(std::optional const& o) -> std::string {
    if (o.has_value()) {
        return cpp2::to_string(o.value());
    }
    return "(empty)";
}

template 
inline auto to_string(std::variant const& v) -> std::string
{
    if (v.valueless_by_exception()) return "(empty)";
    //  Need to guard this with is_any otherwise the get_if is illegal
    if constexpr (is_any) if (std::get_if(&v) != nullptr) return "(empty)";

    return std::visit([](auto&& arg) -> std::string {
        return cpp2::to_string(arg);
    }, v);
}

template < typename T, typename U>
inline auto to_string(std::pair const& p) -> std::string
{
    return "(" + cpp2::to_string(p.first) + ", " + cpp2::to_string(p.second) + ")";
}

template < typename... Ts>
inline auto to_string(std::tuple const& t) -> std::string
{
    if constexpr (sizeof...(Ts) == 0) {
        return "()";
    } else {
        std::string out = "(" + cpp2::to_string(std::get(t));
        std::apply([&out](auto&&, auto&&... args) {
            ((out += ", " + cpp2::to_string(args)), ...);
        }, t);
        out += ")";
        return out;
    }
}


//-----------------------------------------------------------------------
//
//  Speculative: RAII wrapping for the C standard library
//
//  As part of embracing compatibility while also reducing what we have to
//  teach and learn about C++ (which includes the C standard library), I
//  was curious to see if we can improve use of the C standard library
//  from Cpp2 code... UFCS is a part of that, and then RAII destructors is
//  another that goes hand in hand with that, hence this section...
//  but see caveat note at the end.
//
//-----------------------------------------------------------------------
//
template
class c_raii {
    T t;
    D dtor;
public:
    c_raii( T t_, D d )
        : t{ t_ }
        , dtor{ d }
    { }

    ~c_raii() { dtor(t); }

    operator T&() { return t; }

    c_raii(c_raii const&)         = delete;
    auto operator=(c_raii const&) = delete;
};

inline auto fopen( const char* filename, const char* mode ) {

    //  Suppress annoying deprecation warning about fopen
    #ifdef _MSC_VER
        #pragma warning( push )
        #pragma warning( disable : 4996 )
    #endif

    auto x = std::fopen(filename, mode);

    #ifdef _MSC_VER
        #pragma warning( pop )
    #endif

    if (!x) {
        throw std::make_error_condition(std::errc::no_such_file_or_directory);
    }
    return c_raii( x, &fclose );
}

//  Caveat: There's little else in the C stdlib that allocates a resource...
//
//      malloc          is already wrapped like this via std::unique_ptr, which
//                        typically uses malloc or gets memory from the same pool
//      thrd_create     std::jthread is better
//
//  ... is that it? I don't think it's useful to provide a c_raii just for fopen,
//  but perhaps c_raii may be useful for bringing forward third-party C code too,
//  with cpp2::fopen as a starting example.


}


using cpp2::cpp2_new;


//-----------------------------------------------------------------------
//
//  A partial implementation of GSL features Cpp2 relies on,
//  to keep this a standalone header without non-std dependencies
//
//-----------------------------------------------------------------------
//
namespace gsl {

//-----------------------------------------------------------------------
//
//  An implementation of GSL's narrow_cast
//
//-----------------------------------------------------------------------
//
template
constexpr auto narrow_cast(From&& from) noexcept -> To
{
    return static_cast(std::forward(from));
}

}

#endif

Web Proxy Viewer  |  New URL  |  Original Page