/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvxs is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #ifndef UTILPVT_H #define UTILPVT_H #include "osiSockExt.h" #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include # include # include # include #else # include #endif #include #include #include #include #include #include #include #include #include #include #include #ifndef EVUTIL_INVALID_SOCKET # define EVUTIL_INVALID_SOCKET INVALID_SOCKET #endif #ifndef EPICS_ALWAYS_INLINE # if __GNUC__ # define EPICS_ALWAYS_INLINE __inline__ __attribute__((always_inline)) # else # define EPICS_ALWAYS_INLINE inline # endif #endif #include namespace pvxs {namespace impl { template struct promote_print { static T op(const T& v) { return v; }}; template<> struct promote_print { static int op(const char& v) { return v; }}; template<> struct promote_print { static unsigned op(const char& v) { return v; }}; /* specialization of bad_alloc which notes the location from which * the exception originates. */ struct PVXS_API loc_bad_alloc final : public std::bad_alloc { loc_bad_alloc(const char *file, int line); virtual ~loc_bad_alloc(); virtual const char* what() const noexcept override final; private: char msg[64]; }; #define BAD_ALLOC() ::pvxs::impl::loc_bad_alloc(__FILE__, __LINE__) //! in-line string builder (eg. for exception messages) //! eg. @code throw std::runtime_error(SB()<<"Some message"<<42); @endcode struct SB { std::ostringstream strm; SB() {} operator std::string() const { return strm.str(); } std::string str() const { return strm.str(); } template SB& operator<<(const T& i) { strm< struct Range { I a, b; struct iterator { typedef std::forward_iterator_tag iterator_category; typedef I value_type; typedef ptrdiff_t difference_type; typedef I* pointer; typedef I& reference; I val; explicit constexpr iterator(I val) :val(val) {} EPICS_ALWAYS_INLINE I operator*() const { return val; } EPICS_ALWAYS_INLINE iterator& operator++() { val++; return *this; } EPICS_ALWAYS_INLINE iterator operator++(int) { return iterator{val++}; } EPICS_ALWAYS_INLINE bool operator==(const iterator& o) const { return val==o.val; } EPICS_ALWAYS_INLINE bool operator!=(const iterator& o) const { return val!=o.val; } }; EPICS_ALWAYS_INLINE iterator begin() const { return iterator{a}; } EPICS_ALWAYS_INLINE iterator cbegin() const { return begin(); } EPICS_ALWAYS_INLINE iterator end() const { return iterator{b}; } EPICS_ALWAYS_INLINE iterator cend() const { return end(); } }; } // namespace idetail template constexpr idetail::Range range(I end) { return idetail::Range{I(0), end}; } template constexpr idetail::Range range(I begin, I end) { return idetail::Range{begin, end}; } template T parseTo(const std::string& s); // not implemented template<> PVXS_API double parseTo(const std::string& s); template<> PVXS_API uint64_t parseTo(const std::string& s); template<> PVXS_API int64_t parseTo(const std::string& s); #ifdef _WIN32 # define RWLOCK_TYPE SRWLOCK # define RWLOCK_INIT(PLOCK) InitializeSRWLock(PLOCK) # define RWLOCK_DTOR(PLOCK) do{(void)(PLOCK);}while(0) # define RWLOCK_WLOCK(PLOCK) AcquireSRWLockExclusive(PLOCK) # define RWLOCK_WUNLOCK(PLOCK) ReleaseSRWLockExclusive(PLOCK) # define RWLOCK_RLOCK(PLOCK) AcquireSRWLockShared(PLOCK) # define RWLOCK_RUNLOCK(PLOCK) ReleaseSRWLockShared(PLOCK) #else # define RWLOCK_TYPE pthread_rwlock_t # define RWLOCK_INIT(PLOCK) pthread_rwlock_init(PLOCK, nullptr) # define RWLOCK_DTOR(PLOCK) pthread_rwlock_destroy(PLOCK) # define RWLOCK_WLOCK(PLOCK) pthread_rwlock_wrlock(PLOCK) # define RWLOCK_WUNLOCK(PLOCK) pthread_rwlock_unlock(PLOCK) # define RWLOCK_RLOCK(PLOCK) pthread_rwlock_rdlock(PLOCK) # define RWLOCK_RUNLOCK(PLOCK) pthread_rwlock_unlock(PLOCK) #endif class RWLock { RWLOCK_TYPE lock; public: inline RWLock() { RWLOCK_INIT(&lock); } inline ~RWLock() { RWLOCK_DTOR(&lock); } RWLock(const RWLock&) = delete; RWLock(RWLock&&) = delete; RWLock& operator=(const RWLock&) = delete; RWLock& operator=(RWLock&&) = delete; struct UnlockReader { inline void operator()(RWLock *plock) { RWLOCK_RUNLOCK(&plock->lock); } }; inline std::unique_ptr lockReader() { RWLOCK_RLOCK(&lock); return std::unique_ptr{this}; } struct UnlockWriter { inline void operator()(RWLock *plock) { RWLOCK_WUNLOCK(&plock->lock); } }; inline std::unique_ptr lockWriter() { RWLOCK_WLOCK(&lock); return std::unique_ptr{this}; } }; #undef RWLOCK_TYPE #undef RWLOCK_INIT #undef RWLOCK_DTOR #undef RWLOCK_WLOCK #undef RWLOCK_WUNLOCK #undef RWLOCK_RLOCK #undef RWLOCK_RUNLOCK PVXS_API void osdGetRoles(const std::string& account, std::set& roles); void logger_shutdown(); // std::max() isn't constexpr until c++14 :( constexpr size_t cmax(size_t A, size_t B) { return A>B ? A : B; } // gcc 4.9 has aligned_storage but not aligned_union #if GCC_VERSION && GCC_VERSION struct max_sizeof { static const size_t align = 0; static const size_t size = 0; }; template struct max_sizeof { static const size_t align = cmax(alignof(Head), max_sizeof::align); static const size_t size = cmax(sizeof(Head), max_sizeof::size); }; template struct aligned_union { using _info = max_sizeof; typedef typename std::aligned_storage::type type; }; #else template using aligned_union = std::aligned_union; #endif } // namespace impl using namespace impl; inline timeval totv(double t) { timeval ret; ret.tv_sec = t; ret.tv_usec = (t - ret.tv_sec)*1e6; return ret; } //! Scoped restore of std::ostream state (format flags, fill char, and field width) struct Restore { std::ostream& strm; std::ios_base::fmtflags pflags; std::ostream::char_type pfill; std::streamsize pwidth; Restore(std::ostream& strm) :strm(strm) ,pflags(strm.flags()) ,pfill(strm.fill()) ,pwidth(strm.width()) {} ~Restore() { strm.flags(pflags); strm.fill(pfill); strm.width(pwidth); } }; template* Cnt> struct InstCounter { InstCounter() {(*Cnt).fetch_add(1, std::memory_order_relaxed);} ~InstCounter() {(*Cnt).fetch_sub(1, std::memory_order_relaxed);} }; #define INST_COUNTER(KLASS) InstCounter<&cnt_ ## KLASS> instances #define CASE(KLASS) PVXS_API extern std::atomic cnt_ ## KLASS #include "instcounters.h" #undef CASE } // namespace pvxs #endif // UTILPVT_H