/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CLEANUP_H
#define _LINUX_CLEANUP_H

#include <linux/compiler.h>
#include <linux/err.h>
#include <linux/args.h>





#define DEFINE_FREE(_name, _type, _free) \
	static __always_inline void __free_##_name(void *p) { _type _T = *(_type *)p; _free; }

#define __free(_name)	__cleanup(__free_##_name)

#define __get_and_null(p, nullvalue)	    \
	({                                  \
		auto __ptr = &(p);	    \
		auto __val = *__ptr;	    \
		*__ptr = nullvalue;         \
		__val;                      \
	})

static __always_inline __must_check
const volatile void * __must_check_fn(const volatile void *val)
{ return val; }

#define no_free_ptr(p) \
	((typeof(p)) __must_check_fn((__force const volatile void *)__get_and_null(p, NULL)))

#define return_ptr(p)	return no_free_ptr(p)


#define retain_and_null_ptr(p)		((void)__get_and_null(p, NULL))



#define DEFINE_CLASS(_name, _type, _exit, _init, _init_args...)		\
typedef _type class_##_name##_t;					\
typedef _type lock_##_name##_t;						\
static __always_inline void class_##_name##_destructor(_type *p)	\
	__no_context_analysis						\
{ _type _T = *p; _exit; }						\
static __always_inline _type class_##_name##_constructor(_init_args)	\
	__no_context_analysis						\
{ _type t = _init; return t; }

#define EXTEND_CLASS(_name, ext, _init, _init_args...)			\
typedef lock_##_name##_t lock_##_name##ext##_t;			\
typedef class_##_name##_t class_##_name##ext##_t;			\
static __always_inline void class_##_name##ext##_destructor(class_##_name##_t *p) \
{ class_##_name##_destructor(p); }					\
static __always_inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
	__no_context_analysis \
{ class_##_name##_t t = _init; return t; }

#define CLASS(_name, var)						\
	class_##_name##_t var __cleanup(class_##_name##_destructor) =	\
		class_##_name##_constructor

#define CLASS_INIT(_name, _var, _init_expr)                             \
        class_##_name##_t _var __cleanup(class_##_name##_destructor) = (_init_expr)

#define __scoped_class(_name, var, _label, args...)        \
	for (CLASS(_name, var)(args); ; ({ goto _label; })) \
		if (0) {                                   \
_label:                                                    \
			break;                             \
		} else

#define scoped_class(_name, var, args...) \
	__scoped_class(_name, var, __UNIQUE_ID(label), args)



#define __DEFINE_CLASS_IS_CONDITIONAL(_name, _is_cond)	\
static __maybe_unused const bool class_##_name##_is_conditional = _is_cond

#define DEFINE_CLASS_IS_UNCONDITIONAL(_name)		\
	__DEFINE_CLASS_IS_CONDITIONAL(_name, false);	\
	static inline void * class_##_name##_lock_ptr(class_##_name##_t *_T) \
	{ return (void *)1; }

#define __GUARD_IS_ERR(_ptr)                                       \
	({                                                         \
		unsigned long _rc = (__force unsigned long)(_ptr); \
		unlikely((_rc - 1) >= -MAX_ERRNO - 1);             \
	})

#define __DEFINE_GUARD_LOCK_PTR(_name, _exp)                                \
	static __always_inline void *class_##_name##_lock_ptr(class_##_name##_t *_T) \
	{                                                                   \
		void *_ptr = (void *)(__force unsigned long)*(_exp);        \
		if (IS_ERR(_ptr)) {                                         \
			_ptr = NULL;                                        \
		}                                                           \
		return _ptr;                                                \
	}                                                                   \
	static __always_inline int class_##_name##_lock_err(class_##_name##_t *_T) \
	{                                                                   \
		long _rc = (__force unsigned long)*(_exp);                  \
		if (!_rc) {                                                 \
			_rc = -EBUSY;                                       \
		}                                                           \
		if (!IS_ERR_VALUE(_rc)) {                                   \
			_rc = 0;                                            \
		}                                                           \
		return _rc;                                                 \
	}

#define DEFINE_CLASS_IS_GUARD(_name) \
	__DEFINE_CLASS_IS_CONDITIONAL(_name, false); \
	__DEFINE_GUARD_LOCK_PTR(_name, _T)

#define DEFINE_CLASS_IS_COND_GUARD(_name) \
	__DEFINE_CLASS_IS_CONDITIONAL(_name, true); \
	__DEFINE_GUARD_LOCK_PTR(_name, _T)

#define DEFINE_GUARD(_name, _type, _lock, _unlock) \
	DEFINE_CLASS(_name, _type, if (!__GUARD_IS_ERR(_T)) { _unlock; }, ({ _lock; _T; }), _type _T); \
	DEFINE_CLASS_IS_GUARD(_name)

#define DEFINE_GUARD_COND_4(_name, _ext, _lock, _cond) \
	__DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \
	EXTEND_CLASS(_name, _ext, \
		     ({ void *_t = _T; int _RET = (_lock); if (_T && !(_cond)) _t = ERR_PTR(_RET); _t; }), \
		     class_##_name##_t _T) \
	static __always_inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \
	{ return class_##_name##_lock_ptr(_T); } \
	static __always_inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \
	{ return class_##_name##_lock_err(_T); }


#define DEFINE_GUARD_COND_3(_name, _ext, _lock) \
	DEFINE_GUARD_COND_4(_name, _ext, _lock, _RET)

#define DEFINE_GUARD_COND(X...) CONCATENATE(DEFINE_GUARD_COND_, COUNT_ARGS(X))(X)

#define guard(_name) \
	CLASS(_name, __UNIQUE_ID(guard))

#define __guard_ptr(_name) class_##_name##_lock_ptr
#define __guard_err(_name) class_##_name##_lock_err
#define __is_cond_ptr(_name) class_##_name##_is_conditional

#define ACQUIRE(_name, _var)     CLASS(_name, _var)
#define ACQUIRE_ERR(_name, _var) __guard_err(_name)(_var)


#define __scoped_guard(_name, _label, args...)				\
	for (CLASS(_name, scope)(args);					\
	     __guard_ptr(_name)(&scope) || !__is_cond_ptr(_name);	\
	     ({ goto _label; }))					\
		if (0) {						\
_label:									\
			break;						\
		} else

#define scoped_guard(_name, args...)	\
	__scoped_guard(_name, __UNIQUE_ID(label), args)

#define __scoped_cond_guard(_name, _fail, _label, args...)		\
	for (CLASS(_name, scope)(args); true; ({ goto _label; }))	\
		if (!__guard_ptr(_name)(&scope)) {			\
			BUILD_BUG_ON(!__is_cond_ptr(_name));		\
			_fail;						\
_label:									\
			break;						\
		} else

#define scoped_cond_guard(_name, _fail, args...)	\
	__scoped_cond_guard(_name, _fail, __UNIQUE_ID(label), args)



#define __DEFINE_UNLOCK_GUARD(_name, _type, _unlock, ...)		\
typedef _type lock_##_name##_t;						\
typedef struct {							\
	_type *lock;							\
	__VA_ARGS__;							\
} class_##_name##_t;							\
									\
static __always_inline void class_##_name##_destructor(class_##_name##_t *_T) \
	__no_context_analysis						\
{									\
	if (!__GUARD_IS_ERR(_T->lock)) { _unlock; }			\
}									\
									\
__DEFINE_GUARD_LOCK_PTR(_name, &_T->lock)

#define __DEFINE_LOCK_GUARD_1(_name, _type, ...)			\
static __always_inline class_##_name##_t class_##_name##_constructor(_type *l) \
	__no_context_analysis						\
{									\
	class_##_name##_t _t = { .lock = l }, *_T = &_t;		\
	__VA_ARGS__;							\
	return _t;							\
}

#define __DEFINE_LOCK_GUARD_0(_name, ...)				\
static __always_inline class_##_name##_t class_##_name##_constructor(void) \
	__no_context_analysis						\
{									\
	class_##_name##_t _t = { .lock = (void*)1 },			\
			 *_T __maybe_unused = &_t;			\
	__VA_ARGS__;							\
	return _t;							\
}

#define DECLARE_LOCK_GUARD_0_ATTRS(_name, _lock, _unlock)		\
static inline class_##_name##_t class_##_name##_constructor(void) _lock;\
static inline void class_##_name##_destructor(class_##_name##_t *_T) _unlock;


#define DECLARE_LOCK_GUARD_1_ATTRS(_name, _lock, _unlock)		\
static inline class_##_name##_t class_##_name##_constructor(lock_##_name##_t *_T) _lock;\
static __always_inline void __class_##_name##_cleanup_ctx(class_##_name##_t **_T) \
	__no_context_analysis _unlock { }
#define WITH_LOCK_GUARD_1_ATTRS(_name, _T)				\
	class_##_name##_constructor(_T),				\
	*__UNIQUE_ID(unlock) __cleanup(__class_##_name##_cleanup_ctx) = (void *)(unsigned long)(_T)

#define DEFINE_LOCK_GUARD_1(_name, _type, _lock, _unlock, ...)		\
__DEFINE_CLASS_IS_CONDITIONAL(_name, false);				\
__DEFINE_UNLOCK_GUARD(_name, _type, _unlock, __VA_ARGS__)		\
__DEFINE_LOCK_GUARD_1(_name, _type, _lock)

#define DEFINE_LOCK_GUARD_0(_name, _lock, _unlock, ...)			\
__DEFINE_CLASS_IS_CONDITIONAL(_name, false);				\
__DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__)		\
__DEFINE_LOCK_GUARD_0(_name, _lock)

#define DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _cond)		\
	__DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true);		\
	EXTEND_CLASS(_name, _ext,					\
		     ({ class_##_name##_t _t = { .lock = l }, *_T = &_t;\
		        int _RET = (_lock);                             \
		        if (_T->lock && !(_cond)) _T->lock = ERR_PTR(_RET);\
			_t; }),						\
		     typeof_member(class_##_name##_t, lock) l)		\
	static __always_inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \
	{ return class_##_name##_lock_ptr(_T); } \
	static __always_inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \
	{ return class_##_name##_lock_err(_T); }

#define DEFINE_LOCK_GUARD_1_COND_3(_name, _ext, _lock) \
	DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _RET)

#define DEFINE_LOCK_GUARD_1_COND(X...) CONCATENATE(DEFINE_LOCK_GUARD_1_COND_, COUNT_ARGS(X))(X)

#endif 
