typetui 0.2.0

A terminal-based typing test.
Documentation
#include <iostream>
#include <vector>
#include <string>
#include <utility>

class Buffer {
    size_t size_;
    int* data_;

public:
    explicit Buffer(size_t size) : size_(size), data_(new int[size]) {
        std::cout << "Constructor (" << size_ << ")\n";
        for (size_t i = 0; i < size_; ++i) {
            data_[i] = static_cast<int>(i);
        }
    }

    ~Buffer() {
        std::cout << "Destructor (" << size_ << ")\n";
        delete[] data_;
    }

    Buffer(const Buffer& other) : size_(other.size_), data_(new int[other.size_]) {
        std::cout << "Copy constructor (" << size_ << ")\n";
        std::copy(other.data_, other.data_ + size_, data_);
    }

    Buffer& operator=(const Buffer& other) {
        std::cout << "Copy assignment (" << other.size_ << ")\n";
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = new int[size_];
            std::copy(other.data_, other.data_ + size_, data_);
        }
        return *this;
    }

    Buffer(Buffer&& other) noexcept : size_(other.size_), data_(other.data_) {
        std::cout << "Move constructor (" << size_ << ")\n";
        other.data_ = nullptr;
        other.size_ = 0;
    }

    Buffer& operator=(Buffer&& other) noexcept {
        std::cout << "Move assignment (" << other.size_ << ")\n";
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = other.data_;
            other.data_ = nullptr;
            other.size_ = 0;
        }
        return *this;
    }

    size_t size() const { return size_; }
    int* data() const { return data_; }

    int& operator[](size_t index) { return data_[index]; }
    const int& operator[](size_t index) const { return data_[index]; }
};

class StringBuilder {
    std::string data_;

public:
    StringBuilder() = default;
    explicit StringBuilder(const std::string& str) : data_(str) {}

    StringBuilder& append(const std::string& str) & {
        data_ += str;
        return *this;
    }

    StringBuilder append(const std::string& str) && {
        data_ += str;
        return std::move(*this);
    }

    StringBuilder& append(const char* str) & {
        data_ += str;
        return *this;
    }

    StringBuilder append(const char* str) && {
        data_ += str;
        return std::move(*this);
    }

    std::string str() const { return data_; }
    std::string&& str() && { return std::move(data_); }
};

Buffer create_buffer(size_t size) {
    return Buffer(size);
}

void process_buffer(Buffer buf) {
    std::cout << "Processing buffer of size " << buf.size() << "\n";
}

class ResourceManager {
    std::vector<Buffer> buffers_;

public:
    void add_buffer(Buffer buf) {
        buffers_.push_back(std::move(buf));
    }

    Buffer extract_buffer(size_t index) {
        if (index < buffers_.size()) {
            Buffer result = std::move(buffers_[index]);
            buffers_.erase(buffers_.begin() + index);
            return result;
        }
        return Buffer(0);
    }

    const std::vector<Buffer>& buffers() const { return buffers_; }
};

template<typename T>
void swap(T& a, T& b) noexcept {
    T tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}

class BigObject {
    std::vector<int> data_;
    std::string name_;

public:
    BigObject() = default;
    
    explicit BigObject(size_t size, std::string name)
        : data_(size), name_(std::move(name)) {}

    BigObject(const BigObject&) = default;
    BigObject& operator=(const BigObject&) = default;

    BigObject(BigObject&&) noexcept = default;
    BigObject& operator=(BigObject&&) noexcept = default;

    void resize(size_t new_size) {
        data_.resize(new_size);
    }

    void set_name(std::string name) {
        name_ = std::move(name);
    }

    size_t size() const { return data_.size(); }
    const std::string& name() const { return name_; }
};

class MoveOnlyResource {
    int* handle_;

public:
    explicit MoveOnlyResource(int id) : handle_(new int(id)) {
        std::cout << "Creating resource " << *handle_ << "\n";
    }

    ~MoveOnlyResource() {
        if (handle_) {
            std::cout << "Destroying resource " << *handle_ << "\n";
            delete handle_;
        }
    }

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

    MoveOnlyResource(MoveOnlyResource&& other) noexcept : handle_(other.handle_) {
        other.handle_ = nullptr;
    }

    MoveOnlyResource& operator=(MoveOnlyResource&& other) noexcept {
        if (this != &other) {
            delete handle_;
            handle_ = other.handle_;
            other.handle_ = nullptr;
        }
        return *this;
    }

    int get() const { return handle_ ? *handle_ : -1; }
};

template<typename T>
T make_value(T value) {
    return value;
}

template<typename T>
T&& forward_value(typename std::remove_reference<T>::type& value) noexcept {
    return static_cast<T&&>(value);
}

template<typename T>
T&& forward_value(typename std::remove_reference<T>::type&& value) noexcept {
    return static_cast<T&&>(value);
}

template<typename Container>
void insert_sorted(Container& container, typename Container::value_type&& value) {
    auto it = std::lower_bound(container.begin(), container.end(), value);
    container.insert(it, std::move(value));
}

int main() {
    std::cout << "=== Buffer Creation ===\n";
    Buffer buf1(10);
    
    std::cout << "\n=== Move Construction ===\n";
    Buffer buf2 = std::move(buf1);
    
    std::cout << "\n=== Copy and Move ===\n";
    Buffer buf3(5);
    Buffer buf4 = buf3;
    Buffer buf5 = std::move(buf3);
    
    std::cout << "\n=== Function Return ===\n";
    Buffer buf6 = create_buffer(3);
    
    std::cout << "\n=== Passing by Value ===\n";
    process_buffer(std::move(buf6));
    
    std::cout << "\n=== StringBuilder ===\n";
    auto result = StringBuilder().append("Hello, ").append("World!").str();
    std::cout << result << "\n";
    
    std::cout << "\n=== Move-Only Resource ===\n";
    MoveOnlyResource res1(42);
    MoveOnlyResource res2 = std::move(res1);
    std::cout << "Resource 2 value: " << res2.get() << "\n";

    return 0;
}