Add banan-os as a submodule instead of manually copying libraries
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "banan-os"]
|
||||
path = banan-os
|
||||
url = https://git.bananymous.com/Bananymous/banan-os.git
|
||||
812
0001-linux-window-server-sdl2.patch
Normal file
812
0001-linux-window-server-sdl2.patch
Normal file
@@ -0,0 +1,812 @@
|
||||
From 075f6a11926e247ba64efd25a3acf7a3d3be0bbc Mon Sep 17 00:00:00 2001
|
||||
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
|
||||
Date: Wed, 15 Apr 2026 16:51:16 +0300
|
||||
Subject: [PATCH] linux-window-server-sdl2
|
||||
|
||||
---
|
||||
userspace/libraries/LibGUI/Widget/Widget.cpp | 2 +-
|
||||
userspace/libraries/LibGUI/Window.cpp | 9 +-
|
||||
userspace/programs/ProgramLauncher/main.cpp | 2 +-
|
||||
userspace/programs/Terminal/Terminal.cpp | 4 +-
|
||||
.../programs/WindowServer/CMakeLists.txt | 3 +
|
||||
.../programs/WindowServer/Framebuffer.cpp | 52 +--
|
||||
userspace/programs/WindowServer/Window.cpp | 29 +-
|
||||
.../programs/WindowServer/WindowServer.cpp | 47 ++-
|
||||
.../programs/WindowServer/WindowServer.h | 1 +
|
||||
userspace/programs/WindowServer/main.cpp | 362 ++++++++++++------
|
||||
10 files changed, 338 insertions(+), 173 deletions(-)
|
||||
|
||||
diff --git a/userspace/libraries/LibGUI/Widget/Widget.cpp b/userspace/libraries/LibGUI/Widget/Widget.cpp
|
||||
index d6489d87..c532fb04 100644
|
||||
--- a/userspace/libraries/LibGUI/Widget/Widget.cpp
|
||||
+++ b/userspace/libraries/LibGUI/Widget/Widget.cpp
|
||||
@@ -15,7 +15,7 @@ namespace LibGUI::Widget
|
||||
const LibFont::Font& Widget::default_font()
|
||||
{
|
||||
if (!s_default_font.has_value())
|
||||
- MUST(set_default_font("/usr/share/fonts/lat0-16.psfu"_sv));
|
||||
+ MUST(set_default_font("./lat0-16.psfu"_sv));
|
||||
return s_default_font.value();
|
||||
}
|
||||
|
||||
diff --git a/userspace/libraries/LibGUI/Window.cpp b/userspace/libraries/LibGUI/Window.cpp
|
||||
index b4172f70..3a0e9cca 100644
|
||||
--- a/userspace/libraries/LibGUI/Window.cpp
|
||||
+++ b/userspace/libraries/LibGUI/Window.cpp
|
||||
@@ -4,9 +4,8 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
-#include <sys/banan-os.h>
|
||||
#include <sys/epoll.h>
|
||||
-#include <sys/mman.h>
|
||||
+#include <sys/shm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <time.h>
|
||||
@@ -271,7 +270,7 @@ namespace LibGUI
|
||||
|
||||
void Window::cleanup()
|
||||
{
|
||||
- munmap(m_framebuffer_smo, m_width * m_height * 4);
|
||||
+ shmdt(m_framebuffer_smo);
|
||||
close(m_server_fd);
|
||||
close(m_epoll_fd);
|
||||
}
|
||||
@@ -279,7 +278,7 @@ namespace LibGUI
|
||||
BAN::ErrorOr<void> Window::handle_resize_event(const EventPacket::ResizeWindowEvent& event)
|
||||
{
|
||||
if (m_framebuffer_smo)
|
||||
- munmap(m_framebuffer_smo, m_width * m_height * 4);
|
||||
+ shmdt(m_framebuffer_smo);
|
||||
m_framebuffer_smo = nullptr;
|
||||
|
||||
TRY(m_texture.resize(event.width, event.height));
|
||||
@@ -287,7 +286,7 @@ namespace LibGUI
|
||||
if (m_root_widget)
|
||||
TRY(m_root_widget->set_fixed_geometry({ 0, 0, event.width, event.height }));
|
||||
|
||||
- void* framebuffer_addr = smo_map(event.smo_key);
|
||||
+ void* framebuffer_addr = shmat(event.smo_key, nullptr, 0);
|
||||
if (framebuffer_addr == nullptr)
|
||||
return BAN::Error::from_errno(errno);
|
||||
|
||||
diff --git a/userspace/programs/ProgramLauncher/main.cpp b/userspace/programs/ProgramLauncher/main.cpp
|
||||
index c833c582..0e1cc460 100644
|
||||
--- a/userspace/programs/ProgramLauncher/main.cpp
|
||||
+++ b/userspace/programs/ProgramLauncher/main.cpp
|
||||
@@ -182,7 +182,7 @@ int main()
|
||||
attributes.alpha_channel = true;
|
||||
attributes.title_bar = false;
|
||||
|
||||
- auto font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
|
||||
+ auto font = MUST(LibFont::Font::load("./lat0-16.psfu"_sv));
|
||||
|
||||
const auto full_program_list = get_program_list();
|
||||
|
||||
diff --git a/userspace/programs/Terminal/Terminal.cpp b/userspace/programs/Terminal/Terminal.cpp
|
||||
index e1bd317d..8a6b5bd0 100644
|
||||
--- a/userspace/programs/Terminal/Terminal.cpp
|
||||
+++ b/userspace/programs/Terminal/Terminal.cpp
|
||||
@@ -92,7 +92,7 @@ void Terminal::start_shell()
|
||||
close(pts_slave);
|
||||
close(pts_master);
|
||||
|
||||
- execl("/bin/Shell", "Shell", NULL);
|
||||
+ execl("/usr/bin/zsh", "zsh", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ void Terminal::run()
|
||||
m_window->texture().set_bg_color(m_bg_color);
|
||||
m_window->invalidate();
|
||||
|
||||
- m_font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
|
||||
+ m_font = MUST(LibFont::Font::load("./lat0-16.psfu"_sv));
|
||||
|
||||
m_window->set_min_size(m_font.width() * 8, m_font.height() * 2);
|
||||
|
||||
diff --git a/userspace/programs/WindowServer/CMakeLists.txt b/userspace/programs/WindowServer/CMakeLists.txt
|
||||
index 8fdf79f9..fcaf441d 100644
|
||||
--- a/userspace/programs/WindowServer/CMakeLists.txt
|
||||
+++ b/userspace/programs/WindowServer/CMakeLists.txt
|
||||
@@ -13,4 +13,7 @@ banan_link_library(WindowServer libfont)
|
||||
banan_link_library(WindowServer libimage)
|
||||
banan_link_library(WindowServer libinput)
|
||||
|
||||
+find_package(SDL2 REQUIRED CONFIG REQUIRED COMPONENTS SDL2)
|
||||
+target_link_libraries(WindowServer PRIVATE SDL2::SDL2)
|
||||
+
|
||||
install(TARGETS WindowServer OPTIONAL)
|
||||
diff --git a/userspace/programs/WindowServer/Framebuffer.cpp b/userspace/programs/WindowServer/Framebuffer.cpp
|
||||
index 0e727e8f..119f1451 100644
|
||||
--- a/userspace/programs/WindowServer/Framebuffer.cpp
|
||||
+++ b/userspace/programs/WindowServer/Framebuffer.cpp
|
||||
@@ -1,45 +1,53 @@
|
||||
#include "Framebuffer.h"
|
||||
|
||||
-#include <fcntl.h>
|
||||
-#include <stdio.h>
|
||||
-#include <stdlib.h>
|
||||
#include <string.h>
|
||||
-#include <sys/framebuffer.h>
|
||||
-#include <sys/mman.h>
|
||||
+
|
||||
+#include <SDL2/SDL.h>
|
||||
+
|
||||
+static constexpr size_t window_width { 1280 };
|
||||
+static constexpr size_t window_height { 800 };
|
||||
+static constexpr size_t window_bpp { 32 };
|
||||
+
|
||||
+SDL_Renderer* g_renderer { nullptr };
|
||||
+SDL_Texture* g_texture { nullptr };
|
||||
+SDL_Window* g_window { nullptr };
|
||||
|
||||
Framebuffer open_framebuffer()
|
||||
{
|
||||
- int framebuffer_fd = open("/dev/fb0", O_RDWR | O_CLOEXEC);
|
||||
- if (framebuffer_fd == -1)
|
||||
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) == -1)
|
||||
{
|
||||
- perror("open");
|
||||
+ fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- framebuffer_info_t framebuffer_info;
|
||||
- if (pread(framebuffer_fd, &framebuffer_info, sizeof(framebuffer_info), -1) == -1)
|
||||
+ g_window = SDL_CreateWindow("banan gui", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, SDL_WINDOW_SHOWN);
|
||||
+ if (g_window == nullptr)
|
||||
{
|
||||
- perror("pread");
|
||||
+ fprintf(stderr, "Could not create SDL window: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- const size_t framebuffer_bytes = framebuffer_info.width * framebuffer_info.height * (BANAN_FB_BPP / 8);
|
||||
+ g_renderer = SDL_CreateRenderer(g_window, -1, SDL_RENDERER_ACCELERATED);
|
||||
+ if (g_renderer == nullptr)
|
||||
+ {
|
||||
+ fprintf(stderr, "Could not get SDL renderer: %s\n", SDL_GetError());
|
||||
+ exit(1);
|
||||
+ }
|
||||
|
||||
- uint32_t* framebuffer_mmap = (uint32_t*)mmap(NULL, framebuffer_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, framebuffer_fd, 0);
|
||||
- if (framebuffer_mmap == MAP_FAILED)
|
||||
+ g_texture = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, window_width, window_height);
|
||||
+ if (g_texture == nullptr)
|
||||
{
|
||||
- perror("mmap");
|
||||
+ fprintf(stderr, "Could not get SDL texture: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- memset(framebuffer_mmap, 0, framebuffer_bytes);
|
||||
- msync(framebuffer_mmap, framebuffer_bytes, MS_SYNC);
|
||||
+ uint32_t* pixels = new uint32_t[window_width * window_height];
|
||||
+ memset(pixels, 0, window_width * window_height * 4);
|
||||
|
||||
Framebuffer framebuffer;
|
||||
- framebuffer.fd = framebuffer_fd;
|
||||
- framebuffer.mmap = framebuffer_mmap;
|
||||
- framebuffer.width = framebuffer_info.width;
|
||||
- framebuffer.height = framebuffer_info.height;
|
||||
- framebuffer.bpp = BANAN_FB_BPP;
|
||||
+ framebuffer.mmap = pixels;
|
||||
+ framebuffer.width = window_width;
|
||||
+ framebuffer.height = window_height;
|
||||
+ framebuffer.bpp = window_bpp;
|
||||
return framebuffer;
|
||||
}
|
||||
diff --git a/userspace/programs/WindowServer/Window.cpp b/userspace/programs/WindowServer/Window.cpp
|
||||
index 1e66f522..9759eec9 100644
|
||||
--- a/userspace/programs/WindowServer/Window.cpp
|
||||
+++ b/userspace/programs/WindowServer/Window.cpp
|
||||
@@ -5,15 +5,14 @@
|
||||
|
||||
#include <LibGUI/Window.h>
|
||||
|
||||
-#include <sys/banan-os.h>
|
||||
-#include <sys/mman.h>
|
||||
+#include <sys/shm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
- munmap(m_fb_addr, client_width() * client_height() * 4);
|
||||
- smo_delete(m_smo_key);
|
||||
+ shmdt(m_fb_addr);
|
||||
+ shmctl(m_smo_key, IPC_RMID, nullptr);
|
||||
|
||||
LibGUI::EventPacket::DestroyWindowEvent packet;
|
||||
|
||||
@@ -47,16 +46,16 @@ BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
{
|
||||
const size_t fb_bytes = width * height * 4;
|
||||
|
||||
- long smo_key = smo_create(fb_bytes, PROT_READ | PROT_WRITE);
|
||||
- if (smo_key == -1)
|
||||
+ int shmid = shmget(rand(), fb_bytes, IPC_CREAT | IPC_EXCL | 0666);
|
||||
+ if (shmid == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
- BAN::ScopeGuard smo_deleter([&]() { smo_delete(smo_key); });
|
||||
+ BAN::ScopeGuard shmdeleter([&]() { shmctl(shmid, IPC_RMID, nullptr); });
|
||||
|
||||
- uint32_t* fb_addr = static_cast<uint32_t*>(smo_map(smo_key));
|
||||
- if (fb_addr == nullptr)
|
||||
+ uint32_t* fb_addr = static_cast<uint32_t*>(shmat(shmid, nullptr, 0));
|
||||
+ if (fb_addr == (void*)-1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
memset(fb_addr, 0xFF, fb_bytes);
|
||||
- BAN::ScopeGuard smo_unmapper([&]() { munmap(fb_addr, fb_bytes); });
|
||||
+ BAN::ScopeGuard shmdetacher([&]() { shmdt(fb_addr); });
|
||||
|
||||
{
|
||||
const auto old_area = m_client_area;
|
||||
@@ -70,16 +69,14 @@ BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
return title_bar_ret.release_error();
|
||||
}
|
||||
|
||||
- smo_deleter.disable();
|
||||
- smo_unmapper.disable();
|
||||
+ shmdetacher.disable();
|
||||
+ shmdeleter.disable();
|
||||
|
||||
if (m_fb_addr)
|
||||
- munmap(m_fb_addr, client_width() * client_height() * 4);
|
||||
- if (m_smo_key)
|
||||
- smo_delete(m_smo_key);
|
||||
+ shmdt(m_fb_addr);
|
||||
|
||||
m_fb_addr = fb_addr;
|
||||
- m_smo_key = smo_key;
|
||||
+ m_smo_key = shmid;
|
||||
|
||||
m_client_area.max_x = m_client_area.min_x + width;
|
||||
m_client_area.max_y = m_client_area.min_y + height;
|
||||
diff --git a/userspace/programs/WindowServer/WindowServer.cpp b/userspace/programs/WindowServer/WindowServer.cpp
|
||||
index 2c67d6c0..600704fd 100644
|
||||
--- a/userspace/programs/WindowServer/WindowServer.cpp
|
||||
+++ b/userspace/programs/WindowServer/WindowServer.cpp
|
||||
@@ -8,19 +8,20 @@
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
-#include <sys/banan-os.h>
|
||||
-#include <sys/ioctl.h>
|
||||
-#include <sys/mman.h>
|
||||
-#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
+#include <SDL2/SDL.h>
|
||||
+
|
||||
+extern SDL_Renderer* g_renderer;
|
||||
+extern SDL_Texture* g_texture;
|
||||
+
|
||||
WindowServer::WindowServer(Framebuffer& framebuffer, int32_t corner_radius)
|
||||
: m_framebuffer(framebuffer)
|
||||
, m_corner_radius(corner_radius)
|
||||
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
||||
- , m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)))
|
||||
+ , m_font(MUST(LibFont::Font::load("./lat0-16.psfu"_sv)))
|
||||
{
|
||||
MUST(m_background_image.resize(m_framebuffer.width * m_framebuffer.height, 0xFF101010));
|
||||
|
||||
@@ -440,7 +441,7 @@ static void update_volume(const char* new_volume)
|
||||
|
||||
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
{
|
||||
- if (event.key == LibInput::Key::Super)
|
||||
+ if (event.key == LibInput::Key::RightCtrl)
|
||||
m_is_mod_key_held = event.pressed();
|
||||
|
||||
if (event.pressed() && event.key == LibInput::Key::VolumeDown)
|
||||
@@ -461,7 +462,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
- execl("/usr/bin/Terminal", "Terminal", nullptr);
|
||||
+ execl("./build/banan-os/userspace/programs/Terminal/Terminal", "Terminal", nullptr);
|
||||
exit(1);
|
||||
}
|
||||
if (pid == -1)
|
||||
@@ -475,7 +476,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
- execl("/usr/bin/ProgramLauncher", "ProgramLauncher", nullptr);
|
||||
+ execl("./build/banan-os/userspace/programs/ProgramLauncher/ProgramLauncher", "ProgramLauncher", nullptr);
|
||||
exit(1);
|
||||
}
|
||||
if (pid == -1)
|
||||
@@ -1599,16 +1600,34 @@ void WindowServer::sync()
|
||||
|
||||
for (size_t i = 0; i < m_damaged_area_count; i++)
|
||||
{
|
||||
- const fb_msync_region region {
|
||||
- .min_x = static_cast<uint32_t>(m_damaged_areas[i].min_x),
|
||||
- .min_y = static_cast<uint32_t>(m_damaged_areas[i].min_y),
|
||||
- .max_x = static_cast<uint32_t>(m_damaged_areas[i].max_x),
|
||||
- .max_y = static_cast<uint32_t>(m_damaged_areas[i].max_y),
|
||||
+ const SDL_Rect rect {
|
||||
+ .x = m_damaged_areas[i].min_x,
|
||||
+ .y = m_damaged_areas[i].min_y,
|
||||
+ .w = m_damaged_areas[i].max_x - m_damaged_areas[i].min_x,
|
||||
+ .h = m_damaged_areas[i].max_y - m_damaged_areas[i].min_y,
|
||||
};
|
||||
- ioctl(m_framebuffer.fd, FB_MSYNC_RECTANGLE, ®ion);
|
||||
+
|
||||
+ void* pixels;
|
||||
+ int pitch;
|
||||
+ SDL_LockTexture(g_texture, &rect, &pixels, &pitch);
|
||||
+
|
||||
+ for (int32_t y_off = 0; y_off < rect.h; y_off++)
|
||||
+ {
|
||||
+ memcpy(
|
||||
+ static_cast<uint8_t*>(pixels) + y_off * pitch,
|
||||
+ &m_framebuffer.mmap[(rect.y + y_off) * m_framebuffer.width + rect.x],
|
||||
+ rect.w * sizeof(uint32_t)
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ SDL_UnlockTexture(g_texture);
|
||||
}
|
||||
|
||||
m_damaged_area_count = 0;
|
||||
+
|
||||
+ SDL_RenderClear(g_renderer);
|
||||
+ SDL_RenderCopy(g_renderer, g_texture, NULL, NULL);
|
||||
+ SDL_RenderPresent(g_renderer);
|
||||
}
|
||||
|
||||
Rectangle WindowServer::cursor_area() const
|
||||
diff --git a/userspace/programs/WindowServer/WindowServer.h b/userspace/programs/WindowServer/WindowServer.h
|
||||
index 94fbc774..bcd7a6b9 100644
|
||||
--- a/userspace/programs/WindowServer/WindowServer.h
|
||||
+++ b/userspace/programs/WindowServer/WindowServer.h
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
|
||||
bool is_damaged() const { return m_damaged_area_count > 0 || m_is_bouncing_window; }
|
||||
bool is_stopped() const { return m_is_stopped; }
|
||||
+ void stop() { m_is_stopped = true; }
|
||||
|
||||
private:
|
||||
void on_mouse_move_impl(int32_t new_x, int32_t new_y);
|
||||
diff --git a/userspace/programs/WindowServer/main.cpp b/userspace/programs/WindowServer/main.cpp
|
||||
index 41bd7e8c..cb066bd3 100644
|
||||
--- a/userspace/programs/WindowServer/main.cpp
|
||||
+++ b/userspace/programs/WindowServer/main.cpp
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
-#include <sys/banan-os.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -150,6 +149,8 @@ int open_server_fd()
|
||||
|
||||
int g_epoll_fd = -1;
|
||||
|
||||
+static void poll_sdl_events(WindowServer&);
|
||||
+
|
||||
int main()
|
||||
{
|
||||
srand(time(nullptr));
|
||||
@@ -181,14 +182,6 @@ int main()
|
||||
}
|
||||
}
|
||||
|
||||
- if (tty_ctrl(STDIN_FILENO, TTY_CMD_UNSET, TTY_FLAG_ENABLE_INPUT) == -1)
|
||||
- {
|
||||
- dwarnln("tty_ctrl: {}", strerror(errno));
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
- atexit([]() { tty_ctrl(STDIN_FILENO, TTY_CMD_SET, TTY_FLAG_ENABLE_INPUT); });
|
||||
-
|
||||
constexpr int non_terminating_signals[] {
|
||||
SIGCHLD,
|
||||
SIGCONT,
|
||||
@@ -196,11 +189,12 @@ int main()
|
||||
SIGTSTP,
|
||||
SIGTTIN,
|
||||
SIGTTOU,
|
||||
+ SIGWINCH,
|
||||
};
|
||||
constexpr int ignored_signals[] {
|
||||
SIGPIPE,
|
||||
};
|
||||
- for (int sig = _SIGMIN; sig <= _SIGMAX; sig++)
|
||||
+ for (int sig = 1; sig < NSIG; sig++)
|
||||
signal(sig, exit);
|
||||
for (int sig : non_terminating_signals)
|
||||
signal(sig, SIG_DFL);
|
||||
@@ -208,55 +202,10 @@ int main()
|
||||
signal(sig, SIG_IGN);
|
||||
|
||||
MUST(LibInput::KeyboardLayout::initialize());
|
||||
- MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
|
||||
-
|
||||
- int keyboard_fd = open("/dev/keyboard", O_RDONLY | O_CLOEXEC);
|
||||
- if (keyboard_fd == -1)
|
||||
- dwarnln("open keyboard: {}", strerror(errno));
|
||||
- else
|
||||
- {
|
||||
- epoll_event event {
|
||||
- .events = EPOLLIN,
|
||||
- .data = { .fd = keyboard_fd },
|
||||
- };
|
||||
- if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, keyboard_fd, &event) == -1)
|
||||
- {
|
||||
- dwarnln("epoll_ctl keyboard: {}", strerror(errno));
|
||||
- close(keyboard_fd);
|
||||
- keyboard_fd = -1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- int mouse_fd = open("/dev/mouse", O_RDONLY | O_CLOEXEC);
|
||||
- if (mouse_fd == -1)
|
||||
- dwarnln("open mouse: {}", strerror(errno));
|
||||
- else
|
||||
- {
|
||||
- epoll_event event {
|
||||
- .events = EPOLLIN,
|
||||
- .data = { .fd = mouse_fd },
|
||||
- };
|
||||
- if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, mouse_fd, &event) == -1)
|
||||
- {
|
||||
- dwarnln("epoll_ctl mouse: {}", strerror(errno));
|
||||
- close(mouse_fd);
|
||||
- mouse_fd = -1;
|
||||
- }
|
||||
- }
|
||||
+ MUST(LibInput::KeyboardLayout::get().load_from_file("./us.keymap"_sv));
|
||||
|
||||
dprintln("Window server started");
|
||||
|
||||
- if (access("/usr/bin/xbanan", X_OK) == 0)
|
||||
- {
|
||||
- if (fork() == 0)
|
||||
- {
|
||||
- dup2(STDDBG_FILENO, STDOUT_FILENO);
|
||||
- dup2(STDDBG_FILENO, STDERR_FILENO);
|
||||
- execl("/usr/bin/xbanan", "xbanan", NULL);
|
||||
- exit(1);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
auto config = parse_config();
|
||||
|
||||
WindowServer window_server(framebuffer, config.corner_radius);
|
||||
@@ -276,26 +225,23 @@ int main()
|
||||
uint64_t last_sync_us = get_current_us() - sync_interval_us;
|
||||
while (!window_server.is_stopped())
|
||||
{
|
||||
- timespec* ptimeout = nullptr;
|
||||
-
|
||||
timespec timeout = {};
|
||||
- if (window_server.is_damaged())
|
||||
- {
|
||||
- if (const auto current_us = get_current_us(); current_us - last_sync_us > sync_interval_us)
|
||||
- {
|
||||
- window_server.sync();
|
||||
|
||||
- const auto full_intervals = (current_us - last_sync_us) / sync_interval_us;
|
||||
- last_sync_us += full_intervals * sync_interval_us;
|
||||
- }
|
||||
+ if (const auto current_us = get_current_us(); current_us - last_sync_us > sync_interval_us)
|
||||
+ {
|
||||
+ window_server.sync();
|
||||
|
||||
- if (const auto current_us = get_current_us(); current_us - last_sync_us < sync_interval_us)
|
||||
- timeout.tv_nsec = (sync_interval_us - (current_us - last_sync_us)) * 1000;
|
||||
- ptimeout = &timeout;
|
||||
+ const auto full_intervals = (current_us - last_sync_us) / sync_interval_us;
|
||||
+ last_sync_us += full_intervals * sync_interval_us;
|
||||
}
|
||||
|
||||
+ if (const auto current_us = get_current_us(); current_us - last_sync_us < sync_interval_us)
|
||||
+ timeout.tv_nsec = (sync_interval_us - (current_us - last_sync_us)) * 1000;
|
||||
+
|
||||
+ poll_sdl_events(window_server);
|
||||
+
|
||||
epoll_event events[16];
|
||||
- int epoll_events = epoll_pwait2(g_epoll_fd, events, 16, ptimeout, nullptr);
|
||||
+ int epoll_events = epoll_pwait2(g_epoll_fd, events, 16, &timeout, nullptr);
|
||||
if (epoll_events == -1 && errno != EINTR)
|
||||
{
|
||||
dwarnln("epoll_pwait2: {}", strerror(errno));
|
||||
@@ -333,48 +279,6 @@ int main()
|
||||
continue;
|
||||
}
|
||||
|
||||
- if (events[i].data.fd == keyboard_fd)
|
||||
- {
|
||||
- ASSERT(events[i].events & EPOLLIN);
|
||||
-
|
||||
- LibInput::RawKeyEvent event;
|
||||
- if (read(keyboard_fd, &event, sizeof(event)) == -1)
|
||||
- {
|
||||
- dwarnln("read keyboard: {}", strerror(errno));
|
||||
- continue;
|
||||
- }
|
||||
- window_server.on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- if (events[i].data.fd == mouse_fd)
|
||||
- {
|
||||
- ASSERT(events[i].events & EPOLLIN);
|
||||
-
|
||||
- LibInput::MouseEvent event;
|
||||
- if (read(mouse_fd, &event, sizeof(event)) == -1)
|
||||
- {
|
||||
- dwarnln("read mouse: {}", strerror(errno));
|
||||
- continue;
|
||||
- }
|
||||
- switch (event.type)
|
||||
- {
|
||||
- case LibInput::MouseEventType::MouseButtonEvent:
|
||||
- window_server.on_mouse_button(event.button_event);
|
||||
- break;
|
||||
- case LibInput::MouseEventType::MouseMoveEvent:
|
||||
- window_server.on_mouse_move(event.move_event);
|
||||
- break;
|
||||
- case LibInput::MouseEventType::MouseMoveAbsEvent:
|
||||
- window_server.on_mouse_move_abs(event.move_abs_event);
|
||||
- break;
|
||||
- case LibInput::MouseEventType::MouseScrollEvent:
|
||||
- window_server.on_mouse_scroll(event.scroll_event);
|
||||
- break;
|
||||
- }
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
const int client_fd = events[i].data.fd;
|
||||
if (events[i].events & (EPOLLHUP | EPOLLERR))
|
||||
{
|
||||
@@ -500,3 +404,237 @@ int main()
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+#include <SDL2/SDL.h>
|
||||
+
|
||||
+extern SDL_Window* g_window;
|
||||
+struct Keymap
|
||||
+{
|
||||
+ consteval Keymap()
|
||||
+ {
|
||||
+ for (auto& scancode : map)
|
||||
+ scancode = 0;
|
||||
+
|
||||
+ using LibInput::keycode_normal;
|
||||
+ using LibInput::keycode_function;
|
||||
+ using LibInput::keycode_numpad;
|
||||
+
|
||||
+ map[SDL_SCANCODE_GRAVE] = keycode_normal(0, 0);
|
||||
+ map[SDL_SCANCODE_1] = keycode_normal(0, 1);
|
||||
+ map[SDL_SCANCODE_2] = keycode_normal(0, 2);
|
||||
+ map[SDL_SCANCODE_3] = keycode_normal(0, 3);
|
||||
+ map[SDL_SCANCODE_4] = keycode_normal(0, 4);
|
||||
+ map[SDL_SCANCODE_5] = keycode_normal(0, 5);
|
||||
+ map[SDL_SCANCODE_6] = keycode_normal(0, 6);
|
||||
+ map[SDL_SCANCODE_7] = keycode_normal(0, 7);
|
||||
+ map[SDL_SCANCODE_8] = keycode_normal(0, 8);
|
||||
+ map[SDL_SCANCODE_9] = keycode_normal(0, 9);
|
||||
+ map[SDL_SCANCODE_0] = keycode_normal(0, 10);
|
||||
+ map[SDL_SCANCODE_MINUS] = keycode_normal(0, 11);
|
||||
+ map[SDL_SCANCODE_EQUALS] = keycode_normal(0, 12);
|
||||
+ map[SDL_SCANCODE_BACKSPACE] = keycode_normal(0, 13);
|
||||
+
|
||||
+ map[SDL_SCANCODE_TAB] = keycode_normal(1, 0);
|
||||
+ map[SDL_SCANCODE_Q] = keycode_normal(1, 1);
|
||||
+ map[SDL_SCANCODE_W] = keycode_normal(1, 2);
|
||||
+ map[SDL_SCANCODE_E] = keycode_normal(1, 3);
|
||||
+ map[SDL_SCANCODE_R] = keycode_normal(1, 4);
|
||||
+ map[SDL_SCANCODE_T] = keycode_normal(1, 5);
|
||||
+ map[SDL_SCANCODE_Y] = keycode_normal(1, 6);
|
||||
+ map[SDL_SCANCODE_U] = keycode_normal(1, 7);
|
||||
+ map[SDL_SCANCODE_I] = keycode_normal(1, 8);
|
||||
+ map[SDL_SCANCODE_O] = keycode_normal(1, 9);
|
||||
+ map[SDL_SCANCODE_P] = keycode_normal(1, 10);
|
||||
+ map[SDL_SCANCODE_LEFTBRACKET] = keycode_normal(1, 11);
|
||||
+ map[SDL_SCANCODE_RIGHTBRACKET] = keycode_normal(1, 12);
|
||||
+
|
||||
+ map[SDL_SCANCODE_CAPSLOCK] = keycode_normal(2, 0);
|
||||
+ map[SDL_SCANCODE_A] = keycode_normal(2, 1);
|
||||
+ map[SDL_SCANCODE_S] = keycode_normal(2, 2);
|
||||
+ map[SDL_SCANCODE_D] = keycode_normal(2, 3);
|
||||
+ map[SDL_SCANCODE_F] = keycode_normal(2, 4);
|
||||
+ map[SDL_SCANCODE_G] = keycode_normal(2, 5);
|
||||
+ map[SDL_SCANCODE_H] = keycode_normal(2, 6);
|
||||
+ map[SDL_SCANCODE_J] = keycode_normal(2, 7);
|
||||
+ map[SDL_SCANCODE_K] = keycode_normal(2, 8);
|
||||
+ map[SDL_SCANCODE_L] = keycode_normal(2, 9);
|
||||
+ map[SDL_SCANCODE_SEMICOLON] = keycode_normal(2, 10);
|
||||
+ map[SDL_SCANCODE_APOSTROPHE] = keycode_normal(2, 11);
|
||||
+ map[SDL_SCANCODE_BACKSLASH] = keycode_normal(2, 12);
|
||||
+ map[SDL_SCANCODE_RETURN] = keycode_normal(2, 13);
|
||||
+
|
||||
+ map[SDL_SCANCODE_LSHIFT] = keycode_normal(3, 0);
|
||||
+ map[SDL_SCANCODE_NONUSBACKSLASH] = keycode_normal(3, 1);
|
||||
+ map[SDL_SCANCODE_Z] = keycode_normal(3, 2);
|
||||
+ map[SDL_SCANCODE_X] = keycode_normal(3, 3);
|
||||
+ map[SDL_SCANCODE_C] = keycode_normal(3, 4);
|
||||
+ map[SDL_SCANCODE_V] = keycode_normal(3, 5);
|
||||
+ map[SDL_SCANCODE_B] = keycode_normal(3, 6);
|
||||
+ map[SDL_SCANCODE_N] = keycode_normal(3, 7);
|
||||
+ map[SDL_SCANCODE_M] = keycode_normal(3, 8);
|
||||
+ map[SDL_SCANCODE_COMMA] = keycode_normal(3, 9);
|
||||
+ map[SDL_SCANCODE_PERIOD] = keycode_normal(3, 10);
|
||||
+ map[SDL_SCANCODE_SLASH] = keycode_normal(3, 11);
|
||||
+ map[SDL_SCANCODE_RSHIFT] = keycode_normal(3, 12);
|
||||
+
|
||||
+ map[SDL_SCANCODE_LCTRL] = keycode_normal(4, 0);
|
||||
+ map[SDL_SCANCODE_LGUI] = keycode_normal(4, 1);
|
||||
+ map[SDL_SCANCODE_LALT] = keycode_normal(4, 2);
|
||||
+ map[SDL_SCANCODE_SPACE] = keycode_normal(4, 3);
|
||||
+ map[SDL_SCANCODE_RALT] = keycode_normal(4, 4);
|
||||
+ map[SDL_SCANCODE_RCTRL] = keycode_normal(4, 5);
|
||||
+
|
||||
+ map[SDL_SCANCODE_UP] = keycode_normal(5, 0);
|
||||
+ map[SDL_SCANCODE_LEFT] = keycode_normal(5, 1);
|
||||
+ map[SDL_SCANCODE_DOWN] = keycode_normal(5, 2);
|
||||
+ map[SDL_SCANCODE_RIGHT] = keycode_normal(5, 3);
|
||||
+
|
||||
+ map[SDL_SCANCODE_ESCAPE] = keycode_function(0);
|
||||
+ map[SDL_SCANCODE_F1] = keycode_function(1);
|
||||
+ map[SDL_SCANCODE_F2] = keycode_function(2);
|
||||
+ map[SDL_SCANCODE_F3] = keycode_function(3);
|
||||
+ map[SDL_SCANCODE_F4] = keycode_function(4);
|
||||
+ map[SDL_SCANCODE_F5] = keycode_function(5);
|
||||
+ map[SDL_SCANCODE_F6] = keycode_function(6);
|
||||
+ map[SDL_SCANCODE_F7] = keycode_function(7);
|
||||
+ map[SDL_SCANCODE_F8] = keycode_function(8);
|
||||
+ map[SDL_SCANCODE_F9] = keycode_function(9);
|
||||
+ map[SDL_SCANCODE_F10] = keycode_function(10);
|
||||
+ map[SDL_SCANCODE_F11] = keycode_function(11);
|
||||
+ map[SDL_SCANCODE_F12] = keycode_function(12);
|
||||
+ map[SDL_SCANCODE_INSERT] = keycode_function(13);
|
||||
+ map[SDL_SCANCODE_PRINTSCREEN] = keycode_function(14);
|
||||
+ map[SDL_SCANCODE_DELETE] = keycode_function(15);
|
||||
+ map[SDL_SCANCODE_HOME] = keycode_function(16);
|
||||
+ map[SDL_SCANCODE_END] = keycode_function(17);
|
||||
+ map[SDL_SCANCODE_PAGEUP] = keycode_function(18);
|
||||
+ map[SDL_SCANCODE_PAGEDOWN] = keycode_function(19);
|
||||
+ map[SDL_SCANCODE_SCROLLLOCK] = keycode_function(20);
|
||||
+
|
||||
+ map[SDL_SCANCODE_NUMLOCKCLEAR] = keycode_numpad(0, 0);
|
||||
+ map[SDL_SCANCODE_KP_DIVIDE] = keycode_numpad(0, 1);
|
||||
+ map[SDL_SCANCODE_KP_MULTIPLY] = keycode_numpad(0, 2);
|
||||
+ map[SDL_SCANCODE_KP_MINUS] = keycode_numpad(0, 3);
|
||||
+ map[SDL_SCANCODE_KP_7] = keycode_numpad(1, 0);
|
||||
+ map[SDL_SCANCODE_KP_8] = keycode_numpad(1, 1);
|
||||
+ map[SDL_SCANCODE_KP_9] = keycode_numpad(1, 2);
|
||||
+ map[SDL_SCANCODE_KP_PLUS] = keycode_numpad(1, 3);
|
||||
+ map[SDL_SCANCODE_KP_4] = keycode_numpad(2, 0);
|
||||
+ map[SDL_SCANCODE_KP_5] = keycode_numpad(2, 1);
|
||||
+ map[SDL_SCANCODE_KP_6] = keycode_numpad(2, 2);
|
||||
+ map[SDL_SCANCODE_KP_1] = keycode_numpad(3, 0);
|
||||
+ map[SDL_SCANCODE_KP_2] = keycode_numpad(3, 1);
|
||||
+ map[SDL_SCANCODE_KP_3] = keycode_numpad(3, 2);
|
||||
+ map[SDL_SCANCODE_KP_ENTER] = keycode_numpad(3, 3);
|
||||
+ map[SDL_SCANCODE_KP_0] = keycode_numpad(4, 0);
|
||||
+ map[SDL_SCANCODE_KP_COMMA] = keycode_numpad(4, 1);
|
||||
+ };
|
||||
+
|
||||
+ uint8_t map[SDL_NUM_SCANCODES];
|
||||
+};
|
||||
+static Keymap s_sdl_keymap;
|
||||
+
|
||||
+static void poll_sdl_events(WindowServer& window_server)
|
||||
+{
|
||||
+ {
|
||||
+ static int prev_x { 0 };
|
||||
+ static int prev_y { 0 };
|
||||
+
|
||||
+ int x, y;
|
||||
+ SDL_GetMouseState(&x, &y);
|
||||
+
|
||||
+ if (prev_x != x || prev_y != y)
|
||||
+ {
|
||||
+ int w, h;
|
||||
+ SDL_GetWindowSize(g_window, &w, &h);
|
||||
+
|
||||
+ window_server.on_mouse_move_abs({
|
||||
+ .abs_x = x,
|
||||
+ .abs_y = y,
|
||||
+ .min_x = 0,
|
||||
+ .min_y = 0,
|
||||
+ .max_x = w,
|
||||
+ .max_y = h,
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ prev_x = x;
|
||||
+ prev_y = y;
|
||||
+ }
|
||||
+
|
||||
+ SDL_Event event;
|
||||
+ while (SDL_PollEvent(&event))
|
||||
+ {
|
||||
+ switch (event.type)
|
||||
+ {
|
||||
+ case SDL_QUIT:
|
||||
+ window_server.stop();
|
||||
+ break;
|
||||
+ case SDL_WINDOWEVENT:
|
||||
+ if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
+ SDL_ShowCursor(SDL_DISABLE);
|
||||
+ if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
+ SDL_ShowCursor(SDL_ENABLE);
|
||||
+ break;
|
||||
+ case SDL_KEYDOWN:
|
||||
+ case SDL_KEYUP:
|
||||
+ {
|
||||
+ uint16_t modifier = 0;
|
||||
+ if (event.key.keysym.mod & KMOD_LSHIFT)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::LShift;
|
||||
+ if (event.key.keysym.mod & KMOD_RSHIFT)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::RShift;
|
||||
+ if (event.key.keysym.mod & KMOD_LCTRL)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::LCtrl;
|
||||
+ if (event.key.keysym.mod & KMOD_RCTRL)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::RCtrl;
|
||||
+ if (event.key.keysym.mod & KMOD_LALT)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::LAlt;
|
||||
+ if (event.key.keysym.mod & KMOD_RALT)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::RAlt;
|
||||
+ if (event.key.keysym.mod & KMOD_NUM)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::NumLock;
|
||||
+ if (event.key.keysym.mod & KMOD_SCROLL)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::ScrollLock;
|
||||
+ if (event.key.keysym.mod & KMOD_CAPS)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::CapsLock;
|
||||
+ if (event.key.state == SDL_PRESSED)
|
||||
+ modifier |= LibInput::KeyEvent::Modifier::Pressed;
|
||||
+
|
||||
+ window_server.on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw({
|
||||
+ .modifier = modifier,
|
||||
+ .keycode = s_sdl_keymap.map[event.key.keysym.scancode],
|
||||
+ }));
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
+ case SDL_MOUSEBUTTONDOWN:
|
||||
+ case SDL_MOUSEBUTTONUP:
|
||||
+ {
|
||||
+ LibInput::MouseButton button_map[] {
|
||||
+ [0] = LibInput::MouseButton::Left,
|
||||
+ [SDL_BUTTON_LEFT] = LibInput::MouseButton::Left,
|
||||
+ [SDL_BUTTON_MIDDLE] = LibInput::MouseButton::Middle,
|
||||
+ [SDL_BUTTON_RIGHT] = LibInput::MouseButton::Right,
|
||||
+ [SDL_BUTTON_X1] = LibInput::MouseButton::Extra1,
|
||||
+ [SDL_BUTTON_X2] = LibInput::MouseButton::Extra2,
|
||||
+ };
|
||||
+
|
||||
+ window_server.on_mouse_button({
|
||||
+ .button = button_map[event.button.button],
|
||||
+ .pressed = (event.button.state == SDL_PRESSED),
|
||||
+ });
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
+ case SDL_MOUSEWHEEL:
|
||||
+ {
|
||||
+ window_server.on_mouse_scroll({
|
||||
+ .scroll = event.wheel.y,
|
||||
+ });
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#include <BAN/Assert.h>
|
||||
|
||||
#if __is_kernel
|
||||
|
||||
#include <kernel/Panic.h>
|
||||
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
||||
{
|
||||
Kernel::panic_impl(location, msg);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <BAN/Debug.h>
|
||||
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
||||
{
|
||||
derrorln("{}: {}", location, msg);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -1,9 +0,0 @@
|
||||
#include <BAN/New.h>
|
||||
|
||||
void* operator new(size_t size) { return BAN::allocator(size); }
|
||||
void* operator new[](size_t size) { return BAN::allocator(size); }
|
||||
|
||||
void operator delete(void* addr) { BAN::deallocator(addr); }
|
||||
void operator delete[](void* addr) { BAN::deallocator(addr); }
|
||||
void operator delete(void* addr, size_t) { BAN::deallocator(addr); }
|
||||
void operator delete[](void* addr, size_t) { BAN::deallocator(addr); }
|
||||
Binary file not shown.
@@ -1,11 +0,0 @@
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
StringView::StringView(const String& other)
|
||||
: StringView(other.data(), other.size())
|
||||
{ }
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -1,71 +0,0 @@
|
||||
#include <BAN/Time.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
static constexpr bool is_leap_year(uint64_t year)
|
||||
{
|
||||
if (year % 400 == 0)
|
||||
return true;
|
||||
if (year % 100 == 0)
|
||||
return false;
|
||||
if (year % 4 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr uint64_t leap_days_since_epoch(const BAN::Time& time)
|
||||
{
|
||||
uint64_t leap_years = 0;
|
||||
for (uint32_t year = 1970; year < time.year; year++)
|
||||
if (is_leap_year(year))
|
||||
leap_years++;
|
||||
if (is_leap_year(time.year) && time.month >= 3)
|
||||
leap_years++;
|
||||
return leap_years;
|
||||
}
|
||||
|
||||
static constexpr uint64_t month_days[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
|
||||
uint64_t to_unix_time(const BAN::Time& time)
|
||||
{
|
||||
uint64_t years = time.year - 1970;
|
||||
uint64_t days = years * 365 + month_days[time.month - 1] + leap_days_since_epoch(time) + (time.day - 1);
|
||||
uint64_t hours = days * 24 + time.hour;
|
||||
uint64_t minutes = hours * 60 + time.minute;
|
||||
uint64_t seconds = minutes * 60 + time.second;
|
||||
return seconds;
|
||||
}
|
||||
|
||||
BAN::Time from_unix_time(uint64_t unix_time)
|
||||
{
|
||||
BAN::Time time {};
|
||||
|
||||
time.second = unix_time % 60; unix_time /= 60;
|
||||
time.minute = unix_time % 60; unix_time /= 60;
|
||||
time.hour = unix_time % 24; unix_time /= 24;
|
||||
|
||||
uint64_t total_days = unix_time;
|
||||
|
||||
time.week_day = (total_days + 4) % 7 + 1;
|
||||
|
||||
time.year = 1970;
|
||||
while (total_days >= 365U + is_leap_year(time.year))
|
||||
{
|
||||
total_days -= 365U + is_leap_year(time.year);
|
||||
time.year++;
|
||||
}
|
||||
|
||||
bool is_leap_day = is_leap_year(time.year) && total_days == month_days[2];
|
||||
bool had_leap_day = is_leap_year(time.year) && total_days > month_days[2];
|
||||
|
||||
for (time.month = 1; time.month < 12; time.month++)
|
||||
if (total_days < month_days[time.month] + (is_leap_day || had_leap_day))
|
||||
break;
|
||||
|
||||
time.day = total_days - month_days[time.month - 1] + !had_leap_day;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -1,16 +0,0 @@
|
||||
set(BAN_SOURCES
|
||||
BAN/Assert.cpp
|
||||
BAN/New.cpp
|
||||
BAN/StringView.cpp
|
||||
BAN/Time.cpp
|
||||
)
|
||||
|
||||
add_library(ban ${BAN_SOURCES})
|
||||
|
||||
set_target_properties(ban PROPERTIES OUTPUT_NAME libban)
|
||||
|
||||
# set SONAME as cmake doesn't set it for some reason??
|
||||
set_target_properties(ban PROPERTIES LINK_FLAGS "-Wl,-soname,libban.so")
|
||||
|
||||
banan_install_headers(ban)
|
||||
install(TARGETS ban OPTIONAL)
|
||||
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Span.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, size_t S>
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
using size_type = decltype(S);
|
||||
using value_type = T;
|
||||
using iterator = IteratorSimple<T, Array>;
|
||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||
|
||||
public:
|
||||
constexpr Array() = default;
|
||||
constexpr Array(const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + size()); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||
|
||||
constexpr const T& operator[](size_type) const;
|
||||
constexpr T& operator[](size_type);
|
||||
|
||||
constexpr const T& back() const;
|
||||
constexpr T& back();
|
||||
constexpr const T& front() const;
|
||||
constexpr T& front();
|
||||
|
||||
Span<T> span() { return Span(m_data, size()); }
|
||||
Span<const T> span() const { return Span(m_data, size()); }
|
||||
|
||||
constexpr size_type size() const;
|
||||
|
||||
constexpr const T* data() const { return m_data; }
|
||||
constexpr T* data() { return m_data; }
|
||||
|
||||
private:
|
||||
T m_data[S] {};
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr Array<T, S>::Array(const T& value)
|
||||
{
|
||||
for (size_type i = 0; i < S; i++)
|
||||
m_data[i] = value;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr const T& Array<T, S>::operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < S);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr T& Array<T, S>::operator[](size_type index)
|
||||
{
|
||||
ASSERT(index < S);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr const T& Array<T, S>::back() const
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[S - 1];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr T& Array<T, S>::back()
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[S - 1];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr const T& Array<T, S>::front() const
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr T& Array<T, S>::front()
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
constexpr typename Array<T, S>::size_type Array<T, S>::size() const
|
||||
{
|
||||
return S;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define __ban_assert_stringify_helper(s) #s
|
||||
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
|
||||
|
||||
#define ASSERT(cond) \
|
||||
(__builtin_expect(!(cond), 0) \
|
||||
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
|
||||
: (void)0)
|
||||
|
||||
#define ASSERT_NOT_REACHED() \
|
||||
__ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT_NOT_REACHED() reached")
|
||||
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
|
||||
@@ -1,99 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
enum MemoryOrder
|
||||
{
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
||||
};
|
||||
|
||||
template<typename T> concept atomic_c = is_integral_v<T> || is_pointer_v<T>;
|
||||
template<typename T> concept atomic_lockfree_c = (is_integral_v<T> || is_pointer_v<T>) && __atomic_always_lock_free(sizeof(T), 0);
|
||||
|
||||
template<atomic_lockfree_c T, atomic_c U>
|
||||
inline void atomic_store(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { __atomic_store_n(&obj, value, mem_order); }
|
||||
template<atomic_lockfree_c T>
|
||||
inline T atomic_load(T& obj, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_load_n(&obj, mem_order); }
|
||||
|
||||
template<atomic_lockfree_c T, atomic_c U>
|
||||
inline T atomic_exchange(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_exchange_n(&obj, value, mem_order); }
|
||||
template<atomic_lockfree_c T, atomic_lockfree_c U, atomic_c V>
|
||||
inline bool atomic_compare_exchange(T& obj, U& expected, V value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_compare_exchange_n(&obj, &expected, value, false, mem_order, mem_order); }
|
||||
|
||||
#define DECL_ATOMIC_INLINE template<atomic_lockfree_c T, atomic_c U> inline
|
||||
DECL_ATOMIC_INLINE T atomic_add_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_add_fetch (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_sub_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_sub_fetch (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_and_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_and_fetch (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_xor_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_xor_fetch (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_or_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_or_fetch (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_nand_fetch(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_nand_fetch(&obj, value, mem_order); }
|
||||
|
||||
DECL_ATOMIC_INLINE T atomic_fetch_add (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_add (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_fetch_sub (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_sub (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_fetch_and (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_and (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_fetch_xor (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_xor (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_fetch_or (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_or (&obj, value, mem_order); }
|
||||
DECL_ATOMIC_INLINE T atomic_fetch_nand(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_nand(&obj, value, mem_order); }
|
||||
#undef DECL_ATOMIC_INLINE
|
||||
|
||||
template<atomic_lockfree_c T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
||||
class Atomic
|
||||
{
|
||||
Atomic(const Atomic&) = delete;
|
||||
Atomic(Atomic&&) = delete;
|
||||
Atomic& operator=(const Atomic&) volatile = delete;
|
||||
Atomic& operator=(Atomic&&) volatile = delete;
|
||||
|
||||
public:
|
||||
constexpr Atomic() : m_value(0) {}
|
||||
constexpr Atomic(T val) : m_value(val) {}
|
||||
|
||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return atomic_load(m_value, mem_order); }
|
||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { atomic_store(m_value, val, mem_order); }
|
||||
|
||||
inline T operator=(T val) volatile { store(val); return val; }
|
||||
|
||||
inline operator T() const volatile { return load(); }
|
||||
|
||||
inline T operator+=(T val) volatile { return atomic_add_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator-=(T val) volatile { return atomic_sub_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator&=(T val) volatile { return atomic_and_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator^=(T val) volatile { return atomic_xor_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator|=(T val) volatile { return atomic_or_fetch(m_value, val, MEM_ORDER); }
|
||||
|
||||
inline T operator--() volatile { return atomic_sub_fetch(m_value, 1, MEM_ORDER); }
|
||||
inline T operator++() volatile { return atomic_add_fetch(m_value, 1, MEM_ORDER); }
|
||||
|
||||
inline T operator--(int) volatile { return atomic_fetch_sub(m_value, 1, MEM_ORDER); }
|
||||
inline T operator++(int) volatile { return atomic_fetch_add(m_value, 1, MEM_ORDER); }
|
||||
|
||||
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_compare_exchange(m_value, expected, desired, mem_order); }
|
||||
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_exchange(m_value, desired, mem_order); };
|
||||
|
||||
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_add_fetch (m_value, val, mem_order); }
|
||||
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_sub_fetch (m_value, val, mem_order); }
|
||||
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_and_fetch (m_value, val, mem_order); }
|
||||
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_xor_fetch (m_value, val, mem_order); }
|
||||
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_or_fetch (m_value, val, mem_order); }
|
||||
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_nand_fetch(m_value, val, mem_order); }
|
||||
|
||||
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_add (m_value, val, mem_order); }
|
||||
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_sub (m_value, val, mem_order); }
|
||||
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_and (m_value, val, mem_order); }
|
||||
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_xor (m_value, val, mem_order); }
|
||||
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_or (m_value, val, mem_order); }
|
||||
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_nand(m_value, val, mem_order); }
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename To, typename From>
|
||||
constexpr To bit_cast(const From& from)
|
||||
{
|
||||
return __builtin_bit_cast(To, from);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Array.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<size_t N>
|
||||
class Bitset
|
||||
{
|
||||
public:
|
||||
using internal_type = uint64_t;
|
||||
|
||||
public:
|
||||
|
||||
private:
|
||||
BAN::Array<internal_type, BAN::Math::div_round_up(N, sizeof(internal_type) * 8)> m_bits;
|
||||
};
|
||||
|
||||
void foo()
|
||||
{
|
||||
sizeof(Bitset<65>);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Span.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<bool CONST>
|
||||
class ByteSpanGeneral
|
||||
{
|
||||
public:
|
||||
using value_type = maybe_const_t<CONST, uint8_t>;
|
||||
using size_type = size_t;
|
||||
|
||||
public:
|
||||
ByteSpanGeneral() = default;
|
||||
ByteSpanGeneral(value_type* data, size_type size)
|
||||
: m_data(data)
|
||||
, m_size(size)
|
||||
{ }
|
||||
|
||||
template<bool SRC_CONST>
|
||||
ByteSpanGeneral(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
template<bool SRC_CONST>
|
||||
ByteSpanGeneral(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ByteSpanGeneral(const Span<T>& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
template<typename T>
|
||||
ByteSpanGeneral(Span<T>&& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
template<bool SRC_CONST>
|
||||
ByteSpanGeneral& operator=(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
||||
{
|
||||
m_data = other.data();
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
template<bool SRC_CONST>
|
||||
ByteSpanGeneral& operator=(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
||||
{
|
||||
m_data = other.data();
|
||||
m_size = other.size();
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
static ByteSpanGeneral from(S& value) requires(CONST || !is_const_v<S>)
|
||||
{
|
||||
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
S& as() const requires(!CONST || is_const_v<S>)
|
||||
{
|
||||
ASSERT(m_data);
|
||||
ASSERT(m_size >= sizeof(S));
|
||||
return *reinterpret_cast<S*>(m_data);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
Span<S> as_span() const requires(!CONST || is_const_v<S>)
|
||||
{
|
||||
ASSERT(m_data);
|
||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||
}
|
||||
|
||||
[[nodiscard]] ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1)) const
|
||||
{
|
||||
ASSERT(m_data);
|
||||
ASSERT(m_size >= offset);
|
||||
if (length == size_type(-1))
|
||||
length = m_size - offset;
|
||||
ASSERT(m_size >= offset + length);
|
||||
return ByteSpanGeneral(m_data + offset, length);
|
||||
}
|
||||
|
||||
value_type& operator[](size_type offset) const
|
||||
{
|
||||
ASSERT(offset < m_size);
|
||||
return m_data[offset];
|
||||
}
|
||||
|
||||
value_type* data() const { return m_data; }
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_data = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type* m_data { nullptr };
|
||||
size_type m_size { 0 };
|
||||
|
||||
friend class ByteSpanGeneral<!CONST>;
|
||||
};
|
||||
|
||||
using ByteSpan = ByteSpanGeneral<false>;
|
||||
using ConstByteSpan = ByteSpanGeneral<true>;
|
||||
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, size_t S>
|
||||
class CircularQueue
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
|
||||
public:
|
||||
CircularQueue() = default;
|
||||
~CircularQueue();
|
||||
|
||||
void push(const T&);
|
||||
void push(T&&);
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args) requires is_constructible_v<T, Args...>;
|
||||
|
||||
void pop();
|
||||
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
const T& back() const;
|
||||
T& back();
|
||||
|
||||
const T& operator[](size_t index) const;
|
||||
T& operator[](size_t index);
|
||||
|
||||
void clear();
|
||||
|
||||
size_type size() const { return m_size; }
|
||||
bool empty() const { return size() == 0; }
|
||||
bool full() const { return size() == capacity(); }
|
||||
|
||||
static constexpr size_type capacity() { return S; }
|
||||
|
||||
private:
|
||||
T* element_at(size_type);
|
||||
const T* element_at(size_type) const;
|
||||
|
||||
private:
|
||||
alignas(T) uint8_t m_storage[sizeof(T) * capacity()];
|
||||
size_type m_first { 0 };
|
||||
size_type m_size { 0 };
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
CircularQueue<T, S>::~CircularQueue()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::push(const T& value)
|
||||
{
|
||||
emplace(BAN::move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::push(T&& value)
|
||||
{
|
||||
emplace(BAN::move(value));
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
template<typename... Args>
|
||||
void CircularQueue<T, S>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
ASSERT(!full());
|
||||
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
||||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::pop()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
element_at(m_first)->~T();
|
||||
m_first = (m_first + 1) % capacity();
|
||||
m_size--;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& CircularQueue<T, S>::front() const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at(m_first);
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& CircularQueue<T, S>::front()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at(m_first);
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& CircularQueue<T, S>::back() const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at((m_first + m_size - 1) % capacity());
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& CircularQueue<T, S>::back()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at((m_first + m_size - 1) % capacity());
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& CircularQueue<T, S>::operator[](size_t index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return *element_at((m_first + index) % capacity());
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& CircularQueue<T, S>::operator[](size_t index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return *element_at((m_first + index) % capacity());
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::clear()
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
element_at((m_first + i) % capacity())->~T();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||
{
|
||||
ASSERT(index < capacity());
|
||||
return (const T*)(m_storage + index * sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T* CircularQueue<T, S>::element_at(size_type index)
|
||||
{
|
||||
ASSERT(index < capacity());
|
||||
return (T*)(m_storage + index * sizeof(T));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if __is_kernel
|
||||
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
|
||||
|
||||
inline uint64_t _ban_init_start_ms()
|
||||
{
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
inline uint64_t _ban_start_ms = _ban_init_start_ms();
|
||||
|
||||
#define __print_timestamp() \
|
||||
do { \
|
||||
timespec ts; \
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts); \
|
||||
const auto ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000 - _ban_start_ms; \
|
||||
BAN::Formatter::print(__debug_putchar, "[{}.{03}] ", ms / 1000, ms % 1000); \
|
||||
} while (false)
|
||||
|
||||
#define dprintln(...) \
|
||||
do { \
|
||||
flockfile(stddbg); \
|
||||
__print_timestamp(); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar,"\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while (false)
|
||||
|
||||
#define dwarnln(...) \
|
||||
do { \
|
||||
flockfile(stddbg); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||
__print_timestamp(); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define derrorln(...) \
|
||||
do { \
|
||||
flockfile(stddbg); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||
__print_timestamp(); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define dprintln_if(cond, ...) \
|
||||
do { \
|
||||
if constexpr(cond) \
|
||||
dprintln(__VA_ARGS__); \
|
||||
} while(false)
|
||||
|
||||
#define dwarnln_if(cond, ...) \
|
||||
do { \
|
||||
if constexpr(cond) \
|
||||
dwarnln(__VA_ARGS__); \
|
||||
} while(false)
|
||||
|
||||
#define derrorln_if(cond, ...) \
|
||||
do { \
|
||||
if constexpr(cond) \
|
||||
derrorln(__VA_ARGS__); \
|
||||
} while(false)
|
||||
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<integral T>
|
||||
constexpr T swap_endianness(T value)
|
||||
{
|
||||
if constexpr(sizeof(T) == 1)
|
||||
return value;
|
||||
if constexpr(sizeof(T) == 2)
|
||||
return (((value >> 8) & 0xFF) << 0)
|
||||
| (((value >> 0) & 0xFF) << 8);
|
||||
if constexpr(sizeof(T) == 4)
|
||||
return (((value >> 24) & 0xFF) << 0)
|
||||
| (((value >> 16) & 0xFF) << 8)
|
||||
| (((value >> 8) & 0xFF) << 16)
|
||||
| (((value >> 0) & 0xFF) << 24);
|
||||
if constexpr(sizeof(T) == 8)
|
||||
return (((value >> 56) & 0xFF) << 0)
|
||||
| (((value >> 48) & 0xFF) << 8)
|
||||
| (((value >> 40) & 0xFF) << 16)
|
||||
| (((value >> 32) & 0xFF) << 24)
|
||||
| (((value >> 24) & 0xFF) << 32)
|
||||
| (((value >> 16) & 0xFF) << 40)
|
||||
| (((value >> 8) & 0xFF) << 48)
|
||||
| (((value >> 0) & 0xFF) << 56);
|
||||
T result { 0 };
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
result |= ((value >> (i * 8)) & 0xFF) << ((sizeof(T) - i - 1) * 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_little_endian(T value)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return swap_endianness(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T little_endian_to_host(T value)
|
||||
{
|
||||
return host_to_little_endian(value);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_big_endian(T value)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return swap_endianness(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T big_endian_to_host(T value)
|
||||
{
|
||||
return host_to_big_endian(value);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
struct LittleEndian
|
||||
{
|
||||
constexpr LittleEndian()
|
||||
: raw(0)
|
||||
{ }
|
||||
|
||||
constexpr LittleEndian(T value)
|
||||
: raw(host_to_little_endian(value))
|
||||
{ }
|
||||
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_little_endian(raw);
|
||||
}
|
||||
|
||||
private:
|
||||
T raw;
|
||||
};
|
||||
|
||||
template<integral T>
|
||||
struct BigEndian
|
||||
{
|
||||
constexpr BigEndian()
|
||||
: raw(0)
|
||||
{ }
|
||||
|
||||
constexpr BigEndian(T value)
|
||||
: raw(host_to_big_endian(value))
|
||||
{ }
|
||||
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_big_endian(raw);
|
||||
}
|
||||
|
||||
private:
|
||||
T raw;
|
||||
};
|
||||
|
||||
template<integral T>
|
||||
using NetworkEndian = BigEndian<T>;
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_network_endian(T value)
|
||||
{
|
||||
return host_to_big_endian(value);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T network_endian_to_host(T value)
|
||||
{
|
||||
return big_endian_to_host(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <BAN/Variant.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __is_kernel
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/Errors.h>
|
||||
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
||||
#define MUST_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
||||
#else
|
||||
#include <BAN/Debug.h>
|
||||
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } e.release_value(); })
|
||||
#define MUST_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } &e.release_value(); })
|
||||
#endif
|
||||
|
||||
#define TRY(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) return e.release_error(); e.release_value(); })
|
||||
#define TRY_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) return e.release_error(); &e.release_value(); })
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
class Error
|
||||
{
|
||||
#ifdef __is_kernel
|
||||
private:
|
||||
static constexpr uint64_t kernel_error_mask = uint64_t(1) << 63;
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifdef __is_kernel
|
||||
static Error from_error_code(Kernel::ErrorCode error)
|
||||
{
|
||||
return Error((uint64_t)error | kernel_error_mask);
|
||||
}
|
||||
#else
|
||||
template<size_t N>
|
||||
consteval static Error from_literal(const char (&message)[N])
|
||||
{
|
||||
return Error(message);
|
||||
}
|
||||
#endif
|
||||
|
||||
static Error from_errno(int error)
|
||||
{
|
||||
return Error(error);
|
||||
}
|
||||
|
||||
#ifdef __is_kernel
|
||||
Kernel::ErrorCode kernel_error() const
|
||||
{
|
||||
return (Kernel::ErrorCode)(m_error_code & ~kernel_error_mask);
|
||||
}
|
||||
|
||||
bool is_kernel_error() const
|
||||
{
|
||||
return m_error_code & kernel_error_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
constexpr uint64_t get_error_code() const { return m_error_code; }
|
||||
const char* get_message() const
|
||||
{
|
||||
#ifdef __is_kernel
|
||||
if (m_error_code & kernel_error_mask)
|
||||
return Kernel::error_string(kernel_error());
|
||||
#else
|
||||
if (m_message)
|
||||
return m_message;
|
||||
#endif
|
||||
if (auto* desc = strerrordesc_np(m_error_code))
|
||||
return desc;
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr Error(uint64_t error)
|
||||
: m_error_code(error)
|
||||
{}
|
||||
|
||||
#ifndef __is_kernel
|
||||
constexpr Error(const char* message)
|
||||
: m_message(message)
|
||||
{}
|
||||
#endif
|
||||
|
||||
uint64_t m_error_code { 0 };
|
||||
|
||||
#ifndef __is_kernel
|
||||
const char* m_message { nullptr };
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class [[nodiscard]] ErrorOr
|
||||
{
|
||||
BAN_NON_COPYABLE(ErrorOr);
|
||||
public:
|
||||
ErrorOr(const T& value)
|
||||
: m_data(value)
|
||||
{}
|
||||
ErrorOr(T&& value)
|
||||
: m_data(move(value))
|
||||
{}
|
||||
ErrorOr(const Error& error)
|
||||
: m_data(error)
|
||||
{}
|
||||
ErrorOr(Error&& error)
|
||||
: m_data(move(error))
|
||||
{}
|
||||
ErrorOr(ErrorOr&& other)
|
||||
: m_data(move(other.m_data))
|
||||
{}
|
||||
ErrorOr& operator=(ErrorOr&& other)
|
||||
{
|
||||
m_data = move(other.m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool is_error() const { return m_data.template has<Error>(); }
|
||||
const Error& error() const { return m_data.template get<Error>(); }
|
||||
Error& error() { return m_data.template get<Error>(); }
|
||||
const T& value() const { return m_data.template get<T>(); }
|
||||
T& value() { return m_data.template get<T>(); }
|
||||
|
||||
Error release_error() { return move(error()); m_data.clear(); }
|
||||
T release_value() { return move(value()); m_data.clear(); }
|
||||
|
||||
private:
|
||||
Variant<Error, T> m_data;
|
||||
};
|
||||
|
||||
template<lvalue_reference T>
|
||||
class [[nodiscard]] ErrorOr<T>
|
||||
{
|
||||
public:
|
||||
ErrorOr(T value)
|
||||
{
|
||||
m_data.template set<T>(value);
|
||||
}
|
||||
ErrorOr(Error&& error)
|
||||
: m_data(move(error))
|
||||
{ }
|
||||
ErrorOr(const Error& error)
|
||||
: m_data(error)
|
||||
{ }
|
||||
|
||||
bool is_error() const { return m_data.template has<Error>(); }
|
||||
Error& error() { return m_data.template get<Error>(); }
|
||||
const Error& error() const { return m_data.template get<Error>(); }
|
||||
T value() { return m_data.template get<T>(); }
|
||||
|
||||
Error release_error() { return move(error()); m_data.clear(); }
|
||||
T release_value() { return value(); m_data.clear(); }
|
||||
|
||||
private:
|
||||
Variant<Error, T> m_data;
|
||||
};
|
||||
|
||||
template<>
|
||||
class [[nodiscard]] ErrorOr<void>
|
||||
{
|
||||
public:
|
||||
ErrorOr() {}
|
||||
ErrorOr(const Error& error) : m_data(error), m_has_error(true) {}
|
||||
ErrorOr(Error&& error) : m_data(move(error)), m_has_error(true) {}
|
||||
|
||||
bool is_error() const { return m_has_error; }
|
||||
Error& error() { return m_data; }
|
||||
const Error& error() const { return m_data; }
|
||||
void value() { }
|
||||
|
||||
Error release_error() { return move(m_data); }
|
||||
void release_value() { }
|
||||
|
||||
private:
|
||||
Error m_data { Error::from_errno(0) };
|
||||
bool m_has_error { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Error& error, const ValueFormat& format)
|
||||
{
|
||||
print_argument(putc, error.get_message(), format);
|
||||
}
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Move.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
struct ValueFormat;
|
||||
|
||||
template<typename F, typename... Args>
|
||||
concept PrintableArguments = requires(F putc, Args&&... args, const ValueFormat& format)
|
||||
{
|
||||
(print_argument(putc, BAN::forward<Args>(args), format), ...);
|
||||
};
|
||||
|
||||
template<typename F, typename T>
|
||||
inline void print_argument(F putc, T value, const ValueFormat& format);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename F, typename T>
|
||||
inline size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
IMPLEMENTATION
|
||||
|
||||
*/
|
||||
|
||||
struct ValueFormat
|
||||
{
|
||||
int base = 10;
|
||||
int percision = 3;
|
||||
int fill = 0;
|
||||
char fill_char = '0';
|
||||
bool upper = false;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
inline void print(F putc, const char* format)
|
||||
{
|
||||
while (*format)
|
||||
{
|
||||
putc(*format);
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F, typename Arg, typename... Args> requires PrintableArguments<F, Arg, Args...>
|
||||
inline void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
||||
{
|
||||
while (*format && *format != '{')
|
||||
{
|
||||
putc(*format);
|
||||
format++;
|
||||
}
|
||||
|
||||
if (*format == '{')
|
||||
{
|
||||
size_t arg_len = detail::parse_format_and_print_argument(putc, format, forward<Arg>(arg));
|
||||
if (arg_len == size_t(-1))
|
||||
return print(putc, format);
|
||||
print(putc, format + arg_len, forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
inline void println(F putc, const char* format, Args&&... args)
|
||||
{
|
||||
print(putc, format, args...);
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename F, typename Arg>
|
||||
inline size_t parse_format_and_print_argument(F putc, const char* format, Arg&& argument)
|
||||
{
|
||||
ValueFormat value_format;
|
||||
|
||||
if (format[0] != '{')
|
||||
return size_t(-1);
|
||||
|
||||
size_t i = 1;
|
||||
do
|
||||
{
|
||||
if (!format[i] || format[i] == '}')
|
||||
break;
|
||||
|
||||
if (format[i] == ' ')
|
||||
{
|
||||
value_format.fill_char = ' ';
|
||||
i++;
|
||||
}
|
||||
|
||||
if ('0' <= format[i] && format[i] <= '9')
|
||||
{
|
||||
int fill = 0;
|
||||
while ('0' <= format[i] && format[i] <= '9')
|
||||
{
|
||||
fill = (fill * 10) + (format[i] - '0');
|
||||
i++;
|
||||
}
|
||||
value_format.fill = fill;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case 'b': value_format.base = 2; value_format.upper = false; i++; break;
|
||||
case 'B': value_format.base = 2; value_format.upper = true; i++; break;
|
||||
case 'o': value_format.base = 8; value_format.upper = false; i++; break;
|
||||
case 'O': value_format.base = 8; value_format.upper = true; i++; break;
|
||||
case 'd': value_format.base = 10; value_format.upper = false; i++; break;
|
||||
case 'D': value_format.base = 10; value_format.upper = true; i++; break;
|
||||
case 'h': value_format.base = 16; value_format.upper = false; i++; break;
|
||||
case 'H': value_format.base = 16; value_format.upper = true; i++; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!format[i] || format[i] == '}')
|
||||
break;
|
||||
|
||||
if (format[i] == '.')
|
||||
{
|
||||
i++;
|
||||
int percision = 0;
|
||||
while ('0' <= format[i] && format[i] <= '9')
|
||||
{
|
||||
percision = (percision * 10) + (format[i] - '0');
|
||||
i++;
|
||||
}
|
||||
value_format.percision = percision;
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
if (format[i] != '}')
|
||||
return size_t(-1);
|
||||
|
||||
print_argument(putc, forward<Arg>(argument), value_format);
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
inline char value_to_base_char(uint8_t value, int base, bool upper)
|
||||
{
|
||||
if (base <= 10)
|
||||
return value + '0';
|
||||
if (base <= 36)
|
||||
{
|
||||
if (value < 10)
|
||||
return value + '0';
|
||||
return value + (upper ? 'A' : 'a') - 10;
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
|
||||
template<typename F, typename T>
|
||||
inline void print_integer(F putc, T value, const ValueFormat& format)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
for (int i = 0; i < format.fill - 1; i++)
|
||||
putc(format.fill_char);
|
||||
putc('0');
|
||||
return;
|
||||
}
|
||||
|
||||
bool sign = false;
|
||||
|
||||
// Fits signed 64-bit binary number and null
|
||||
char buffer[66];
|
||||
char* ptr = buffer + sizeof(buffer);
|
||||
*(--ptr) = '\0';
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
sign = true;
|
||||
T digit = (format.base - (value % format.base)) % format.base;
|
||||
*(--ptr) = value_to_base_char(digit, format.base, format.upper);
|
||||
value = -(value / format.base);
|
||||
}
|
||||
|
||||
while (value)
|
||||
{
|
||||
*(--ptr) = value_to_base_char(value % format.base, format.base, format.upper);
|
||||
value /= format.base;
|
||||
}
|
||||
|
||||
while (ptr >= buffer + sizeof(buffer) - format.fill)
|
||||
*(--ptr) = format.fill_char;
|
||||
|
||||
if (sign)
|
||||
*(--ptr) = '-';
|
||||
|
||||
print(putc, ptr);
|
||||
}
|
||||
|
||||
template<typename F, typename T>
|
||||
inline void print_floating(F putc, T value, const ValueFormat& format)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
putc('-');
|
||||
return print_floating(putc, -value, format);
|
||||
}
|
||||
|
||||
int64_t int_part = (int64_t)value;
|
||||
T frac_part = value - (T)int_part;
|
||||
|
||||
print_integer(putc, int_part, format);
|
||||
|
||||
if (format.percision > 0)
|
||||
putc('.');
|
||||
|
||||
for (int i = 0; i < format.percision; i++)
|
||||
{
|
||||
frac_part *= format.base;
|
||||
if (i == format.percision - 1)
|
||||
frac_part += 0.5;
|
||||
|
||||
putc(value_to_base_char((uint8_t)frac_part % format.base, format.base, format.upper));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void print_pointer(F putc, void* ptr, const ValueFormat& format)
|
||||
{
|
||||
uintptr_t value = (uintptr_t)ptr;
|
||||
print(putc, "0x");
|
||||
for (int i = sizeof(void*) * 8 - 4; i >= 0; i -= 4)
|
||||
putc(value_to_base_char((value >> i) & 0xF, 16, format.upper));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
TEMPLATE SPECIALIZATIONS
|
||||
|
||||
*/
|
||||
|
||||
template<typename F, integral T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
||||
template<typename F, floating_point T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_floating(putc, value, format); }
|
||||
template<typename F, pointer T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
|
||||
|
||||
template<typename F> inline void print_argument(F putc, char value, const ValueFormat&) { putc(value); }
|
||||
template<typename F> inline void print_argument(F putc, bool value, const ValueFormat&) { print(putc, value ? "true" : "false"); }
|
||||
template<typename F> inline void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value); }
|
||||
template<typename F> inline void print_argument(F putc, char* value, const ValueFormat&) { print(putc, value); }
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
|
||||
template<typename, size_t> class Array;
|
||||
template<typename> class ErrorOr;
|
||||
template<typename> class Function;
|
||||
template<typename> class Queue;
|
||||
class String;
|
||||
class StringView;
|
||||
template<typename> class Vector;
|
||||
template<typename> class LinkedList;
|
||||
template<typename... Ts> requires (!is_const_v<Ts> && ...) class Variant;
|
||||
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename>
|
||||
class Function;
|
||||
template<typename Ret, typename... Args>
|
||||
class Function<Ret(Args...)>
|
||||
{
|
||||
public:
|
||||
Function() = default;
|
||||
Function(Ret(*function)(Args...))
|
||||
{
|
||||
static_assert(sizeof(CallablePointer) <= m_size);
|
||||
new (m_storage) CallablePointer(function);
|
||||
}
|
||||
template<typename Own>
|
||||
Function(Ret(Own::*function)(Args...), Own& owner)
|
||||
{
|
||||
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
||||
new (m_storage) CallableMember<Own>(function, owner);
|
||||
}
|
||||
template<typename Own>
|
||||
Function(Ret(Own::*function)(Args...) const, const Own& owner)
|
||||
{
|
||||
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
||||
new (m_storage) CallableMemberConst<Own>(function, owner);
|
||||
}
|
||||
template<typename Lambda>
|
||||
Function(Lambda lambda) requires requires(Lambda lamda, Args&&... args) { { lambda(forward<Args>(args)...) } -> BAN::same_as<Ret>; }
|
||||
{
|
||||
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
|
||||
new (m_storage) CallableLambda<Lambda>(lambda);
|
||||
}
|
||||
|
||||
~Function()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
Ret operator()(Args... args) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return reinterpret_cast<const CallableBase*>(m_storage)->call(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
for (size_t i = 0; i < m_size; i++)
|
||||
if (m_storage[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (*this)
|
||||
reinterpret_cast<CallableBase*>(m_storage)->~CallableBase();
|
||||
memset(m_storage, 0, m_size);
|
||||
}
|
||||
|
||||
static constexpr size_t size() { return m_size; }
|
||||
|
||||
private:
|
||||
struct CallableBase
|
||||
{
|
||||
virtual ~CallableBase() {}
|
||||
virtual Ret call(Args...) const = 0;
|
||||
};
|
||||
|
||||
struct CallablePointer : public CallableBase
|
||||
{
|
||||
CallablePointer(Ret(*function)(Args...))
|
||||
: m_function(function)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return m_function(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Ret(*m_function)(Args...) = nullptr;
|
||||
};
|
||||
|
||||
template<typename Own>
|
||||
struct CallableMember : public CallableBase
|
||||
{
|
||||
CallableMember(Ret(Own::*function)(Args...), Own& owner)
|
||||
: m_owner(owner)
|
||||
, m_function(function)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return (m_owner.*m_function)(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Own& m_owner;
|
||||
Ret(Own::*m_function)(Args...) = nullptr;
|
||||
};
|
||||
|
||||
template<typename Own>
|
||||
struct CallableMemberConst : public CallableBase
|
||||
{
|
||||
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own& owner)
|
||||
: m_owner(owner)
|
||||
, m_function(function)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return (m_owner.*m_function)(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
const Own& m_owner;
|
||||
Ret(Own::*m_function)(Args...) const = nullptr;
|
||||
};
|
||||
|
||||
template<typename Lambda>
|
||||
struct CallableLambda : public CallableBase
|
||||
{
|
||||
CallableLambda(Lambda lambda)
|
||||
: m_lambda(lambda)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return m_lambda(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Lambda m_lambda;
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr size_t m_size = sizeof(void*) * 8;
|
||||
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/String.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct GUID
|
||||
{
|
||||
uint32_t component1 { 0 };
|
||||
uint16_t component2 { 0 };
|
||||
uint16_t component3 { 0 };
|
||||
uint8_t component45[8] { };
|
||||
|
||||
bool operator==(const GUID& other) const
|
||||
{
|
||||
return memcmp(this, &other, sizeof(GUID)) == 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::String> to_string() const
|
||||
{
|
||||
char buffer[37];
|
||||
char* ptr = buffer;
|
||||
|
||||
const auto append_hex_nibble =
|
||||
[&ptr](uint8_t nibble)
|
||||
{
|
||||
if (nibble < 10)
|
||||
*ptr++ = '0' + nibble;
|
||||
else
|
||||
*ptr++ = 'A' + nibble - 10;
|
||||
};
|
||||
|
||||
const auto append_hex_byte =
|
||||
[&append_hex_nibble](uint8_t byte)
|
||||
{
|
||||
append_hex_nibble(byte >> 4);
|
||||
append_hex_nibble(byte & 0xF);
|
||||
};
|
||||
|
||||
append_hex_byte((component1 >> 24) & 0xFF);
|
||||
append_hex_byte((component1 >> 16) & 0xFF);
|
||||
append_hex_byte((component1 >> 8) & 0xFF);
|
||||
append_hex_byte((component1 >> 0) & 0xFF);
|
||||
*ptr++ = '-';
|
||||
append_hex_byte((component2 >> 8) & 0xFF);
|
||||
append_hex_byte((component2 >> 0) & 0xFF);
|
||||
*ptr++ = '-';
|
||||
append_hex_byte((component3 >> 8) & 0xFF);
|
||||
append_hex_byte((component3 >> 0) & 0xFF);
|
||||
*ptr++ = '-';
|
||||
append_hex_byte(component45[0]);
|
||||
append_hex_byte(component45[1]);
|
||||
*ptr++ = '-';
|
||||
append_hex_byte(component45[2]);
|
||||
append_hex_byte(component45[3]);
|
||||
append_hex_byte(component45[4]);
|
||||
append_hex_byte(component45[5]);
|
||||
append_hex_byte(component45[6]);
|
||||
append_hex_byte(component45[7]);
|
||||
*ptr = '\0';
|
||||
|
||||
BAN::String guid;
|
||||
TRY(guid.append(buffer));
|
||||
return BAN::move(guid);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(GUID) == 16);
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct hash;
|
||||
|
||||
using hash_t = uint32_t;
|
||||
|
||||
inline constexpr hash_t u32_hash(uint32_t val)
|
||||
{
|
||||
val = ((val >> 16) ^ val) * 0x119de1f3;
|
||||
val = ((val >> 16) ^ val) * 0x119de1f3;
|
||||
val = ((val >> 16) ^ val);
|
||||
return val;
|
||||
}
|
||||
|
||||
inline constexpr hash_t u64_hash(uint64_t val)
|
||||
{
|
||||
hash_t low = u32_hash(val);
|
||||
hash_t high = u32_hash(val >> 32);
|
||||
return low ^ high;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
struct hash<T>
|
||||
{
|
||||
constexpr hash_t operator()(T val) const
|
||||
{
|
||||
if constexpr(sizeof(val) <= sizeof(uint32_t))
|
||||
return u32_hash(val);
|
||||
return u64_hash(val);
|
||||
}
|
||||
};
|
||||
|
||||
template<pointer T>
|
||||
struct hash<T>
|
||||
{
|
||||
constexpr hash_t operator()(T val) const
|
||||
{
|
||||
return hash<uintptr_t>()((uintptr_t)val);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||
class HashMap
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
template<typename... Args>
|
||||
Entry(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
: key(key)
|
||||
, value(forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
template<typename... Args>
|
||||
Entry(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
: key(BAN::move(key))
|
||||
, value(forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
Key key;
|
||||
T value;
|
||||
};
|
||||
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using key_type = Key;
|
||||
using value_type = T;
|
||||
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
||||
using const_iterator = ConstIteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
||||
|
||||
public:
|
||||
HashMap() = default;
|
||||
HashMap(const HashMap<Key, T, HASH>&);
|
||||
HashMap(HashMap<Key, T, HASH>&&);
|
||||
~HashMap();
|
||||
|
||||
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||
|
||||
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
||||
ErrorOr<iterator> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
||||
ErrorOr<iterator> insert(Key&& key, const T& value) { return emplace(move(key), value); }
|
||||
ErrorOr<iterator> insert(Key&& key, T&& value) { return emplace(move(key), move(value)); }
|
||||
|
||||
ErrorOr<iterator> insert_or_assign(const Key& key, const T& value) { return emplace_or_assign(key, value); }
|
||||
ErrorOr<iterator> insert_or_assign(const Key& key, T&& value) { return emplace_or_assign(key, move(value)); }
|
||||
ErrorOr<iterator> insert_or_assign(Key&& key, const T& value) { return emplace_or_assign(move(key), value); }
|
||||
ErrorOr<iterator> insert_or_assign(Key&& key, T&& value) { return emplace_or_assign(move(key), move(value)); }
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{ return emplace(Key(key), forward<Args>(args)...); }
|
||||
template<typename... Args>
|
||||
ErrorOr<iterator> emplace(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{ return emplace_or_assign(Key(key), forward<Args>(args)...); }
|
||||
template<typename... Args>
|
||||
ErrorOr<iterator> emplace_or_assign(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
||||
|
||||
ErrorOr<void> reserve(size_type);
|
||||
|
||||
void remove(const Key&);
|
||||
void remove(iterator it);
|
||||
void clear();
|
||||
|
||||
T& operator[](const Key&);
|
||||
const T& operator[](const Key&) const;
|
||||
|
||||
iterator find(const Key& key);
|
||||
const_iterator find(const Key& key) const;
|
||||
bool contains(const Key&) const;
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
|
||||
private:
|
||||
ErrorOr<void> rebucket(size_type);
|
||||
LinkedList<Entry>& get_bucket(const Key&);
|
||||
const LinkedList<Entry>& get_bucket(const Key&) const;
|
||||
Vector<LinkedList<Entry>>::iterator get_bucket_iterator(const Key&);
|
||||
Vector<LinkedList<Entry>>::const_iterator get_bucket_iterator(const Key&) const;
|
||||
|
||||
private:
|
||||
Vector<LinkedList<Entry>> m_buckets;
|
||||
size_type m_size = 0;
|
||||
|
||||
friend iterator;
|
||||
};
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
HashMap<Key, T, HASH>::HashMap(HashMap<Key, T, HASH>&& other)
|
||||
{
|
||||
*this = move(other);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
HashMap<Key, T, HASH>::~HashMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(const HashMap<Key, T, HASH>& other)
|
||||
{
|
||||
clear();
|
||||
m_buckets = other.m_buckets;
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(HashMap<Key, T, HASH>&& other)
|
||||
{
|
||||
clear();
|
||||
m_buckets = move(other.m_buckets);
|
||||
m_size = other.m_size;
|
||||
other.m_size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
template<typename... Args>
|
||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
ASSERT(!contains(key));
|
||||
TRY(rebucket(m_size + 1));
|
||||
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
TRY(bucket_it->emplace_back(move(key), forward<Args>(args)...));
|
||||
m_size++;
|
||||
|
||||
return iterator(m_buckets.end(), bucket_it, prev(bucket_it->end(), 1));
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
template<typename... Args>
|
||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
if (empty())
|
||||
return emplace(move(key), forward<Args>(args)...);
|
||||
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
for (auto entry_it = bucket_it->begin(); entry_it != bucket_it->end(); entry_it++)
|
||||
{
|
||||
if (entry_it->key != key)
|
||||
continue;
|
||||
entry_it->value = T(forward<Args>(args)...);
|
||||
return iterator(m_buckets.end(), bucket_it, entry_it);
|
||||
}
|
||||
|
||||
return emplace(move(key), forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
ErrorOr<void> HashMap<Key, T, HASH>::reserve(size_type size)
|
||||
{
|
||||
TRY(rebucket(size));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
void HashMap<Key, T, HASH>::remove(const Key& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it != end())
|
||||
remove(it);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
void HashMap<Key, T, HASH>::remove(iterator it)
|
||||
{
|
||||
it.outer_current()->remove(it.inner_current());
|
||||
m_size--;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
void HashMap<Key, T, HASH>::clear()
|
||||
{
|
||||
m_buckets.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
T& HashMap<Key, T, HASH>::operator[](const Key& key)
|
||||
{
|
||||
ASSERT(!empty());
|
||||
auto& bucket = get_bucket(key);
|
||||
for (Entry& entry : bucket)
|
||||
if (entry.key == key)
|
||||
return entry.value;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
const T& HashMap<Key, T, HASH>::operator[](const Key& key) const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
const auto& bucket = get_bucket(key);
|
||||
for (const Entry& entry : bucket)
|
||||
if (entry.key == key)
|
||||
return entry.value;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
typename HashMap<Key, T, HASH>::iterator HashMap<Key, T, HASH>::find(const Key& key)
|
||||
{
|
||||
if (empty())
|
||||
return end();
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
||||
if (it->key == key)
|
||||
return iterator(m_buckets.end(), bucket_it, it);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
typename HashMap<Key, T, HASH>::const_iterator HashMap<Key, T, HASH>::find(const Key& key) const
|
||||
{
|
||||
if (empty())
|
||||
return end();
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
||||
if (it->key == key)
|
||||
return const_iterator(m_buckets.end(), bucket_it, it);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
||||
{
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
bool HashMap<Key, T, HASH>::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
typename HashMap<Key, T, HASH>::size_type HashMap<Key, T, HASH>::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
ErrorOr<void> HashMap<Key, T, HASH>::rebucket(size_type bucket_count)
|
||||
{
|
||||
if (m_buckets.size() >= bucket_count)
|
||||
return {};
|
||||
|
||||
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||
Vector<LinkedList<Entry>> new_buckets;
|
||||
TRY(new_buckets.resize(new_bucket_count));
|
||||
|
||||
for (auto& bucket : m_buckets)
|
||||
{
|
||||
for (auto it = bucket.begin(); it != bucket.end();)
|
||||
{
|
||||
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
|
||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||
}
|
||||
}
|
||||
|
||||
m_buckets = move(new_buckets);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
||||
{
|
||||
return *get_bucket_iterator(key);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
||||
{
|
||||
return *get_bucket_iterator(key);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key)
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
auto index = HASH()(key) % m_buckets.size();
|
||||
return next(m_buckets.begin(), index);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::const_iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key) const
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
auto index = HASH()(key) % m_buckets.size();
|
||||
return next(m_buckets.begin(), index);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, typename HASH = hash<T>>
|
||||
class HashSet
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using iterator = IteratorDouble<T, Vector, LinkedList, HashSet>;
|
||||
using const_iterator = ConstIteratorDouble<T, Vector, LinkedList, HashSet>;
|
||||
|
||||
public:
|
||||
HashSet() = default;
|
||||
HashSet(const HashSet&);
|
||||
HashSet(HashSet&&);
|
||||
|
||||
HashSet& operator=(const HashSet&);
|
||||
HashSet& operator=(HashSet&&);
|
||||
|
||||
ErrorOr<void> insert(const T&);
|
||||
ErrorOr<void> insert(T&&);
|
||||
void remove(const T&);
|
||||
void clear();
|
||||
|
||||
ErrorOr<void> reserve(size_type);
|
||||
|
||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
||||
|
||||
bool contains(const T&) const;
|
||||
|
||||
size_type size() const;
|
||||
bool empty() const;
|
||||
|
||||
private:
|
||||
ErrorOr<void> rebucket(size_type);
|
||||
LinkedList<T>& get_bucket(const T&);
|
||||
const LinkedList<T>& get_bucket(const T&) const;
|
||||
|
||||
private:
|
||||
Vector<LinkedList<T>> m_buckets;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>::HashSet(const HashSet& other)
|
||||
: m_buckets(other.m_buckets)
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>::HashSet(HashSet&& other)
|
||||
: m_buckets(move(other.m_buckets))
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet& other)
|
||||
{
|
||||
clear();
|
||||
m_buckets = other.m_buckets;
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet&& other)
|
||||
{
|
||||
clear();
|
||||
m_buckets = move(other.m_buckets);
|
||||
m_size = other.m_size;
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
ErrorOr<void> HashSet<T, HASH>::insert(const T& key)
|
||||
{
|
||||
return insert(move(T(key)));
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
ErrorOr<void> HashSet<T, HASH>::insert(T&& key)
|
||||
{
|
||||
if (!empty() && get_bucket(key).contains(key))
|
||||
return {};
|
||||
|
||||
TRY(rebucket(m_size + 1));
|
||||
TRY(get_bucket(key).push_back(move(key)));
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
void HashSet<T, HASH>::remove(const T& key)
|
||||
{
|
||||
if (empty()) return;
|
||||
auto& bucket = get_bucket(key);
|
||||
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
||||
{
|
||||
if (*it == key)
|
||||
{
|
||||
bucket.remove(it);
|
||||
m_size--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
void HashSet<T, HASH>::clear()
|
||||
{
|
||||
m_buckets.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
ErrorOr<void> HashSet<T, HASH>::reserve(size_type size)
|
||||
{
|
||||
TRY(rebucket(size));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
bool HashSet<T, HASH>::contains(const T& key) const
|
||||
{
|
||||
if (empty()) return false;
|
||||
return get_bucket(key).contains(key);
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
typename HashSet<T, HASH>::size_type HashSet<T, HASH>::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
bool HashSet<T, HASH>::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
ErrorOr<void> HashSet<T, HASH>::rebucket(size_type bucket_count)
|
||||
{
|
||||
if (m_buckets.size() >= bucket_count)
|
||||
return {};
|
||||
|
||||
size_type new_bucket_count = Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||
Vector<LinkedList<T>> new_buckets;
|
||||
if (new_buckets.resize(new_bucket_count).is_error())
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
for (auto& bucket : m_buckets)
|
||||
{
|
||||
for (auto it = bucket.begin(); it != bucket.end();)
|
||||
{
|
||||
size_type new_bucket_index = HASH()(*it) % new_buckets.size();
|
||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||
}
|
||||
}
|
||||
|
||||
m_buckets = move(new_buckets);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
size_type index = HASH()(key) % m_buckets.size();
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
const LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
size_type index = HASH()(key) % m_buckets.size();
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Swap.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void heapify_up(It begin, size_t index, Comp comp)
|
||||
{
|
||||
size_t parent = (index - 1) / 2;
|
||||
while (parent < index)
|
||||
{
|
||||
if (comp(*(begin + index), *(begin + parent)))
|
||||
break;
|
||||
swap(*(begin + parent), *(begin + index));
|
||||
index = parent;
|
||||
parent = (index - 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void heapify_down(It begin, size_t index, size_t len, Comp comp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const size_t lchild = 2 * index + 1;
|
||||
const size_t rchild = 2 * index + 2;
|
||||
|
||||
size_t child = 0;
|
||||
if (lchild < len && !comp(*(begin + lchild), *(begin + index)))
|
||||
{
|
||||
if (rchild < len && !comp(*(begin + rchild), *(begin + lchild)))
|
||||
child = rchild;
|
||||
else
|
||||
child = lchild;
|
||||
}
|
||||
else if (rchild < len && !comp(*(begin + rchild), *(begin + index)))
|
||||
child = rchild;
|
||||
else
|
||||
break;
|
||||
|
||||
swap(*(begin + child), *(begin + index));
|
||||
index = child;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void make_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
size_t index = (len - 2) / 2;
|
||||
while (index < len)
|
||||
detail::heapify_down(begin, index--, len, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void push_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
detail::heapify_up(begin, len - 1, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void pop_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
swap(*begin, *(begin + len - 1));
|
||||
detail::heapify_down(begin, 0, len - 1, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void sort_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
while (begin != end)
|
||||
pop_heap(begin, end--, comp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/Hash.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct IPv4Address
|
||||
{
|
||||
constexpr IPv4Address(uint32_t u32_address)
|
||||
{
|
||||
raw = u32_address;
|
||||
}
|
||||
|
||||
constexpr IPv4Address(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4)
|
||||
{
|
||||
octets[0] = oct1;
|
||||
octets[1] = oct2;
|
||||
octets[2] = oct3;
|
||||
octets[3] = oct4;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IPv4Address& other) const
|
||||
{
|
||||
return raw == other.raw;
|
||||
}
|
||||
|
||||
constexpr IPv4Address mask(const IPv4Address& other) const
|
||||
{
|
||||
return IPv4Address(raw & other.raw);
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t octets[4];
|
||||
uint32_t raw;
|
||||
} __attribute__((packed));
|
||||
};
|
||||
static_assert(sizeof(IPv4Address) == 4);
|
||||
|
||||
template<>
|
||||
struct hash<IPv4Address>
|
||||
{
|
||||
constexpr hash_t operator()(IPv4Address ipv4) const
|
||||
{
|
||||
return hash<uint32_t>()(ipv4.raw);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const IPv4Address& ipv4, const ValueFormat&)
|
||||
{
|
||||
ValueFormat format {
|
||||
.base = 10,
|
||||
.percision = 0,
|
||||
.fill = 0,
|
||||
.upper = false,
|
||||
};
|
||||
|
||||
print_argument(putc, ipv4.octets[0], format);
|
||||
for (size_t i = 1; i < 4; i++)
|
||||
{
|
||||
putc('.');
|
||||
print_argument(putc, ipv4.octets[i], format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
enum class Iteration
|
||||
{
|
||||
Continue,
|
||||
Break
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename It>
|
||||
constexpr It next(It it, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
|
||||
constexpr It next(It it, size_t count)
|
||||
{
|
||||
return it + count;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
constexpr It prev(It it, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
--it;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
|
||||
constexpr It prev(It it, size_t count)
|
||||
{
|
||||
return it - count;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
constexpr size_t distance(It it1, It it2)
|
||||
{
|
||||
size_t dist = 0;
|
||||
while (it1 != it2)
|
||||
{
|
||||
++it1;
|
||||
++dist;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
|
||||
constexpr size_t distance(It it1, It it2)
|
||||
{
|
||||
return it2 - it1;
|
||||
}
|
||||
|
||||
template<typename T, typename Container, bool CONST>
|
||||
class IteratorSimpleGeneral
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
public:
|
||||
constexpr IteratorSimpleGeneral() = default;
|
||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||
constexpr IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
||||
: m_pointer(other.m_pointer)
|
||||
, m_valid(other.m_valid)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr const T& operator*() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T&> operator*()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
constexpr const T* operator->() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T*> operator->()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral& operator++()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
++m_pointer;
|
||||
return *this;
|
||||
}
|
||||
constexpr IteratorSimpleGeneral operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral& operator--()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
--m_pointer;
|
||||
return *this;
|
||||
}
|
||||
constexpr IteratorSimpleGeneral operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
constexpr size_t operator-(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this && other);
|
||||
return m_pointer - other.m_pointer;
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral operator+(size_t offset) const
|
||||
{
|
||||
return IteratorSimpleGeneral(m_pointer + offset);
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral operator-(size_t offset) const
|
||||
{
|
||||
return IteratorSimpleGeneral(m_pointer - offset);
|
||||
}
|
||||
|
||||
constexpr bool operator<(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return m_pointer < other.m_pointer;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return m_pointer == other.m_pointer;
|
||||
}
|
||||
constexpr bool operator!=(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
||||
: m_pointer(pointer)
|
||||
, m_valid(true)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
maybe_const_t<CONST, T>* m_pointer = nullptr;
|
||||
bool m_valid = false;
|
||||
|
||||
friend IteratorSimpleGeneral<T, Container, !CONST>;
|
||||
friend Container;
|
||||
};
|
||||
|
||||
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container, bool CONST>
|
||||
class IteratorDoubleGeneral
|
||||
{
|
||||
public:
|
||||
using Inner = InnerContainer<T>;
|
||||
using Outer = OuterContainer<Inner>;
|
||||
|
||||
using InnerIterator = either_or_t<CONST, typename Inner::const_iterator, typename Inner::iterator>;
|
||||
using OuterIterator = either_or_t<CONST, typename Outer::const_iterator, typename Outer::iterator>;
|
||||
|
||||
using value_type = T;
|
||||
|
||||
public:
|
||||
constexpr IteratorDoubleGeneral() = default;
|
||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||
constexpr IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
||||
: m_outer_end(other.m_outer_end)
|
||||
, m_outer_current(other.m_outer_current)
|
||||
, m_inner_current(other.m_inner_current)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr const T& operator*() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator*();
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T&> operator*()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator*();
|
||||
}
|
||||
|
||||
constexpr const T* operator->() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator->();
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T*> operator->()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator->();
|
||||
}
|
||||
|
||||
constexpr IteratorDoubleGeneral& operator++()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
m_inner_current++;
|
||||
find_valid_or_end();
|
||||
return *this;
|
||||
}
|
||||
constexpr IteratorDoubleGeneral operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IteratorDoubleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this && other);
|
||||
if (m_outer_end != other.m_outer_end)
|
||||
return false;
|
||||
if (m_outer_current != other.m_outer_current)
|
||||
return false;
|
||||
if (m_outer_current == m_outer_end)
|
||||
return true;
|
||||
ASSERT(m_inner_current && other.m_inner_current);
|
||||
return m_inner_current == other.m_inner_current;
|
||||
}
|
||||
constexpr bool operator!=(const IteratorDoubleGeneral& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const
|
||||
{
|
||||
return !!m_outer_current;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
||||
: m_outer_end(outer_end)
|
||||
, m_outer_current(outer_current)
|
||||
{
|
||||
if (outer_current != outer_end)
|
||||
{
|
||||
m_inner_current = m_outer_current->begin();
|
||||
find_valid_or_end();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
|
||||
: m_outer_end(outer_end)
|
||||
, m_outer_current(outer_current)
|
||||
, m_inner_current(inner_current)
|
||||
{
|
||||
find_valid_or_end();
|
||||
}
|
||||
|
||||
constexpr void find_valid_or_end()
|
||||
{
|
||||
while (m_inner_current == m_outer_current->end())
|
||||
{
|
||||
m_outer_current++;
|
||||
if (m_outer_current == m_outer_end)
|
||||
break;
|
||||
m_inner_current = m_outer_current->begin();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr OuterIterator outer_current() { return m_outer_current; }
|
||||
constexpr InnerIterator inner_current() { return m_inner_current; }
|
||||
|
||||
private:
|
||||
OuterIterator m_outer_end;
|
||||
OuterIterator m_outer_current;
|
||||
InnerIterator m_inner_current;
|
||||
|
||||
friend class IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, !CONST>;
|
||||
friend Container;
|
||||
};
|
||||
|
||||
template<typename T, typename Container>
|
||||
using IteratorSimple = IteratorSimpleGeneral<T, Container, false>;
|
||||
|
||||
template<typename T, typename Container>
|
||||
using ConstIteratorSimple = IteratorSimpleGeneral<T, Container, true>;
|
||||
|
||||
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container>
|
||||
using IteratorDouble = IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, false>;
|
||||
|
||||
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container>
|
||||
using ConstIteratorDouble = IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, true>;
|
||||
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class numeric_limits
|
||||
{
|
||||
public:
|
||||
numeric_limits() = delete;
|
||||
|
||||
static inline constexpr T max()
|
||||
{
|
||||
if constexpr(is_same_v<T, char>)
|
||||
return __SCHAR_MAX__;
|
||||
if constexpr(is_same_v<T, signed char>)
|
||||
return __SCHAR_MAX__;
|
||||
if constexpr(is_same_v<T, unsigned char>)
|
||||
return (T)__SCHAR_MAX__ * 2 + 1;
|
||||
|
||||
if constexpr(is_same_v<T, short>)
|
||||
return __SHRT_MAX__;
|
||||
if constexpr(is_same_v<T, int>)
|
||||
return __INT_MAX__;
|
||||
if constexpr(is_same_v<T, long>)
|
||||
return __LONG_MAX__;
|
||||
if constexpr(is_same_v<T, long long>)
|
||||
return __LONG_LONG_MAX__;
|
||||
|
||||
if constexpr(is_same_v<T, unsigned short>)
|
||||
return (T)__SHRT_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned int>)
|
||||
return (T)__INT_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned long>)
|
||||
return (T)__LONG_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned long long>)
|
||||
return (T)__LONG_LONG_MAX__ * 2 + 1;
|
||||
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX__;
|
||||
}
|
||||
|
||||
static inline constexpr T min()
|
||||
{
|
||||
if constexpr(is_signed_v<T> && is_integral_v<T>)
|
||||
return -max() - 1;
|
||||
|
||||
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
|
||||
return 0;
|
||||
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN__;
|
||||
}
|
||||
|
||||
static inline constexpr bool has_infinity()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_HAS_INFINITY__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_HAS_INFINITY__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_HAS_INFINITY__;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline constexpr T infinity() requires(has_infinity())
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_inff();
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_inf();
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_infl();
|
||||
}
|
||||
|
||||
static inline constexpr bool has_quiet_NaN()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_HAS_QUIET_NAN__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_HAS_QUIET_NAN__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_HAS_QUIET_NAN__;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_nanf("");
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_nan("");
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_nanl("");
|
||||
}
|
||||
|
||||
static inline constexpr int max_exponent2()
|
||||
{
|
||||
static_assert(__FLT_RADIX__ == 2);
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int max_exponent10()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX_10_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX_10_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX_10_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int min_exponent2()
|
||||
{
|
||||
static_assert(__FLT_RADIX__ == 2);
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int min_exponent10()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN_10_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN_10_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN_10_EXP__;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,426 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, bool CONST>
|
||||
class LinkedListIterator;
|
||||
|
||||
template<typename T>
|
||||
class LinkedList
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
using iterator = LinkedListIterator<T, false>;
|
||||
using const_iterator = LinkedListIterator<T, true>;
|
||||
|
||||
public:
|
||||
LinkedList() = default;
|
||||
LinkedList(const LinkedList<T>& other) requires is_copy_constructible_v<T> { *this = other; }
|
||||
LinkedList(LinkedList<T>&& other) { *this = move(other); }
|
||||
~LinkedList() { clear(); }
|
||||
|
||||
LinkedList<T>& operator=(const LinkedList<T>&) requires is_copy_constructible_v<T>;
|
||||
LinkedList<T>& operator=(LinkedList<T>&&);
|
||||
|
||||
ErrorOr<void> push_back(const T&);
|
||||
ErrorOr<void> push_back(T&&);
|
||||
ErrorOr<void> insert(iterator, const T&);
|
||||
ErrorOr<void> insert(iterator, T&&);
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(iterator, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
void pop_back();
|
||||
iterator remove(iterator);
|
||||
void clear();
|
||||
|
||||
iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter);
|
||||
|
||||
iterator begin() { return iterator(m_data, empty()); }
|
||||
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
||||
iterator end() { return iterator(m_last, true); }
|
||||
const_iterator end() const { return const_iterator(m_last, true); }
|
||||
|
||||
const T& back() const;
|
||||
T& back();
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
bool contains(const T&) const;
|
||||
|
||||
size_type size() const;
|
||||
bool empty() const;
|
||||
|
||||
private:
|
||||
struct Node
|
||||
{
|
||||
T value;
|
||||
Node* next;
|
||||
Node* prev;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<Node*> allocate_node(Args&&...) const;
|
||||
|
||||
Node* remove_node(iterator);
|
||||
void insert_node(iterator, Node*);
|
||||
|
||||
Node* m_data = nullptr;
|
||||
Node* m_last = nullptr;
|
||||
size_type m_size = 0;
|
||||
|
||||
friend class LinkedListIterator<T, true>;
|
||||
friend class LinkedListIterator<T, false>;
|
||||
};
|
||||
|
||||
template<typename T, bool CONST>
|
||||
class LinkedListIterator
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using data_type = maybe_const_t<CONST, typename LinkedList<T>::Node>;
|
||||
|
||||
public:
|
||||
LinkedListIterator() = default;
|
||||
template<bool C>
|
||||
LinkedListIterator(const LinkedListIterator<T, C>&, enable_if_t<C == CONST || !C>* = 0);
|
||||
|
||||
LinkedListIterator<T, CONST>& operator++();
|
||||
LinkedListIterator<T, CONST>& operator--();
|
||||
LinkedListIterator<T, CONST> operator++(int);
|
||||
LinkedListIterator<T, CONST> operator--(int);
|
||||
|
||||
template<bool ENABLE = !CONST>
|
||||
enable_if_t<ENABLE, T&> operator*();
|
||||
const T& operator*() const;
|
||||
|
||||
template<bool ENABLE = !CONST>
|
||||
enable_if_t<ENABLE, T*> operator->();
|
||||
const T* operator->() const;
|
||||
|
||||
bool operator==(const LinkedListIterator<T, CONST>&) const;
|
||||
bool operator!=(const LinkedListIterator<T, CONST>&) const;
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
LinkedListIterator(data_type*, bool);
|
||||
|
||||
private:
|
||||
data_type* m_current = nullptr;
|
||||
bool m_past_end = false;
|
||||
|
||||
friend class LinkedList<T>;
|
||||
friend class LinkedListIterator<T, !CONST>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other) requires is_copy_constructible_v<T>
|
||||
{
|
||||
clear();
|
||||
for (const T& elem : other)
|
||||
MUST(push_back(elem));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>& LinkedList<T>::operator=(LinkedList<T>&& other)
|
||||
{
|
||||
clear();
|
||||
m_data = other.m_data;
|
||||
m_last = other.m_last;
|
||||
m_size = other.m_size;
|
||||
other.m_data = nullptr;
|
||||
other.m_last = nullptr;
|
||||
other.m_size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>::Node* LinkedList<T>::remove_node(iterator iter)
|
||||
{
|
||||
ASSERT(!empty() && iter);
|
||||
Node* node = iter.m_current;
|
||||
Node* prev = node->prev;
|
||||
Node* next = node->next;
|
||||
(prev ? prev->next : m_data) = next;
|
||||
(next ? next->prev : m_last) = prev;
|
||||
m_size--;
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::insert_node(iterator iter, Node* node)
|
||||
{
|
||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||
Node* prev = next ? next->prev : m_last;
|
||||
node->next = next;
|
||||
node->prev = prev;
|
||||
(prev ? prev->next : m_data) = node;
|
||||
(next ? next->prev : m_last) = node;
|
||||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
||||
{
|
||||
return push_back(move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> LinkedList<T>::push_back(T&& value)
|
||||
{
|
||||
return insert(end(), move(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> LinkedList<T>::insert(iterator iter, const T& value)
|
||||
{
|
||||
return insert(iter, move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
||||
{
|
||||
Node* new_node = TRY(allocate_node(move(value)));
|
||||
insert_node(iter, new_node);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
return emplace(end(), forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
||||
insert_node(iter, new_node);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::pop_back()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
remove(iterator(m_last, false));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
||||
{
|
||||
ASSERT(!empty() && iter);
|
||||
Node* node = remove_node(iter);
|
||||
Node* next = node->next;
|
||||
node->value.~T();
|
||||
BAN::deallocator(node);
|
||||
return next ? iterator(next, false) : iterator(m_last, true);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::clear()
|
||||
{
|
||||
Node* ptr = m_data;
|
||||
while (ptr)
|
||||
{
|
||||
Node* next = ptr->next;
|
||||
ptr->value.~T();
|
||||
BAN::deallocator(ptr);
|
||||
ptr = next;
|
||||
}
|
||||
m_data = nullptr;
|
||||
m_last = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>::iterator LinkedList<T>::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter)
|
||||
{
|
||||
ASSERT(!empty() && src_iter);
|
||||
Node* node = remove_node(src_iter);
|
||||
iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true);
|
||||
dest_list.insert_node(dest_iter, node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& LinkedList<T>::back() const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *const_iterator(m_last, false);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& LinkedList<T>::back()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *iterator(m_last, false);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& LinkedList<T>::front() const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *const_iterator(m_data, false);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& LinkedList<T>::front()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *iterator(m_data, false);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool LinkedList<T>::contains(const T& value) const
|
||||
{
|
||||
if (empty()) return false;
|
||||
for (Node* node = m_data;; node = node->next)
|
||||
{
|
||||
if (node->value == value)
|
||||
return true;
|
||||
if (node == m_last)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename LinkedList<T>::size_type LinkedList<T>::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool LinkedList<T>::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node(Args&&... args) const
|
||||
{
|
||||
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
||||
if (node == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
new (&node->value) T(forward<Args>(args)...);
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
template<bool C>
|
||||
LinkedListIterator<T, CONST>::LinkedListIterator(const LinkedListIterator<T, C>& other, enable_if_t<C == CONST || !C>*)
|
||||
: m_current(other.m_current)
|
||||
, m_past_end(other.m_past_end)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
LinkedListIterator<T, CONST>::LinkedListIterator(data_type* node, bool past_end)
|
||||
: m_current(node)
|
||||
, m_past_end(past_end)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
LinkedListIterator<T, CONST>& LinkedListIterator<T, CONST>::operator++()
|
||||
{
|
||||
ASSERT(m_current);
|
||||
ASSERT(m_current->next || !m_past_end);
|
||||
if (m_current->next)
|
||||
m_current = m_current->next;
|
||||
else
|
||||
m_past_end = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
LinkedListIterator<T, CONST>& LinkedListIterator<T, CONST>::operator--()
|
||||
{
|
||||
ASSERT(m_current);
|
||||
ASSERT(m_current->prev || m_past_end);
|
||||
if (m_past_end)
|
||||
m_past_end = false;
|
||||
else
|
||||
m_current = m_current->prev;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
LinkedListIterator<T, CONST> LinkedListIterator<T, CONST>::operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
LinkedListIterator<T, CONST> LinkedListIterator<T, CONST>::operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
template<bool ENABLE>
|
||||
enable_if_t<ENABLE, T&> LinkedListIterator<T, CONST>::operator*()
|
||||
{
|
||||
ASSERT(m_current);
|
||||
return m_current->value;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
const T& LinkedListIterator<T, CONST>::operator*() const
|
||||
{
|
||||
ASSERT(m_current);
|
||||
return m_current->value;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
template<bool ENABLE>
|
||||
enable_if_t<ENABLE, T*> LinkedListIterator<T, CONST>::operator->()
|
||||
{
|
||||
ASSERT(m_current);
|
||||
return &m_current->value;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
const T* LinkedListIterator<T, CONST>::operator->() const
|
||||
{
|
||||
ASSERT(m_current);
|
||||
return &m_current->value;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
bool LinkedListIterator<T, CONST>::operator==(const LinkedListIterator<T, CONST>& other) const
|
||||
{
|
||||
if (m_current != other.m_current)
|
||||
return false;
|
||||
return m_past_end == other.m_past_end;
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
bool LinkedListIterator<T, CONST>::operator!=(const LinkedListIterator<T, CONST>& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template<typename T, bool CONST>
|
||||
LinkedListIterator<T, CONST>::operator bool() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct MACAddress
|
||||
{
|
||||
uint8_t address[6];
|
||||
|
||||
constexpr bool operator==(const MACAddress& other) const
|
||||
{
|
||||
return
|
||||
address[0] == other.address[0] &&
|
||||
address[1] == other.address[1] &&
|
||||
address[2] == other.address[2] &&
|
||||
address[3] == other.address[3] &&
|
||||
address[4] == other.address[4] &&
|
||||
address[5] == other.address[5];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const MACAddress& mac, const ValueFormat&)
|
||||
{
|
||||
ValueFormat format {
|
||||
.base = 16,
|
||||
.percision = 0,
|
||||
.fill = 2,
|
||||
.upper = true,
|
||||
};
|
||||
|
||||
print_argument(putc, mac.address[0], format);
|
||||
for (size_t i = 1; i < 6; i++)
|
||||
{
|
||||
putc(':');
|
||||
print_argument(putc, mac.address[i], format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Limits.h>
|
||||
#include <BAN/Numbers.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace BAN::Math
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T abs(T x)
|
||||
{
|
||||
return x < 0 ? -x : x;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T min(T a, T b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T max(T a, T b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T clamp(T x, T min, T max)
|
||||
{
|
||||
return x < min ? min : x > max ? max : x;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
inline constexpr T gcd(T a, T b)
|
||||
{
|
||||
T t;
|
||||
while (b)
|
||||
{
|
||||
t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
inline constexpr T lcm(T a, T b)
|
||||
{
|
||||
return a / gcd(a, b) * b;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
inline constexpr T div_round_up(T a, T b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
inline constexpr bool is_power_of_two(T x)
|
||||
{
|
||||
if (x == 0)
|
||||
return false;
|
||||
return (x & (x - 1)) == 0;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
||||
{
|
||||
if (a == 0 || b == 0)
|
||||
return false;
|
||||
if ((a > 0) == (b > 0))
|
||||
return a > BAN::numeric_limits<T>::max() / b;
|
||||
else
|
||||
return a < BAN::numeric_limits<T>::min() / b;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_addition_overflow(T a, T b)
|
||||
{
|
||||
if (a > 0 && b > 0)
|
||||
return a > BAN::numeric_limits<T>::max() - b;
|
||||
if (a < 0 && b < 0)
|
||||
return a < BAN::numeric_limits<T>::min() - b;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||
inline constexpr T ilog2(T x)
|
||||
{
|
||||
if constexpr(is_same_v<T, unsigned int>)
|
||||
return sizeof(T) * 8 - __builtin_clz(x) - 1;
|
||||
if constexpr(is_same_v<T, unsigned long>)
|
||||
return sizeof(T) * 8 - __builtin_clzl(x) - 1;
|
||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T floor(T x)
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_floorf(x);
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_floor(x);
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_floorl(x);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T ceil(T x)
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_ceilf(x);
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_ceil(x);
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_ceill(x);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T round(T x)
|
||||
{
|
||||
if (x == (T)0.0)
|
||||
return x;
|
||||
if (x > (T)0.0)
|
||||
return floor<T>(x + (T)0.5);
|
||||
return ceil<T>(x - (T)0.5);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T trunc(T x)
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_truncf(x);
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_trunc(x);
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_truncl(x);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T rint(T x)
|
||||
{
|
||||
asm("frndint" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T fmod(T a, T b)
|
||||
{
|
||||
asm(
|
||||
"1:"
|
||||
"fprem;"
|
||||
"fnstsw %%ax;"
|
||||
"testb $4, %%ah;"
|
||||
"jne 1b;"
|
||||
: "+t"(a)
|
||||
: "u"(b)
|
||||
: "ax"
|
||||
);
|
||||
return a;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
static T modf(T x, T* iptr)
|
||||
{
|
||||
const T frac = BAN::Math::fmod<T>(x, 1);
|
||||
*iptr = x - frac;
|
||||
return frac;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T frexp(T num, int* exp)
|
||||
{
|
||||
if (num == 0.0)
|
||||
{
|
||||
*exp = 0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
T _exp;
|
||||
asm("fxtract" : "+t"(num), "=u"(_exp));
|
||||
*exp = (int)_exp + 1;
|
||||
return num / (T)2.0;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T copysign(T x, T y)
|
||||
{
|
||||
if ((x < (T)0.0) != (y < (T)0.0))
|
||||
x = -x;
|
||||
return x;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T fyl2x(T x, T y)
|
||||
{
|
||||
asm("fyl2x" : "+t"(x) : "u"(y) : "st(1)");
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T log(T x)
|
||||
{
|
||||
return detail::fyl2x<T>(x, numbers::ln2_v<T>);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T log2(T x)
|
||||
{
|
||||
return detail::fyl2x<T>(x, 1.0);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T log10(T x)
|
||||
{
|
||||
return detail::fyl2x<T>(x, numbers::lg2_v<T>);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T logb(T x)
|
||||
{
|
||||
static_assert(FLT_RADIX == 2);
|
||||
return log2<T>(x);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T exp2(T x)
|
||||
{
|
||||
if (abs(x) <= (T)1.0)
|
||||
{
|
||||
asm("f2xm1" : "+t"(x));
|
||||
return x + (T)1.0;
|
||||
}
|
||||
|
||||
asm(
|
||||
"fld1;"
|
||||
"fld %%st(1);"
|
||||
"fprem;"
|
||||
"f2xm1;"
|
||||
"faddp;"
|
||||
"fscale;"
|
||||
"fstp %%st(1);"
|
||||
: "+t"(x)
|
||||
);
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T exp(T x)
|
||||
{
|
||||
return exp2<T>(x * numbers::log2e_v<T>);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T pow(T x, T y)
|
||||
{
|
||||
asm(
|
||||
"fyl2x;"
|
||||
"fld1;"
|
||||
"fld %%st(1);"
|
||||
"fprem;"
|
||||
"f2xm1;"
|
||||
"faddp;"
|
||||
"fscale;"
|
||||
: "+t"(x), "+u"(y)
|
||||
);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T scalbn(T x, int n)
|
||||
{
|
||||
asm("fscale" : "+t"(x) : "u"(static_cast<T>(n)));
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T ldexp(T x, int y)
|
||||
{
|
||||
const bool exp_sign = y < 0;
|
||||
if (exp_sign)
|
||||
y = -y;
|
||||
|
||||
T exp = (T)1.0;
|
||||
T mult = (T)2.0;
|
||||
while (y)
|
||||
{
|
||||
if (y & 1)
|
||||
exp *= mult;
|
||||
mult *= mult;
|
||||
y >>= 1;
|
||||
}
|
||||
|
||||
if (exp_sign)
|
||||
exp = (T)1.0 / exp;
|
||||
|
||||
return x * exp;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T sqrt(T x)
|
||||
{
|
||||
asm("fsqrt" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T cbrt(T value)
|
||||
{
|
||||
if (value == 0.0)
|
||||
return 0.0;
|
||||
return pow<T>(value, 1.0 / 3.0);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T sin(T x)
|
||||
{
|
||||
asm("fsin" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T cos(T x)
|
||||
{
|
||||
asm("fcos" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr void sincos(T x, T& sin, T& cos)
|
||||
{
|
||||
asm("fsincos" : "=t"(cos), "=u"(sin) : "0"(x));
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T tan(T x)
|
||||
{
|
||||
T one, ret;
|
||||
asm(
|
||||
"fptan"
|
||||
: "=t"(one), "=u"(ret)
|
||||
: "0"(x)
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T atan2(T y, T x)
|
||||
{
|
||||
asm(
|
||||
"fpatan"
|
||||
: "+t"(x)
|
||||
: "u"(y)
|
||||
: "st(1)"
|
||||
);
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T atan(T x)
|
||||
{
|
||||
return atan2<T>(x, 1.0);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T asin(T x)
|
||||
{
|
||||
if (x == (T)0.0)
|
||||
return (T)0.0;
|
||||
if (x == (T)1.0)
|
||||
return numbers::pi_v<T> / (T)2.0;
|
||||
if (x == (T)-1.0)
|
||||
return -numbers::pi_v<T> / (T)2.0;
|
||||
return (T)2.0 * atan<T>(x / (T(1.0) + sqrt<T>((T)1.0 - x * x)));
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T acos(T x)
|
||||
{
|
||||
if (x == (T)0.0)
|
||||
return numbers::pi_v<T> / (T)2.0;
|
||||
if (x == (T)1.0)
|
||||
return (T)0.0;
|
||||
if (x == (T)-1.0)
|
||||
return numbers::pi_v<T>;
|
||||
return (T)2.0 * atan<T>(sqrt<T>((T)1.0 - x * x) / ((T)1.0 + x));
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T sinh(T x)
|
||||
{
|
||||
return (exp<T>(x) - exp<T>(-x)) / (T)2.0;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T cosh(T x)
|
||||
{
|
||||
return (exp<T>(x) + exp<T>(-x)) / (T)2.0;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T tanh(T x)
|
||||
{
|
||||
const T exp_px = exp<T>(x);
|
||||
const T exp_nx = exp<T>(-x);
|
||||
return (exp_px - exp_nx) / (exp_px + exp_nx);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T asinh(T x)
|
||||
{
|
||||
return log<T>(x + sqrt<T>(x * x + (T)1.0));
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T acosh(T x)
|
||||
{
|
||||
return log<T>(x + sqrt<T>(x * x - (T)1.0));
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T atanh(T x)
|
||||
{
|
||||
return (T)0.5 * log<T>(((T)1.0 + x) / ((T)1.0 - x));
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T hypot(T x, T y)
|
||||
{
|
||||
return sqrt<T>(x * x + y * y);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
constexpr remove_reference_t<T>&& move(T&& arg)
|
||||
{
|
||||
return static_cast<remove_reference_t<T>&&>(arg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T&& forward(remove_reference_t<T>& arg)
|
||||
{
|
||||
return static_cast<T&&>(arg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T&& forward(remove_reference_t<T>&& arg)
|
||||
{
|
||||
static_assert(!is_lvalue_reference_v<T>);
|
||||
return static_cast<T&&>(arg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__is_kernel)
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
#if defined(__is_kernel)
|
||||
static constexpr void*(&allocator)(size_t) = kmalloc;
|
||||
static constexpr void*(&reallocator)(void*, size_t) = nullptr;
|
||||
static constexpr void(&deallocator)(void*) = kfree;
|
||||
#else
|
||||
static constexpr void*(&allocator)(size_t) = malloc;
|
||||
static constexpr void*(&reallocator)(void*, size_t) = realloc;
|
||||
static constexpr void(&deallocator)(void*) = free;
|
||||
#endif
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define BAN_NON_COPYABLE(class) \
|
||||
private: \
|
||||
class(const class&) = delete; \
|
||||
class& operator=(const class&) = delete
|
||||
|
||||
#define BAN_NON_MOVABLE(class) \
|
||||
private: \
|
||||
class(class&&) = delete; \
|
||||
class& operator=(class&&) = delete
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
namespace BAN::numbers
|
||||
{
|
||||
|
||||
template<floating_point T> inline constexpr T e_v = 2.71828182845904523536;
|
||||
template<floating_point T> inline constexpr T log2e_v = 1.44269504088896340736;
|
||||
template<floating_point T> inline constexpr T lge_v = 0.43429448190325182765;
|
||||
template<floating_point T> inline constexpr T lg2_v = 0.30102999566398119521;
|
||||
template<floating_point T> inline constexpr T ln2_v = 0.69314718055994530942;
|
||||
template<floating_point T> inline constexpr T ln10_v = 2.30258509299404568402;
|
||||
template<floating_point T> inline constexpr T pi_v = 3.14159265358979323846;
|
||||
template<floating_point T> inline constexpr T sqrt2_v = 1.41421356237309504880;
|
||||
template<floating_point T> inline constexpr T sqrt3_v = 1.73205080756887729353;
|
||||
|
||||
inline constexpr double e = e_v<double>;
|
||||
inline constexpr double log2e = log2e_v<double>;
|
||||
inline constexpr double lge = lge_v<double>;
|
||||
inline constexpr double lg2 = lge_v<double>;
|
||||
inline constexpr double ln2 = ln2_v<double>;
|
||||
inline constexpr double ln10 = ln10_v<double>;
|
||||
inline constexpr double pi = pi_v<double>;
|
||||
inline constexpr double sqrt2 = sqrt2_v<double>;
|
||||
inline constexpr double sqrt3 = sqrt3_v<double>;
|
||||
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Optional
|
||||
{
|
||||
public:
|
||||
constexpr Optional();
|
||||
constexpr Optional(Optional&&);
|
||||
constexpr Optional(const Optional&);
|
||||
constexpr Optional(const T&);
|
||||
constexpr Optional(T&&);
|
||||
|
||||
~Optional();
|
||||
|
||||
constexpr Optional& operator=(Optional&&);
|
||||
constexpr Optional& operator=(const Optional&);
|
||||
|
||||
template<typename... Args>
|
||||
constexpr Optional& emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
constexpr T* operator->();
|
||||
constexpr const T* operator->() const;
|
||||
|
||||
constexpr T& operator*();
|
||||
constexpr const T& operator*() const;
|
||||
|
||||
constexpr bool has_value() const;
|
||||
|
||||
constexpr T release_value();
|
||||
constexpr T& value();
|
||||
constexpr const T& value() const;
|
||||
constexpr T& value_or(T&);
|
||||
constexpr const T& value_or(const T&) const;
|
||||
|
||||
constexpr void clear();
|
||||
|
||||
private:
|
||||
alignas(T) uint8_t m_storage[sizeof(T)] {};
|
||||
bool m_has_value { false };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional()
|
||||
: m_has_value(false)
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(Optional<T>&& other)
|
||||
: m_has_value(other.has_value())
|
||||
{
|
||||
if (other.has_value())
|
||||
new (m_storage) T(move(other.release_value()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(const Optional<T>& other)
|
||||
: m_has_value(other.has_value())
|
||||
{
|
||||
if (other.has_value())
|
||||
new (m_storage) T(other.value());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(const T& value)
|
||||
: m_has_value(true)
|
||||
{
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(T&& value)
|
||||
: m_has_value(true)
|
||||
{
|
||||
new (m_storage) T(move(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>::~Optional()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>& Optional<T>::operator=(Optional&& other)
|
||||
{
|
||||
clear();
|
||||
m_has_value = other.has_value();
|
||||
if (other.has_value())
|
||||
new (m_storage) T(move(other.release_value()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>& Optional<T>::operator=(const Optional& other)
|
||||
{
|
||||
clear();
|
||||
m_has_value = other.has_value();
|
||||
if (other.has_value())
|
||||
new (m_storage) T(other.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
constexpr Optional<T>& Optional<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
clear();
|
||||
m_has_value = true;
|
||||
new (m_storage) T(forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T* Optional<T>::operator->()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return &value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T* Optional<T>::operator->() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return &value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T& Optional<T>::operator*()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T& Optional<T>::operator*() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool Optional<T>::has_value() const
|
||||
{
|
||||
return m_has_value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T Optional<T>::release_value()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
T released_value = move(value());
|
||||
value().~T();
|
||||
m_has_value = false;
|
||||
return move(released_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T& Optional<T>::value()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return *reinterpret_cast<T*>(&m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T& Optional<T>::value() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return *reinterpret_cast<const T*>(&m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T& Optional<T>::value_or(T& empty)
|
||||
{
|
||||
if (!has_value())
|
||||
return empty;
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T& Optional<T>::value_or(const T& empty) const
|
||||
{
|
||||
if (!has_value())
|
||||
return empty;
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr void Optional<T>::clear()
|
||||
{
|
||||
if (m_has_value)
|
||||
value().~T();
|
||||
m_has_value = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if __has_include(<new>)
|
||||
#include <new>
|
||||
#else
|
||||
#include <stddef.h>
|
||||
|
||||
inline void* operator new(size_t, void* addr) { return addr; }
|
||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "BAN/Errors.h"
|
||||
#include <BAN/Vector.h>
|
||||
#include <BAN/Heap.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, typename Comp = less<T>>
|
||||
class PriorityQueue
|
||||
{
|
||||
public:
|
||||
PriorityQueue() = default;
|
||||
PriorityQueue(Comp comp)
|
||||
: m_comp(comp)
|
||||
{ }
|
||||
|
||||
ErrorOr<void> push(const T& value)
|
||||
{
|
||||
TRY(m_data.push_back(value));
|
||||
push_heap(m_data.begin(), m_data.end());
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> push(T&& value)
|
||||
{
|
||||
TRY(m_data.push_back(move(value)));
|
||||
push_heap(m_data.begin(), m_data.end());
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
TRY(m_data.emplace_back(forward<Args>(args)...));
|
||||
push_heap(m_data.begin(), m_data.end());
|
||||
return {};
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
pop_heap(m_data.begin(), m_data.end());
|
||||
m_data.pop_back();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> reserve(Vector<T>::size_type size)
|
||||
{
|
||||
return m_data.reserve(size);
|
||||
}
|
||||
|
||||
T& top() { return m_data.front(); }
|
||||
const T& top() const { return m_data.front(); }
|
||||
|
||||
bool empty() const { return m_data.empty(); }
|
||||
Vector<T>::size_type size() const { return m_data.size(); }
|
||||
Vector<T>::size_type capacity() const { return m_data.capacity(); }
|
||||
|
||||
private:
|
||||
Comp m_comp;
|
||||
Vector<T> m_data;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Queue
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
using iterator = IteratorSimple<T, Queue>;
|
||||
using const_iterator = ConstIteratorSimple<T, Queue>;
|
||||
|
||||
public:
|
||||
Queue() = default;
|
||||
Queue(Queue<T>&&);
|
||||
Queue(const Queue<T>&);
|
||||
~Queue();
|
||||
|
||||
Queue<T>& operator=(Queue<T>&&);
|
||||
Queue<T>& operator=(const Queue<T>&);
|
||||
|
||||
ErrorOr<void> push(T&&);
|
||||
ErrorOr<void> push(const T&);
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
void pop();
|
||||
void clear();
|
||||
|
||||
bool empty() const;
|
||||
size_type capacity() const;
|
||||
size_type size() const;
|
||||
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
private:
|
||||
ErrorOr<void> ensure_capacity(size_type size);
|
||||
|
||||
private:
|
||||
T* m_data = nullptr;
|
||||
size_type m_capacity = 0;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Queue<T>::Queue(Queue<T>&& other)
|
||||
{
|
||||
m_data = other.m_data;
|
||||
m_capacity = other.m_capacity;
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_data = nullptr;
|
||||
other.m_capacity = 0;
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Queue<T>::Queue(const Queue<T>& other)
|
||||
{
|
||||
MUST(ensure_capacity(other.size()));
|
||||
for (size_type i = 0; i < other.size(); i++)
|
||||
new (m_data + i) T(other.m_data[i]);
|
||||
m_size = other.m_size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Queue<T>::~Queue()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Queue<T>& Queue<T>::operator=(Queue<T>&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
m_data = other.m_data;
|
||||
m_capacity = other.m_capacity;
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_data = nullptr;
|
||||
other.m_capacity = 0;
|
||||
other.m_size = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Queue<T>& Queue<T>::operator=(const Queue<T>& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
for (size_type i = 0; i < other.size(); i++)
|
||||
new (m_data + i) T(other.m_data[i]);
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Queue<T>::push(T&& value)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
new (m_data + m_size) T(move(value));
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Queue<T>::push(const T& value)
|
||||
{
|
||||
return push(move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> Queue<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
new (m_data + m_size) T(forward<Args>(args)...);
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Queue<T>::reserve(size_type size)
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Queue<T>::shrink_to_fit()
|
||||
{
|
||||
size_type temp = m_capacity;
|
||||
m_capacity = 0;
|
||||
auto error_or = ensure_capacity(m_size);
|
||||
if (error_or.is_error())
|
||||
{
|
||||
m_capacity = temp;
|
||||
return error_or;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Queue<T>::pop()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
for (size_type i = 0; i < m_size - 1; i++)
|
||||
m_data[i] = move(m_data[i + 1]);
|
||||
m_data[m_size - 1].~T();
|
||||
m_size--;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Queue<T>::clear()
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
m_data[i].~T();
|
||||
BAN::deallocator(m_data);
|
||||
m_data = nullptr;
|
||||
m_capacity = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Queue<T>::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename Queue<T>::size_type Queue<T>::capacity() const
|
||||
{
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename Queue<T>::size_type Queue<T>::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Queue<T>::front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Queue<T>::front()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Queue<T>::ensure_capacity(size_type size)
|
||||
{
|
||||
if (m_capacity > size)
|
||||
return {};
|
||||
size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
|
||||
T* new_data = (T*)BAN::allocator(new_cap * sizeof(T));
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
new (new_data + i) T(move(m_data[i]));
|
||||
m_data[i].~T();
|
||||
}
|
||||
BAN::deallocator(m_data);
|
||||
m_data = new_data;
|
||||
m_capacity = new_cap;
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class RefCounted
|
||||
{
|
||||
BAN_NON_COPYABLE(RefCounted);
|
||||
BAN_NON_MOVABLE(RefCounted);
|
||||
|
||||
public:
|
||||
uint32_t ref_count() const
|
||||
{
|
||||
return m_ref_count;
|
||||
}
|
||||
|
||||
void ref() const
|
||||
{
|
||||
uint32_t old = m_ref_count.fetch_add(1, MemoryOrder::memory_order_relaxed);
|
||||
ASSERT(old > 0);
|
||||
}
|
||||
|
||||
bool try_ref() const
|
||||
{
|
||||
uint32_t expected = m_ref_count.load(MemoryOrder::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
if (expected == 0)
|
||||
return false;
|
||||
if (m_ref_count.compare_exchange(expected, expected + 1, MemoryOrder::memory_order_acquire))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void unref() const
|
||||
{
|
||||
uint32_t old = m_ref_count.fetch_sub(1);
|
||||
ASSERT(old > 0);
|
||||
if (old == 1)
|
||||
delete static_cast<const T*>(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
RefCounted() = default;
|
||||
virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
|
||||
|
||||
private:
|
||||
mutable Atomic<uint32_t> m_ref_count = 1;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class RefPtr
|
||||
{
|
||||
public:
|
||||
RefPtr() = default;
|
||||
RefPtr(T* pointer)
|
||||
{
|
||||
m_pointer = pointer;
|
||||
if (m_pointer)
|
||||
m_pointer->ref();
|
||||
}
|
||||
~RefPtr() { clear(); }
|
||||
|
||||
template<typename U>
|
||||
static RefPtr adopt(U* pointer)
|
||||
{
|
||||
RefPtr ptr;
|
||||
ptr.m_pointer = pointer;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// NOTE: don't use is_constructible_v<T, Args...> as RefPtr<T> is allowed with friends
|
||||
template<typename... Args>
|
||||
static ErrorOr<RefPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
||||
{
|
||||
T* pointer = new T(forward<Args>(args)...);
|
||||
if (pointer == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
return adopt(pointer);
|
||||
}
|
||||
|
||||
RefPtr(const RefPtr& other) { *this = other; }
|
||||
RefPtr(RefPtr&& other) { *this = move(other); }
|
||||
template<typename U>
|
||||
RefPtr(const RefPtr<U>& other) { *this = other; }
|
||||
template<typename U>
|
||||
RefPtr(RefPtr<U>&& other) { *this = move(other); }
|
||||
|
||||
RefPtr& operator=(const RefPtr& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
if (m_pointer)
|
||||
m_pointer->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefPtr& operator=(RefPtr&& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
RefPtr& operator=(const RefPtr<U>& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
if (m_pointer)
|
||||
m_pointer->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
RefPtr& operator=(RefPtr<U>&& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* ptr() { ASSERT(!empty()); return m_pointer; }
|
||||
const T* ptr() const { ASSERT(!empty()); return m_pointer; }
|
||||
|
||||
T& operator*() { return *ptr(); }
|
||||
const T& operator*() const { return *ptr(); }
|
||||
|
||||
T* operator->() { return ptr(); }
|
||||
const T* operator->() const { return ptr(); }
|
||||
|
||||
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
||||
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
||||
|
||||
bool empty() const { return m_pointer == nullptr; }
|
||||
explicit operator bool() const { return m_pointer; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (m_pointer)
|
||||
m_pointer->unref();
|
||||
m_pointer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_pointer = nullptr;
|
||||
|
||||
template<typename U>
|
||||
friend class RefPtr;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Function.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
class ScopeGuard
|
||||
{
|
||||
public:
|
||||
ScopeGuard(const BAN::Function<void()>& func)
|
||||
: m_func(func)
|
||||
{ }
|
||||
~ScopeGuard()
|
||||
{
|
||||
if (m_enabled)
|
||||
m_func();
|
||||
}
|
||||
void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
}
|
||||
private:
|
||||
BAN::Function<void()> m_func;
|
||||
bool m_enabled { true };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Heap.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Swap.h>
|
||||
#include <BAN/Traits.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN::sort
|
||||
{
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void exchange_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
for (It lhs = begin; lhs != end; ++lhs)
|
||||
for (It rhs = next(lhs, 1); rhs != end; ++rhs)
|
||||
if (!comp(*lhs, *rhs))
|
||||
swap(*lhs, *rhs);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
It partition(It begin, It end, Comp comp)
|
||||
{
|
||||
It pivot = prev(end, 1);
|
||||
|
||||
It it1 = begin;
|
||||
for (It it2 = begin; it2 != pivot; ++it2)
|
||||
{
|
||||
if (comp(*it2, *pivot))
|
||||
{
|
||||
swap(*it1, *it2);
|
||||
++it1;
|
||||
}
|
||||
}
|
||||
|
||||
swap(*it1, *pivot);
|
||||
|
||||
return it1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void quick_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
return;
|
||||
It mid = detail::partition(begin, end, comp);
|
||||
quick_sort(begin, mid, comp);
|
||||
quick_sort(++mid, end, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void insertion_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
return;
|
||||
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
||||
{
|
||||
auto x = move(*it1);
|
||||
It it2 = it1;
|
||||
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
||||
*it2 = move(*prev(it2, 1));
|
||||
*it2 = move(x);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void heap_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
make_heap(begin, end, comp);
|
||||
sort_heap(begin, end, comp);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void intro_sort_impl(It begin, It end, size_t max_depth, Comp comp)
|
||||
{
|
||||
if (distance(begin, end) <= 16)
|
||||
return insertion_sort(begin, end, comp);
|
||||
if (max_depth == 0)
|
||||
return heap_sort(begin, end, comp);
|
||||
It mid = detail::partition(begin, end, comp);
|
||||
intro_sort_impl(begin, mid, max_depth - 1, comp);
|
||||
intro_sort_impl(++mid, end, max_depth - 1, comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void intro_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<unsigned_integral T>
|
||||
consteval T lsb_index(T value)
|
||||
{
|
||||
for (T result = 0;; result++)
|
||||
if (value & (1 << result))
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, size_t radix = 256>
|
||||
requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
||||
{
|
||||
using value_type = it_value_type_t<It>;
|
||||
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return {};
|
||||
|
||||
Vector<value_type> temp;
|
||||
TRY(temp.resize(len));
|
||||
|
||||
Vector<size_t> counts;
|
||||
TRY(counts.resize(radix));
|
||||
|
||||
constexpr size_t mask = radix - 1;
|
||||
constexpr size_t shift = detail::lsb_index(radix);
|
||||
|
||||
for (size_t s = 0; s < sizeof(value_type) * 8; s += shift)
|
||||
{
|
||||
for (auto& cnt : counts)
|
||||
cnt = 0;
|
||||
for (It it = begin; it != end; ++it)
|
||||
counts[(*it >> s) & mask]++;
|
||||
|
||||
for (size_t i = 0; i < radix - 1; i++)
|
||||
counts[i + 1] += counts[i];
|
||||
|
||||
for (It it = end; it != begin;)
|
||||
{
|
||||
--it;
|
||||
temp[--counts[(*it >> s) & mask]] = *it;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < temp.size(); j++)
|
||||
*next(begin, j) = temp[j];
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
return intro_sort(begin, end, comp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Iterators.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Span
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using iterator = IteratorSimple<value_type, Span>;
|
||||
using const_iterator = ConstIteratorSimple<value_type, Span>;
|
||||
|
||||
private:
|
||||
template<typename S>
|
||||
static inline constexpr bool can_init_from_v = is_same_v<value_type, const S> || is_same_v<value_type, S>;
|
||||
|
||||
public:
|
||||
Span() = default;
|
||||
Span(value_type* data, size_type size)
|
||||
: m_data(data)
|
||||
, m_size(size)
|
||||
{ }
|
||||
|
||||
template<typename S>
|
||||
Span(const Span<S>& other) requires can_init_from_v<S>
|
||||
: m_data(other.m_data)
|
||||
, m_size(other.m_size)
|
||||
{ }
|
||||
template<typename S>
|
||||
Span(Span<S>&& other) requires can_init_from_v<S>
|
||||
: m_data(other.m_data)
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
Span& operator=(const Span<S>& other) requires can_init_from_v<S>
|
||||
{
|
||||
m_data = other.m_data;
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
template<typename S>
|
||||
Span& operator=(Span<S>&& other) requires can_init_from_v<S>
|
||||
{
|
||||
m_data = other.m_data;
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
value_type& operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
value_type* data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_data = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
Span slice(size_type start, size_type length = ~size_type(0)) const
|
||||
{
|
||||
ASSERT(start <= m_size);
|
||||
if (length == ~size_type(0))
|
||||
length = m_size - start;
|
||||
ASSERT(m_size - start >= length);
|
||||
return Span(m_data + start, length);
|
||||
}
|
||||
|
||||
Span<const value_type> as_const() const { return *this; }
|
||||
|
||||
private:
|
||||
value_type* m_data = nullptr;
|
||||
size_type m_size = 0;
|
||||
|
||||
friend class Span<const value_type>;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,362 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
class String
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = char;
|
||||
using iterator = IteratorSimple<char, String>;
|
||||
using const_iterator = ConstIteratorSimple<char, String>;
|
||||
static constexpr size_type sso_capacity = 15;
|
||||
|
||||
public:
|
||||
String() {}
|
||||
String(const String& other) { *this = other; }
|
||||
String(String&& other) { *this = move(other); }
|
||||
String(StringView other) { *this = other; }
|
||||
~String() { clear(); }
|
||||
|
||||
template<typename... Args>
|
||||
static BAN::ErrorOr<String> formatted(const char* format, Args&&... args)
|
||||
{
|
||||
size_type length = 0;
|
||||
BAN::Formatter::print([&](char) { length++; }, format, BAN::forward<Args>(args)...);
|
||||
|
||||
String result;
|
||||
TRY(result.reserve(length));
|
||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, BAN::forward<Args>(args)...);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
String& operator=(const String& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& operator=(String&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (other.has_sso())
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
else
|
||||
{
|
||||
m_storage.general_storage = other.m_storage.general_storage;
|
||||
m_has_sso = false;
|
||||
}
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_size = 0;
|
||||
other.m_storage.sso_storage = SSOStorage();
|
||||
other.m_has_sso = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& operator=(StringView other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size());
|
||||
m_size = other.size();
|
||||
data()[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr<void> push_back(char c)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
data()[m_size] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> insert(char c, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
memmove(data() + index + 1, data() + index, m_size - index);
|
||||
data()[index] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> insert(StringView str, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||
memcpy(data() + index, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> append(StringView str)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memcpy(data() + m_size, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void remove(size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
memmove(data() + index, data() + index + 1, m_size - index);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (!has_sso())
|
||||
{
|
||||
deallocator(m_storage.general_storage.data);
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
}
|
||||
m_size = 0;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
const_iterator begin() const { return const_iterator(data()); }
|
||||
iterator begin() { return iterator(data()); }
|
||||
const_iterator end() const { return const_iterator(data() + size()); }
|
||||
iterator end() { return iterator(data() + size()); }
|
||||
|
||||
char front() const { ASSERT(m_size > 0); return data()[0]; }
|
||||
char& front() { ASSERT(m_size > 0); return data()[0]; }
|
||||
|
||||
char back() const { ASSERT(m_size > 0); return data()[m_size - 1]; }
|
||||
char& back() { ASSERT(m_size > 0); return data()[m_size - 1]; }
|
||||
|
||||
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
||||
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
||||
|
||||
bool operator==(const String& str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(StringView str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const char* cstr) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != cstr[i])
|
||||
return false;
|
||||
if (cstr[size()] != '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
|
||||
{
|
||||
if (m_size == new_size)
|
||||
return {};
|
||||
|
||||
// expanding
|
||||
if (m_size < new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
memset(data() + m_size, init_c, new_size - m_size);
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> reserve(size_type new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> shrink_to_fit()
|
||||
{
|
||||
if (has_sso())
|
||||
return {};
|
||||
|
||||
if (fits_in_sso())
|
||||
{
|
||||
char* data = m_storage.general_storage.data;
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
memcpy(this->data(), data, m_size + 1);
|
||||
deallocator(data);
|
||||
return {};
|
||||
}
|
||||
|
||||
GeneralStorage& storage = m_storage.general_storage;
|
||||
if (storage.capacity == m_size)
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(m_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
memcpy(new_data, storage.data, m_size);
|
||||
deallocator(storage.data);
|
||||
|
||||
storage.capacity = m_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringView sv() const { return StringView(data(), size()); }
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
|
||||
size_type capacity() const
|
||||
{
|
||||
if (has_sso())
|
||||
return sso_capacity;
|
||||
return m_storage.general_storage.capacity;
|
||||
}
|
||||
|
||||
char* data()
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
private:
|
||||
ErrorOr<void> ensure_capacity(size_type new_size)
|
||||
{
|
||||
if (m_size >= new_size)
|
||||
return {};
|
||||
if (has_sso() && fits_in_sso(new_size))
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(new_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
if (m_size)
|
||||
memcpy(new_data, data(), m_size + 1);
|
||||
|
||||
if (has_sso())
|
||||
{
|
||||
m_storage.general_storage = GeneralStorage();
|
||||
m_has_sso = false;
|
||||
}
|
||||
else
|
||||
deallocator(m_storage.general_storage.data);
|
||||
|
||||
auto& storage = m_storage.general_storage;
|
||||
storage.capacity = new_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool has_sso() const { return m_has_sso; }
|
||||
|
||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||
|
||||
private:
|
||||
struct SSOStorage
|
||||
{
|
||||
char data[sso_capacity + 1] {};
|
||||
};
|
||||
struct GeneralStorage
|
||||
{
|
||||
size_type capacity { 0 };
|
||||
char* data { nullptr };
|
||||
};
|
||||
|
||||
private:
|
||||
union {
|
||||
SSOStorage sso_storage;
|
||||
GeneralStorage general_storage;
|
||||
} m_storage { .sso_storage = SSOStorage() };
|
||||
size_type m_size : sizeof(size_type) * 8 - 1 { 0 };
|
||||
size_type m_has_sso : 1 { true };
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<String>
|
||||
{
|
||||
hash_t operator()(const String& string) const
|
||||
{
|
||||
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
|
||||
constexpr hash_t FNV_prime = 0x01000193;
|
||||
|
||||
hash_t hash = FNV_offset_basis;
|
||||
for (String::size_type i = 0; i < string.size(); i++)
|
||||
{
|
||||
hash *= FNV_prime;
|
||||
hash ^= (uint8_t)string[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const String& string, const ValueFormat&)
|
||||
{
|
||||
for (String::size_type i = 0; i < string.size(); i++)
|
||||
putc(string[i]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
class StringView
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = char;
|
||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||
|
||||
public:
|
||||
constexpr StringView() {}
|
||||
constexpr StringView(const char* string, size_type len = -1)
|
||||
{
|
||||
if (len == size_type(-1))
|
||||
for (len = 0; string[len];)
|
||||
len++;
|
||||
m_data = string;
|
||||
m_size = len;
|
||||
}
|
||||
StringView(const String&);
|
||||
|
||||
constexpr const_iterator begin() const { return const_iterator(m_data); }
|
||||
constexpr const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
constexpr char operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
constexpr bool operator==(StringView other) const
|
||||
{
|
||||
if (m_size != other.m_size)
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] != other.m_data[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const char* other) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] != other[i])
|
||||
return false;
|
||||
return other[m_size] == '\0';
|
||||
}
|
||||
|
||||
constexpr StringView substring(size_type index, size_type len = -1) const
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
if (len == size_type(-1))
|
||||
len = m_size - index;
|
||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||
StringView result;
|
||||
result.m_data = m_data + index;
|
||||
result.m_size = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr char back() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
constexpr char front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(bool(*comp)(char)) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (comp(m_data[i]))
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> rfind(char ch) const
|
||||
{
|
||||
for (size_type i = m_size; i > 0; i--)
|
||||
if (m_data[i - 1] == ch)
|
||||
return i - 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> rfind(bool(*comp)(char)) const
|
||||
{
|
||||
for (size_type i = m_size; i > 0; i--)
|
||||
if (comp(m_data[i - 1]))
|
||||
return i - 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr bool starts_with(BAN::StringView target) const
|
||||
{
|
||||
if (target.size() > m_size)
|
||||
return false;
|
||||
for (size_type i = 0; i < target.size(); i++)
|
||||
if (m_data[i] != target[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool contains(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr size_type count(char ch) const
|
||||
{
|
||||
size_type result = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool empty() const { return m_size == 0; }
|
||||
constexpr size_type size() const { return m_size; }
|
||||
constexpr const char* data() const { return m_data; }
|
||||
|
||||
private:
|
||||
const char* m_data = nullptr;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<StringView>
|
||||
{
|
||||
hash_t operator()(StringView string) const
|
||||
{
|
||||
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
|
||||
constexpr hash_t FNV_prime = 0x01000193;
|
||||
|
||||
hash_t hash = FNV_offset_basis;
|
||||
for (StringView::size_type i = 0; i < string.size(); i++)
|
||||
{
|
||||
hash *= FNV_prime;
|
||||
hash ^= (uint8_t)string[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const StringView& sv, const ValueFormat&)
|
||||
{
|
||||
for (StringView::size_type i = 0; i < sv.size(); i++)
|
||||
putc(sv[i]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Move.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
void swap(T& lhs, T& rhs)
|
||||
{
|
||||
T tmp = move(lhs);
|
||||
lhs = move(rhs);
|
||||
rhs = move(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct Time
|
||||
{
|
||||
uint32_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t week_day;
|
||||
};
|
||||
|
||||
uint64_t to_unix_time(const BAN::Time&);
|
||||
BAN::Time from_unix_time(uint64_t);
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Time& time, const ValueFormat&)
|
||||
{
|
||||
constexpr const char* week_days[] { "", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
constexpr const char* months[] { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
print(putc, "{} {} {} {2}:{2}:{2} GMT+0 {4}", week_days[time.week_day], months[time.month], time.day, time.hour, time.minute, time.second, time.year);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T> struct remove_reference { using type = T; };
|
||||
template<typename T> struct remove_reference<T&> { using type = T; };
|
||||
template<typename T> struct remove_reference<T&&> { using type = T; };
|
||||
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
|
||||
|
||||
template<typename T> struct remove_const { using type = T; };
|
||||
template<typename T> struct remove_const<const T> { using type = T; };
|
||||
template<typename T> using remove_const_t = typename remove_const<T>::type;
|
||||
|
||||
template<typename T> struct remove_volatile { using type = T; };
|
||||
template<typename T> struct remove_volatile<volatile T> { using type = T; };
|
||||
template<typename T> using remove_volatile_t = typename remove_volatile<T>::type;
|
||||
|
||||
template<typename T> struct remove_cv { using type = remove_volatile_t<remove_const_t<T>>; };
|
||||
template<typename T> using remove_cv_t = typename remove_cv<T>::type;
|
||||
|
||||
template<typename T> struct remove_const_and_reference { using type = remove_const_t<remove_reference_t<T>>; };
|
||||
template<typename T> using remove_const_and_reference_t = typename remove_const_and_reference<T>::type;
|
||||
|
||||
template<bool B, typename T = void> struct enable_if {};
|
||||
template<typename T> struct enable_if<true, T> { using type = T; };
|
||||
template<bool B, typename T = void> using enable_if_t = typename enable_if<B, T>::type;
|
||||
|
||||
template<bool B, typename T> struct maybe_const { using type = T; };
|
||||
template<typename T> struct maybe_const<true, T> { using type = const T; };
|
||||
template<bool B, typename T> using maybe_const_t = typename maybe_const<B, T>::type;
|
||||
|
||||
template<bool B, typename T1, typename T2> struct either_or { using type = T2; };
|
||||
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
||||
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
||||
|
||||
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
||||
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
||||
using true_type = integral_constant<bool, true>;
|
||||
using false_type = integral_constant<bool, false>;
|
||||
|
||||
template<typename T, typename S> struct is_same : false_type {};
|
||||
template<typename T> struct is_same<T, T> : true_type {};
|
||||
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
|
||||
template<typename T, typename S> concept same_as = BAN::is_same_v<T, S>;
|
||||
|
||||
template<typename T> struct is_lvalue_reference : false_type {};
|
||||
template<typename T> struct is_lvalue_reference<T&> : true_type {};
|
||||
template<typename T> inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;
|
||||
template<typename T> concept lvalue_reference = is_lvalue_reference_v<T>;
|
||||
|
||||
template<typename T, typename... Args> struct is_constructible { static constexpr bool value = __is_constructible(T, Args...); };
|
||||
template<typename T, typename... Args> inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
|
||||
|
||||
template<typename T> struct is_default_constructible { static constexpr bool value = is_constructible_v<T>; };
|
||||
template<typename T> inline constexpr bool is_default_constructible_v = is_default_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_copy_constructible { static constexpr bool value = is_constructible_v<T, const T&>; };
|
||||
template<typename T> inline constexpr bool is_copy_constructible_v = is_copy_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
||||
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_trivially_copyable { static constexpr bool value = __is_trivially_copyable(T); };
|
||||
template<typename T> inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
|
||||
|
||||
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
||||
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||
template<typename T> concept integral = is_integral_v<T>;
|
||||
|
||||
template<typename T> struct is_floating_point : false_type {};
|
||||
template<> struct is_floating_point<float> : true_type {};
|
||||
template<> struct is_floating_point<double> : true_type {};
|
||||
template<> struct is_floating_point<long double> : true_type {};
|
||||
template<typename T> inline constexpr bool is_floating_point_v = is_floating_point<T>::value;
|
||||
template<typename T> concept floating_point = is_floating_point_v<T>;
|
||||
|
||||
template<typename T> struct is_pointer : false_type {};
|
||||
template<typename T> struct is_pointer<T*> : true_type {};
|
||||
template<typename T> struct is_pointer<T* const> : true_type {};
|
||||
template<typename T> struct is_pointer<T* volatile> : true_type {};
|
||||
template<typename T> struct is_pointer<T* const volatile> : true_type {};
|
||||
template<typename T> inline constexpr bool is_pointer_v = is_pointer<T>::value;
|
||||
template<typename T> concept pointer = is_pointer_v<T>;
|
||||
|
||||
template<typename T> struct is_const : false_type {};
|
||||
template<typename T> struct is_const<const T> : true_type {};
|
||||
template<typename T> inline constexpr bool is_const_v = is_const<T>::value;
|
||||
|
||||
template<typename T> struct is_arithmetic { static constexpr bool value = is_integral_v<T> || is_floating_point_v<T>; };
|
||||
template<typename T> inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
||||
|
||||
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
||||
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
||||
|
||||
template<typename T> struct is_pod { static constexpr bool value = __is_pod(T); };
|
||||
template<typename T> inline constexpr bool is_pod_v = is_pod<T>::value;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
||||
template<typename T> struct is_signed<T, false> : false_type {};
|
||||
|
||||
template<typename T, bool = is_arithmetic_v<T>> struct is_unsigned { static constexpr bool value = T(0) < T(-1); };
|
||||
template<typename T> struct is_unsigned<T, false> : false_type {};
|
||||
}
|
||||
template<typename T> struct is_signed : detail::is_signed<T> {};
|
||||
template<typename T> inline constexpr bool is_signed_v = is_signed<T>::value;
|
||||
template<typename T> concept signed_integral = is_signed_v<T> && is_integral_v<T>;
|
||||
|
||||
template<typename T> struct is_unsigned : detail::is_unsigned<T> {};
|
||||
template<typename T> inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
||||
template<typename T> concept unsigned_integral = is_unsigned_v<T> && is_integral_v<T>;
|
||||
|
||||
#define __BAN_TRAITS_MAKE_UNSIGNED_CV(__type) \
|
||||
template<> struct make_unsigned<__type> { using type = unsigned __type; }; \
|
||||
template<> struct make_unsigned<const __type> { using type = unsigned const __type; }; \
|
||||
template<> struct make_unsigned<volatile __type> { using type = unsigned volatile __type; }; \
|
||||
template<> struct make_unsigned<const volatile __type> { using type = unsigned const volatile __type; };
|
||||
|
||||
template<typename T> requires is_arithmetic_v<T> struct make_unsigned { using type = T; };
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(char)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(short)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(int)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(long)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(long long)
|
||||
template<typename T> using make_unsigned_t = typename make_unsigned<T>::type;
|
||||
#undef __BAN_TRAITS_MAKE_UNSIGNED_CV
|
||||
|
||||
#define __BAN_TRAITS_MAKE_SIGNED_CV(__type) \
|
||||
template<> struct make_signed<unsigned __type> { using type = __type; }; \
|
||||
template<> struct make_signed<unsigned const __type> { using type = const __type; }; \
|
||||
template<> struct make_signed<unsigned volatile __type> { using type = volatile __type; }; \
|
||||
template<> struct make_signed<unsigned const volatile __type> { using type = const volatile __type; };
|
||||
|
||||
template<typename T> requires is_arithmetic_v<T> struct make_signed { using type = T; };
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(char)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(short)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(int)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(long)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(long long)
|
||||
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
||||
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
||||
|
||||
template<typename T> struct it_value_type { using value_type = T::value_type; };
|
||||
template<typename T> struct it_value_type<T*> { using value_type = T; };
|
||||
template<typename T> using it_value_type_t = typename it_value_type<T>::value_type;
|
||||
|
||||
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
||||
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
||||
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN::UTF8
|
||||
{
|
||||
|
||||
static constexpr uint32_t invalid = 0xFFFFFFFF;
|
||||
|
||||
constexpr uint32_t byte_length(uint8_t first_byte)
|
||||
{
|
||||
if ((first_byte & 0x80) == 0x00)
|
||||
return 1;
|
||||
if ((first_byte & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
if ((first_byte & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
if ((first_byte & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
return UTF8::invalid;
|
||||
}
|
||||
|
||||
template<typename T> requires (sizeof(T) == 1)
|
||||
constexpr uint32_t to_codepoint(const T* bytes)
|
||||
{
|
||||
uint32_t length = byte_length(bytes[0]);
|
||||
|
||||
for (uint32_t i = 1; i < length; i++)
|
||||
if (((uint8_t)bytes[i] & 0xC0) != 0x80)
|
||||
return UTF8::invalid;
|
||||
|
||||
switch (length)
|
||||
{
|
||||
case 1: return (((uint8_t)bytes[0] & 0x80) != 0x00) ? UTF8::invalid : (uint8_t)bytes[0];
|
||||
case 2: return (((uint8_t)bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x1F) << 6) | ((uint8_t)bytes[1] & 0x3F);
|
||||
case 3: return (((uint8_t)bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x0F) << 12) | (((uint8_t)bytes[1] & 0x3F) << 6) | ((uint8_t)bytes[2] & 0x3F);
|
||||
case 4: return (((uint8_t)bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x07) << 18) | (((uint8_t)bytes[1] & 0x3F) << 12) | (((uint8_t)bytes[2] & 0x3F) << 6) | ((uint8_t)bytes[3] & 0x3F);
|
||||
}
|
||||
|
||||
return UTF8::invalid;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool from_codepoints(const T* codepoints, size_t count, char* out)
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)out;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
if (codepoints[i] < 0x80)
|
||||
{
|
||||
*ptr++ = codepoints[i];
|
||||
}
|
||||
else if (codepoints[i] < 0x800)
|
||||
{
|
||||
*ptr++ = 0xC0 | ((codepoints[i] >> 6) & 0x1F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
|
||||
}
|
||||
else if (codepoints[i] < 0x10000)
|
||||
{
|
||||
*ptr++ = 0xE0 | ((codepoints[i] >> 12) & 0x0F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 6) & 0x3F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
|
||||
}
|
||||
else if (codepoints[i] < 0x110000)
|
||||
{
|
||||
*ptr++ = 0xF0 | ((codepoints[i] >> 18) & 0x07);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 12) & 0x3F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 6) & 0x3F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class UniqPtr
|
||||
{
|
||||
BAN_NON_COPYABLE(UniqPtr);
|
||||
|
||||
public:
|
||||
UniqPtr() = default;
|
||||
|
||||
template<typename U>
|
||||
UniqPtr(UniqPtr<U>&& other)
|
||||
{
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
}
|
||||
|
||||
~UniqPtr()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
static UniqPtr adopt(T* pointer)
|
||||
{
|
||||
UniqPtr uniq;
|
||||
uniq.m_pointer = pointer;
|
||||
return uniq;
|
||||
}
|
||||
|
||||
// NOTE: don't use is_constructible_v<T, Args...> as UniqPtr<T> is allowed with friends
|
||||
template<typename... Args>
|
||||
static BAN::ErrorOr<UniqPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
||||
{
|
||||
UniqPtr uniq;
|
||||
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
||||
if (uniq.m_pointer == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return uniq;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
UniqPtr& operator=(UniqPtr<U>&& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
T* ptr() { return m_pointer; }
|
||||
const T* ptr() const { return m_pointer; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (m_pointer)
|
||||
delete m_pointer;
|
||||
m_pointer = nullptr;
|
||||
}
|
||||
|
||||
operator bool() const { return m_pointer != nullptr; }
|
||||
|
||||
private:
|
||||
T* m_pointer = nullptr;
|
||||
|
||||
template<typename U>
|
||||
friend class UniqPtr;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t size_ref_as_ptr() { return is_lvalue_reference_v<T> ? sizeof(remove_reference_t<T>*) : sizeof(T); }
|
||||
template<typename T>
|
||||
constexpr size_t align_ref_as_ptr() { return is_lvalue_reference_v<T> ? alignof(remove_reference_t<T>*) : alignof(T); }
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr<T>(); }
|
||||
template<typename T0, typename T1, typename... Ts>
|
||||
constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr<T0>() > size_ref_as_ptr<T1>() ? max_size_ref_as_ptr<T0, Ts...>() : max_size_ref_as_ptr<T1, Ts...>(); }
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr<T>(); }
|
||||
template<typename T0, typename T1, typename... Ts>
|
||||
constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr<T0>() > align_ref_as_ptr<T1>() ? max_align_ref_as_ptr<T0, Ts...>() : max_align_ref_as_ptr<T1, Ts...>(); }
|
||||
|
||||
template<typename T, typename T0, typename... Ts>
|
||||
constexpr size_t index()
|
||||
{
|
||||
if constexpr(is_same_v<T, T0>)
|
||||
return 0;
|
||||
else if constexpr(sizeof...(Ts) == 0)
|
||||
return 1;
|
||||
else
|
||||
return index<T, Ts...>() + 1;
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void destruct(size_t index, uint8_t* data)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
reinterpret_cast<T*>(data)->~T();
|
||||
}
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
destruct<Ts...>(index - 1, data);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void move_construct(size_t index, uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
new (target) T(move(*reinterpret_cast<T*>(source)));
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
move_construct<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void copy_construct(size_t index, const uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
new (target) T(*reinterpret_cast<const T*>(source));
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
copy_construct<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void move_assign(size_t index, uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
*reinterpret_cast<T*>(target) = move(*reinterpret_cast<T*>(source));
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
move_assign<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void copy_assign(size_t index, const uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
*reinterpret_cast<T*>(target) = *reinterpret_cast<const T*>(source);
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
copy_assign<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
requires (!is_const_v<Ts> && ...)
|
||||
class Variant
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr bool can_have() { return detail::index<T, Ts...>() != invalid_index(); }
|
||||
static constexpr size_t invalid_index() { return sizeof...(Ts); }
|
||||
|
||||
public:
|
||||
Variant() = default;
|
||||
|
||||
Variant(Variant&& other)
|
||||
: m_index(other.m_index)
|
||||
{
|
||||
if (!other.has_value())
|
||||
return;
|
||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
Variant(const Variant& other)
|
||||
: m_index(other.m_index)
|
||||
{
|
||||
if (!other.has_value())
|
||||
return;
|
||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
: m_index(detail::index<T, Ts...>())
|
||||
{
|
||||
new (m_storage) T(move(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Variant(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
: m_index(detail::index<T, Ts...>())
|
||||
{
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
|
||||
~Variant()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
Variant& operator=(Variant&& other)
|
||||
{
|
||||
if (m_index == other.m_index)
|
||||
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
m_index = other.m_index;
|
||||
}
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variant& operator=(const Variant& other)
|
||||
{
|
||||
if (m_index == other.m_index)
|
||||
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
m_index = other.m_index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Variant& operator=(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (size_t index = detail::index<T, Ts...>(); index == m_index)
|
||||
get<T>() = move(value);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
new (m_storage) T(move(value));
|
||||
m_index = index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Variant& operator=(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (size_t index = detail::index<T, Ts...>(); index == m_index)
|
||||
get<T>() = value;
|
||||
else
|
||||
{
|
||||
clear();
|
||||
new (m_storage) T(value);
|
||||
m_index = index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool has() const requires (can_have<T>())
|
||||
{
|
||||
return m_index == detail::index<T, Ts...>();
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void emplace(Args&&... args) requires (can_have<T>() && is_constructible_v<T, Args...>)
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
new (m_storage) T(BAN::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (has<T>())
|
||||
get<T>() = move(value);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
new (m_storage) T(move(value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (has<T>())
|
||||
get<T>() = value;
|
||||
else
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(T value) requires (can_have<T>() && is_lvalue_reference_v<T>)
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
*reinterpret_cast<remove_reference_t<T>**>(m_storage) = &value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& get() requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return *reinterpret_cast<T*>(m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& get() const requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return *reinterpret_cast<const T*>(m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T get() requires (can_have<T>() && is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return **reinterpret_cast<remove_reference_t<T>**>(m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T get() const requires (can_have<T>() && is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
|
||||
}
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return m_index != invalid_index();
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return has_value();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (m_index != invalid_index())
|
||||
{
|
||||
detail::destruct<Ts...>(m_index, m_storage);
|
||||
m_index = invalid_index();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(detail::max_align_ref_as_ptr<Ts...>()) uint8_t m_storage[detail::max_size_ref_as_ptr<Ts...>()] {};
|
||||
size_t m_index { invalid_index() };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
#include <BAN/Span.h>
|
||||
#include <BAN/Swap.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
// T must be move assignable, move constructable (and copy constructable for some functions)
|
||||
template<typename T>
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
using iterator = IteratorSimple<T, Vector>;
|
||||
using const_iterator = ConstIteratorSimple<T, Vector>;
|
||||
|
||||
public:
|
||||
Vector() = default;
|
||||
Vector(Vector<T>&&);
|
||||
Vector(const Vector<T>&);
|
||||
Vector(size_type, const T& = T());
|
||||
~Vector();
|
||||
|
||||
Vector<T>& operator=(Vector<T>&&);
|
||||
Vector<T>& operator=(const Vector<T>&);
|
||||
|
||||
ErrorOr<void> push_back(T&&);
|
||||
ErrorOr<void> push_back(const T&);
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(size_type, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
ErrorOr<void> insert(size_type, T&&);
|
||||
ErrorOr<void> insert(size_type, const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
void pop_back();
|
||||
void remove(size_type);
|
||||
void clear();
|
||||
|
||||
T* data() { return m_data; }
|
||||
const T* data() const { return m_data; }
|
||||
|
||||
bool contains(const T&) const;
|
||||
|
||||
Span<T> span() { return Span(m_data, m_size); }
|
||||
Span<const T> span() const { return Span(m_data, m_size); }
|
||||
|
||||
const T& operator[](size_type) const;
|
||||
T& operator[](size_type);
|
||||
|
||||
const T& back() const;
|
||||
T& back();
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
void reverse();
|
||||
|
||||
ErrorOr<void> resize(size_type) requires is_default_constructible_v<T>;
|
||||
ErrorOr<void> resize(size_type, const T&) requires is_copy_constructible_v<T>;
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
size_type capacity() const;
|
||||
|
||||
private:
|
||||
ErrorOr<void> ensure_capacity(size_type);
|
||||
|
||||
private:
|
||||
T* m_data = nullptr;
|
||||
size_type m_capacity = 0;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vector<T>::Vector(Vector<T>&& other)
|
||||
{
|
||||
m_data = other.m_data;
|
||||
m_capacity = other.m_capacity;
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_data = nullptr;
|
||||
other.m_capacity = 0;
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T>::Vector(const Vector<T>& other)
|
||||
{
|
||||
MUST(ensure_capacity(other.m_size));
|
||||
for (size_type i = 0; i < other.m_size; i++)
|
||||
new (m_data + i) T(other.m_data[i]);
|
||||
m_size = other.m_size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T>::Vector(size_type size, const T& value)
|
||||
{
|
||||
MUST(ensure_capacity(size));
|
||||
for (size_type i = 0; i < size; i++)
|
||||
new (m_data + i) T(value);
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T>::~Vector()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T>& Vector<T>::operator=(Vector<T>&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
m_data = other.m_data;
|
||||
m_capacity = other.m_capacity;
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_data = nullptr;
|
||||
other.m_capacity = 0;
|
||||
other.m_size = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
|
||||
{
|
||||
MUST(ensure_capacity(other.size()));
|
||||
for (size_type i = 0; i < BAN::Math::min(size(), other.size()); i++)
|
||||
m_data[i] = other.m_data[i];
|
||||
for (size_type i = size(); i < other.size(); i++)
|
||||
new (m_data + i) T(other[i]);
|
||||
for (size_type i = other.size(); i < size(); i++)
|
||||
m_data[i].~T();
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::push_back(T&& value)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
new (m_data + m_size) T(move(value));
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::push_back(const T& value)
|
||||
{
|
||||
return push_back(move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> Vector<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
new (m_data + m_size) T(forward<Args>(args)...);
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
if (index < m_size)
|
||||
{
|
||||
new (m_data + m_size) T(move(m_data[m_size - 1]));
|
||||
for (size_type i = m_size - 1; i > index; i--)
|
||||
m_data[i] = move(m_data[i - 1]);
|
||||
m_data[index] = move(T(forward<Args>(args)...));
|
||||
}
|
||||
else
|
||||
{
|
||||
new (m_data + m_size) T(forward<Args>(args)...);
|
||||
}
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::insert(size_type index, T&& value)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
if (index < m_size)
|
||||
{
|
||||
new (m_data + m_size) T(move(m_data[m_size - 1]));
|
||||
for (size_type i = m_size - 1; i > index; i--)
|
||||
m_data[i] = move(m_data[i - 1]);
|
||||
m_data[index] = move(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
new (m_data + m_size) T(move(value));
|
||||
}
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::insert(size_type index, const T& value)
|
||||
{
|
||||
return insert(index, move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector<T>::pop_back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_data[m_size - 1].~T();
|
||||
m_size--;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector<T>::remove(size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
for (size_type i = index; i < m_size - 1; i++)
|
||||
m_data[i] = move(m_data[i + 1]);
|
||||
m_data[m_size - 1].~T();
|
||||
m_size--;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector<T>::clear()
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
m_data[i].~T();
|
||||
BAN::deallocator(m_data);
|
||||
m_data = nullptr;
|
||||
m_capacity = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector<T>::contains(const T& other) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == other)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Vector<T>::operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Vector<T>::operator[](size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Vector<T>::back() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Vector<T>::back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Vector<T>::front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Vector<T>::front()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector<T>::reverse()
|
||||
{
|
||||
for (size_type i = 0; i < m_size / 2; i++)
|
||||
BAN::swap(m_data[i], m_data[m_size - i - 1]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::resize(size_type size) requires is_default_constructible_v<T>
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
if (size < m_size)
|
||||
for (size_type i = size; i < m_size; i++)
|
||||
m_data[i].~T();
|
||||
if (size > m_size)
|
||||
for (size_type i = m_size; i < size; i++)
|
||||
new (m_data + i) T();
|
||||
m_size = size;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::resize(size_type size, const T& value) requires is_copy_constructible_v<T>
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
if (size < m_size)
|
||||
for (size_type i = size; i < m_size; i++)
|
||||
m_data[i].~T();
|
||||
if (size > m_size)
|
||||
for (size_type i = m_size; i < size; i++)
|
||||
new (m_data + i) T(value);
|
||||
m_size = size;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::reserve(size_type size)
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::shrink_to_fit()
|
||||
{
|
||||
size_type temp = m_capacity;
|
||||
m_capacity = 0;
|
||||
auto error_or = ensure_capacity(m_size);
|
||||
if (error_or.is_error())
|
||||
{
|
||||
m_capacity = temp;
|
||||
return error_or;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector<T>::empty() const
|
||||