aboutsummaryrefslogblamecommitdiffstats
path: root/util/generic/yexception.h
blob: 3e7958126a416b92816903223d183c317f1c9dcd (plain) (tree)
1
2
3
4
5
6
7
8
9
            
 
                         
                   
                   
                    
                    
                  
 


                                 
                                     
                                 


                    
 

                             













                                                              
                                             





                                                           
                                                             
 
                                        
                                                       
                                                      
         
                                                     
 
                                      
            
                      

                               
                                                                                            
                                                    
                    
                                  

                      
                                                                                    
                                                            
     
                                


                                                        
                                                       

                               
                                       
       
                            


               
                                         
     

                                 


                

                
  
                                         
  
                                           



                                         
                                                                                                     






                                                                                             
  
                                                                                            



                                                                
                                   
                                                                  
                                                            



                                    
                                                                         
                                                                                      
                       
 
                                                      
 
                                  
 
   
                                                                                               

                                                                                               
  
                                                                                                  
                                                                                


                                                  
  
                                                                     









                                                                                         
                                  
 
                                       
 
                                                   



                                                        
                   
                                     
 










                                                                                                                             
                                                                                                                                                            
                                                                                           
                                                                                                                                                                            
                                                                                                              

                
                                                                         







                                                       
                                                                                                                                 


                   
                                                                                                                    








                                                                                                                                    
#pragma once

#include "bt_exception.h"
#include "strbuf.h"
#include "string.h"
#include "utility.h"
#include "va_args.h"
#include <utility>

#include <util/stream/tempbuf.h>
#include <util/system/compat.h>
#include <util/system/compiler.h>
#include <util/system/defaults.h>
#include <util/system/error.h>
#include <util/system/src_location.h>
#include <util/system/platform.h>

#include <exception>

#include <cstdio>

class TBackTrace;

namespace NPrivateException {
    class TTempBufCuttingWrapperOutput: public IOutputStream {
    public:
        TTempBufCuttingWrapperOutput(TTempBuf& tempbuf)
            : TempBuf_(tempbuf)
        {
        }

        void DoWrite(const void* data, size_t len) override {
            TempBuf_.Append(data, Min(len, TempBuf_.Left()));
        }

    private:
        TTempBuf& TempBuf_;
    };

    class yexception: public std::exception {
    public:
        yexception();
        yexception(const yexception&) = default;
        yexception(yexception&&) = default;

        yexception& operator=(const yexception&) = default;
        yexception& operator=(yexception&&) = default;

        const char* what() const noexcept override;
        virtual const TBackTrace* BackTrace() const noexcept;

        template <class T>
        inline void Append(const T& t) {
            TTempBufCuttingWrapperOutput tempBuf(Buf_);
            static_cast<IOutputStream&>(tempBuf) << t;
            ZeroTerminate();
        }

        TStringBuf AsStrBuf() const Y_LIFETIME_BOUND;

    private:
        void ZeroTerminate() noexcept;

    private:
        TTempBuf Buf_;
    };

    template <class E, class T>
    static inline std::enable_if_t<std::is_base_of<yexception, std::decay_t<E>>::value, E&&>
    operator<<(E&& e Y_LIFETIME_BOUND, const T& t) {
        e.Append(t);

        return std::forward<E>(e);
    }

    template <class T>
    static inline T&& operator+(const TSourceLocation& sl, T&& t Y_LIFETIME_BOUND) {
        return std::forward<T>(t << sl << TStringBuf(": "));
    }
} // namespace NPrivateException

class yexception: public NPrivateException::yexception {
};

Y_DECLARE_OUT_SPEC(inline, yexception, stream, value) {
    stream << value.AsStrBuf();
}

class TSystemError: public yexception {
public:
    TSystemError(int status)
        : Status_(status)
    {
        Init();
    }

    TSystemError()
        : TSystemError(LastSystemError())
    {
    }

    int Status() const noexcept {
        return Status_;
    }

private:
    void Init();

private:
    int Status_;
};

class TIoException: public TSystemError {
};

class TIoSystemError: public TIoException {
};

class TFileError: public TIoSystemError {
};

/**
 * TBadArgumentException should be thrown when an argument supplied to some function (or constructor)
 * is invalid or incorrect.
 *
 * \note
 * A special case when such argument is given to a function which performs type casting
 * (e.g. integer from string) is covered by the TBadCastException class which is derived from
 * TBadArgumentException.
 */
struct TBadArgumentException: public virtual yexception {
};

/**
 * TBadCastException should be thrown to indicate the failure of some type casting procedure
 * (e.g. reading an integer parameter from string).
 */
struct TBadCastException: public virtual TBadArgumentException {
};

#define ythrow throw __LOCATION__ +

namespace NPrivate {
    /// Encapsulates data for one of the most common case in which
    /// exception message consists of single constant string
    struct TSimpleExceptionMessage {
        TSourceLocation Location;
        TStringBuf Message;
    };

    [[noreturn]] void ThrowYException(const TSimpleExceptionMessage& sm);
    [[noreturn]] void ThrowYExceptionWithBacktrace(const TSimpleExceptionMessage& sm);
} // namespace NPrivate

void fputs(const std::exception& e, FILE* f = stderr);

TString CurrentExceptionMessage();

/**
 * Formats current exception for logging purposes. Includes formatted backtrace if it is stored
 * alongside the exception.
 * The output format is a subject to change, do not depend or canonize it.
 * The speed of this method is not guaranteed either. Do not call it in hot paths of your code.
 *
 * The lack of current exception prior to the invocation indicates logical bug in the client code.
 * Y_ABORT_UNLESS asserts the existence of exception, otherwise panic and abort.
 */
TString FormatCurrentException();
void FormatCurrentExceptionTo(IOutputStream& out);

/*
 * A neat method that detects whether stack unwinding is in progress.
 * As its std counterpart (that is std::uncaught_exception())
 * was removed from the standard, this method uses std::uncaught_exceptions() internally.
 *
 * If you are struggling to use this method, please, consider reading
 *
 * http://www.gotw.ca/gotw/047.htm
 * and
 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4152.pdf
 *
 * DO NOT USE THIS METHOD IN DESTRUCTORS.
 */
bool UncaughtException() noexcept;

std::string CurrentExceptionTypeName();

TString FormatExc(const std::exception& exception);

#define Y_THROW_UNLESS_EX(CONDITION, THROW_EXPRESSION) \
    do {                                               \
        if (Y_UNLIKELY(!(CONDITION))) {                \
            ythrow THROW_EXPRESSION;                   \
        }                                              \
    } while (false)
#define Y_ENSURE_EX Y_THROW_UNLESS_EX

/// @def Y_ENSURE_SIMPLE
/// This macro works like the Y_ENSURE, but requires the second argument to be a constant string view.
/// Should not be used directly.
#define Y_ENSURE_SIMPLE(CONDITION, MESSAGE, THROW_FUNCTION)                                                                 \
    do {                                                                                                                    \
        if (Y_UNLIKELY(!(CONDITION))) {                                                                                     \
            /* use variable to guarantee evaluation at compile time */                                                      \
            static constexpr const ::NPrivate::TSimpleExceptionMessage __SIMPLE_EXCEPTION_MESSAGE{__LOCATION__, (MESSAGE)}; \
            THROW_FUNCTION(__SIMPLE_EXCEPTION_MESSAGE);                                                                     \
        }                                                                                                                   \
    } while (false)

#define Y_ENSURE_IMPL_1(CONDITION) Y_ENSURE_SIMPLE(CONDITION, ::TStringBuf("Condition violated: `" Y_STRINGIZE(CONDITION) "'"), ::NPrivate::ThrowYException)
#define Y_ENSURE_IMPL_2(CONDITION, MESSAGE) Y_ENSURE_EX(CONDITION, yexception() << MESSAGE)

#define Y_ENSURE_BT_IMPL_1(CONDITION) Y_ENSURE_SIMPLE(CONDITION, ::TStringBuf("Condition violated: `" Y_STRINGIZE(CONDITION) "'"), ::NPrivate::ThrowYExceptionWithBacktrace)
#define Y_ENSURE_BT_IMPL_2(CONDITION, MESSAGE) Y_ENSURE_EX(CONDITION, TWithBackTrace<yexception>() << MESSAGE)

/**
 * @def Y_ENSURE
 *
 * This macro is intended to be used as a shortcut for `if () { throw }`.
 *
 * @code
 * void DoSomethingLovely(const int x, const int y) {
 *     Y_ENSURE(x > y, "`x` must be greater than `y`");
 *     Y_ENSURE(x > y); // if you are too lazy
 *     // actually doing something nice here
 * }
 * @endcode
 */
#define Y_THROW_UNLESS(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, Y_ENSURE_IMPL_2, Y_ENSURE_IMPL_1)(__VA_ARGS__))
#define Y_ENSURE Y_THROW_UNLESS

/**
 * @def Y_ENSURE_BT
 *
 * This macro is intended to be used as a shortcut for `if () { throw TWithBackTrace<yexception>() << "message"; }`.
 *
 * @code
 * void DoSomethingLovely(const int x, const int y) {
 *     Y_ENSURE_BT(x > y, "`x` must be greater than `y`");
 *     Y_ENSURE_BT(x > y); // if you are too lazy
 *     // actually doing something nice here
 * }
 * @endcode
 */
#define Y_ENSURE_BT(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, Y_ENSURE_BT_IMPL_2, Y_ENSURE_BT_IMPL_1)(__VA_ARGS__))