#pragma once
#include <queue>
#include <mutex>
#include <optional>

template<typename T>
class safe_queue {
public:
    void push(const T& value) {
        std::lock_guard lock(mutex);
        queue.push(value);
    }

    void push(T&& value) {
        std::lock_guard lock(mutex);
        queue.push(std::move(value));
    }

    [[nodiscard]] std::optional<T> pop() {
        std::lock_guard lock(mutex);
        if (queue.empty()) {
            return std::nullopt;
        }
        T value = std::move(queue.front());
        queue.pop();
        return value;
    }

    [[nodiscard]] auto empty() const {
        std::lock_guard lock(mutex);
        return queue.empty();
    }

    [[nodiscard]] auto size() const {
        std::lock_guard lock(mutex);
        return queue.size();
    }
private:
    mutable std::mutex mutex;
    std::queue<T> queue;
};
