// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#ifndef QOHOSCOMMON_H
#define QOHOSCOMMON_H

//
//  W A R N I N G
//  -------------
//
// This file is not part of the Qt API.  It exists purely as an
// implementation detail.  This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//

#include <QtCore/qglobal.h>
#include <QtCore/qlogging.h>
#include <QtCore/qdebug.h>
#include <cstdlib>
#include <functional>
#include <memory>
#include <mutex>
#ifndef QT_NO_EXCEPTIONS
#include <stdexcept>
#endif
#include <type_traits>
#include <utility>

#define Q_OHOS_NAMED_FUNC(func) (QT_PREPEND_NAMESPACE(makeQOhosNamedFunc)<decltype(&func), &func>)(QT_STRINGIFY(func))

#define qOhosReportFatalErrorAndAbort(...) \
    do { \
        QT_PREPEND_NAMESPACE(QMessageLogger)(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).fatal(__VA_ARGS__); \
        std::abort(); \
    } while (false)

QT_BEGIN_NAMESPACE

template<typename T>
class QOhosOptional;

namespace qohoscommon_h_detail {

template<typename A, typename B, typename = void>
struct HasEqualityComparatorT : std::false_type {};

template<typename A, typename B>
struct HasEqualityComparatorT<A, B, decltype(void(std::declval<A>() == std::declval<B>()))>
    : std::true_type {};

template<typename A, typename B>
constexpr bool hasEqualityComparator = HasEqualityComparatorT<A, B>::value;

template<typename>
struct IsQOhosOptional : std::false_type {};

template<typename T>
struct IsQOhosOptional<QOhosOptional<T>> : std::true_type {};

template<typename T>
constexpr bool isQOhosOptional = IsQOhosOptional<T>::value;

}

template<typename Func, typename... FuncArgs>
using QOhosInvokeResult = decltype(std::declval<Func>()(std::declval<FuncArgs>()...));

template<typename ...Ts>
using QOhosConsumer = std::function<void(Ts...)>;

template<typename T>
using QOhosSupplier = std::function<T()>;

template<typename FuncPtr, FuncPtr func>
class QOhosNamedFunc
{
public:
    static constexpr FuncPtr funcPtr = func;

    QOhosNamedFunc(const char *funcName);

    const char *name() const;
    FuncPtr ptr() const;

    operator FuncPtr() const;

private:
    static_assert(
        std::is_pointer<FuncPtr>::value && std::is_function<std::remove_pointer_t<FuncPtr>>::value,
        "FuncPtr must be a function pointer type");

    const char *m_funcName;
};

template<typename FuncPtr, FuncPtr func>
QOhosNamedFunc<FuncPtr, func> makeQOhosNamedFunc(const char *funcName)
{
    return {funcName};
}

class QOhosNoOpConsumer
{
public:
    template<typename ...Ts>
    void operator()(const Ts &...) const;
};

template<typename ...Ts>
QOhosConsumer<Ts...> makeQOhosNoOpConsumer();

QOhosNoOpConsumer makeQOhosNoOpConsumer();

template<typename T>
class QOhosOptional
{
    static_assert(
        std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
        "Only copyable types are supported");

public:
    explicit QOhosOptional(const T &value);
    QOhosOptional(const QOhosOptional<void> &empty);

    QOhosOptional() = default;
    QOhosOptional(const QOhosOptional<T> &other);
    QOhosOptional<T> &operator=(const QOhosOptional<T> &other);
    QOhosOptional<T> &operator=(const T &value);
    QOhosOptional<T> &operator=(const QOhosOptional<void> &empty);

    ~QOhosOptional();

    bool hasValue() const;
    T valueOr(const T &fallback) const;

    const T &value() const;
    T &value();

    void reset();

    template<typename... Args>
    T &emplace(Args &&...args);


    template<typename Func>
    std::enable_if_t<
        qohoscommon_h_detail::isQOhosOptional<QOhosInvokeResult<Func, T>>,
        QOhosInvokeResult<Func, T>>
    andThen(Func &&func) const;

    template<typename Func>
    QOhosOptional<QOhosInvokeResult<Func, T>> transform(Func &&func) const;

private:
    T &storedValueRef();
    const T &storedValueRef() const;
    template<typename... InitArgs>
    void initializeStoredValue(InitArgs &&...initArgs);

    std::aligned_storage_t<sizeof(T), alignof(T)> m_rawStoredValue;
    bool m_hasValue = false;
};

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator==(const QOhosOptional<T> &lhs, const QOhosOptional<U> &rhs);

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator!=(const QOhosOptional<T> &lhs, const QOhosOptional<U> &rhs);

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator==(const QOhosOptional<T> &lhs, const U &rhs);

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator!=(const QOhosOptional<T> &lhs, const U &rhs);

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator==(const T &lhs, const QOhosOptional<U> &rhs);

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator!=(const T &lhs, const QOhosOptional<U> &rhs);

template<>
class QOhosOptional<void>
{
};

template<typename T>
class QOhosSpan
{
public:
    QOhosSpan(T *data, std::size_t size) Q_DECL_NOEXCEPT;

    T *begin() const Q_DECL_NOEXCEPT;
    T *end() const Q_DECL_NOEXCEPT;

    T *data() const Q_DECL_NOEXCEPT;
    std::size_t size() const Q_DECL_NOEXCEPT;

    T &operator[](std::size_t index) const;

    QOhosSpan<T> subspan(std::size_t offset) const;
    QOhosSpan<T> subspan(std::size_t offset, std::size_t length) const;

private:
    T *m_data;
    std::size_t m_size;
};

template<typename T>
QOhosSpan<T> makeQOhosSpan(T *data, std::size_t count);

template<typename T>
QOhosOptional<T> makeQOhosOptional(const T &value);

QOhosOptional<void> makeEmptyQOhosOptional();

template<typename T>
class QOhosMutexProtectedValue
{
public:
    QOhosMutexProtectedValue();

    QOhosMutexProtectedValue(const QOhosMutexProtectedValue<T> &other) = delete;
    QOhosMutexProtectedValue &operator=(const QOhosMutexProtectedValue<T> &other) = delete;

    QOhosMutexProtectedValue(QOhosMutexProtectedValue<T> &&other) = delete;
    QOhosMutexProtectedValue &operator=(QOhosMutexProtectedValue<T> &&other) = delete;

    template<typename ProcessFunc>
    void processValue(ProcessFunc &&processFunc);

    template<typename EvalFunc>
    auto evalWithValue(EvalFunc &&evalFunc) const -> decltype(evalFunc(std::declval<const T &>()));

private:
    mutable std::mutex m_valueMutex;
    T m_value{};
};

namespace QtOhos {

template<typename T>
std::shared_ptr<T> moveToSharedPtr(T &&obj);

template<typename T>
std::shared_ptr<T> makeSharedPtrWithAttachedExtraData(
    std::shared_ptr<T> baseSharedPtr, std::shared_ptr<void> extraData);

template<typename T>
std::weak_ptr<T> makeWeakPtr(const std::shared_ptr<T> &obj);

std::shared_ptr<void> makeDestroyNotifier(std::function<void()> callOnDestroy);

}

template<typename FuncPtr, FuncPtr func>
QOhosNamedFunc<FuncPtr, func>::QOhosNamedFunc(const char *funcName)
    : m_funcName(funcName)
{
}

template<typename FuncPtr, FuncPtr func>
const char *QOhosNamedFunc<FuncPtr, func>::name() const
{
    return m_funcName;
}

template<typename FuncPtr, FuncPtr func>
FuncPtr QOhosNamedFunc<FuncPtr, func>::ptr() const
{
    return func;
}

template<typename FuncPtr, FuncPtr func>
QOhosNamedFunc<FuncPtr, func>::operator FuncPtr() const
{
    return func;
}

template<typename ...Ts>
void QOhosNoOpConsumer::operator()(const Ts &...) const
{
}

template<typename ...Ts>
QOhosConsumer<Ts...> makeQOhosNoOpConsumer()
{
    return [](const Ts &...) {
    };
}

inline QOhosNoOpConsumer makeQOhosNoOpConsumer()
{
    return QOhosNoOpConsumer();
}

template<typename T>
QOhosOptional<T>::QOhosOptional(const T &value)
{
    initializeStoredValue(value);
}

template<typename T>
QOhosOptional<T>::QOhosOptional(const QOhosOptional<void> &)
{
}

template<typename T>
QOhosOptional<T>::QOhosOptional(const QOhosOptional<T> &other)
{
    if (other.m_hasValue) {
        initializeStoredValue(other.storedValueRef());
    }
}

template<typename T>
QOhosOptional<T> &QOhosOptional<T>::operator=(const QOhosOptional<T> &other)
{
    if (&other == this) {
        return *this;
    }

    if (other.m_hasValue) {
        if (m_hasValue) {
            storedValueRef() = other.storedValueRef();
        } else {
            initializeStoredValue(other.storedValueRef());
        }
    } else {
        reset();
    }

    return *this;
}

template<typename T>
QOhosOptional<T> &QOhosOptional<T>::operator=(const T &value)
{
    *this = QOhosOptional<T>(value);
    return *this;
}

template<typename T>
QOhosOptional<T> &QOhosOptional<T>::operator=(const QOhosOptional<void> &)
{
    reset();
    return *this;
}

template<typename T>
QOhosOptional<T>::~QOhosOptional()
{
    reset();
}

template<typename T>
void QOhosOptional<T>::reset()
{
    if (m_hasValue) {
        m_hasValue = false;
        storedValueRef().~T();
    }
}

template<typename T>
T &QOhosOptional<T>::storedValueRef()
{
    return *reinterpret_cast<T *>(&m_rawStoredValue);
}

template<typename T>
const T &QOhosOptional<T>::storedValueRef() const
{
    return *reinterpret_cast<const T *>(&m_rawStoredValue);
}

template<typename T>
template<typename... InitArgs>
void QOhosOptional<T>::initializeStoredValue(InitArgs &&...initArgs)
{
    new (&m_rawStoredValue) T(std::forward<InitArgs...>(initArgs...));
    m_hasValue = true;
}

template<typename T>
bool QOhosOptional<T>::hasValue() const
{
    return m_hasValue;
}

template<typename T>
T QOhosOptional<T>::valueOr(const T &fallback) const
{
    return hasValue() ? storedValueRef() : fallback;
}

template<typename T>
const T &QOhosOptional<T>::value() const
{
    if (!m_hasValue) {
#ifndef QT_NO_EXCEPTIONS
        throw std::runtime_error("Can't access value inside empty QOhosOptional<>");
#else
        qFatal("Can't access value inside empty QOhosOptional<>");
        std::abort();
#endif
    }

    return storedValueRef();
}

template<typename T>
T &QOhosOptional<T>::value()
{
    if (!m_hasValue) {
#ifndef QT_NO_EXCEPTIONS
        throw std::runtime_error("Can't access value inside empty QOhosOptional<>");
#else
        qFatal("Can't access value inside empty QOhosOptional<>");
        std::abort();
#endif
    }

    return storedValueRef();
}

template<typename T>
template<typename... Args>
T &QOhosOptional<T>::emplace(Args &&...args)
{
    reset();
    initializeStoredValue(std::forward<Args...>(args)...);
    return storedValueRef();
}

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator==(const QOhosOptional<T> &lhs, const QOhosOptional<U> &rhs)
{
    return (lhs.hasValue() && rhs.hasValue())
        ? lhs.value() == rhs.value()
        : (!lhs.hasValue() && !rhs.hasValue());
}

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator!=(const QOhosOptional<T> &lhs, const QOhosOptional<U> &rhs)
{
    return !(lhs == rhs);
}

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator==(const QOhosOptional<T> &lhs, const U &rhs)
{
    return lhs.hasValue() && lhs.value() == rhs;
}

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator!=(const QOhosOptional<T> &lhs, const U &rhs)
{
    return !(lhs == rhs);
}

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator==(const T &lhs, const QOhosOptional<U> &rhs)
{
    return rhs.hasValue() && lhs == rhs.value();
}

template<typename T, typename U>
std::enable_if_t<qohoscommon_h_detail::hasEqualityComparator<T, U>, bool>
operator!=(const T &lhs, const QOhosOptional<U> &rhs)
{
    return !(lhs == rhs);
}

template<typename T>
template<typename Func>
std::enable_if_t<
    qohoscommon_h_detail::isQOhosOptional<QOhosInvokeResult<Func, T>>,
    QOhosInvokeResult<Func, T>>
QOhosOptional<T>::andThen(Func &&func) const
{
    return hasValue() ? func(value()) : QOhosInvokeResult<Func, T>();
}

template<typename T>
template<typename Func>
QOhosOptional<QOhosInvokeResult<Func, T>> QOhosOptional<T>::transform(Func &&func) const
{
    using TransformedT = QOhosInvokeResult<Func, T>;
    return hasValue()
        ? QOhosOptional<TransformedT>(func(value()))
        : QOhosOptional<TransformedT>();
}

template<typename T>
QOhosSpan<T>::QOhosSpan(T *data, std::size_t size) Q_DECL_NOEXCEPT
    : m_data(data)
    , m_size(size)
{
}

template<typename T>
T *QOhosSpan<T>::begin() const Q_DECL_NOEXCEPT
{
    return m_data;
}

template<typename T>
T *QOhosSpan<T>::end() const Q_DECL_NOEXCEPT
{
    return m_data + m_size;
}

template<typename T>
T *QOhosSpan<T>::data() const Q_DECL_NOEXCEPT
{
    return m_data;
}

template<typename T>
std::size_t QOhosSpan<T>::size() const Q_DECL_NOEXCEPT
{
    return m_size;
}

template<typename T>
T &QOhosSpan<T>::operator[](std::size_t index) const
{
    return m_data[index];
}

template<typename T>
QOhosSpan<T> QOhosSpan<T>::subspan(std::size_t offset) const
{
    if (offset >= m_size) {
#ifndef QT_NO_EXCEPTIONS
        throw std::out_of_range("offset >= span size");
#else
        qFatal("offset >= span size");
        std::abort();
#endif
    }
    return QOhosSpan<T>(m_data + offset, m_size - offset);
}

template<typename T>
QOhosSpan<T> QOhosSpan<T>::subspan(std::size_t offset, std::size_t length) const
{
    if (offset >= m_size) {
#ifndef QT_NO_EXCEPTIONS
        throw std::out_of_range("offset >= span size");
#else
        qFatal("offset >= span size");
        std::abort();
#endif
    }
    return QOhosSpan<T>(m_data + offset, std::min(m_size - offset, length));
}

template<typename T>
QOhosSpan<T> makeQOhosSpan(T *data, std::size_t count)
{
    return QOhosSpan<T>(data, count);
}

template<typename T>
QOhosOptional<T> makeQOhosOptional(const T &value)
{
    return QOhosOptional<T>(value);
}

inline QOhosOptional<void> makeEmptyQOhosOptional()
{
    return {};
}

template<typename T>
QOhosMutexProtectedValue<T>::QOhosMutexProtectedValue() = default;

template<typename T>
template<typename ProcessFunc>
void QOhosMutexProtectedValue<T>::processValue(ProcessFunc &&processFunc)
{
    std::lock_guard<std::mutex> valueLock(m_valueMutex);
    std::forward<ProcessFunc>(processFunc)(m_value);
}

template<typename T>
template<typename EvalFunc>
auto QOhosMutexProtectedValue<T>::evalWithValue(EvalFunc &&evalFunc) const -> decltype(evalFunc(std::declval<const T &>()))
{
    std::lock_guard<std::mutex> valueLock(m_valueMutex);
    return std::forward<EvalFunc>(evalFunc)(m_value);
}

namespace QtOhos {

template<typename T>
std::shared_ptr<T> moveToSharedPtr(T &&obj)
{
    return std::make_shared<T>(std::forward<T>(obj));
}

template<typename T>
std::shared_ptr<T> makeSharedPtrWithAttachedExtraData(
    std::shared_ptr<T> baseSharedPtr, std::shared_ptr<void> extraData)
{
    auto *baseRawPtr = baseSharedPtr.get();
    return std::shared_ptr<T>(
        moveToSharedPtr(
            std::make_pair(
                std::move(baseSharedPtr),
                std::move(extraData))),
        baseRawPtr);
}

template<typename T>
std::weak_ptr<T> makeWeakPtr(const std::shared_ptr<T> &obj)
{
    return obj;
}

inline std::shared_ptr<void> makeDestroyNotifier(std::function<void()> callOnDestroy)
{
    class DestroyNotifier
    {
    public:
        explicit DestroyNotifier(std::function<void()> callOnDestroy)
            : callOnDestroy(std::move(callOnDestroy))
        {
        }

        DestroyNotifier(const DestroyNotifier &) = delete;
        DestroyNotifier(DestroyNotifier &&) = delete;
        DestroyNotifier &operator=(const DestroyNotifier &) = delete;
        DestroyNotifier &operator=(DestroyNotifier &&) = delete;

        ~DestroyNotifier()
        {
            callOnDestroy();
        };

    private:
        std::function<void()> callOnDestroy;
    };

    return std::make_shared<DestroyNotifier>(std::move(callOnDestroy));
}

}

QT_END_NAMESPACE

#endif
