Full Code of tripleslash/rocket for AI

master ce3a936f21bc cached
5 files
122.0 KB
24.9k tokens
374 symbols
1 requests
Download .txt
Repository: tripleslash/rocket
Branch: master
Commit: ce3a936f21bc
Files: 5
Total size: 122.0 KB

Directory structure:
gitextract_zivlhdr6/

├── .gitignore
├── CMakeLists.txt
├── README.md
├── example.cpp
└── rocket.hpp

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.vscode
.clangd
build
compile_commands.json

================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.2)
project(rocket CXX)

option(BUILD_EXAMPLES "Build examples" ON)

# C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# generate compile_commands.json if possible
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# include dir of rocket.hpp
include_directories(${CMAKE_CURRENT_SOURCE_DIR})

if(BUILD_EXAMPLES)
    message(STATUS "build examples")
    add_executable(example example.cpp)    
endif()


================================================
FILE: README.md
================================================
# rocket - Fast C++ Observer Pattern

Rocket is a public-domain, single-header implementation of a signal/slots library for C++.

The library was developed because existing solutions were too inflexible, too slow, or came as a part of a larger dependency (for example boost::signals and boost::signals2).

## Design goals

1. Efficiency. The library takes special care to not use cache unfriendly code (such as calling virtual methods) unless absolutely necessary.
2. Low memory footprint (does not allocate during signal emission).
3. Modern C++. No bloat from overloading 50 template specializations for each function.
4. Single header file implementation.
5. No dependencies.

The API was heavily inspired by boost::signals2. If you are already familiar with boost::signals2, switching to rocket will be a no brainer.

## What makes rocket unique?

1. The library provides both a thread-safe and a thread-unsafe implementation. No efficiency loss due to locks or atomics in the thread-unsafe implementation.
2. Policy based design. Specify at declaration time and invocation time of the signal how _you_ want the call results to be returned.
3. The signals are reentrant. This property is a must have for any event processing library because it must be possible to recursively emit signals, or disconnect slots from within a signal handler.
4. Support for smart `scoped_connection`'s and `scoped_connection_container`'s.
5. Support for automatic lifetime tracking of observers via `rocket::trackable`.
6. Allows slots to get an instance to the `current_connection` object (see example 5).
7. Allows slots to preemtively abort the emission of the signal (see example 6).
8. Support for Qt-style `queued_connection`'s. If a slot is connected to a signal with this flag, the slots execution will be scheduled on the same thread that connected the slot to the signal (see example 7).
9. Supports `set_interval` and `set_timeout` functions to connect periodic events to the current threads dispatch queue (you can opt-out of this feature by defining `ROCKET_NO_TIMERS`).


## Performance

Because the main focus of this library was to provide an efficient single threaded implementation, `rocket::signal` has about the same overhead as an iteration through an `std::list<std::function<T>>`.

Here are some performance benchmarks between boost::signals2 and rocket for registering 10 slots to each signal type and emitting each one 1000 times.

| Library         | Avg. execution time |
| --------------  | -------------------:|
| boost::signals2 |          810.389 µs |
| rocket::signal  |           98.155 µs |

## 1. Creating your first signal

```cpp
#include <iostream>

int main()
{
    rocket::signal<void()> thread_unsafe_signal;
    rocket::thread_safe_signal<void()> thread_safe_signal;

    // Connecting the first handler to our signal
    thread_unsafe_signal.connect([]() {
        std::cout << "First handler called!" << std::endl;
    });
    
    // Connecting a second handler to our signal using alternative syntax
    thread_unsafe_signal += []() {
        std::cout << "Second handler called!" << std::endl;
    };
    
    // Invoking the signal
    thread_unsafe_signal();
}

// Output:
//     First handler called!
//     Second handler called!
```

## 2. Connecting class methods to the signal

```cpp
#include <string>
#include <iostream>

class Subject {
public:
    void setName(const std::string& newName)
    {
        if (name != newName) {
            name = newName;
            nameChanged(newName);
        }
    }

public:
    rocket::signal<void(std::string)> nameChanged;

private:
    std::string name;
};

class Observer {
public:
    Observer(Subject& subject)
    {
        // Register the `onNameChanged`-function of this object as a listener and
        // store the resultant connection object in the listener's connection set.

        // This is all your need to do for the most common case, if you want the
        // connection to be broken when the observer is destroyed.
        connections += {
            subject.nameChanged.connect<&Observer::onNameChanged>(this)
        };
    }

    void onNameChanged(const std::string& name)
    {
        std::cout << "Subject received new name: " << name << std::endl;
    }

private:
    rocket::scoped_connection_container connections;
};

int main()
{
    Subject s;
    Observer o{ s };
    s.setName("Peter");
}

// Output:
//     Subject received new name: Peter
```

### Another example: Binding pure virtual interface methods

```cpp
#include <string>
#include <iostream>
#include <memory>

class ILogger {
public:
    virtual void logMessage(const std::string& message) = 0;
};

class ConsoleLogger : public ILogger {
public:
    void logMessage(const std::string& message) override {
        std::cout << "New log message: " << message << std::endl;
    }
};

class App {
public:
    void run()
    {
        if (work()) {
            onSuccess("I finished my work!");
        }
    }
    
    bool work()
    {
        return true;
    }
    
public:
    rocket::signal<void(std::string)> onSuccess;
};

int main()
{
    std::unique_ptr<App> app = std::make_unique<App>();

    std::unique_ptr<ILogger> logger = std::make_unique<ConsoleLogger>();
    app->onSuccess.connect<&ILogger::logMessage>(logger.get());

    app->run();
}

// Output:
//     New log message: I finished my work!
```

## 3.a Handling lifetime and scope of connection objects

What if we want to destroy our logger instance from example 2 but continue to use the app instance?

**Solution:** We use `scoped_connection`-objects to track our connected slots!

```cpp
// [...] (See example 2)

int main()
{
    std::unique_ptr<App> app = std::make_unique<App>();
    {
        std::unique_ptr<ILogger> logger = std::make_unique<ConsoleLogger>();
        
        rocket::scoped_connection connection = app->onSuccess
            .connect(logger.get(), &ILogger::logMessage);
            
        app->run();
    } //<-- `logger`-instance is destroyed at the end of this block
      //<-- The `connection`-object is also destroyed here
      //        and therefore removed from App::onSuccess.
     
    // Run the app a second time
    //
    // This would normally cause a crash / undefined behavior because the logger
    // instance is destroyed at this point, but App::onSuccess still referenced it
    // in example 2.
   
    app->run();
}

// Output:
//     New log message: I finished my work!
```

## 3.b Advanced lifetime tracking

The library can also track the lifetime of your class objects for you, if the connected slot instances inherit from the `rocket::trackable` base class.

```cpp
// [...] (See example 2)

struct ILogger : rocket::trackable
{
    virtual void logMessage(const std::string& message) = 0;
};

// [...] (See example 2)

int main()
{
    std::unique_ptr<App> app = std::make_unique<App>();
    {
        std::unique_ptr<ILogger> logger = std::make_unique<ConsoleLogger>();
        app->onSuccess.connect(logger.get(), &ILogger::logMessage);
        
        app->run();
    } //<-- `logger`-instance is destroyed at the end of this block
    
      //<-- Because `ILogger` inherits from `rocket::trackable`, the signal knows
      //        about its destruction and will automatically disconnect the slot!
      
    // Run the app a second time
    //
    // This would normally cause a crash / undefined behavior because the logger
    // instance is destroyed at this point, but App::onSuccess still referenced it
    // in example 2.
    
    app->run();
}
```

## 4. Getting return values from a call to a signal

Slots can also return values to the emitting signal.
Because a signal can have several slots attached to it, the return values are collected by using the so called `value collectors`.

The default value collector returns an `optional<T>` from a call to a `signal<T(...)>::operator()`

However, this behaviour can be overriden at declaration time of the signal as well as during signal invocation.

```cpp
#include <cmath>
#include <iostream>

int main()
{
    rocket::signal<int(int)> signal;
    
    // The library supports argument and return type transformation between the
    // signal and the slots. We show this by connecting the `float sqrtf(float)`
    // function to a signal with an `int` argument and `int` return value.
    
    signal.connect(std::sqrtf);
    
    std::cout << "Computed value: " << *signal(16);
}

// Output:
//     Computed value: 4
```

```cpp
#include <cmath>
#include <iostream>
#include <iomanip>

int main()
{
    // Because we set `rocket::range` as the value collector for this signal
    // calling operator() now returns the return values of all connected slots.
    
    rocket::signal<float(float), rocket::range<float>> signal;
    
    // Lets connect a couple more functions to our signal and print all the
    // return values.
    
    signal.connect(std::sinf);
    signal.connect(std::cosf);
    
    std::cout << std::fixed << std::setprecision(2);
    
    for (auto result : signal(3.14159)) {
        std::cout << result << std::endl;
    }
    
    // We can also override the return value collector at invocation time
    std::cout << "First return value: " << signal.invoke<rocket::first<float>>(3.14159);
    std::cout << std::endl;
    std::cout << "Last return value: " << signal.invoke<rocket::last<float>>(3.14159);
}

// Output:
//     0.00
//     -1.00
//     First return value: 0.00
//     Last return value: -1.00
```

## 5. Accessing the current connection object inside a slot

Sometimes it is desirable to get an instance to the current connection object inside of a slot function. An example would be if you want to make a callback that only fires once and then disconnects itself from the signal that called it.

```cpp
#include <iostream>

int main()
{
    rocket::signal<void()> signal;

    signal.connect([] {
        std::cout << "Slot called. Now disconnecting..." << std::endl;
        
        // `current_connection` is stored in thread-local-storage.
        rocket::current_connection().disconnect();
    });
    
    signal();
    signal();
    signal();
}

// Output:
//     Slot called. Now disconnecting...
```

## 6. Preemtively aborting the emission of a signal

A slot can preemtively abort the emission of a signal if it needs to. This is useful in scenarios where your slot functions try to find some value and you just want the result of the first slot that found one and stop other slots from running.

```cpp
#include <iostream>

int main()
{
    rocket::signal<void()> signal;
    
    signal.connect([] {
        std::cout << "First slot called. Aborting emission of other slots." << std::endl;
        
        rocket::abort_emission();
        // Notice that this doesn't disconnect the other slots. It just breaks out of the
        // signal emitting loop.
    });
 
    signal.connect([] {
        std::cout << "Second slot called. Should never happen." << std::endl;
    });
    
    signal();
}

// Output:
//     First slot called. Aborting emission of other slots.
```

## 7. Using `queued_connection` to build a message queue between threads

An observer can connect slots to a subject with the `queued_connection`-flag. Instead of calling the slot directly when the signal is invoked, rocket will schedule the execution in the same thread from where the observer called the `connect`-function. With this system it is extremely easy to build a message queue between different threads.

Lets say we have a subject called `ModelFileLoaderThread`. It loads files from disc and does some expensive preprocessing.
We also have an observer. The `RenderThread`. The `RenderThread` now wants to know whenever a new file is fully loaded, so it can display it in the scene.

```cpp
class ModelFileLoaderThread {
public:
    void start() {
        shouldRun = true;
        thread = std::thread(&ModelFileLoaderThread::run, this);
    }

    void shutdown() {
        shouldRun = false;
        thread.join();
    }

    void pushLoadRequest(const std::string& fileName) {
        std::scoped_lock<std::mutex> guard{ mutex };
        loadRequests.push_front(fileName);
    }

private:
    void run() {
        while (shouldRun) {
            std::forward_list<std::string> requests;
            {
                std::scoped_lock<std::mutex> guard{ mutex };
                loadRequests.swap(requests);
            }
            for (auto& fileName : requests) {
                ModelFilePtr modelFile = new ModelFile(fileName);

                if (modelFile->loadModel()) {
                    modelLoaded(modelFile);
                } else {
                    modelLoadFailed(fileName);
                }
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    }
    
public:
    rocket::thread_safe_signal<void(ModelFilePtr)> modelLoaded;
    rocket::thread_safe_signal<void(std::string)> modelLoadFailed;

private:
    std::thread thread;
    volatile bool shouldRun = false;
    
    std::mutex mutex;
    std::forward_list<std::string> loadRequests;
};
```

```cpp
class RenderThread {
public:
    void initialize() {
        modelLoaderThread.start();

        // Connect to the thread using queued_connection flag
        modelLoaderThread.modelLoaded.connect<&RenderThread::onModelLoaded>(this, rocket::queued_connection);
        modelLoaderThread.modelLoadFailed.connect<&RenderThread::onModelLoadFailed>(this, rocket::queued_connection);
    }
    
    void shutdown() {
        modelLoaderThread.shutdown();
    }
    
    void render() {
        rocket::dispatch_queued_calls();    //<-- This call is required so rocket can call the queued slots from this thread
  
        for (IRenderablePtr& renderable : renderables) {
            renderable->render();
        }
    }
    
private:
    // These slots are actually executed from inside the `rocket::dispatch_queued_calls` method

    void onModelLoaded(ModelFilePtr const& modelFile) {
        // No lock needed, because onModelLoaded is called on render thread!
        renderables.push_back(new ModelRenderer(modelFile));
    }

    void onModelLoadFailed(std::string const& fileName) {
        // Show log message
    }
    
private:
    std::list<IRenderablePtr> renderables;
    ModelFileLoaderThread modelLoaderThread;
};
```

## 8. Using `set_interval` and `set_timeout`

Other than signals and slots, rocket can also schedule timers for you! They work similar to the `queued_connections` shown in example 7.

```cpp
// [...] (See example 7)

class RenderThread {
public:
    void initialize() {
        modelLoaderThread.start();

        connections += {
            // Register a timer that gets called every 5000 ms
            rocket::set_interval<&RenderThread::onClearRenderablesTimerExpired>(this, 5000),
            
            // Connect to the thread using queued_connection flag
            modelLoaderThread.modelLoaded.connect<&RenderThread::onModelLoaded>(this, rocket::queued_connection),
            modelLoaderThread.modelLoadFailed.connect<&RenderThread::onModelLoadFailed>(this, rocket::queued_connection)
        };
    }

    void shutdown() {
        modelLoaderThread.shutdown();
    }
    
    void render() {
        rocket::dispatch_queued_calls();    //<-- This call is required so rocket can call the queued slots from this thread
  
        for (IRenderablePtr& renderable : renderables) {
            // Will be rendered for at most 5 seconds because `onClearRenderablesTimerExpired` periodically clears the renderables
            renderable->render();
        }
    }
    
private:
    // These slots are actually executed from inside the `rocket::dispatch_queued_calls` method

    void onModelLoaded(ModelFilePtr const& modelFile) {
        // No lock needed, because onModelLoaded is called on render thread!
        renderables.push_back(new ModelRenderer(modelFile));
    }

    void onModelLoadFailed(std::string const& fileName) {
        // Show log message
    }

    void onClearRenderablesTimerExpired() {
        // Called every 5000 ms from inside the `rocket::dispatch_queud_calls` method
        renderables.clear();
    }

private:
    rocket::scoped_connection_container connections;

    std::list<IRenderablePtr> renderables;
    ModelFileLoaderThread modelLoaderThread;
};
```


================================================
FILE: example.cpp
================================================

#include "rocket.hpp"
#include <iostream>

struct Testing : rocket::trackable
{
    int hello(float a)
    {
        std::cout << "Testing: " << a << std::endl;
        return 0;
    }
};

struct NonDefaultConstructible
{
    explicit NonDefaultConstructible(int x)
        : value{ x }
    {
    }

    ~NonDefaultConstructible()
    {
        std::cout << "Destructor called for value: " << value << std::endl;
    }

    NonDefaultConstructible(NonDefaultConstructible&& n)
        : value{ n.value }
    {
        n.value = 0;
    }

    NonDefaultConstructible& operator = (NonDefaultConstructible&& n)
    {
        value = n.value;
        n.value = 0;
        return *this;
    }

private:
    int value;

    NonDefaultConstructible() = delete;

    NonDefaultConstructible(NonDefaultConstructible const&) = delete;
    NonDefaultConstructible& operator = (NonDefaultConstructible const&) = delete;
};

struct TestShared : std::enable_shared_from_this<TestShared>
{
    int hello(int a)
    {
        return 321;
    }
};

int main()
{
    NonDefaultConstructible n{ 1337 };
    {
        rocket::stable_list<NonDefaultConstructible> list;
        list.push_back(std::move(n));
    }
    {
        rocket::stable_list<int> list1{ 1, 2, 3, 4, 5 };
        rocket::stable_list<int> list2{ list1.crbegin(), list1.crend() };

        list2.resize(3);
        std::cout << "List size: " << list2.size() << std::endl;

        for (auto elem : list2)
            std::cout << elem << ' ';

        std::cout << std::endl;
    }

    rocket::signal<int(int)> test;

    test.connect([](int x) {
        return x * 3;
    });
    test.connect([](int x) {
        return x * 1;
    });
    test.connect([](int x) {
        return x * 2;
    });

    {
        // Give me the minimal value of all slots
        typedef rocket::minimum<int> selector;

        std::cout << "Minimum: " << test.invoke<selector>(5) << std::endl;
    }

    {
        // Give me the last result in an optional (default behaviour)
        rocket::optional<int> r{ test(5) };
        std::cout << "Optional: " << *r << std::endl;
    }

    // Connect a new slot via scoped connections
    {
        rocket::scoped_connection scoped{
            test.connect([](int x) {
                return x * 4;
            })
        };

        // Give me all results in a list
        typedef rocket::range<int> selector;

        std::cout << "Range: ";

        for (int x : test.invoke<selector>(5)) {
            std::cout << x << " ";
        }
        std::cout << std::endl;
    }

    {
        // The connections are only connected as long as the testing-object is alive
        Testing testing;

        test.connect(testing, &Testing::hello);
        test.connect(testing, &Testing::hello);

        test(1337);
    }

    {
        auto classPtr = std::make_shared<TestShared>();
        auto f = rocket::bind_weak_ptr(classPtr, &TestShared::hello);
        f(2);
    }

    {
        // A slot that kills itself after the first call
        test.connect([](int) {
            // Get the connection object associated with this slot and kill it
            rocket::current_connection().disconnect();

            std::cout << "called slot disconnect!" << std::endl;
            return 0;
        });

        test(1337);
        test(1337);
    }

    {
        // A slot that aborts emission after the first call
        test.connect([](int) {
            rocket::abort_emission();

            std::cout << "called abort!" << std::endl;
            return 0;
        });

        test.connect([](int) {
            std::cout << "This should never show up, as the previous slot aborts the emission!" << std::endl;
            return 0;
        });

        test(1337);
    }

    std::cin.get();
    return 0;
}



================================================
FILE: rocket.hpp
================================================
/***********************************************************************************
 * rocket - lightweight & fast signal/slots & utility library                      *
 *                                                                                 *
 *   v2.1 - public domain                                                          *
 *   no warranty is offered or implied; use this code at your own risk             *
 *                                                                                 *
 * AUTHORS                                                                         *
 *                                                                                 *
 *   Written by Michael Bleis                                                      *
 *                                                                                 *
 *                                                                                 *
 * LICENSE                                                                         *
 *                                                                                 *
 *   This software is dual-licensed to the public domain and under the following   *
 *   license: you are granted a perpetual, irrevocable license to copy, modify,    *
 *   publish, and distribute this file as you see fit.                             *
 ***********************************************************************************/

#ifndef ROCKET_HPP_INCLUDED
#define ROCKET_HPP_INCLUDED

/***********************************************************************************
 * CONFIGURATION                                                                   *
 * ------------------------------------------------------------------------------- *
 * Define this if you want to disable exceptions.                                  *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_NO_EXCEPTIONS
#    define ROCKET_NO_EXCEPTIONS
#endif

/***********************************************************************************
 * ------------------------------------------------------------------------------- *
 * Define this if you want to disable the `stable_list` collection in rocket.      *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_NO_STABLE_LIST
#    define ROCKET_NO_STABLE_LIST
#endif

/***********************************************************************************
 * ------------------------------------------------------------------------------- *
 * Define this if you want to disable `set_timeout` and `set_interval` features.   *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_NO_TIMERS
#    define ROCKET_NO_TIMERS
#endif

/***********************************************************************************
 * ------------------------------------------------------------------------------- *
 * Define this if you want to disable the connection blocking feature.             *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_NO_BLOCKING_CONNECTIONS
#    define ROCKET_NO_BLOCKING_CONNECTIONS
#endif

/***********************************************************************************
 * ------------------------------------------------------------------------------- *
 * Define this if you want to disable the queued connection feature.               *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_NO_QUEUED_CONNECTIONS
#    define ROCKET_NO_QUEUED_CONNECTIONS
#endif

/***********************************************************************************
 * ------------------------------------------------------------------------------- *
 * Define this if you want to disable the smart pointer extensions feature.        *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_NO_SMARTPOINTER_EXTENSIONS
#    define ROCKET_NO_SMARTPOINTER_EXTENSIONS
#endif

/***********************************************************************************
 * ------------------------------------------------------------------------------- *
 * Redefine this if your compiler doesn't support the `thread_local`-keyword.      *
 * For Visual Studio < 2015 you can define it to `__declspec(thread)` for example. *
 * ------------------------------------------------------------------------------- */

#ifndef ROCKET_THREAD_LOCAL
#    define ROCKET_THREAD_LOCAL thread_local
#endif


#include <atomic>
#include <cassert>
#include <cstddef>
#include <forward_list>
#include <functional>
#include <initializer_list>
#include <limits>
#include <list>
#include <mutex>
#include <optional>
#include <type_traits>
#include <utility>

#ifndef ROCKET_NO_QUEUED_CONNECTIONS
#    include <deque>
#    include <future>
#    include <thread>
#    include <tuple>
#    include <unordered_map>
#endif

#ifndef ROCKET_NO_EXCEPTIONS
#    include <exception>
#endif

#ifndef ROCKET_NO_SMARTPOINTER_EXTENSIONS
#    include <memory>
#endif

#if !defined(ROCKET_NO_STABLE_LIST) || !defined(ROCKET_NO_QUEUED_CONNECTIONS)
#    include <iterator>
#endif

#if !defined(ROCKET_NO_TIMERS) || !defined(ROCKET_NO_QUEUED_CONNECTIONS)
#    include <chrono>
#endif

#if __has_cpp_attribute(likely)
#    define ROCKET_LIKELY [[likely]]
#else
#    define ROCKET_LIKELY
#endif

#if __has_cpp_attribute(unlikely)
#    define ROCKET_UNLIKELY [[unlikely]]
#else
#    define ROCKET_UNLIKELY
#endif

#if __has_cpp_attribute(maybe_unused)
#    define ROCKET_MAYBE_UNUSED [[maybe_unused]]
#else
#    define ROCKET_MAYBE_UNUSED
#endif

#if __has_cpp_attribute(nodiscard)
#    define ROCKET_NODISCARD [[nodiscard]]
#else
#    define ROCKET_NODISCARD
#endif

#if __has_cpp_attribute(no_unique_address)
#    define ROCKET_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#    if defined(_MSC_VER) && __cplusplus >= 202002L
#        define ROCKET_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#    else
#        define ROCKET_NO_UNIQUE_ADDRESS
#    endif
#endif

namespace rocket
{
    template <class T>
    struct minimum
    {
        using value_type = T;
        using result_type = T;

        template <class U>
        void operator()(U&& value)
        {
            if (!has_value || value < current)
            {
                current = std::forward<U>(value);
                has_value = true;
            }
        }

        ROCKET_NODISCARD result_type result()
        {
            return std::move(current);
        }

    private:
        value_type current{};
        bool has_value{ false };
    };

    template <class T>
    struct maximum
    {
        using value_type = T;
        using result_type = T;

        template <class U>
        void operator()(U&& value)
        {
            if (!has_value || value > current)
            {
                current = std::forward<U>(value);
                has_value = true;
            }
        }

        ROCKET_NODISCARD result_type result()
        {
            return std::move(current);
        }

    private:
        value_type current{};
        bool has_value{ false };
    };

    template <class T>
    struct first
    {
        using value_type = T;
        using result_type = T;

        template <class U>
        void operator()(U&& value)
        {
            if (!has_value)
            {
                current = std::forward<U>(value);
                has_value = true;
            }
        }

        ROCKET_NODISCARD result_type result()
        {
            return std::move(current);
        }

    private:
        value_type current{};
        bool has_value{ false };
    };

    template <class T>
    struct last
    {
        using value_type = T;
        using result_type = T;

        template <class U>
        void operator()(U&& value)
        {
            current = std::forward<U>(value);
        }

        ROCKET_NODISCARD result_type result()
        {
            return std::move(current);
        }

    private:
        value_type current{};
    };

    template <class T>
    struct range
    {
        using value_type = T;
        using result_type = std::list<T>;

        template <class U>
        void operator()(U&& value)
        {
            values.emplace_back(std::forward<U>(value));
        }

        ROCKET_NODISCARD result_type result()
        {
            return std::move(values);
        }

    private:
        std::list<value_type> values;
    };

#ifndef ROCKET_NO_EXCEPTIONS
    struct error : std::exception
    {
    };

    struct bad_optional_access final : error
    {
        const char* what() const noexcept override
        {
            return "rocket: Bad optional access.";
        }
    };

    struct invocation_slot_error final : error
    {
        const char* what() const noexcept override
        {
            return "rocket: One of the slots has raised an exception during the signal invocation.";
        }
    };
#endif

    template <class T>
    using optional = std::optional<T>;

    template <class T>
    struct intrusive_ptr final
    {
        using value_type = T;
        using element_type = T;
        using pointer = T*;
        using reference = T&;

        template <class U>
        friend struct intrusive_ptr;

        constexpr intrusive_ptr() noexcept
            : ptr{ nullptr }
        {
        }

        constexpr intrusive_ptr(std::nullptr_t) noexcept
            : ptr{ nullptr }
        {
        }

        explicit intrusive_ptr(pointer p) noexcept
            : ptr{ p }
        {
            if (ptr)
            {
                ptr->addref();
            }
        }

        intrusive_ptr(intrusive_ptr const& p) noexcept
            : ptr{ p.ptr }
        {
            if (ptr)
            {
                ptr->addref();
            }
        }

        intrusive_ptr(intrusive_ptr&& p) noexcept
            : ptr{ p.ptr }
        {
            p.ptr = nullptr;
        }

        template <class U>
        explicit intrusive_ptr(intrusive_ptr<U> const& p) noexcept
            : ptr{ p.ptr }
        {
            if (ptr)
            {
                ptr->addref();
            }
        }

        template <class U>
        explicit intrusive_ptr(intrusive_ptr<U>&& p) noexcept
            : ptr{ p.ptr }
        {
            p.ptr = nullptr;
        }

        ~intrusive_ptr() noexcept
        {
            if (ptr)
            {
                ptr->release();
            }
        }

        ROCKET_NODISCARD pointer get() const noexcept
        {
            return ptr;
        }

        pointer detach() noexcept
        {
            pointer p = ptr;
            ptr = nullptr;
            return p;
        }

        ROCKET_NODISCARD operator pointer() const noexcept
        {
            return ptr;
        }

        ROCKET_NODISCARD pointer operator->() const noexcept
        {
            assert(ptr != nullptr);
            return ptr;
        }

        ROCKET_NODISCARD reference operator*() const noexcept
        {
            assert(ptr != nullptr);
            return *ptr;
        }

        ROCKET_NODISCARD pointer* operator&() noexcept
        {
            assert(ptr == nullptr);
            return &ptr;
        }

        ROCKET_NODISCARD pointer const* operator&() const noexcept
        {
            return &ptr;
        }

        intrusive_ptr& operator=(pointer p) noexcept
        {
            if (p)
            {
                p->addref();
            }
            pointer o = ptr;
            ptr = p;
            if (o)
            {
                o->release();
            }
            return *this;
        }

        intrusive_ptr& operator=(std::nullptr_t) noexcept
        {
            if (ptr)
            {
                ptr->release();
                ptr = nullptr;
            }
            return *this;
        }

        intrusive_ptr& operator=(intrusive_ptr const& p) noexcept
        {
            return (*this = p.ptr);
        }

        intrusive_ptr& operator=(intrusive_ptr&& p) noexcept
        {
            if (ptr)
            {
                ptr->release();
            }
            ptr = p.ptr;
            p.ptr = nullptr;
            return *this;
        }

        template <class U>
        intrusive_ptr& operator=(intrusive_ptr<U> const& p) noexcept
        {
            return (*this = p.ptr);
        }

        template <class U>
        intrusive_ptr& operator=(intrusive_ptr<U>&& p) noexcept
        {
            if (ptr)
            {
                ptr->release();
            }
            ptr = p.ptr;
            p.ptr = nullptr;
            return *this;
        }

        void swap(pointer* pp) noexcept
        {
            pointer p = ptr;
            ptr = *pp;
            *pp = p;
        }

        void swap(intrusive_ptr& p) noexcept
        {
            swap(&p.ptr);
        }

    private:
        pointer ptr;
    };

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator==(intrusive_ptr<T> const& a, intrusive_ptr<U> const& b) noexcept
    {
        return a.get() == b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator==(intrusive_ptr<T> const& a, U* b) noexcept
    {
        return a.get() == b;
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator==(T* a, intrusive_ptr<U> const& b) noexcept
    {
        return a == b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator!=(intrusive_ptr<T> const& a, intrusive_ptr<U> const& b) noexcept
    {
        return a.get() != b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator!=(intrusive_ptr<T> const& a, U* b) noexcept
    {
        return a.get() != b;
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator!=(T* a, intrusive_ptr<U> const& b) noexcept
    {
        return a != b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator<(intrusive_ptr<T> const& a, intrusive_ptr<U> const& b) noexcept
    {
        return a.get() < b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator<(intrusive_ptr<T> const& a, U* b) noexcept
    {
        return a.get() < b;
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator<(T* a, intrusive_ptr<U> const& b) noexcept
    {
        return a < b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator<=(intrusive_ptr<T> const& a, intrusive_ptr<U> const& b) noexcept
    {
        return a.get() <= b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator<=(intrusive_ptr<T> const& a, U* b) noexcept
    {
        return a.get() <= b;
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator<=(T* a, intrusive_ptr<U> const& b) noexcept
    {
        return a <= b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator>(intrusive_ptr<T> const& a, intrusive_ptr<U> const& b) noexcept
    {
        return a.get() > b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator>(intrusive_ptr<T> const& a, U* b) noexcept
    {
        return a.get() > b;
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator>(T* a, intrusive_ptr<U> const& b) noexcept
    {
        return a > b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator>=(intrusive_ptr<T> const& a, intrusive_ptr<U> const& b) noexcept
    {
        return a.get() >= b.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator>=(intrusive_ptr<T> const& a, U* b) noexcept
    {
        return a.get() >= b;
    }

    template <class T, class U>
    ROCKET_NODISCARD inline bool operator>=(T* a, intrusive_ptr<U> const& b) noexcept
    {
        return a >= b.get();
    }

    template <class T>
    ROCKET_NODISCARD inline bool operator==(intrusive_ptr<T> const& a, std::nullptr_t) noexcept
    {
        return a.get() == nullptr;
    }

    template <class T>
    ROCKET_NODISCARD inline bool operator==(std::nullptr_t, intrusive_ptr<T> const& b) noexcept
    {
        return nullptr == b.get();
    }

    template <class T>
    ROCKET_NODISCARD inline bool operator!=(intrusive_ptr<T> const& a, std::nullptr_t) noexcept
    {
        return a.get() != nullptr;
    }

    template <class T>
    ROCKET_NODISCARD inline bool operator!=(std::nullptr_t, intrusive_ptr<T> const& b) noexcept
    {
        return nullptr != b.get();
    }

    template <class T>
    ROCKET_NODISCARD inline T* get_pointer(intrusive_ptr<T> const& p) noexcept
    {
        return p.get();
    }

    template <class T, class U>
    ROCKET_NODISCARD inline intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const& p) noexcept
    {
        return intrusive_ptr<T>{ static_cast<T*>(p.get()) };
    }

    template <class T, class U>
    ROCKET_NODISCARD inline intrusive_ptr<T> const_pointer_cast(intrusive_ptr<U> const& p) noexcept
    {
        return intrusive_ptr<T>{ const_cast<T*>(p.get()) };
    }

    template <class T, class U>
    ROCKET_NODISCARD inline intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const& p) noexcept
    {
        return intrusive_ptr<T>{ dynamic_cast<T*>(p.get()) };
    }

    template <class T, class U>
    ROCKET_NODISCARD inline intrusive_ptr<T> reinterpret_pointer_cast(intrusive_ptr<U> const& p) noexcept
    {
        return intrusive_ptr<T>{ reinterpret_cast<T*>(p.get()) };
    }

    struct ref_count final
    {
        unsigned long addref() noexcept
        {
            return ++count;
        }

        unsigned long release() noexcept
        {
            return --count;
        }

        ROCKET_NODISCARD unsigned long get() const noexcept
        {
            return count;
        }

    private:
        unsigned long count{ 0 };
    };

    struct ref_count_atomic final
    {
        unsigned long addref() noexcept
        {
            return ++count;
        }

        unsigned long release() noexcept
        {
            return --count;
        }

        ROCKET_NODISCARD unsigned long get() const noexcept
        {
            return count.load(std::memory_order_relaxed);
        }

    private:
        std::atomic<unsigned long> count{ 0 };
    };

    template <class Class, class RefCount = ref_count>
    struct ref_counted
    {
        ref_counted() noexcept = default;

        ref_counted(ref_counted const&) noexcept
        {
        }

        ref_counted& operator=(ref_counted const&) noexcept
        {
            return *this;
        }

        void addref() noexcept
        {
            count.addref();
        }

        void release() noexcept
        {
            if (count.release() == 0)
            {
                delete static_cast<Class*>(this);
            }
        }

    protected:
        ~ref_counted() noexcept = default;

    private:
        RefCount count{};
    };

#ifndef ROCKET_NO_STABLE_LIST
    template <class T>
    class stable_list final
    {
        struct link_element final : ref_counted<link_element>
        {
            link_element() noexcept = default;

            ~link_element() noexcept
            {
                if (next)
                {                 // If we have a next element upon destruction
                    value()->~T();// then this link is used, else it's a dummy
                }
            }

            template <class... Args>
            void construct(Args&&... args) noexcept(noexcept(T{ std::forward<Args>(args)... }))
            {
                new (storage()) T{ std::forward<Args>(args)... };
            }

            T* value() noexcept
            {
                return std::launder(static_cast<T*>(storage()));
            }

            void* storage() noexcept
            {
                return static_cast<void*>(&buffer);
            }

            intrusive_ptr<link_element> next;
            intrusive_ptr<link_element> prev;

            alignas(T) std::byte buffer[sizeof(T)];
        };

        intrusive_ptr<link_element> head;
        intrusive_ptr<link_element> tail;

        std::size_t elements;

    public:
        template <class U>
        struct iterator_base final
        {
            using iterator_category = std::bidirectional_iterator_tag;
            using value_type = std::remove_const_t<U>;
            using difference_type = ptrdiff_t;
            using reference = U&;
            using pointer = U*;

            template <class V>
            friend class stable_list;

            iterator_base() noexcept = default;
            ~iterator_base() noexcept = default;

            iterator_base(iterator_base const& i) noexcept
                : element{ i.element }
            {
            }

            iterator_base(iterator_base&& i) noexcept
                : element{ std::move(i.element) }
            {
            }

            template <class V>
            explicit iterator_base(iterator_base<V> const& i) noexcept
                : element{ i.element }
            {
            }

            template <class V>
            explicit iterator_base(iterator_base<V>&& i) noexcept
                : element{ std::move(i.element) }
            {
            }

            iterator_base& operator=(iterator_base const& i) noexcept
            {
                element = i.element;
                return *this;
            }

            iterator_base& operator=(iterator_base&& i) noexcept
            {
                element = std::move(i.element);
                return *this;
            }

            template <class V>
            iterator_base& operator=(iterator_base<V> const& i) noexcept
            {
                element = i.element;
                return *this;
            }

            template <class V>
            iterator_base& operator=(iterator_base<V>&& i) noexcept
            {
                element = std::move(i.element);
                return *this;
            }

            iterator_base& operator++() noexcept
            {
                element = element->next;
                return *this;
            }

            iterator_base operator++(int) noexcept
            {
                iterator_base i{ *this };
                ++(*this);
                return i;
            }

            iterator_base& operator--() noexcept
            {
                element = element->prev;
                return *this;
            }

            iterator_base operator--(int) noexcept
            {
                iterator_base i{ *this };
                --(*this);
                return i;
            }

            ROCKET_NODISCARD reference operator*() const noexcept
            {
                return *element->value();
            }

            ROCKET_NODISCARD pointer operator->() const noexcept
            {
                return element->value();
            }

            template <class V>
            ROCKET_NODISCARD bool operator==(iterator_base<V> const& i) const noexcept
            {
                return element == i.element;
            }

            template <class V>
            ROCKET_NODISCARD bool operator!=(iterator_base<V> const& i) const noexcept
            {
                return element != i.element;
            }

        private:
            intrusive_ptr<link_element> element;

            iterator_base(link_element* p) noexcept
                : element{ p }
            {
            }
        };

        using value_type = T;
        using reference = T&;
        using pointer = T*;
        using const_pointer = const T*;

        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t;

        using iterator = iterator_base<T>;
        using const_iterator = iterator_base<T const>;
        using reverse_iterator = std::reverse_iterator<iterator>;
        using const_reverse_iterator = std::reverse_iterator<const_iterator>;

        stable_list()
        {
            init();
        }

        ~stable_list()
        {
            destroy();
        }

        stable_list(stable_list const& l)
        {
            init();
            insert(end(), l.begin(), l.end());
        }

        stable_list(stable_list&& l)
            : head{ std::move(l.head) }
            , tail{ std::move(l.tail) }
            , elements{ l.elements }
        {
            l.init();
        }

        stable_list(std::initializer_list<value_type> l)
        {
            init();
            insert(end(), l.begin(), l.end());
        }

        template <class Iterator>
        stable_list(Iterator ibegin, Iterator iend)
        {
            init();
            insert(end(), ibegin, iend);
        }

        explicit stable_list(size_type count, value_type const& value)
        {
            init();
            insert(end(), count, value);
        }

        explicit stable_list(size_type count)
        {
            init();
            insert(end(), count, value_type{});
        }

        stable_list& operator=(stable_list const& l)
        {
            if (this != &l)
            {
                clear();
                insert(end(), l.begin(), l.end());
            }
            return *this;
        }

        stable_list& operator=(stable_list&& l)
        {
            destroy();
            head = std::move(l.head);
            tail = std::move(l.tail);
            elements = l.elements;
            l.init();
            return *this;
        }

        ROCKET_NODISCARD iterator begin() noexcept
        {
            return iterator{ head->next };
        }

        ROCKET_NODISCARD iterator end() noexcept
        {
            return iterator{ tail };
        }

        ROCKET_NODISCARD const_iterator begin() const noexcept
        {
            return const_iterator{ head->next };
        }

        ROCKET_NODISCARD const_iterator end() const noexcept
        {
            return const_iterator{ tail };
        }

        ROCKET_NODISCARD const_iterator cbegin() const noexcept
        {
            return const_iterator{ head->next };
        }

        ROCKET_NODISCARD const_iterator cend() const noexcept
        {
            return const_iterator{ tail };
        }

        ROCKET_NODISCARD reverse_iterator rbegin() noexcept
        {
            return reverse_iterator{ end() };
        }

        ROCKET_NODISCARD reverse_iterator rend() noexcept
        {
            return reverse_iterator{ begin() };
        }

        ROCKET_NODISCARD const_reverse_iterator rbegin() const noexcept
        {
            return const_reverse_iterator{ cend() };
        }

        ROCKET_NODISCARD const_reverse_iterator rend() const noexcept
        {
            return const_reverse_iterator{ cbegin() };
        }

        ROCKET_NODISCARD const_reverse_iterator crbegin() const noexcept
        {
            return const_reverse_iterator{ cend() };
        }

        ROCKET_NODISCARD const_reverse_iterator crend() const noexcept
        {
            return const_reverse_iterator{ cbegin() };
        }

        ROCKET_NODISCARD reference front() noexcept
        {
            return *begin();
        }

        ROCKET_NODISCARD reference back() noexcept
        {
            return *rbegin();
        }

        ROCKET_NODISCARD value_type const& front() const noexcept
        {
            return *cbegin();
        }

        ROCKET_NODISCARD value_type const& back() const noexcept
        {
            return *crbegin();
        }

        ROCKET_NODISCARD bool empty() const noexcept
        {
            return cbegin() == cend();
        }

        void clear() noexcept
        {
            erase(begin(), end());
        }

        void push_front(value_type const& value)
        {
            insert(begin(), value);
        }

        void push_front(value_type&& value)
        {
            insert(begin(), std::move(value));
        }

        void push_back(value_type const& value)
        {
            insert(end(), value);
        }

        void push_back(value_type&& value)
        {
            insert(end(), std::move(value));
        }

        template <class... Args>
        reference emplace_front(Args&&... args)
        {
            return *emplace(begin(), std::forward<Args>(args)...);
        }

        template <class... Args>
        reference emplace_back(Args&&... args)
        {
            return *emplace(end(), std::forward<Args>(args)...);
        }

        void pop_front() noexcept
        {
            head->next = head->next->next;
            head->next->prev = head;
            --elements;
        }

        void pop_back() noexcept
        {
            tail->prev = tail->prev->prev;
            tail->prev->next = tail;
            --elements;
        }

        iterator insert(iterator const& pos, value_type const& value)
        {
            return iterator{ make_link(pos.element, value) };
        }

        iterator insert(iterator const& pos, value_type&& value)
        {
            return iterator{ make_link(pos.element, std::move(value)) };
        }

        template <class Iterator>
        iterator insert(iterator const& pos, Iterator ibegin, Iterator iend)
        {
            iterator iter{ end() };
            while (ibegin != iend)
            {
                iterator tmp{ insert(pos, *ibegin++) };
                if (iter == end())
                {
                    iter = std::move(tmp);
                }
            }
            return iter;
        }

        iterator insert(iterator const& pos, std::initializer_list<value_type> l)
        {
            return insert(pos, l.begin(), l.end());
        }

        iterator insert(iterator const& pos, size_type count, value_type const& value)
        {
            iterator iter{ end() };
            for (size_type i = 0; i < count; ++i)
            {
                iterator tmp{ insert(pos, value) };
                if (iter == end())
                {
                    iter = std::move(tmp);
                }
            }
            return iter;
        }

        template <class... Args>
        iterator emplace(iterator const& pos, Args&&... args)
        {
            return iterator{ make_link(pos.element, std::forward<Args>(args)...) };
        }

        void append(value_type const& value)
        {
            insert(end(), value);
        }

        void append(value_type&& value)
        {
            insert(end(), std::move(value));
        }

        template <class Iterator>
        void append(Iterator ibegin, Iterator iend)
        {
            insert(end(), ibegin, iend);
        }

        void append(std::initializer_list<value_type> l)
        {
            insert(end(), std::move(l));
        }

        void append(size_type count, value_type const& value)
        {
            insert(end(), count, value);
        }

        void assign(size_type count, value_type const& value)
        {
            clear();
            append(count, value);
        }

        template <class Iterator>
        void assign(Iterator ibegin, Iterator iend)
        {
            clear();
            append(ibegin, iend);
        }

        void assign(std::initializer_list<value_type> l)
        {
            clear();
            append(std::move(l));
        }

        void resize(size_type count)
        {
            resize(count, value_type{});
        }

        void resize(size_type count, value_type const& value)
        {
            size_type cursize = size();
            if (count > cursize)
            {
                for (size_type i = cursize; i < count; ++i)
                {
                    push_back(value);
                }
            }
            else
            {
                for (size_type i = count; i < cursize; ++i)
                {
                    pop_back();
                }
            }
        }

        ROCKET_NODISCARD size_type size() const noexcept
        {
            return elements;
        }

        ROCKET_NODISCARD size_type max_size() const noexcept
        {
            return std::numeric_limits<size_type>::max();
        }

        iterator erase(iterator const& pos) noexcept
        {
            pos.element->prev->next = pos.element->next;
            pos.element->next->prev = pos.element->prev;
            --elements;
            return iterator{ pos.element->next };
        }

        iterator erase(iterator const& first, iterator const& last) noexcept
        {
            auto link = first.element;
            while (link != last.element)
            {
                auto next = link->next;
                link->prev = first.element->prev;
                link->next = last.element;
                --elements;
                link = std::move(next);
            }

            first.element->prev->next = last.element;
            last.element->prev = first.element->prev;
            return last;
        }

        void remove(value_type const& value) noexcept
        {
            for (auto itr = begin(); itr != end(); ++itr)
            {
                if (*itr == value)
                {
                    erase(itr);
                }
            }
        }

        template <class Predicate>
        void remove_if(Predicate const& pred)
        {
            for (auto itr = begin(); itr != end(); ++itr)
            {
                if (pred(*itr))
                {
                    erase(itr);
                }
            }
        }

        void swap(stable_list& other) noexcept
        {
            if (this != &other)
            {
                head.swap(other.head);
                tail.swap(other.tail);
                std::swap(elements, other.elements);
            }
        }

    private:
        void init()
        {
            head = new link_element;
            tail = new link_element;
            head->next = tail;
            tail->prev = head;
            elements = 0;
        }

        void destroy()
        {
            clear();
            head->next = nullptr;
            tail->prev = nullptr;
        }

        template <class... Args>
        link_element* make_link(link_element* l, Args&&... args)
        {
            intrusive_ptr<link_element> link{ new link_element };
            link->construct(std::forward<Args>(args)...);
            link->prev = l->prev;
            link->next = l;
            link->prev->next = link;
            link->next->prev = link;
            ++elements;
            return link;
        }
    };
#endif//~ ROCKET_NO_STABLE_LIST

    template <bool ThreadSafe>
    struct threading_policy
    {
        static constexpr bool is_thread_safe = ThreadSafe;
    };

    using thread_safe_policy = threading_policy<true>;
    using thread_unsafe_policy = threading_policy<false>;

    namespace detail
    {
        template <class>
        struct expand_signature;

        template <class R, class... Args>
        struct expand_signature<R(Args...)> final
        {
            using return_type = R;
            using signature_type = R(Args...);
        };

        template <class Signature>
        using get_return_type = typename expand_signature<Signature>::return_type;

        struct shared_lock final : ref_counted<shared_lock, ref_count_atomic>
        {
            std::mutex mutex;
        };

        template <class ThreadingPolicy>
        struct shared_lock_state;

        template <>
        struct shared_lock_state<thread_unsafe_policy> final
        {
            using threading_policy = thread_unsafe_policy;

            constexpr void lock() noexcept
            {
            }

            constexpr bool try_lock() noexcept
            {
                return true;
            }

            constexpr void unlock() noexcept
            {
            }

            constexpr void swap(shared_lock_state&) noexcept
            {
            }
        };

        template <>
        struct shared_lock_state<thread_safe_policy> final
        {
            using threading_policy = thread_safe_policy;

            shared_lock_state()
                : lock_primitive{ new shared_lock }
            {
            }

            ~shared_lock_state() = default;

            shared_lock_state(shared_lock_state const& s)
                : lock_primitive{ s.lock_primitive }
            {
            }

            shared_lock_state(shared_lock_state&& s)
                : lock_primitive{ std::move(s.lock_primitive) }
            {
                s.lock_primitive = new shared_lock;
            }

            shared_lock_state& operator=(shared_lock_state const& rhs)
            {
                lock_primitive = rhs.lock_primitive;
                return *this;
            }

            shared_lock_state& operator=(shared_lock_state&& rhs)
            {
                lock_primitive = std::move(rhs.lock_primitive);
                rhs.lock_primitive = new shared_lock;
                return *this;
            }

            void lock()
            {
                lock_primitive->mutex.lock();
            }

            bool try_lock()
            {
                return lock_primitive->mutex.try_lock();
            }

            void unlock()
            {
                lock_primitive->mutex.unlock();
            }

            void swap(shared_lock_state& s) noexcept
            {
                lock_primitive.swap(s.lock_primitive);
            }

            intrusive_ptr<shared_lock> lock_primitive;
        };

        template <class ThreadingPolicy>
        struct connection_base;

        template <>
        struct connection_base<thread_unsafe_policy> : ref_counted<connection_base<thread_unsafe_policy>>
        {
            using threading_policy = thread_unsafe_policy;

            virtual ~connection_base() noexcept = default;

            ROCKET_NODISCARD bool is_connected() const noexcept
            {
                return prev != nullptr;
            }

            void disconnect() noexcept
            {
                if (prev != nullptr)
                {
                    next->prev = prev;
                    prev->next = next;

                    // To mark a connection as disconnected, just set its prev-link to null but
                    // leave the next link alive so we can still traverse through the connections
                    // if the slot gets disconnected during signal emit.
                    prev = nullptr;
                }
            }

#ifndef ROCKET_NO_QUEUED_CONNECTIONS
            ROCKET_NODISCARD std::thread::id get_tid() const noexcept
            {
                return std::thread::id{};
            }

            ROCKET_NODISCARD constexpr bool is_queued() const noexcept
            {
                return false;
            }
#endif//~ ROCKET_NO_QUEUED_CONNECTIONS

#ifndef ROCKET_NO_BLOCKING_CONNECTIONS
            void block() noexcept
            {
                ++block_count;
            }

            void unblock() noexcept
            {
                if (block_count > 0)
                {
                    --block_count;
                }
            }

            ROCKET_NODISCARD bool is_blocked() const noexcept
            {
                return block_count > 0;
            }

            unsigned long block_count{ 0 };
#endif//~ ROCKET_NO_BLOCKING_CONNECTIONS

            intrusive_ptr<connection_base> next;
            intrusive_ptr<connection_base> prev;
        };

        template <>
        struct connection_base<thread_safe_policy> : ref_counted<connection_base<thread_safe_policy>, ref_count_atomic>
        {
            using threading_policy = thread_safe_policy;

            virtual ~connection_base() noexcept = default;

            ROCKET_NODISCARD bool is_connected() const noexcept
            {
                return prev != nullptr;
            }

            void disconnect() noexcept
            {
                std::scoped_lock<std::mutex> guard{ lock->mutex };

                if (prev != nullptr)
                {
                    next->prev = prev;
                    prev->next = next;

                    // To mark a connection as disconnected, just set its prev-link to null but
                    // leave the next link alive so we can still traverse through the connections
                    // if the slot gets disconnected during signal emit.
                    prev = nullptr;
                }
            }

#ifndef ROCKET_NO_QUEUED_CONNECTIONS
            ROCKET_NODISCARD std::thread::id const& get_tid() const noexcept
            {
                return thread_id;
            }

            ROCKET_NODISCARD bool is_queued() const noexcept
            {
                return thread_id != std::thread::id{} && thread_id != std::this_thread::get_id();
            }
#endif//~ ROCKET_NO_QUEUED_CONNECTIONS

#ifndef ROCKET_NO_BLOCKING_CONNECTIONS
            void block() noexcept
            {
                std::scoped_lock<std::mutex> guard{ lock->mutex };
                ++block_count;
            }

            void unblock() noexcept
            {
                std::scoped_lock<std::mutex> guard{ lock->mutex };
                if (block_count > 0)
                {
                    --block_count;
                }
            }

            ROCKET_NODISCARD bool is_blocked() const noexcept
            {
                return (*static_cast<unsigned long const volatile*>(&block_count)) > 0;
            }

            unsigned long block_count{ 0 };
#endif//~ ROCKET_NO_BLOCKING_CONNECTIONS

            intrusive_ptr<connection_base> next;
            intrusive_ptr<connection_base> prev;

            intrusive_ptr<shared_lock> lock;

#ifndef ROCKET_NO_QUEUED_CONNECTIONS
            std::thread::id thread_id;
#endif
        };

        template <class ThreadingPolicy, class T>
        struct functional_connection : connection_base<ThreadingPolicy>
        {
            std::function<T> slot;
        };

#ifndef ROCKET_NO_TIMERS
        struct timed_connection final : functional_connection<thread_unsafe_policy, void()>
        {
            std::chrono::time_point<std::chrono::steady_clock> expires_at;
            std::chrono::microseconds interval;
        };
#endif
        // Should make sure that this is POD
        struct thread_local_data final
        {
            void* current_connection;
            bool is_thread_safe_connection;
            bool emission_aborted;
        };

        ROCKET_NODISCARD inline thread_local_data* get_thread_local_data() noexcept
        {
            static ROCKET_THREAD_LOCAL thread_local_data th;
            return &th;
        }

        struct connection_scope final
        {
            connection_scope(void* base, bool is_thread_safe, thread_local_data* th) noexcept
                : th{ th }
                , prev{ th->current_connection }
                , prevThreadSafe{ th->is_thread_safe_connection }
            {
                th->current_connection = base;
                th->is_thread_safe_connection = is_thread_safe;
            }

            ~connection_scope() noexcept
            {
                th->current_connection = prev;
                th->is_thread_safe_connection = prevThreadSafe;
            }

            thread_local_data* th;
            void* prev;
            bool prevThreadSafe;
        };

        struct abort_scope final
        {
            abort_scope(thread_local_data* th) noexcept
                : th{ th }
                , prev{ th->emission_aborted }
            {
                th->emission_aborted = false;
            }

            ~abort_scope() noexcept
            {
                th->emission_aborted = prev;
            }

            thread_local_data* th;
            bool prev;
        };

#ifndef ROCKET_NO_SMARTPOINTER_EXTENSIONS
        template <class Instance, class Class, class R, class... Args>
        struct weak_mem_fn final
        {
            explicit weak_mem_fn(std::weak_ptr<Instance> c, R (Class::*method)(Args...))
                : weak{ std::move(c) }
                , method{ method }
            {
            }

            template <class... Args1>
            auto operator()(Args1&&... args) const
            {
                if constexpr (std::is_void_v<R>)
                {
                    if (auto strong = weak.lock())
                    {
                        (strong.get()->*method)(std::forward<Args1>(args)...);
                    }
                }
                else
                {
                    if (auto strong = weak.lock())
                    {
                        return optional<R>{ (strong.get()->*method)(std::forward<Args1>(args)...) };
                    }
                    return optional<R>{};
                }
            }

        private:
            std::weak_ptr<Instance> weak;
            R (Class::*method)(Args...);
        };

        template <class Instance, class Class, class R, class... Args>
        struct shared_mem_fn final
        {
            explicit shared_mem_fn(std::shared_ptr<Instance> c, R (Class::*method)(Args...))
                : shared{ std::move(c) }
                , method{ method }
            {
            }

            template <class... Args1>
            R operator()(Args1&&... args) const
            {
                return (shared.get()->*method)(std::forward<Args1>(args)...);
            }

        private:
            std::shared_ptr<Instance> shared;
            R (Class::*method)(Args...);
        };
#endif//~ ROCKET_NO_SMARTPOINTER_EXTENSIONS
    } // namespace detail

#ifndef ROCKET_NO_SMARTPOINTER_EXTENSIONS
    template <class Instance, class Class, class R, class... Args>
    inline auto bind_weak_ptr(std::weak_ptr<Instance> c, R (Class::*method)(Args...))
    {
        return detail::weak_mem_fn<Instance, Class, R, Args...>{ std::move(c), method };
    }

    template <class Instance, class Class, class R, class... Args>
    inline auto bind_weak_ptr(std::shared_ptr<Instance> c, R (Class::*method)(Args...))
    {
        return detail::weak_mem_fn<Instance, Class, R, Args...>{ std::move(c), method };
    }

    template <class Instance, class Class, class R, class... Args>
    inline auto bind_shared_ptr(std::shared_ptr<Instance> c, R (Class::*method)(Args...))
    {
        return detail::shared_mem_fn<Instance, Class, R, Args...>{ std::move(c), method };
    }
#endif

    struct connection
    {
        connection() noexcept
            : base{ nullptr }
            , is_thread_safe{ false }
        {
        }

        ~connection() noexcept
        {
            release();
        }

        connection(connection&& rhs) noexcept
            : base{ rhs.base }
            , is_thread_safe{ rhs.is_thread_safe }
        {
            rhs.base = nullptr;
            rhs.is_thread_safe = false;
        }

        connection(connection const& rhs) noexcept
            : base{ rhs.base }
            , is_thread_safe{ rhs.is_thread_safe }
        {
            addref();
        }

        explicit connection(void* base, bool is_thread_safe) noexcept
            : base{ base }
            , is_thread_safe{ is_thread_safe }
        {
            addref();
        }

        connection& operator=(connection&& rhs) noexcept
        {
            release();
            base = rhs.base;
            is_thread_safe = rhs.is_thread_safe;
            rhs.base = nullptr;
            rhs.is_thread_safe = false;
            return *this;
        }

        connection& operator=(connection const& rhs) noexcept
        {
            if (this != &rhs)
            {
                release();
                base = rhs.base;
                is_thread_safe = rhs.is_thread_safe;
                addref();
            }
            return *this;
        }

        ROCKET_NODISCARD bool operator==(connection const& rhs) const noexcept
        {
            return base == rhs.base && is_thread_safe == rhs.is_thread_safe;
        }

        ROCKET_NODISCARD bool operator!=(connection const& rhs) const noexcept
        {
            return base != rhs.base || is_thread_safe != rhs.is_thread_safe;
        }

        ROCKET_NODISCARD explicit operator bool() const noexcept
        {
            return is_connected();
        }

        ROCKET_NODISCARD bool is_connected() const noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    return std::launder(safe)->is_connected();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    return std::launder(unsafe)->is_connected();
                }
            }
            return false;
        }

#ifndef ROCKET_NO_BLOCKING_CONNECTIONS
        ROCKET_NODISCARD bool is_blocked() const noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    return std::launder(safe)->is_blocked();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    return std::launder(unsafe)->is_blocked();
                }
            }
            return false;
        }

        void block() noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    std::launder(safe)->block();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    std::launder(unsafe)->block();
                }
            }
        }

        void unblock() noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    std::launder(safe)->unblock();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    std::launder(unsafe)->unblock();
                }
            }
        }
#endif//~ ROCKET_NO_BLOCKING_CONNECTIONS

        void disconnect() noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    std::launder(safe)->disconnect();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    std::launder(unsafe)->disconnect();
                }

                release();
            }
        }

        void swap(connection& other) noexcept
        {
            if (this != &other)
            {
                void* tmp_base{ base };
                bool tmp_is_thread_safe{ is_thread_safe };
                base = other.base;
                is_thread_safe = other.is_thread_safe;
                other.base = tmp_base;
                other.is_thread_safe = tmp_is_thread_safe;
            }
        }

    private:
        void* base;
        bool is_thread_safe;

        void addref() noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    std::launder(safe)->addref();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    std::launder(unsafe)->addref();
                }
            }
        }

        void release() noexcept
        {
            if (base != nullptr)
            {
                if (is_thread_safe)
                {
                    auto safe{ static_cast<detail::connection_base<thread_safe_policy>*>(base) };
                    std::launder(safe)->release();
                }
                else
                {
                    auto unsafe{ static_cast<detail::connection_base<thread_unsafe_policy>*>(base) };
                    std::launder(unsafe)->release();
                }

                base = nullptr;
                is_thread_safe = false;
            }
        }
    };

    struct scoped_connection final : connection
    {
        scoped_connection() noexcept = default;

        ~scoped_connection() noexcept
        {
            disconnect();
        }

        scoped_connection(connection const& rhs) noexcept
            : connection{ rhs }
        {
        }

        scoped_connection(connection&& rhs) noexcept
            : connection{ std::move(rhs) }
        {
        }

        scoped_connection(scoped_connection&& rhs) noexcept
            : connection{ std::move(rhs) }
        {
        }

        scoped_connection& operator=(connection&& rhs) noexcept
        {
            disconnect();

            connection::operator=(std::move(rhs));
            return *this;
        }

        scoped_connection& operator=(scoped_connection&& rhs) noexcept
        {
            disconnect();

            connection::operator=(std::move(rhs));
            return *this;
        }

        scoped_connection& operator=(connection const& rhs) noexcept
        {
            disconnect();

            connection::operator=(rhs);
            return *this;
        }

    private:
        scoped_connection(scoped_connection const&) = delete;

        scoped_connection& operator=(scoped_connection const&) = delete;
    };

    struct scoped_connection_container final
    {
        scoped_connection_container() = default;
        ~scoped_connection_container() = default;

        scoped_connection_container(scoped_connection_container&& s)
            : connections{ std::move(s.connections) }
        {
        }

        scoped_connection_container& operator=(scoped_connection_container&& rhs)
        {
            connections = std::move(rhs.connections);
            return *this;
        }

        scoped_connection_container(std::initializer_list<connection> list)
        {
            append(list);
        }

        void append(connection const& conn)
        {
            connections.push_front(scoped_connection{ conn });
        }

        void append(std::initializer_list<connection> list)
        {
            for (auto const& connection : list)
            {
                append(connection);
            }
        }

        scoped_connection_container& operator+=(connection const& conn)
        {
            append(conn);
            return *this;
        }

        scoped_connection_container& operator+=(std::initializer_list<connection> list)
        {
            for (auto const& connection : list)
            {
                append(connection);
            }
            return *this;
        }

        void disconnect() noexcept
        {
            connections.clear();
        }

    private:
        scoped_connection_container(scoped_connection_container const&) = delete;
        scoped_connection_container& operator=(scoped_connection_container const&) = delete;

        std::forward_list<scoped_connection> connections;
    };

    struct trackable
    {
        void add_tracked_connection(connection const& conn)
        {
            container.append(conn);
        }

        void disconnect_tracked_connections() noexcept
        {
            container.disconnect();
        }

    private:
        scoped_connection_container container;
    };

    ROCKET_NODISCARD inline connection current_connection() noexcept
    {
        auto th = detail::get_thread_local_data();
        return connection{ th->current_connection, th->is_thread_safe_connection };
    }

    inline void abort_emission() noexcept
    {
        detail::get_thread_local_data()->emission_aborted = true;
    }

#ifndef ROCKET_NO_BLOCKING_CONNECTIONS
    struct scoped_connection_blocker final
    {
        scoped_connection_blocker(connection c) noexcept
            : conn{ std::move(c) }
        {
            conn.block();
        }

        ~scoped_connection_blocker() noexcept
        {
            conn.unblock();
        }

    private:
        scoped_connection_blocker(scoped_connection_blocker const&) = delete;
        scoped_connection_blocker& operator=(scoped_connection_blocker const&) = delete;

        connection conn;
    };
#endif//~ ROCKET_NO_BLOCKING_CONNECTIONS

    namespace detail
    {
#ifndef ROCKET_NO_TIMERS
        struct timer_queue final
        {
            using slot_type = std::function<void()>;

            timer_queue()
            {
                init();
            }

            ~timer_queue() noexcept
            {
                destroy();
            }

            timer_queue(timer_queue&& q)
                : head{ std::move(q.head) }
                , tail{ std::move(q.tail) }
            {
                q.init();
            }

            timer_queue(timer_queue const& q)
            {
                init();
                copy(q);
            }

            timer_queue& operator=(timer_queue&& rhs)
            {
                destroy();
                head = std::move(rhs.head);
                tail = std::move(rhs.tail);
                rhs.init();
                return *this;
            }

            timer_queue& operator=(timer_queue const& rhs)
            {
                if (this != &rhs)
                {
                    clear();
                    copy(rhs);
                }
                return *this;
            }

            template <class Rep = unsigned long, class Period = std::milli>
            connection set_interval(slot_type slot, std::chrono::duration<Rep, Period> const& interval)
            {
                assert(slot != nullptr);

                auto expires_at = std::chrono::steady_clock::now() + interval;
                auto interval_microsecs = std::chrono::duration_cast<std::chrono::microseconds>(interval);
                connection_base* base
                    = make_link(tail, std::move(slot), std::move(expires_at), std::move(interval_microsecs));
                return connection{ static_cast<void*>(base), false };
            }

            template <auto Method, class Rep = unsigned long, class Period = std::milli>
            connection set_interval(std::chrono::duration<Rep, Period> const& interval)
            {
                return set_interval<Rep, Period>([] { (*Method)(); }, interval);
            }

            template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
            connection set_interval(
                Instance& object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& interval)
            {
                connection c{ set_interval<Rep, Period>([&object, method] { (object.*method)(); }, interval) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable&>(object).add_tracked_connection(c);
                }
                return c;
            }

            template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
            connection set_interval(Instance& object, std::chrono::duration<Rep, Period> const& interval)
            {
                connection c{ set_interval<Rep, Period>([&object] { (object.*Method)(); }, interval) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable&>(object).add_tracked_connection(c);
                }
                return c;
            }

            template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
            connection set_interval(
                Instance* object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& interval)
            {
                connection c{ set_interval<Rep, Period>([object, method] { (object->*method)(); }, interval) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable*>(object)->add_tracked_connection(c);
                }
                return c;
            }

            template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
            connection set_interval(Instance* object, std::chrono::duration<Rep, Period> const& interval)
            {
                connection c{ set_interval<Rep, Period>([object] { (object->*Method)(); }, interval) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable*>(object)->add_tracked_connection(c);
                }
                return c;
            }

            template <class Rep = unsigned long, class Period = std::milli>
            connection set_timeout(slot_type slot, std::chrono::duration<Rep, Period> const& timeout)
            {
                assert(slot != nullptr);

                auto expires_at = std::chrono::steady_clock::now() + timeout;
                connection_base* base
                    = make_link(tail, std::move(slot), std::move(expires_at), std::chrono::microseconds(-1));
                return connection{ static_cast<void*>(base), false };
            }

            template <auto Method, class Rep = unsigned long, class Period = std::milli>
            connection set_timeout(std::chrono::duration<Rep, Period> const& timeout)
            {
                return set_timeout<Rep, Period>([] { (*Method)(); }, timeout);
            }

            template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
            connection set_timeout(
                Instance& object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& timeout)
            {
                connection c{ set_timeout<Rep, Period>([&object, method] { (object.*method)(); }, timeout) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable&>(object).add_tracked_connection(c);
                }
                return c;
            }

            template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
            connection set_timeout(Instance& object, std::chrono::duration<Rep, Period> const& timeout)
            {
                connection c{ set_timeout<Rep, Period>([&object] { (object.*Method)(); }, timeout) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable&>(object).add_tracked_connection(c);
                }
                return c;
            }

            template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
            connection set_timeout(
                Instance* object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& timeout)
            {
                connection c{ set_timeout<Rep, Period>([object, method] { (object->*method)(); }, timeout) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable*>(object)->add_tracked_connection(c);
                }
                return c;
            }

            template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
            connection set_timeout(Instance* object, std::chrono::duration<Rep, Period> const& timeout)
            {
                connection c{ set_timeout<Rep, Period>([object] { (object->*Method)(); }, timeout) };
                if constexpr (std::is_convertible_v<Instance*, trackable*>)
                {
                    static_cast<trackable*>(object)->add_tracked_connection(c);
                }
                return c;
            }

            void clear() noexcept
            {
                intrusive_ptr<connection_base> current{ head->next };
                while (current != tail)
                {
                    intrusive_ptr<connection_base> next{ current->next };
                    current->next = tail;
                    current->prev = nullptr;
                    current = std::move(next);
                }

                head->next = tail;
                tail->prev = head;
            }

            void swap(timer_queue& other) noexcept
            {
                if (this != &other)
                {
                    head.swap(other.head);
                    tail.swap(other.tail);
                }
            }

            bool dispatch(std::chrono::time_point<std::chrono::steady_clock> execute_until)
            {
#    ifndef ROCKET_NO_EXCEPTIONS
                bool error{ false };
#    endif
                bool not_enough_time{ false };
                std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now();
                {
                    detail::thread_local_data* th{ detail::get_thread_local_data() };
                    detail::abort_scope ascope{ th };

                    intrusive_ptr<connection_base> current{ head->next };
                    intrusive_ptr<connection_base> end{ tail };

                    while (current != end)
                    {
                        assert(current != nullptr);

                        if (current->prev != nullptr
#    ifndef ROCKET_NO_BLOCKING_CONNECTIONS
                            && current->block_count == 0
#    endif
                        )
                            ROCKET_LIKELY
                            {
                                detail::connection_scope cscope{ current, false, th };

                                timed_connection* conn
                                    = std::launder(static_cast<timed_connection*>(static_cast<void*>(current)));

                                if (conn->expires_at <= now)
                                {
                                    if (conn->interval.count() < 0)
                                    {
                                        conn->disconnect();
                                    }
                                    else
                                    {
                                        conn->expires_at = now + conn->interval;
                                    }
#    ifndef ROCKET_NO_EXCEPTIONS
                                    try
                                    {
#    endif
                                        conn->slot();
#    ifndef ROCKET_NO_EXCEPTIONS
                                    }
                                    catch (...)
                                    {
                                        error = true;
                                    }
#    endif
                                    if (execute_until != std::chrono::time_point<std::chrono::steady_clock>{})
                                        ROCKET_UNLIKELY
                                        {
                                            // Check if we already spent the maximum allowed time executing callbacks
                                            if (execute_until <= std::chrono::steady_clock::now())
                                            {
                                                not_enough_time = true;
                                                break;
                                            }
                                        }

                                    if (th->emission_aborted)
                                        ROCKET_UNLIKELY
                                        {
                                            break;
                                        }
                                }
                            }

                        current = current->next;
                    }
                }

#    ifndef ROCKET_NO_EXCEPTIONS
                if (error)
                    ROCKET_UNLIKELY
                    {
                        throw invocation_slot_error{};
                    }
#    endif
                return not_enough_time;
            }

        private:
            using connection_base = detail::connection_base<thread_unsafe_policy>;

            void init()
            {
                head = new connection_base;
                tail = new connection_base;
                head->next = tail;
                tail->prev = head;
            }

            void destroy() noexcept
            {
                clear();
                head->next = nullptr;
                tail->prev = nullptr;
            }

            void copy(timer_queue const& q)
            {
                intrusive_ptr<connection_base> current{ q.head->next };
                intrusive_ptr<connection_base> end{ q.tail };

                while (current != end)
                {
                    timed_connection* conn = std::launder(static_cast<timed_connection*>(static_cast<void*>(current)));

                    make_link(tail, conn->slot, conn->expires_at, conn->interval);
                    current = current->next;
                }
            }

            timed_connection* make_link(
                connection_base* l,
                slot_type slot,
                std::chrono::time_point<std::chrono::steady_clock> expires_at,
                std::chrono::microseconds interval)
            {
                intrusive_ptr<timed_connection> link{ new timed_connection };
                link->slot = std::move(slot);
                link->expires_at = std::move(expires_at);
                link->interval = std::move(interval);
                link->prev = l->prev;
                link->next = l;
                link->prev->next = link;
                link->next->prev = link;
                return link;
            }

            intrusive_ptr<connection_base> head;
            intrusive_ptr<connection_base> tail;
        };

        inline timer_queue* get_timer_queue() noexcept
        {
            static ROCKET_THREAD_LOCAL timer_queue queue;
            return &queue;
        }

#endif//~ ROCKET_NO_TIMERS

#ifndef ROCKET_NO_QUEUED_CONNECTIONS
        struct call_queue final
        {
            void put(std::thread::id tid, std::packaged_task<void()> task)
            {
                std::scoped_lock<std::mutex> guard{ mutex };
                queue[tid].emplace_back(std::move(task));
            }

            bool dispatch(std::chrono::time_point<std::chrono::steady_clock> execute_until)
            {
                std::thread::id tid = std::this_thread::get_id();
                std::deque<std::packaged_task<void()>> thread_queue;

                {
                    std::scoped_lock<std::mutex> guard{ mutex };

                    auto iterator = queue.find(tid);
                    if (iterator != queue.end())
                    {
                        thread_queue.swap(iterator->second);
                        queue.erase(iterator);
                    }
                }

                auto itr = thread_queue.begin();
                auto end = thread_queue.end();

                while (itr != end)
                {
                    (itr++)->operator()();

                    if (execute_until != std::chrono::time_point<std::chrono::steady_clock>{})
                        ROCKET_UNLIKELY
                        {
                            // check if we already spent the maximum allowed time executing callbacks
                            if (execute_until <= std::chrono::steady_clock::now())
                            {
                                break;
                            }
                        }
                }

                if (itr != end)
                    ROCKET_UNLIKELY
                    {
                        // readd unfinished work to the queue
                        auto rbegin = std::make_reverse_iterator(end);
                        auto rend = std::make_reverse_iterator(itr);

                        std::scoped_lock<std::mutex> guard{ mutex };
                        std::deque<std::packaged_task<void()>>& original_queue = queue[tid];

                        for (auto it = rbegin; it != rend; ++it)
                        {
                            original_queue.push_front(std::move(*it));
                        }
                    }
                return itr != end;
            }

        private:
            std::mutex mutex;
            std::unordered_map<std::thread::id, std::deque<std::packaged_task<void()>>> queue;
        };

        inline call_queue* get_call_queue() noexcept
        {
            static call_queue queue;
            return &queue;
        }

        template <class T>
        struct decay
        {
            typedef typename std::remove_reference<T>::type U;
            typedef typename std::conditional<
                std::is_array<U>::value,
                typename std::remove_extent<U>::type*,
                typename std::conditional<
                    std::is_function<U>::value,
                    typename std::add_pointer<U>::type,
                    typename std::conditional<
                        std::is_const<U>::value || !std::is_reference<T>::value,
                        typename std::remove_cv<U>::type,
                        T>::type>::type>::type type;
        };

        template <class T>
        struct unwrap_refwrapper
        {
            using type = T;
        };

        template <class T>
        struct unwrap_refwrapper<std::reference_wrapper<T>>
        {
            using type = T&;
        };

        template <class T>
        using special_decay_t = typename unwrap_refwrapper<typename decay<T>::type>::type;

        // This make_tuple implementation is different from std::make_tuple.
        // This one preserves non-const references as actual reference values.
        // However const references will be stored by value.

        // make_tuple(int const&) => tuple<int>
        // make_tuple(int&) => tuple<int&>

        template <class... Types>
        ROCKET_NODISCARD auto make_tuple(Types&&... args)
        {
            return std::tuple<special_decay_t<Types>...>(std::forward<Types>(args)...);
        }
#endif//~ ROCKET_NO_QUEUED_CONNECTIONS
    } // namespace detail

#if !defined(ROCKET_NO_TIMERS) || !defined(ROCKET_NO_QUEUED_CONNECTIONS)
    template <class Rep, class Period>
    inline void dispatch_queued_calls(std::chrono::duration<Rep, Period> const& max_time_to_execute)
    {
        std::chrono::time_point<std::chrono::steady_clock> execute_until{};
        if (max_time_to_execute.count() > 0)
            ROCKET_UNLIKELY
            {
                execute_until = std::chrono::steady_clock::now() + max_time_to_execute;
            }
#    ifndef ROCKET_NO_TIMERS
        bool not_enough_time = detail::get_timer_queue()->dispatch(execute_until);
        if (not_enough_time)
            ROCKET_UNLIKELY
            {
                return;
            }
#    endif
#    ifndef ROCKET_NO_QUEUED_CONNECTIONS
        detail::get_call_queue()->dispatch(execute_until);
#    endif
    }

    inline void dispatch_queued_calls()
    {
        dispatch_queued_calls(std::chrono::microseconds::zero());
    }
#endif

#ifndef ROCKET_NO_TIMERS
    template <class Rep = unsigned long, class Period = std::milli>
    inline connection set_interval(std::function<void()> slot, std::chrono::duration<Rep, Period> const& interval)
    {
        return detail::get_timer_queue()->template set_interval<Rep, Period>(std::move(slot), interval);
    }

    template <auto Method, class Rep = unsigned long, class Period = std::milli>
    inline connection set_interval(std::chrono::duration<Rep, Period> const& interval)
    {
        return detail::get_timer_queue()->template set_interval<Method, Rep, Period>(interval);
    }

    template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
    inline connection set_interval(
        Instance& object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& interval)
    {
        return detail::get_timer_queue()->template set_interval<Instance, Class, R, Rep, Period>(
            object, method, interval);
    }

    template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
    inline connection set_interval(Instance& object, std::chrono::duration<Rep, Period> const& interval)
    {
        return detail::get_timer_queue()->template set_interval<Method, Instance, Rep, Period>(object, interval);
    }

    template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
    inline connection set_interval(
        Instance* object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& interval)
    {
        return detail::get_timer_queue()->template set_interval<Instance, Class, R, Rep, Period>(
            object, method, interval);
    }

    template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
    inline connection set_interval(Instance* object, std::chrono::duration<Rep, Period> const& interval)
    {
        return detail::get_timer_queue()->template set_interval<Method, Instance, Rep, Period>(object, interval);
    }

    template <class Rep = unsigned long, class Period = std::milli>
    inline connection set_timeout(std::function<void()> slot, std::chrono::duration<Rep, Period> const& timeout)
    {
        return detail::get_timer_queue()->template set_timeout<Rep, Period>(std::move(slot), timeout);
    }

    template <auto Method, class Rep = unsigned long, class Period = std::milli>
    inline connection set_timeout(std::chrono::duration<Rep, Period> const& timeout)
    {
        return detail::get_timer_queue()->template set_timeout<Method, Rep, Period>(timeout);
    }

    template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
    inline connection set_timeout(
        Instance& object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& timeout)
    {
        return detail::get_timer_queue()->template set_timeout<Instance, Class, R, Rep, Period>(
            object, method, timeout);
    }

    template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
    inline connection set_timeout(Instance& object, std::chrono::duration<Rep, Period> const& timeout)
    {
        return detail::get_timer_queue()->template set_timeout<Method, Instance, Rep, Period>(object, timeout);
    }

    template <class Instance, class Class, class R, class Rep = unsigned long, class Period = std::milli>
    inline connection set_timeout(
        Instance* object, R (Class::*method)(), std::chrono::duration<Rep, Period> const& timeout)
    {
        return detail::get_timer_queue()->template set_timeout<Instance, Class, R, Rep, Period>(
            object, method, timeout);
    }

    template <auto Method, class Instance, class Rep = unsigned long, class Period = std::milli>
    inline connection set_timeout(Instance* object, std::chrono::duration<Rep, Period> const& timeout)
    {
        return detail::get_timer_queue()->template set_timeout<Method, Instance, Rep, Period>(object, timeout);
    }

    // Overloads for milliseconds
    inline connection set_interval(std::function<void()> slot, unsigned long interval_ms)
    {
        return detail::get_timer_queue()->template set_interval<>(
            std::move(slot), std::chrono::milliseconds(interval_ms));
    }

    template <auto Method>
    inline connection set_interval(unsigned long interval_ms)
    {
        return detail::get_timer_queue()->template set_interval<Method>(std::chrono::milliseconds(interval_ms));
    }

    template <class Instance, class Class, class R>
    inline connection set_interval(Instance& object, R (Class::*method)(), unsigned long interval_ms)
    {
        return detail::get_timer_queue()->template set_interval<Instance, Class, R>(
            object, method, std::chrono::milliseconds(interval_ms));
    }

    template <auto Method, class Instance>
    inline connection set_interval(Instance& object, unsigned long interval_ms)
    {
        return detail::get_timer_queue()->template set_interval<Method, Instance>(
            object, std::chrono::milliseconds(interval_ms));
    }

    template <class Instance, class Class, class R>
    inline connection set_interval(Instance* object, R (Class::*method)(), unsigned long interval_ms)
    {
        return detail::get_timer_queue()->template set_interval<Instance, Class, R>(
            object, method, std::chrono::milliseconds(interval_ms));
    }

    template <auto Method, class Instance>
    inline connection set_interval(Instance* object, unsigned long interval_ms)
    {
        return detail::get_timer_queue()->template set_interval<Method, Instance>(
            object, std::chrono::milliseconds(interval_ms));
    }

    inline connection set_timeout(std::function<void()> slot, unsigned long timeout_ms)
    {
        return detail::get_timer_queue()->template set_timeout<>(
            std::move(slot), std::chrono::milliseconds(timeout_ms));
    }

    template <auto Method>
    inline connection set_timeout(unsigned long timeout_ms)
    {
        return detail::get_timer_queue()->template set_timeout<Method>(std::chrono::milliseconds(timeout_ms));
    }

    template <class Instance, class Class, class R>
    inline connection set_timeout(Instance& object, R (Class::*method)(), unsigned long timeout_ms)
    {
        return detail::get_timer_queue()->template set_timeout<Instance, Class, R>(
            object, method, std::chrono::milliseconds(timeout_ms));
    }

    template <auto Method, class Instance>
    inline connection set_timeout(Instance& object, unsigned long timeout_ms)
    {
        return detail::get_timer_queue()->template set_timeout<Method, Instance>(
            object, std::chrono::milliseconds(timeout_ms));
    }

    template <class Instance, class Class, class R>
    inline connection set_timeout(Instance* object, R (Class::*method)(), unsigned long timeout_ms)
    {
        return detail::get_timer_queue()->template set_timeout<Instance, Class, R>(
            object, method, std::chrono::milliseconds(timeout_ms));
    }

    template <auto Method, class Instance>
    inline connection set_timeout(Instance* object, unsigned long timeout_ms)
    {
        return detail::get_timer_queue()->template set_timeout<Method, Instance>(
            object, std::chrono::milliseconds(timeout_ms));
    }

    inline void clear_timers() noexcept
    {
        detail::get_timer_queue()->clear();
    }
#endif//~ ROCKET_NO_TIMERS

    template <class T>
    struct default_collector final : last<optional<T>>
    {
    };

    template <>
    struct default_collector<void>
    {
        using value_type = void;
        using result_type = void;

        void operator()() noexcept
        {
            /* do nothing for void types */
        }

        void result() noexcept
        {
            /* do nothing for void types */
        }
    };

    enum connection_flags : unsigned int
    {
        direct_connection = 0,
#ifndef ROCKET_NO_QUEUED_CONNECTIONS
        queued_connection = 1 << 0,
#endif
        connect_as_first_slot = 1 << 1,
    };

    template <
        class Signature,
        class Collector = default_collector<detail::get_return_type<Signature>>,
        class ThreadingPolicy = thread_unsafe_policy>
    struct signal;

    template <class Collector, class ThreadingPolicy, class R, class... Args>
    struct signal<R(Args...), Collector, ThreadingPolicy> final
    {
        using threading_policy = ThreadingPolicy;
        using signature_type = R(Args...);
        using slot_type = std::function<signature_type>;

        signal()
        {
            init();
        }

        ~signal() noexcept
        {
            std::scoped_lock<shared_lock_state> guard{ lock_state };
            destroy();
        }

        signal(signal&& s)
        {
            static_assert(
                std::is_same_v<threading_policy, thread_unsafe_policy>,
                "Thread safe signals can't be moved or swapped.");

            head = std::move(s.head);
            tail = std::move(s.tail);
            s.init();
        }

        signal(signal const& s)
        {
            init();

            std::scoped_lock<shared_lock_state> guard{ s.lock_state };
            copy(s);
        }

        signal& operator=(signal&& rhs)
        {
            static_assert(
                std::is_same_v<threading_policy, thread_unsafe_policy>,
                "Thread safe signals can't be moved or swapped.");

            destroy();
            head = std::move(rhs.head);
            tail = std::move(rhs.tail);
            rhs.init();
            return *this;
        }

        signal& operator=(signal const& rhs)
        {
            if (this != &rhs)
            {
                std::scoped_lock<shared_lock_state, shared_lock_state> guard{ lock_state, rhs.lock_state };
                clear_without_lock();
                copy(rhs);
            }
            return *this;
        }

        connection connect(slot_type slot, connection_flags flags = direct_connection)
        {
            assert(slot != nullptr);


#ifndef ROCKET_NO_QUEUED_CONNECTIONS
            std::thread::id tid{};

            if constexpr (std::is_same_v<threading_policy, thread_safe_policy>)
            {
                if ((flags & queued_connection) != 0)
                    ROCKET_UNLIKELY
                    {
                        tid = std::this_thread::get_id();
                    }
            }
            else
            {
                assert((flags & queued_connection) == 0);
            }
#endif

            bool first = (flags & connect_as_first_slot) != 0;

            std::scoped_lock<shared_lock_state> guard{ lock_state };
            connection_base* base = make_link(
                first ? head->next : tail,
                std::move(slot)
#ifndef ROCKET_NO_QUEUED_CONNECTIONS
                    ,
                tid
#endif
            );

            return connection{ static_cast<void*>(base), std::is_same_v<threading_policy, thread_safe_policy> };
        }

        template <class R1, class... Args1>
        connection connect(R1 (*method)(Args1...), connection_flags flags = direct_connection)
        {
            return connect([method](Args const&... args) { return R((*method)(Args1(args)...)); }, flags);
        }

        template <auto Method>
        connection connect(connection_flags flags = direct_connection)
        {
            return connect([](Args const&... args) { return R((*Method)(args...)); }, flags);
        }

        template <class Instance, class Class, class R1, class... Args1>
        connection connect(Instance& object, R1 (Class::*method)(Args1...), connection_flags flags = direct_connection)
        {
            connection c{ connect(
                [&object, method](Args const&... args) { return R((object.*method)(Args1(args)...)); }, flags) };
            if constexpr (std::is_convertible_v<Instance*, trackable*>)
            {
                static_cast<trackable&>(object).add_tracked_connection(c);
            }
            return c;
        }

        template <auto Method, class Instance>
        connection connect(Instance& object, connection_flags flags = direct_connection)
        {
            connection c{ connect([&object](Args const&... args) { return R((object.*Method)(args...)); }, flags) };
            if constexpr (std::is_convertible_v<Instance*, trackable*>)
            {
                static_cast<trackable&>(object).add_tracked_connection(c);
            }
            return c;
        }

        template <class Instance, class Class, class R1, class... Args1>
        connection connect(Instance* object, R1 (Class::*method)(Args1...), connection_flags flags = direct_connection)
        {
            connection c{ connect(
                [object, method](Args const&... args) { return R((object->*method)(Args1(args)...)); }, flags) };
            if constexpr (std::is_convertible_v<Instance*, trackable*>)
            {
                static_cast<trackable*>(object)->add_tracked_connection(c);
            }
            return c;
        }

        template <auto Method, class Instance>
        connection connect(Instance* object, connection_flags flags = direct_connection)
        {
            connection c{ connect([object](Args const&... args) { return R((object->*Method)(args...)); }, flags) };
            if constexpr (std::is_convertible_v<Instance*, trackable*>)
            {
                static_cast<trackable*>(object)->add_tracked_connection(c);
            }
            return c;
        }

        connection operator+=(slot_type slot)
        {
            return connect(std::move(slot));
        }

        void clear() noexcept
        {
            std::scoped_lock<shared_lock_state> guard{ lock_state };
            clear_without_lock();
        }

        void swap(signal& other) noexcept
        {
            static_assert(
                std::is_same_v<threading_policy, thread_unsafe_policy>,
                "Thread safe signals can't be moved or swapped.");

            if (this != &other)
            {
                head.swap(other.head);
                tail.swap(other.tail);
            }
        }

        ROCKET_NODISCARD std::size_t get_slot_count() const noexcept
        {
            std::size_t count{ 0 };
            std::scoped_lock<shared_lock_state> guard{ lock_state };
            intrusive_ptr<connection_base> current{ head->next };
            intrusive_ptr<connection_base> end{ tail };
            while (current != end)
            {
                if (current->prev != nullptr)
                {
                    ++count;
                }
                current = current->next;
            }
            return count;
        }

        template <class ValueCollector = Collector>
        auto invoke(Args const&... args) const
        {
#ifndef ROCKET_NO_EXCEPTIONS
            bool error{ false };
#endif
            ValueCollector collector{};
            {
                detail::thread_local_data* th{ detail::get_thread_local_data() };
                detail::abort_scope ascope{ th };

                lock_state.lock();

                intrusive_ptr<connection_base> current{ head->next };
                intrusive_ptr<connection_base> end{ tail };

                while (current != end)
                {
                    assert(current != nullptr);

                    if (current->prev != nullptr
#ifndef ROCKET_NO_BLOCKING_CONNECTIONS
                        && current->block_count == 0
#endif
                    )
                        ROCKET_LIKELY
                        {
                            detail::connection_scope cscope{ current,
                                                             std::is_same_v<threading_policy, thread_safe_policy>,
                                                             th };

                            lock_state.unlock();

                            functional_connection* conn
                                = std::launder(static_cast<functional_connection*>(static_cast<void*>(current)));

                            if constexpr (std::is_same_v<threading_policy, thread_unsafe_policy>)
                            {
#ifndef ROCKET_NO_EXCEPTIONS
                                try
                                {
#endif
                                    if constexpr (std::is_void_v<R>)
                                    {
                                        conn->slot(args...);
                                        collector();
                                    }
                                    else
                                    {
                                        collector(conn->slot(args...));
                                    }
#ifndef ROCKET_NO_EXCEPTIONS
                                }
                                catch (...)
                                {
                                    error = true;
                                }
#endif
                            }
                            else
                            {
#ifndef ROCKET_NO_QUEUED_CONNECTIONS
                                if (current->is_queued())
                                    ROCKET_UNLIKELY
                                    {
                                        if constexpr (std::is_void_v<R>)
                                        {
                                            std::packaged_task<void()> task(
                                                [current, args = detail::make_tuple(args...)]
                                                {
                                                    if (current->is_connected())
                                                        ROCKET_LIKELY
                                                        {
                                                            detail::thread_local_data* th{
                                                                detail::get_thread_local_data()
                                                            };
                                                            detail::connection_scope cscope{
                                                                current,
                                                                std::is_same_v<threading_policy, thread_safe_policy>,
                                                                th
                                                            };

                                                            functional_connection* conn
                                                                = std::launder(static_cast<functional_connection*>(
                                                                    static_cast<void*>(current)));

                                                            std::apply(conn->slot, args);
                                                        }
                                                });

                                            detail::get_call_queue()->put(current->get_tid(), std::move(task));
                                        }
                                        else
                                        {
                                            // If we are calling a queued slot, and our signal requires a return value
                                            // we actually have to block the thread until the slot was dispatched
                                            std::packaged_task<void()> task(
                                                [current, &collector, args = std::forward_as_tuple(args...)]
                                                {
                                                    if (current->is_connected())
                                                        ROCKET_LIKELY
                                                        {
                                                            detail::thread_local_data* th{
                                                                detail::get_thread_local_data()
                                                            };
                                                            detail::connection_scope cscope{
                                                                current,
                                                                std::is_same_v<threading_policy, thread_safe_policy>,
                                                                th
                                                            };

                                                            functional_connection* conn
                                                                = std::launder(static_cast<functional_connection*>(
                                                                    static_cast<void*>(current)));

                                                            collector(std::apply(conn->slot, args));
                                                        }
                                                });

                                            std::future<void> future{ task.get_future() };
                                            detail::get_call_queue()->put(current->get_tid(), std::move(task));
#    ifndef ROCKET_NO_EXCEPTIONS
                                            try
                                            {
#    endif
                                                future.get();
#    ifndef ROCKET_NO_EXCEPTIONS
                                            }
                                            catch (...)
                                            {
                                                error = true;
                                            }
#    endif
                                        }
                                    }
                                else
#endif//~ ROCKET_NO_QUEUED_CONNECTIONS
                                {
#ifndef ROCKET_NO_EXCEPTIONS
                                    try
                                    {
#endif
                                        if constexpr (std::is_void_v<R>)
                                        {
                                            conn->slot(args...);
                                            collector();
                                        }
                                        else
                                        {
                                            collector(conn->slot(args...));
                                        }
#ifndef ROCKET_NO_EXCEPTIONS
                                    }
                                    catch (...)
                                    {
                                        error = true;
                                    }
#endif
                                }
                            }

                            lock_state.lock();

                            if (th->emission_aborted)
                                ROCKET_UNLIKELY
                                {
                                    break;
                                }
                        }

                    current = current->next;
                }

                lock_state.unlock();
            }

#ifndef ROCKET_NO_EXCEPTIONS
            if (error)
                ROCKET_UNLIKELY
                {
                    throw invocation_slot_error{};
                }
#endif
            return collector.result();
        }

        auto operator()(Args const&... args) const
        {
            return invoke(args...);
        }

    private:
        using shared_lock_state = detail::shared_lock_state<threading_policy>;
        using connection_base = detail::connection_base<threading_policy>;
        using functional_connection = detail::functional_connection<threading_policy, signature_type>;

        void init()
        {
            head = new connection_base;
            tail = new connection_base;
            head->next = tail;
            tail->prev = head;
        }

        void destroy() noexcept
        {
            clear_without_lock();
            head->next = nullptr;
            tail->prev = nullptr;
        }

        void clear_without_lock() noexcept
        {
            intrusive_ptr<connection_base> current{ head->next };
            while (current != tail)
            {
                intrusive_ptr<connection_base> next{ current->next };
                current->next = tail;
                current->prev = nullptr;
                current = std::move(next);
            }

            head->next = tail;
            tail->prev = head;
        }

        void copy(signal const& s)
        {
            intrusive_ptr<connection_base> current{ s.head->next };
            intrusive_ptr<connection_base> end{ s.tail };

            while (current != end)
            {
                functional_connection* conn
                    = std::launder(static_cast<functional_connection*>(static_cast<void*>(current)));

                make_link(
                    tail,
                    conn->slot
#ifndef ROCKET_NO_QUEUED_CONNECTIONS
                    ,
                    conn->get_tid()
#endif
                );
                current = current->next;
            }
        }

        functional_connection* make_link(
            connection_base* l,
            slot_type slot
#ifndef ROCKET_NO_QUEUED_CONNECTIONS
            ,
            ROCKET_MAYBE_UNUSED std::thread::id tid
#endif
        )
        {
            intrusive_ptr<functional_connection> link{ new functional_connection };

            if constexpr (std::is_same_v<threading_policy, thread_safe_policy>)
            {
                link->lock = lock_state.lock_primitive;
#ifndef ROCKET_NO_QUEUED_CONNECTIONS
                link->thread_id = std::move(tid);
#endif
            }

            link->slot = std::move(slot);
            link->prev = l->prev;
            link->next = l;
            link->prev->next = link;
            link->next->prev = link;
            return link;
        }

        intrusive_ptr<connection_base> head;
        intrusive_ptr<connection_base> tail;

        ROCKET_NO_UNIQUE_ADDRESS mutable shared_lock_state lock_state;
    };

    template <class Signature, class Collector = default_collector<detail::get_return_type<Signature>>>
    using thread_safe_signal = signal<Signature, Collector, thread_safe_policy>;

    template <class Instance, class Class, class R, class... Args>
    ROCKET_NODISCARD inline std::function<R(Args...)> slot(Instance& object, R (Class::*method)(Args...))
    {
        return [&object, method](Args const&... args) { return (object.*method)(args...); };
    }

    template <class Instance, class Class, class R, class... Args>
    ROCKET_NODISCARD inline std::function<R(Args...)> slot(Instance* object, R (Class::*method)(Args...))
    {
        return [object, method](Args const&... args) { return (object->*method)(args...); };
    }

    template <class T>
    inline void swap(intrusive_ptr<T>& p1, intrusive_ptr<T>& p2) noexcept
    {
        p1.swap(p2);
    }

#ifndef ROCKET_NO_STABLE_LIST
    template <class T>
    inline void swap(stable_list<T>& l1, stable_list<T>& l2) noexcept
    {
        l1.swap(l2);
    }
#endif//~ ROCKET_NO_STABLE_LIST

    inline void swap(connection& c1, connection& c2) noexcept
    {
        c1.swap(c2);
    }

    template <class Signature, class Collector, class ThreadingPolicy>
    inline void swap(
        signal<Signature, Collector, ThreadingPolicy>& s1, signal<Signature, Collector, ThreadingPolicy>& s2) noexcept
    {
        s1.swap(s2);
    }
}// namespace rocket

#endif
Download .txt
gitextract_zivlhdr6/

├── .gitignore
├── CMakeLists.txt
├── README.md
├── example.cpp
└── rocket.hpp
Download .txt
SYMBOL INDEX (374 symbols across 2 files)

FILE: example.cpp
  type Testing (line 5) | struct Testing : rocket::trackable
    method hello (line 7) | int hello(float a)
  type NonDefaultConstructible (line 14) | struct NonDefaultConstructible
    method NonDefaultConstructible (line 16) | explicit NonDefaultConstructible(int x)
    method NonDefaultConstructible (line 26) | NonDefaultConstructible(NonDefaultConstructible&& n)
    method NonDefaultConstructible (line 32) | NonDefaultConstructible& operator = (NonDefaultConstructible&& n)
    method NonDefaultConstructible (line 42) | NonDefaultConstructible() = delete;
    method NonDefaultConstructible (line 44) | NonDefaultConstructible(NonDefaultConstructible const&) = delete;
    method NonDefaultConstructible (line 45) | NonDefaultConstructible& operator = (NonDefaultConstructible const&) =...
  type TestShared (line 48) | struct TestShared : std::enable_shared_from_this<TestShared>
    method hello (line 50) | int hello(int a)
  function main (line 56) | int main()

FILE: rocket.hpp
  type rocket (line 159) | namespace rocket
    type minimum (line 162) | struct minimum
      method result (line 177) | result()
    type maximum (line 188) | struct maximum
      method result (line 203) | result()
    type first (line 214) | struct first
      method result (line 229) | result()
    type last (line 240) | struct last
      method result (line 251) | result()
    type range (line 261) | struct range
      method result (line 272) | result()
    type error (line 282) | struct error : std::exception
    type bad_optional_access (line 286) | struct bad_optional_access final : error
    type invocation_slot_error (line 294) | struct invocation_slot_error final : error
    type intrusive_ptr (line 307) | struct intrusive_ptr final
      method intrusive_ptr (line 317) | constexpr intrusive_ptr() noexcept
      method intrusive_ptr (line 322) | constexpr intrusive_ptr(std::nullptr_t) noexcept
      method intrusive_ptr (line 327) | explicit intrusive_ptr(pointer p) noexcept
      method intrusive_ptr (line 336) | intrusive_ptr(intrusive_ptr const& p) noexcept
      method intrusive_ptr (line 345) | intrusive_ptr(intrusive_ptr&& p) noexcept
      method intrusive_ptr (line 352) | explicit intrusive_ptr(intrusive_ptr<U> const& p) noexcept
      method intrusive_ptr (line 362) | explicit intrusive_ptr(intrusive_ptr<U>&& p) noexcept
      method ROCKET_NODISCARD (line 376) | ROCKET_NODISCARD pointer get() const noexcept
      method pointer (line 381) | pointer detach() noexcept
      method ROCKET_NODISCARD (line 388) | ROCKET_NODISCARD operator pointer() const noexcept
      method ROCKET_NODISCARD (line 393) | ROCKET_NODISCARD pointer operator->() const noexcept
      method ROCKET_NODISCARD (line 399) | ROCKET_NODISCARD reference operator*() const noexcept
      method ROCKET_NODISCARD (line 405) | ROCKET_NODISCARD pointer* operator&() noexcept
      method ROCKET_NODISCARD (line 411) | ROCKET_NODISCARD pointer const* operator&() const noexcept
      method intrusive_ptr (line 416) | intrusive_ptr& operator=(pointer p) noexcept
      method intrusive_ptr (line 431) | intrusive_ptr& operator=(std::nullptr_t) noexcept
      method intrusive_ptr (line 441) | intrusive_ptr& operator=(intrusive_ptr const& p) noexcept
      method intrusive_ptr (line 446) | intrusive_ptr& operator=(intrusive_ptr&& p) noexcept
      method intrusive_ptr (line 458) | intrusive_ptr& operator=(intrusive_ptr<U> const& p) noexcept
      method intrusive_ptr (line 464) | intrusive_ptr& operator=(intrusive_ptr<U>&& p) noexcept
      method swap (line 475) | void swap(pointer* pp) noexcept
      method swap (line 482) | void swap(intrusive_ptr& p) noexcept
    function ROCKET_NODISCARD (line 492) | ROCKET_NODISCARD inline bool operator==(intrusive_ptr<T> const& a, int...
    function ROCKET_NODISCARD (line 498) | ROCKET_NODISCARD inline bool operator==(intrusive_ptr<T> const& a, U* ...
    function ROCKET_NODISCARD (line 504) | ROCKET_NODISCARD inline bool operator==(T* a, intrusive_ptr<U> const& ...
    function ROCKET_NODISCARD (line 510) | ROCKET_NODISCARD inline bool operator!=(intrusive_ptr<T> const& a, int...
    function ROCKET_NODISCARD (line 516) | ROCKET_NODISCARD inline bool operator!=(intrusive_ptr<T> const& a, U* ...
    function ROCKET_NODISCARD (line 522) | ROCKET_NODISCARD inline bool operator!=(T* a, intrusive_ptr<U> const& ...
    function ROCKET_NODISCARD (line 528) | ROCKET_NODISCARD inline bool operator<(intrusive_ptr<T> const& a, intr...
    function ROCKET_NODISCARD (line 534) | ROCKET_NODISCARD inline bool operator<(intrusive_ptr<T> const& a, U* b...
    function ROCKET_NODISCARD (line 540) | ROCKET_NODISCARD inline bool operator<(T* a, intrusive_ptr<U> const& b...
    function ROCKET_NODISCARD (line 546) | ROCKET_NODISCARD inline bool operator<=(intrusive_ptr<T> const& a, int...
    function ROCKET_NODISCARD (line 552) | ROCKET_NODISCARD inline bool operator<=(intrusive_ptr<T> const& a, U* ...
    function ROCKET_NODISCARD (line 558) | ROCKET_NODISCARD inline bool operator<=(T* a, intrusive_ptr<U> const& ...
    function ROCKET_NODISCARD (line 564) | ROCKET_NODISCARD inline bool operator>(intrusive_ptr<T> const& a, intr...
    function ROCKET_NODISCARD (line 570) | ROCKET_NODISCARD inline bool operator>(intrusive_ptr<T> const& a, U* b...
    function ROCKET_NODISCARD (line 576) | ROCKET_NODISCARD inline bool operator>(T* a, intrusive_ptr<U> const& b...
    function ROCKET_NODISCARD (line 582) | ROCKET_NODISCARD inline bool operator>=(intrusive_ptr<T> const& a, int...
    function ROCKET_NODISCARD (line 588) | ROCKET_NODISCARD inline bool operator>=(intrusive_ptr<T> const& a, U* ...
    function ROCKET_NODISCARD (line 594) | ROCKET_NODISCARD inline bool operator>=(T* a, intrusive_ptr<U> const& ...
    function ROCKET_NODISCARD (line 600) | ROCKET_NODISCARD inline bool operator==(intrusive_ptr<T> const& a, std...
    function ROCKET_NODISCARD (line 606) | ROCKET_NODISCARD inline bool operator==(std::nullptr_t, intrusive_ptr<...
    function ROCKET_NODISCARD (line 612) | ROCKET_NODISCARD inline bool operator!=(intrusive_ptr<T> const& a, std...
    function ROCKET_NODISCARD (line 618) | ROCKET_NODISCARD inline bool operator!=(std::nullptr_t, intrusive_ptr<...
    function ROCKET_NODISCARD (line 624) | ROCKET_NODISCARD inline T* get_pointer(intrusive_ptr<T> const& p) noex...
    function ROCKET_NODISCARD (line 630) | ROCKET_NODISCARD inline intrusive_ptr<T> static_pointer_cast(intrusive...
    function ROCKET_NODISCARD (line 636) | ROCKET_NODISCARD inline intrusive_ptr<T> const_pointer_cast(intrusive_...
    function ROCKET_NODISCARD (line 642) | ROCKET_NODISCARD inline intrusive_ptr<T> dynamic_pointer_cast(intrusiv...
    function ROCKET_NODISCARD (line 648) | ROCKET_NODISCARD inline intrusive_ptr<T> reinterpret_pointer_cast(intr...
    type ref_count (line 653) | struct ref_count final
      method addref (line 655) | unsigned long addref() noexcept
      method release (line 660) | unsigned long release() noexcept
      method get (line 665) | ROCKET_NODISCARD unsigned long get() const noexcept
    type ref_count_atomic (line 674) | struct ref_count_atomic final
      method addref (line 676) | unsigned long addref() noexcept
      method release (line 681) | unsigned long release() noexcept
      method get (line 686) | ROCKET_NODISCARD unsigned long get() const noexcept
    type ref_counted (line 696) | struct ref_counted
      method ref_counted (line 698) | ref_counted() noexcept = default;
      method ref_counted (line 700) | ref_counted(ref_counted const&) noexcept
      method ref_counted (line 704) | ref_counted& operator=(ref_counted const&) noexcept
      method addref (line 709) | void addref() noexcept
      method release (line 714) | void release() noexcept
    class stable_list (line 731) | class stable_list final
      type link_element (line 733) | struct link_element final : ref_counted<link_element>
        method link_element (line 735) | link_element() noexcept = default;
        method construct (line 746) | void construct(Args&&... args) noexcept(noexcept(T{ std::forward<A...
        method T (line 751) | T* value() noexcept
      type iterator_base (line 774) | struct iterator_base final
        method iterator_base (line 785) | iterator_base() noexcept = default;
        method iterator_base (line 788) | iterator_base(iterator_base const& i) noexcept
        method iterator_base (line 793) | iterator_base(iterator_base&& i) noexcept
        method iterator_base (line 799) | explicit iterator_base(iterator_base<V> const& i) noexcept
        method iterator_base (line 805) | explicit iterator_base(iterator_base<V>&& i) noexcept
        method iterator_base (line 810) | iterator_base& operator=(iterator_base const& i) noexcept
        method iterator_base (line 816) | iterator_base& operator=(iterator_base&& i) noexcept
        method iterator_base (line 823) | iterator_base& operator=(iterator_base<V> const& i) noexcept
        method iterator_base (line 830) | iterator_base& operator=(iterator_base<V>&& i) noexcept
        method iterator_base (line 836) | iterator_base& operator++() noexcept
        method iterator_base (line 842) | iterator_base operator++(int) noexcept
        method iterator_base (line 849) | iterator_base& operator--() noexcept
        method iterator_base (line 855) | iterator_base operator--(int) noexcept
        method ROCKET_NODISCARD (line 862) | ROCKET_NODISCARD reference operator*() const noexcept
        method ROCKET_NODISCARD (line 867) | ROCKET_NODISCARD pointer operator->() const noexcept
        method ROCKET_NODISCARD (line 873) | ROCKET_NODISCARD bool operator==(iterator_base<V> const& i) const ...
        method ROCKET_NODISCARD (line 879) | ROCKET_NODISCARD bool operator!=(iterator_base<V> const& i) const ...
        method iterator_base (line 887) | iterator_base(link_element* p) noexcept
      method stable_list (line 906) | stable_list()
      method stable_list (line 916) | stable_list(stable_list const& l)
      method stable_list (line 922) | stable_list(stable_list&& l)
      method stable_list (line 930) | stable_list(std::initializer_list<value_type> l)
      method stable_list (line 937) | stable_list(Iterator ibegin, Iterator iend)
      method stable_list (line 943) | explicit stable_list(size_type count, value_type const& value)
      method stable_list (line 949) | explicit stable_list(size_type count)
      method stable_list (line 955) | stable_list& operator=(stable_list const& l)
      method stable_list (line 965) | stable_list& operator=(stable_list&& l)
      method ROCKET_NODISCARD (line 975) | ROCKET_NODISCARD iterator begin() noexcept
      method ROCKET_NODISCARD (line 980) | ROCKET_NODISCARD iterator end() noexcept
      method begin (line 985) | begin() const noexcept
      method end (line 990) | end() const noexcept
      method cbegin (line 995) | cbegin() const noexcept
      method cend (line 1000) | cend() const noexcept
      method rbegin (line 1005) | rbegin() noexcept
      method rend (line 1010) | rend() noexcept
      method rbegin (line 1015) | rbegin() const noexcept
      method rend (line 1020) | rend() const noexcept
      method crbegin (line 1025) | crbegin() const noexcept
      method crend (line 1030) | crend() const noexcept
      method ROCKET_NODISCARD (line 1035) | ROCKET_NODISCARD reference front() noexcept
      method ROCKET_NODISCARD (line 1040) | ROCKET_NODISCARD reference back() noexcept
      method ROCKET_NODISCARD (line 1045) | ROCKET_NODISCARD value_type const& front() const noexcept
      method ROCKET_NODISCARD (line 1050) | ROCKET_NODISCARD value_type const& back() const noexcept
      method ROCKET_NODISCARD (line 1055) | ROCKET_NODISCARD bool empty() const noexcept
      method clear (line 1060) | void clear() noexcept
      method push_front (line 1065) | void push_front(value_type const& value)
      method push_front (line 1070) | void push_front(value_type&& value)
      method push_back (line 1075) | void push_back(value_type const& value)
      method push_back (line 1080) | void push_back(value_type&& value)
      method reference (line 1086) | reference emplace_front(Args&&... args)
      method reference (line 1092) | reference emplace_back(Args&&... args)
      method pop_front (line 1097) | void pop_front() noexcept
      method pop_back (line 1104) | void pop_back() noexcept
      method iterator (line 1111) | iterator insert(iterator const& pos, value_type const& value)
      method iterator (line 1116) | iterator insert(iterator const& pos, value_type&& value)
      method iterator (line 1122) | iterator insert(iterator const& pos, Iterator ibegin, Iterator iend)
      method iterator (line 1136) | iterator insert(iterator const& pos, std::initializer_list<value_typ...
      method iterator (line 1141) | iterator insert(iterator const& pos, size_type count, value_type con...
      method iterator (line 1156) | iterator emplace(iterator const& pos, Args&&... args)
      method append (line 1161) | void append(value_type const& value)
      method append (line 1166) | void append(value_type&& value)
      method append (line 1172) | void append(Iterator ibegin, Iterator iend)
      method append (line 1177) | void append(std::initializer_list<value_type> l)
      method append (line 1182) | void append(size_type count, value_type const& value)
      method assign (line 1187) | void assign(size_type count, value_type const& value)
      method assign (line 1194) | void assign(Iterator ibegin, Iterator iend)
      method assign (line 1200) | void assign(std::initializer_list<value_type> l)
      method resize (line 1206) | void resize(size_type count)
      method resize (line 1211) | void resize(size_type count, value_type const& value)
      method ROCKET_NODISCARD (line 1230) | ROCKET_NODISCARD size_type size() const noexcept
      method ROCKET_NODISCARD (line 1235) | ROCKET_NODISCARD size_type max_size() const noexcept
      method iterator (line 1240) | iterator erase(iterator const& pos) noexcept
      method iterator (line 1248) | iterator erase(iterator const& first, iterator const& last) noexcept
      method remove (line 1265) | void remove(value_type const& value) noexcept
      method remove_if (line 1277) | void remove_if(Predicate const& pred)
      method swap (line 1288) | void swap(stable_list& other) noexcept
      method init (line 1299) | void init()
      method destroy (line 1308) | void destroy()
      method link_element (line 1316) | link_element* make_link(link_element* l, Args&&... args)
        method link_element (line 735) | link_element() noexcept = default;
        method construct (line 746) | void construct(Args&&... args) noexcept(noexcept(T{ std::forward<A...
        method T (line 751) | T* value() noexcept
    type threading_policy (line 1331) | struct threading_policy
    type detail (line 1339) | namespace detail
      type expand_signature (line 1342) | struct expand_signature
      type shared_lock (line 1354) | struct shared_lock final : ref_counted<shared_lock, ref_count_atomic>
      type shared_lock_state (line 1360) | struct shared_lock_state
      type shared_lock_state<thread_unsafe_policy> (line 1363) | struct shared_lock_state<thread_unsafe_policy> final
        method lock (line 1367) | constexpr void lock() noexcept
        method try_lock (line 1371) | constexpr bool try_lock() noexcept
        method unlock (line 1376) | constexpr void unlock() noexcept
        method swap (line 1380) | constexpr void swap(shared_lock_state&) noexcept
      type shared_lock_state<thread_safe_policy> (line 1386) | struct shared_lock_state<thread_safe_policy> final
        method shared_lock_state (line 1390) | shared_lock_state()
        method shared_lock_state (line 1397) | shared_lock_state(shared_lock_state const& s)
        method shared_lock_state (line 1402) | shared_lock_state(shared_lock_state&& s)
        method shared_lock_state (line 1408) | shared_lock_state& operator=(shared_lock_state const& rhs)
        method shared_lock_state (line 1414) | shared_lock_state& operator=(shared_lock_state&& rhs)
        method lock (line 1421) | void lock()
        method try_lock (line 1426) | bool try_lock()
        method unlock (line 1431) | void unlock()
        method swap (line 1436) | void swap(shared_lock_state& s) noexcept
      type connection_base (line 1445) | struct connection_base
      type connection_base<thread_unsafe_policy> (line 1448) | struct connection_base<thread_unsafe_policy> : ref_counted<connectio...
        method ROCKET_NODISCARD (line 1454) | ROCKET_NODISCARD bool is_connected() const noexcept
        method disconnect (line 1459) | void disconnect() noexcept
        method noexcept (line 1474) | const noexcept
        method ROCKET_NODISCARD (line 1479) | ROCKET_NODISCARD constexpr bool is_queued() const noexcept
        method block (line 1486) | void block() noexcept
        method unblock (line 1491) | void unblock() noexcept
        method ROCKET_NODISCARD (line 1499) | ROCKET_NODISCARD bool is_blocked() const noexcept
      type connection_base<thread_safe_policy> (line 1512) | struct connection_base<thread_safe_policy> : ref_counted<connection_...
        method ROCKET_NODISCARD (line 1518) | ROCKET_NODISCARD bool is_connected() const noexcept
        method disconnect (line 1523) | void disconnect() noexcept
        method noexcept (line 1540) | const noexcept
        method ROCKET_NODISCARD (line 1545) | ROCKET_NODISCARD bool is_queued() const noexcept
        method block (line 1552) | void block() noexcept
        method unblock (line 1558) | void unblock() noexcept
        method ROCKET_NODISCARD (line 1567) | ROCKET_NODISCARD bool is_blocked() const noexcept
      type functional_connection (line 1586) | struct functional_connection : connection_base<ThreadingPolicy>
      type timed_connection (line 1592) | struct timed_connection final : functional_connection<thread_unsafe_...
      type thread_local_data (line 1599) | struct thread_local_data final
      function ROCKET_NODISCARD (line 1606) | ROCKET_NODISCARD inline thread_local_data* get_thread_local_data() n...
      type connection_scope (line 1612) | struct connection_scope final
        method connection_scope (line 1614) | connection_scope(void* base, bool is_thread_safe, thread_local_dat...
      type abort_scope (line 1634) | struct abort_scope final
        method abort_scope (line 1636) | abort_scope(thread_local_data* th) noexcept
      type weak_mem_fn (line 1654) | struct weak_mem_fn final
        method weak_mem_fn (line 1656) | explicit weak_mem_fn(std::weak_ptr<Instance> c, R (Class::*method)...
      type shared_mem_fn (line 1688) | struct shared_mem_fn final
        method shared_mem_fn (line 1690) | explicit shared_mem_fn(std::shared_ptr<Instance> c, R (Class::*met...
        method R (line 1697) | R operator()(Args1&&... args) const
      type timer_queue (line 2114) | struct timer_queue final
        method timer_queue (line 2118) | timer_queue()
        method timer_queue (line 2128) | timer_queue(timer_queue&& q)
        method timer_queue (line 2135) | timer_queue(timer_queue const& q)
        method timer_queue (line 2141) | timer_queue& operator=(timer_queue&& rhs)
        method timer_queue (line 2150) | timer_queue& operator=(timer_queue const& rhs)
        method connection (line 2161) | connection set_interval(slot_type slot, std::chrono::duration<Rep,...
        method connection (line 2173) | connection set_interval(std::chrono::duration<Rep, Period> const& ...
        method connection (line 2179) | connection set_interval(
        method connection (line 2191) | connection set_interval(Instance& object, std::chrono::duration<Re...
        method connection (line 2202) | connection set_interval(
        method connection (line 2214) | connection set_interval(Instance* object, std::chrono::duration<Re...
        method connection (line 2225) | connection set_timeout(slot_type slot, std::chrono::duration<Rep, ...
        method connection (line 2236) | connection set_timeout(std::chrono::duration<Rep, Period> const& t...
        method connection (line 2242) | connection set_timeout(
        method connection (line 2254) | connection set_timeout(Instance& object, std::chrono::duration<Rep...
        method connection (line 2265) | connection set_timeout(
        method connection (line 2277) | connection set_timeout(Instance* object, std::chrono::duration<Rep...
        method clear (line 2287) | void clear() noexcept
        method swap (line 2302) | void swap(timer_queue& other) noexcept
        method dispatch (line 2311) | bool dispatch(std::chrono::time_point<std::chrono::steady_clock> e...
    function bind_weak_ptr (line 1711) | inline auto bind_weak_ptr(std::weak_ptr<Instance> c, R (Class::*method...
    function bind_weak_ptr (line 1717) | inline auto bind_weak_ptr(std::shared_ptr<Instance> c, R (Class::*meth...
    function bind_shared_ptr (line 1723) | inline auto bind_shared_ptr(std::shared_ptr<Instance> c, R (Class::*me...
    type connection (line 1729) | struct connection
      method connection (line 1731) | connection() noexcept
      method connection (line 1742) | connection(connection&& rhs) noexcept
      method connection (line 1750) | connection(connection const& rhs) noexcept
      method connection (line 1757) | explicit connection(void* base, bool is_thread_safe) noexcept
      method connection (line 1764) | connection& operator=(connection&& rhs) noexcept
      method connection (line 1774) | connection& operator=(connection const& rhs) noexcept
      method ROCKET_NODISCARD (line 1786) | ROCKET_NODISCARD bool operator==(connection const& rhs) const noexcept
      method ROCKET_NODISCARD (line 1791) | ROCKET_NODISCARD bool operator!=(connection const& rhs) const noexcept
      method ROCKET_NODISCARD (line 1801) | ROCKET_NODISCARD bool is_connected() const noexcept
      method ROCKET_NODISCARD (line 1820) | ROCKET_NODISCARD bool is_blocked() const noexcept
      method block (line 1838) | void block() noexcept
      method unblock (line 1855) | void unblock() noexcept
      method disconnect (line 1873) | void disconnect() noexcept
      method swap (line 1892) | void swap(connection& other) noexcept
      method addref (line 1909) | void addref() noexcept
      method release (line 1926) | void release() noexcept
    type scoped_connection (line 1947) | struct scoped_connection final : connection
      method scoped_connection (line 1949) | scoped_connection() noexcept = default;
      method scoped_connection (line 1956) | scoped_connection(connection const& rhs) noexcept
      method scoped_connection (line 1961) | scoped_connection(connection&& rhs) noexcept
      method scoped_connection (line 1966) | scoped_connection(scoped_connection&& rhs) noexcept
      method scoped_connection (line 1971) | scoped_connection& operator=(connection&& rhs) noexcept
      method scoped_connection (line 1979) | scoped_connection& operator=(scoped_connection&& rhs) noexcept
      method scoped_connection (line 1987) | scoped_connection& operator=(connection const& rhs) noexcept
      method scoped_connection (line 1996) | scoped_connection(scoped_connection const&) = delete;
      method scoped_connection (line 1998) | scoped_connection& operator=(scoped_connection const&) = delete;
    type scoped_connection_container (line 2001) | struct scoped_connection_container final
      method scoped_connection_container (line 2003) | scoped_connection_container() = default;
      method scoped_connection_container (line 2006) | scoped_connection_container(scoped_connection_container&& s)
      method scoped_connection_container (line 2011) | scoped_connection_container& operator=(scoped_connection_container&&...
      method scoped_connection_container (line 2017) | scoped_connection_container(std::initializer_list<connection> list)
      method append (line 2022) | void append(connection const& conn)
      method append (line 2027) | void append(std::initializer_list<connection> list)
      method scoped_connection_container (line 2035) | scoped_connection_container& operator+=(connection const& conn)
      method scoped_connection_container (line 2041) | scoped_connection_container& operator+=(std::initializer_list<connec...
      method disconnect (line 2050) | void disconnect() noexcept
      method scoped_connection_container (line 2056) | scoped_connection_container(scoped_connection_container const&) = de...
      method scoped_connection_container (line 2057) | scoped_connection_container& operator=(scoped_connection_container c...
    type trackable (line 2062) | struct trackable
      method add_tracked_connection (line 2064) | void add_tracked_connection(connection const& conn)
      method disconnect_tracked_connections (line 2069) | void disconnect_tracked_connections() noexcept
    function ROCKET_NODISCARD (line 2078) | ROCKET_NODISCARD inline connection current_connection() noexcept
    function abort_emission (line 2084) | inline void abort_emission() noexcept
    type scoped_connection_blocker (line 2090) | struct scoped_connection_blocker final
      method scoped_connection_blocker (line 2092) | scoped_connection_blocker(connection c) noexcept
      method scoped_connection_blocker (line 2104) | scoped_connection_blocker(scoped_connection_blocker const&) = delete;
      method scoped_connection_blocker (line 2105) | scoped_connection_blocker& operator=(scoped_connection_blocker const...
    type detail (line 2111) | namespace detail
      type expand_signature (line 1342) | struct expand_signature
      type shared_lock (line 1354) | struct shared_lock final : ref_counted<shared_lock, ref_count_atomic>
      type shared_lock_state (line 1360) | struct shared_lock_state
      type shared_lock_state<thread_unsafe_policy> (line 1363) | struct shared_lock_state<thread_unsafe_policy> final
        method lock (line 1367) | constexpr void lock() noexcept
        method try_lock (line 1371) | constexpr bool try_lock() noexcept
        method unlock (line 1376) | constexpr void unlock() noexcept
        method swap (line 1380) | constexpr void swap(shared_lock_state&) noexcept
      type shared_lock_state<thread_safe_policy> (line 1386) | struct shared_lock_state<thread_safe_policy> final
        method shared_lock_state (line 1390) | shared_lock_state()
        method shared_lock_state (line 1397) | shared_lock_state(shared_lock_state const& s)
        method shared_lock_state (line 1402) | shared_lock_state(shared_lock_state&& s)
        method shared_lock_state (line 1408) | shared_lock_state& operator=(shared_lock_state const& rhs)
        method shared_lock_state (line 1414) | shared_lock_state& operator=(shared_lock_state&& rhs)
        method lock (line 1421) | void lock()
        method try_lock (line 1426) | bool try_lock()
        method unlock (line 1431) | void unlock()
        method swap (line 1436) | void swap(shared_lock_state& s) noexcept
      type connection_base (line 1445) | struct connection_base
      type connection_base<thread_unsafe_policy> (line 1448) | struct connection_base<thread_unsafe_policy> : ref_counted<connectio...
        method ROCKET_NODISCARD (line 1454) | ROCKET_NODISCARD bool is_connected() const noexcept
        method disconnect (line 1459) | void disconnect() noexcept
        method noexcept (line 1474) | const noexcept
        method ROCKET_NODISCARD (line 1479) | ROCKET_NODISCARD constexpr bool is_queued() const noexcept
        method block (line 1486) | void block() noexcept
        method unblock (line 1491) | void unblock() noexcept
        method ROCKET_NODISCARD (line 1499) | ROCKET_NODISCARD bool is_blocked() const noexcept
      type connection_base<thread_safe_policy> (line 1512) | struct connection_base<thread_safe_policy> : ref_counted<connection_...
        method ROCKET_NODISCARD (line 1518) | ROCKET_NODISCARD bool is_connected() const noexcept
        method disconnect (line 1523) | void disconnect() noexcept
        method noexcept (line 1540) | const noexcept
        method ROCKET_NODISCARD (line 1545) | ROCKET_NODISCARD bool is_queued() const noexcept
        method block (line 1552) | void block() noexcept
        method unblock (line 1558) | void unblock() noexcept
        method ROCKET_NODISCARD (line 1567) | ROCKET_NODISCARD bool is_blocked() const noexcept
      type functional_connection (line 1586) | struct functional_connection : connection_base<ThreadingPolicy>
      type timed_connection (line 1592) | struct timed_connection final : functional_connection<thread_unsafe_...
      type thread_local_data (line 1599) | struct thread_local_data final
      function ROCKET_NODISCARD (line 1606) | ROCKET_NODISCARD inline thread_local_data* get_thread_local_data() n...
      type connection_scope (line 1612) | struct connection_scope final
        method connection_scope (line 1614) | connection_scope(void* base, bool is_thread_safe, thread_local_dat...
      type abort_scope (line 1634) | struct abort_scope final
        method abort_scope (line 1636) | abort_scope(thread_local_data* th) noexcept
      type weak_mem_fn (line 1654) | struct weak_mem_fn final
        method weak_mem_fn (line 1656) | explicit weak_mem_fn(std::weak_ptr<Instance> c, R (Class::*method)...
      type shared_mem_fn (line 1688) | struct shared_mem_fn final
        method shared_mem_fn (line 1690) | explicit shared_mem_fn(std::shared_ptr<Instance> c, R (Class::*met...
        method R (line 1697) | R operator()(Args1&&... args) const
      type timer_queue (line 2114) | struct timer_queue final
        method timer_queue (line 2118) | timer_queue()
        method timer_queue (line 2128) | timer_queue(timer_queue&& q)
        method timer_queue (line 2135) | timer_queue(timer_queue const& q)
        method timer_queue (line 2141) | timer_queue& operator=(timer_queue&& rhs)
        method timer_queue (line 2150) | timer_queue& operator=(timer_queue const& rhs)
        method connection (line 2161) | connection set_interval(slot_type slot, std::chrono::duration<Rep,...
        method connection (line 2173) | connection set_interval(std::chrono::duration<Rep, Period> const& ...
        method connection (line 2179) | connection set_interval(
        method connection (line 2191) | connection set_interval(Instance& object, std::chrono::duration<Re...
        method connection (line 2202) | connection set_interval(
        method connection (line 2214) | connection set_interval(Instance* object, std::chrono::duration<Re...
        method connection (line 2225) | connection set_timeout(slot_type slot, std::chrono::duration<Rep, ...
        method connection (line 2236) | connection set_timeout(std::chrono::duration<Rep, Period> const& t...
        method connection (line 2242) | connection set_timeout(
        method connection (line 2254) | connection set_timeout(Instance& object, std::chrono::duration<Rep...
        method connection (line 2265) | connection set_timeout(
        method connection (line 2277) | connection set_timeout(Instance* object, std::chrono::duration<Rep...
        method clear (line 2287) | void clear() noexcept
        method swap (line 2302) | void swap(timer_queue& other) noexcept
        method dispatch (line 2311) | bool dispatch(std::chrono::time_point<std::chrono::steady_clock> e...
    function init (line 2399) | void init()
    function destroy (line 2407) | void destroy() noexcept
    function copy (line 2414) | void copy(timer_queue const& q)
    function timed_connection (line 2428) | timed_connection* make_link(
  type expand_signature<R(Args...)> (line 1345) | struct expand_signature<R(Args...)> final
  function timer_queue (line 2449) | inline timer_queue* get_timer_queue() noexcept
  type call_queue (line 2458) | struct call_queue final
    method put (line 2460) | void put(std::thread::id tid, std::packaged_task<void()> task)
    method dispatch (line 2466) | bool dispatch(std::chrono::time_point<std::chrono::steady_clock> execu...
  function call_queue (line 2523) | inline call_queue* get_call_queue() noexcept
    method put (line 2460) | void put(std::thread::id tid, std::packaged_task<void()> task)
    method dispatch (line 2466) | bool dispatch(std::chrono::time_point<std::chrono::steady_clock> execu...
  type decay (line 2530) | struct decay
  type unwrap_refwrapper (line 2546) | struct unwrap_refwrapper
  type unwrap_refwrapper<std::reference_wrapper<T>> (line 2552) | struct unwrap_refwrapper<std::reference_wrapper<T>>
  function make_tuple (line 2568) | ROCKET_NODISCARD auto make_tuple(Types&&... args)
  function dispatch_queued_calls (line 2577) | inline void dispatch_queued_calls(std::chrono::duration<Rep, Period> con...
  function dispatch_queued_calls (line 2598) | inline void dispatch_queued_calls()
  function connection (line 2606) | inline connection set_interval(std::function<void()> slot, std::chrono::...
  function connection (line 2612) | inline connection set_interval(std::chrono::duration<Rep, Period> const&...
  function connection (line 2618) | inline connection set_interval(
  function connection (line 2626) | inline connection set_interval(Instance& object, std::chrono::duration<R...
  function connection (line 2632) | inline connection set_interval(
  function connection (line 2640) | inline connection set_interval(Instance* object, std::chrono::duration<R...
  function connection (line 2646) | inline connection set_timeout(std::function<void()> slot, std::chrono::d...
  function connection (line 2652) | inline connection set_timeout(std::chrono::duration<Rep, Period> const& ...
  function connection (line 2658) | inline connection set_timeout(
  function connection (line 2666) | inline connection set_timeout(Instance& object, std::chrono::duration<Re...
  function connection (line 2672) | inline connection set_timeout(
  function connection (line 2680) | inline connection set_timeout(Instance* object, std::chrono::duration<Re...
  function connection (line 2686) | inline connection set_interval(std::function<void()> slot, unsigned long...
  function connection (line 2693) | inline connection set_interval(unsigned long interval_ms)
  function connection (line 2699) | inline connection set_interval(Instance& object, R (Class::*method)(), u...
  function connection (line 2706) | inline connection set_interval(Instance& object, unsigned long interval_ms)
  function connection (line 2713) | inline connection set_interval(Instance* object, R (Class::*method)(), u...
  function connection (line 2720) | inline connection set_interval(Instance* object, unsigned long interval_ms)
  function connection (line 2726) | inline connection set_timeout(std::function<void()> slot, unsigned long ...
  function connection (line 2733) | inline connection set_timeout(unsigned long timeout_ms)
  function connection (line 2739) | inline connection set_timeout(Instance& object, R (Class::*method)(), un...
  function connection (line 2746) | inline connection set_timeout(Instance& object, unsigned long timeout_ms)
  function connection (line 2753) | inline connection set_timeout(Instance* object, R (Class::*method)(), un...
  function connection (line 2760) | inline connection set_timeout(Instance* object, unsigned long timeout_ms)
  function clear_timers (line 2766) | inline void clear_timers() noexcept
  type default_collector (line 2773) | struct default_collector final : last<optional<T>>
  type default_collector<void> (line 2778) | struct default_collector<void>
    method result (line 2788) | void result() noexcept
  type connection_flags (line 2794) | enum connection_flags : unsigned int
  type signal (line 2807) | struct signal
  type signal<R(Args...), Collector, ThreadingPolicy> (line 2810) | struct signal<R(Args...), Collector, ThreadingPolicy> final
    method signal (line 2816) | signal()
    method signal (line 2827) | signal(signal&& s)
    method signal (line 2838) | signal(signal const& s)
    method signal (line 2846) | signal& operator=(signal&& rhs)
    method signal (line 2859) | signal& operator=(signal const& rhs)
    method connection (line 2870) | connection connect(slot_type slot, connection_flags flags = direct_con...
    method connection (line 2908) | connection connect(R1 (*method)(Args1...), connection_flags flags = di...
    method connection (line 2914) | connection connect(connection_flags flags = direct_connection)
    method connection (line 2920) | connection connect(Instance& object, R1 (Class::*method)(Args1...), co...
    method connection (line 2932) | connection connect(Instance& object, connection_flags flags = direct_c...
    method connection (line 2943) | connection connect(Instance* object, R1 (Class::*method)(Args1...), co...
    method connection (line 2955) | connection connect(Instance* object, connection_flags flags = direct_c...
    method connection (line 2965) | connection operator+=(slot_type slot)
    method clear (line 2970) | void clear() noexcept
    method swap (line 2976) | void swap(signal& other) noexcept
    method noexcept (line 2989) | const noexcept
    method invoke (line 3007) | auto invoke(Args const&... args) const
    method if (line 3169) | if (th->emission_aborted)
  function init (line 3202) | void init()
  function destroy (line 3210) | void destroy() noexcept
  function clear_without_lock (line 3217) | void clear_without_lock() noexcept
  function copy (line 3232) | void copy(signal const& s)
  function functional_connection (line 3254) | functional_connection* make_link(
  function ROCKET_NODISCARD (line 3291) | ROCKET_NODISCARD inline std::function<R(Args...)> slot(Instance& object,...
  function ROCKET_NODISCARD (line 3297) | ROCKET_NODISCARD inline std::function<R(Args...)> slot(Instance* object,...
  function swap (line 3303) | inline void swap(intrusive_ptr<T>& p1, intrusive_ptr<T>& p2) noexcept
  function swap (line 3310) | inline void swap(stable_list<T>& l1, stable_list<T>& l2) noexcept
  function swap (line 3316) | inline void swap(connection& c1, connection& c2) noexcept
  function swap (line 3322) | inline void swap(
Condensed preview — 5 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (129K chars).
[
  {
    "path": ".gitignore",
    "chars": 43,
    "preview": ".vscode\n.clangd\nbuild\ncompile_commands.json"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 450,
    "preview": "cmake_minimum_required(VERSION 3.2)\nproject(rocket CXX)\n\noption(BUILD_EXAMPLES \"Build examples\" ON)\n\n# C++ standard\nset("
  },
  {
    "path": "README.md",
    "chars": 16379,
    "preview": "# rocket - Fast C++ Observer Pattern\n\nRocket is a public-domain, single-header implementation of a signal/slots library "
  },
  {
    "path": "example.cpp",
    "chars": 3794,
    "preview": "\n#include \"rocket.hpp\"\n#include <iostream>\n\nstruct Testing : rocket::trackable\n{\n    int hello(float a)\n    {\n        st"
  },
  {
    "path": "rocket.hpp",
    "chars": 104293,
    "preview": "/***********************************************************************************\n * rocket - lightweight & fast sign"
  }
]

About this extraction

This page contains the full source code of the tripleslash/rocket GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5 files (122.0 KB), approximately 24.9k tokens, and a symbol index with 374 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!