File diff suppressed because one or more lines are too long
271
src/Config.cppm
271
src/Config.cppm
@@ -1,271 +0,0 @@
|
|||||||
module;
|
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
|
||||||
|
|
||||||
#include "dhos_config.h"
|
|
||||||
|
|
||||||
export module LunarWM.Config;
|
|
||||||
|
|
||||||
import std;
|
|
||||||
|
|
||||||
static auto default_configuration_paths()
|
|
||||||
-> std::vector<std::filesystem::path> const
|
|
||||||
{
|
|
||||||
std::vector<std::filesystem::path> paths = {
|
|
||||||
"lunarwm/lunarwm.dcfg",
|
|
||||||
"lunarwm.dcfg",
|
|
||||||
"/etc/lunarwm.dcfg",
|
|
||||||
"/etc/lunarwm/lunarwm.dcfg",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (char const *xdg_dirs
|
|
||||||
= std::getenv("XDG_CONFIG_DIRS")) { // NOLINT(concurrency-mt-unsafe)
|
|
||||||
std::string const dirs { xdg_dirs };
|
|
||||||
std::istringstream ss { dirs };
|
|
||||||
std::string dir;
|
|
||||||
while (std::getline(ss, dir, ':')) {
|
|
||||||
if (!dir.empty()) {
|
|
||||||
paths.push_back(
|
|
||||||
std::filesystem::path(dir) / "lunarwm/lunarwm.dcfg");
|
|
||||||
paths.push_back(std::filesystem::path(dir) / "lunarwm.dcfg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (char const *home
|
|
||||||
= std::getenv("HOME")) { // NOLINT(concurrency-mt-unsafe)
|
|
||||||
std::filesystem::path const home_path(home);
|
|
||||||
paths.push_back(home_path / ".config/lunarwm/lunarwm.dcfg");
|
|
||||||
}
|
|
||||||
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline auto string_to_modifier(std::string_view str)
|
|
||||||
-> std::optional<wlr_keyboard_modifier>
|
|
||||||
{
|
|
||||||
if (boost::iequals(str, "shift")) {
|
|
||||||
return WLR_MODIFIER_SHIFT;
|
|
||||||
} else if (boost::iequals(str, "ctrl")) {
|
|
||||||
return WLR_MODIFIER_CTRL;
|
|
||||||
} else if (boost::iequals(str, "alt")) {
|
|
||||||
return WLR_MODIFIER_ALT;
|
|
||||||
} else if (boost::iequals(str, "mod2")) {
|
|
||||||
return WLR_MODIFIER_MOD2;
|
|
||||||
} else if (boost::iequals(str, "mod3")) {
|
|
||||||
return WLR_MODIFIER_MOD3;
|
|
||||||
} else if (boost::iequals(str, "logo") || boost::iequals(str, "win")
|
|
||||||
|| boost::iequals(str, "super") || boost::iequals(str, "mod4")) {
|
|
||||||
return WLR_MODIFIER_LOGO;
|
|
||||||
} else if (boost::iequals(str, "mod5")) {
|
|
||||||
return WLR_MODIFIER_MOD5;
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace LunarWM::Config {
|
|
||||||
|
|
||||||
struct Configuration {
|
|
||||||
dhos::Value e;
|
|
||||||
|
|
||||||
struct KeyCombo {
|
|
||||||
uint32_t modifiers {};
|
|
||||||
xkb_keysym_t sym {};
|
|
||||||
|
|
||||||
static auto parse(std::string const &str,
|
|
||||||
std::unordered_map<std::string, uint32_t> const &modifier_alias)
|
|
||||||
-> std::optional<Configuration::KeyCombo>;
|
|
||||||
};
|
|
||||||
struct Keybind {
|
|
||||||
KeyCombo combo;
|
|
||||||
dhos::Value action;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct {
|
|
||||||
struct {
|
|
||||||
std::vector<std::string> xkb_options;
|
|
||||||
} keyboard {};
|
|
||||||
} input {};
|
|
||||||
|
|
||||||
std::unordered_map<std::string, uint32_t> modifier_aliases;
|
|
||||||
std::vector<Keybind> keybindings;
|
|
||||||
|
|
||||||
dhos::Object custom_lib;
|
|
||||||
|
|
||||||
void execute_keybind(Keybind const &keybind)
|
|
||||||
{
|
|
||||||
dhos::eval(keybind.action, &this->custom_lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_to_custom_lib(std::string const &name, dhos::Builtin const &fn)
|
|
||||||
{
|
|
||||||
this->custom_lib.insert_or_assign(name, dhos::Value(fn, e.env));
|
|
||||||
}
|
|
||||||
|
|
||||||
void load() { this->load(default_configuration_paths()); }
|
|
||||||
void load(std::vector<std::filesystem::path> const &paths);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto Configuration::KeyCombo::parse(std::string const &str,
|
|
||||||
std::unordered_map<std::string, uint32_t> const &modifier_alias)
|
|
||||||
-> std::optional<Configuration::KeyCombo>
|
|
||||||
{
|
|
||||||
std::istringstream iss(str);
|
|
||||||
std::string component;
|
|
||||||
std::vector<std::string> components;
|
|
||||||
components.reserve(5);
|
|
||||||
while (std::getline(iss, component, '-')) {
|
|
||||||
boost::algorithm::trim(component);
|
|
||||||
if (component.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
components.push_back(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (components.size() < 2) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_keyboard_modifier mods {};
|
|
||||||
for (auto const &entry :
|
|
||||||
std::span(components.begin(), components.end() - 1)) {
|
|
||||||
auto mod_opt = string_to_modifier(entry);
|
|
||||||
if (!mod_opt) {
|
|
||||||
if (modifier_alias.contains(entry)) {
|
|
||||||
mod_opt = static_cast<wlr_keyboard_modifier>(
|
|
||||||
modifier_alias.at(entry));
|
|
||||||
} else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mods = static_cast<wlr_keyboard_modifier>(
|
|
||||||
static_cast<unsigned>(mods) | static_cast<unsigned>(*mod_opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const &key_name = components.back();
|
|
||||||
xkb_keysym_t const sym = xkb_keysym_from_name(key_name.c_str(),
|
|
||||||
static_cast<enum xkb_keysym_flags>(XKB_KEYSYM_CASE_INSENSITIVE));
|
|
||||||
if (sym == XKB_KEY_NoSymbol) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
Configuration::KeyCombo const combo {
|
|
||||||
.modifiers = mods,
|
|
||||||
.sym = sym,
|
|
||||||
};
|
|
||||||
return combo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Configuration::load(std::vector<std::filesystem::path> const &paths)
|
|
||||||
{
|
|
||||||
for (auto const &path : paths) {
|
|
||||||
try {
|
|
||||||
e = dhos::eval(dhos::parse_config(path), &this->custom_lib);
|
|
||||||
if (!e.is_obj()) {
|
|
||||||
throw std::runtime_error("Top level is not an object!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static dhos::Object base = dhos::make_default_lib();
|
|
||||||
auto merged = dhos::merge_lib(base, &this->custom_lib);
|
|
||||||
dhos::get_env_tbl(&*e.env)["lib"] = dhos::Value(merged, e.env);
|
|
||||||
|
|
||||||
if (e["input"].is_obj()) {
|
|
||||||
auto const &input = e["input"];
|
|
||||||
if (input["keyboard"].is_obj()) {
|
|
||||||
auto const &keyboard = input["keyboard"];
|
|
||||||
if (keyboard["xkb_options"].is_arr()) {
|
|
||||||
auto const &arr = keyboard["xkb_options"].arr();
|
|
||||||
this->input.keyboard.xkb_options.clear();
|
|
||||||
for (auto const &value : arr) {
|
|
||||||
if (value.is_str()) {
|
|
||||||
this->input.keyboard.xkb_options.push_back(
|
|
||||||
value.str());
|
|
||||||
} else {
|
|
||||||
// FIXME: Send warning
|
|
||||||
std::println("Invalid xkb_options type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e["modifier_aliases"].is_obj()) {
|
|
||||||
auto const &modifier_aliases = e["modifier_aliases"];
|
|
||||||
this->modifier_aliases.clear();
|
|
||||||
|
|
||||||
for (auto const &[k, v] : modifier_aliases.obj()) {
|
|
||||||
if (!v.is_str()) {
|
|
||||||
// FIXME: Send warning
|
|
||||||
std::println("Invalid modifier aliases value");
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
auto const to_parse = v.str() + "-a";
|
|
||||||
std::println(
|
|
||||||
"Sending alias value to parse: {}", to_parse);
|
|
||||||
auto const kc_opt = KeyCombo::parse(to_parse, {});
|
|
||||||
if (kc_opt) {
|
|
||||||
auto const mod_opt = kc_opt->modifiers;
|
|
||||||
this->modifier_aliases[k] = mod_opt;
|
|
||||||
} else {
|
|
||||||
// FIXME: Send warning
|
|
||||||
std::println(
|
|
||||||
"Invalid modifier aliases value format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e["keybindings"].is_arr()) {
|
|
||||||
auto const &keybindings = e["keybindings"].arr();
|
|
||||||
this->keybindings.clear();
|
|
||||||
|
|
||||||
for (auto const &v : keybindings) {
|
|
||||||
if (v.is_obj()) {
|
|
||||||
auto const &o = v.obj();
|
|
||||||
if (!o.contains("bind") || !o.contains("action")
|
|
||||||
|| !o.at("bind").is_str()
|
|
||||||
|| !o.at("action").is_call()) {
|
|
||||||
// FIXME: Send warning
|
|
||||||
std::println("Invalid keybinding object format");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const combo_opt = KeyCombo::parse(
|
|
||||||
o.at("bind").str(), this->modifier_aliases);
|
|
||||||
if (!combo_opt) {
|
|
||||||
// FIXME: Send warning
|
|
||||||
std::println("Invalid keybinding combo");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const &combo = *combo_opt;
|
|
||||||
|
|
||||||
this->keybindings.push_back({
|
|
||||||
.combo = combo,
|
|
||||||
.action = o.at("action"),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// FIXME: Send warning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} catch (std::filesystem::filesystem_error const &e) {
|
|
||||||
(void)e;
|
|
||||||
} catch (std::exception &e) {
|
|
||||||
(void)e;
|
|
||||||
std::println("Exception for config file: {}", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw std::runtime_error("Unable to find a valid configuration file!");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // LunarWM::Config
|
|
||||||
1572
src/LunarWM.c
Normal file
1572
src/LunarWM.c
Normal file
File diff suppressed because it is too large
Load Diff
1818
src/LunarWM.cppm
1818
src/LunarWM.cppm
File diff suppressed because it is too large
Load Diff
173
src/LunarWM.h
Normal file
173
src/LunarWM.h
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
#ifndef LUNAR_WM_H
|
||||||
|
#define LUNAR_WM_H
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#include <GLES3/gl31.h>
|
||||||
|
#include <openxr/openxr.h>
|
||||||
|
#include <openxr/openxr_platform.h>
|
||||||
|
|
||||||
|
#include <wayland-client-protocol.h>
|
||||||
|
#include <wayland-egl.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
|
#include <wlr/backend/session.h>
|
||||||
|
#include <wlr/backend/wayland.h>
|
||||||
|
#include <wlr/render/allocator.h>
|
||||||
|
#include <wlr/render/egl.h>
|
||||||
|
#include <wlr/render/gles2.h>
|
||||||
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_cursor.h>
|
||||||
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <raymath.h>
|
||||||
|
#include <rlgl.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct LunarWM;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct LunarWM *server;
|
||||||
|
|
||||||
|
struct wl_list link;
|
||||||
|
struct wlr_keyboard *wlr_keyboard;
|
||||||
|
|
||||||
|
struct wl_listener modifiers;
|
||||||
|
struct wl_listener key;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
} LunarWM_Keyboard;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct LunarWM *server;
|
||||||
|
|
||||||
|
struct wl_listener commit;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
|
||||||
|
struct wlr_xdg_toplevel *xdg_toplevel;
|
||||||
|
struct wlr_surface *surface;
|
||||||
|
struct wlr_texture *texture;
|
||||||
|
|
||||||
|
struct wlr_buffer *locked_buffer;
|
||||||
|
struct wlr_gles2_texture_attribs attribs;
|
||||||
|
struct wlr_gles2_texture *gles_texture;
|
||||||
|
Texture2D rl_texture;
|
||||||
|
} LunarWM_Toplevel;
|
||||||
|
|
||||||
|
bool LunarWM_Toplevel_init(
|
||||||
|
LunarWM_Toplevel *tl, struct LunarWM *wm, struct wlr_xdg_toplevel *xdg);
|
||||||
|
bool LunarWM_Toplevel_destroy(LunarWM_Toplevel *this);
|
||||||
|
|
||||||
|
bool LunarWM_Toplevel_update(LunarWM_Toplevel *this);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
XrSwapchain swapchain;
|
||||||
|
int64_t swapchain_format;
|
||||||
|
GLuint *v_image_views;
|
||||||
|
} LunarWM_SwapchainInfo;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
XrSwapchain handle;
|
||||||
|
XrSwapchainImageOpenGLESKHR *a_imgs;
|
||||||
|
uint32_t a_imgs_count;
|
||||||
|
} LunarWM_SwapchainImagesEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
|
||||||
|
XrHandTrackerEXT hand_tracker;
|
||||||
|
} LunarWM_Hand;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
XrTime predicted_display_time;
|
||||||
|
XrCompositionLayerProjection layer_projection;
|
||||||
|
XrCompositionLayerBaseHeader *layers[10];
|
||||||
|
uint32_t layers_count;
|
||||||
|
XrCompositionLayerProjectionView
|
||||||
|
layer_projection_views[10]; // Hopefully we dont have more than 10.
|
||||||
|
uint32_t layer_projection_views_count;
|
||||||
|
} LunarWM_RenderLayerInfo;
|
||||||
|
|
||||||
|
typedef struct LunarWM {
|
||||||
|
struct {
|
||||||
|
struct wl_display *display;
|
||||||
|
struct wl_event_loop *event_loop;
|
||||||
|
|
||||||
|
struct wlr_backend *backend;
|
||||||
|
struct wlr_renderer *renderer;
|
||||||
|
struct wlr_session *session;
|
||||||
|
|
||||||
|
struct wlr_egl *egl;
|
||||||
|
EGLDisplay egl_display;
|
||||||
|
EGLContext egl_context;
|
||||||
|
EGLConfig egl_config;
|
||||||
|
|
||||||
|
struct wlr_allocator *allocator;
|
||||||
|
struct wlr_compositor *compositor;
|
||||||
|
struct wlr_subcompositor *subcompositor;
|
||||||
|
struct wlr_data_device_manager *data_device_manager;
|
||||||
|
|
||||||
|
struct wlr_seat *seat;
|
||||||
|
struct wl_list keyboards;
|
||||||
|
struct wl_listener new_input_listener;
|
||||||
|
|
||||||
|
struct wlr_xdg_shell *xdg_shell;
|
||||||
|
struct wl_listener new_xdg_toplevel_listener;
|
||||||
|
struct wl_listener new_xdg_popup_listener;
|
||||||
|
|
||||||
|
struct wlr_cursor *cursor;
|
||||||
|
|
||||||
|
LunarWM_Toplevel **v_toplevels;
|
||||||
|
} wayland;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
XrInstance instance;
|
||||||
|
XrSystemId system_id;
|
||||||
|
XrSession session;
|
||||||
|
XrSessionState session_state;
|
||||||
|
struct {
|
||||||
|
LunarWM_SwapchainInfo *v_color;
|
||||||
|
LunarWM_SwapchainInfo *v_depth;
|
||||||
|
} swapchains;
|
||||||
|
LunarWM_SwapchainImagesEntry
|
||||||
|
swapchain_images[2]; // 0 is color, 1 is depth
|
||||||
|
XrViewConfigurationView *a_view_configuration_views;
|
||||||
|
uint32_t view_configuration_views_count;
|
||||||
|
XrEnvironmentBlendMode environment_blend_mode;
|
||||||
|
XrSpace local_space, view_space;
|
||||||
|
LunarWM_Hand hands[2];
|
||||||
|
XrSystemHandTrackingPropertiesEXT hand_tracking_system_properties;
|
||||||
|
|
||||||
|
PFN_xrCreateHandTrackerEXT CreateHandTrackerEXT;
|
||||||
|
PFN_xrDestroyHandTrackerEXT DestroyHandTrackerEXT;
|
||||||
|
PFN_xrLocateHandJointsEXT LocateHandJointsEXT;
|
||||||
|
|
||||||
|
bool session_running;
|
||||||
|
} xr;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
GLuint fbo;
|
||||||
|
RenderTexture2D tmp_rt;
|
||||||
|
Camera3D camera;
|
||||||
|
} renderer;
|
||||||
|
|
||||||
|
bool initialized;
|
||||||
|
bool running;
|
||||||
|
} LunarWM;
|
||||||
|
|
||||||
|
bool LunarWM_init(LunarWM *wm);
|
||||||
|
void LunarWM_destroy(LunarWM *this);
|
||||||
|
|
||||||
|
void LunarWM_terminate(LunarWM *this);
|
||||||
|
void LunarWM_run(LunarWM *this);
|
||||||
|
|
||||||
|
extern LunarWM g_wm;
|
||||||
|
|
||||||
|
#endif // LUNAR_WM_H
|
||||||
224
src/Math.cppm
224
src/Math.cppm
@@ -1,224 +0,0 @@
|
|||||||
export module LunarWM.Math;
|
|
||||||
|
|
||||||
import std;
|
|
||||||
|
|
||||||
export namespace LunarWM::Math {
|
|
||||||
|
|
||||||
template<typename T = float>
|
|
||||||
requires std::is_arithmetic_v<T> struct Vec2 {
|
|
||||||
template<typename U = T>
|
|
||||||
requires std::is_arithmetic_v<U>
|
|
||||||
auto operator+(Vec2<U> const &other) -> Vec2<U>
|
|
||||||
{
|
|
||||||
return { x + other.x, y + other.y };
|
|
||||||
}
|
|
||||||
template<typename U = T>
|
|
||||||
requires std::is_arithmetic_v<U>
|
|
||||||
auto operator-(Vec2<U> const &other) -> Vec2<U>
|
|
||||||
{
|
|
||||||
return { x - other.x, y - other.y };
|
|
||||||
}
|
|
||||||
template<typename U = T>
|
|
||||||
requires std::is_arithmetic_v<U>
|
|
||||||
auto operator*(Vec2<U> const &other) -> Vec2<U>
|
|
||||||
{
|
|
||||||
return { x * other.x, y * other.x };
|
|
||||||
}
|
|
||||||
template<typename U = T>
|
|
||||||
requires std::is_arithmetic_v<U> auto operator*(T scalar) -> Vec2<U>
|
|
||||||
{
|
|
||||||
return { x * scalar, y * scalar };
|
|
||||||
}
|
|
||||||
template<typename U = T>
|
|
||||||
requires std::is_arithmetic_v<U> auto operator/(T scalar) -> Vec2<U>
|
|
||||||
{
|
|
||||||
return { x / scalar, y / scalar };
|
|
||||||
}
|
|
||||||
template<typename U = T>
|
|
||||||
requires std::is_arithmetic_v<U> auto operator-() -> Vec2
|
|
||||||
{
|
|
||||||
return { -x, -y };
|
|
||||||
}
|
|
||||||
auto length() const -> T { return std::sqrt(x * x + y * y); }
|
|
||||||
auto lengthSquared() const -> T { return x * x + y * y; }
|
|
||||||
auto normalized() const -> Vec2<T>
|
|
||||||
{
|
|
||||||
T len = length();
|
|
||||||
if (len == T(0)) {
|
|
||||||
return { T(0), T(0) };
|
|
||||||
}
|
|
||||||
return *this / len;
|
|
||||||
}
|
|
||||||
|
|
||||||
T x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
requires std::is_arithmetic_v<T>
|
|
||||||
auto operator*(T scalar, Vec2<T> const &v) -> Vec2<T>
|
|
||||||
{
|
|
||||||
return { v.x * scalar, v.y * scalar };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T = float>
|
|
||||||
requires std::is_arithmetic_v<T> struct Rect {
|
|
||||||
Rect(Vec2<T> pos, Vec2<T> size)
|
|
||||||
: pos(pos)
|
|
||||||
, size(size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Rect(T x, T y, T w, T h)
|
|
||||||
: pos({ x, y })
|
|
||||||
, size({ w, h })
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
auto x() -> T & { return pos.x; }
|
|
||||||
auto y() -> T & { return pos.y; }
|
|
||||||
auto w() -> T & { return size.x; }
|
|
||||||
auto h() -> T & { return size.y; }
|
|
||||||
|
|
||||||
auto x() const -> T { return pos.x; }
|
|
||||||
auto y() const -> T { return pos.y; }
|
|
||||||
auto w() const -> T { return size.x; }
|
|
||||||
auto h() const -> T { return size.y; }
|
|
||||||
|
|
||||||
auto left() const -> T { return x(); }
|
|
||||||
auto right() const -> T { return x() + w(); }
|
|
||||||
auto top() const -> T { return y(); }
|
|
||||||
auto bottom() const -> T { return y() + h(); }
|
|
||||||
|
|
||||||
auto left() -> T & { return x(); }
|
|
||||||
auto top() -> T & { return y(); }
|
|
||||||
|
|
||||||
Vec2<T> pos, size;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T = float>
|
|
||||||
requires std::is_arithmetic_v<T> struct Box {
|
|
||||||
template<typename U = int>
|
|
||||||
requires std::is_arithmetic_v<U> auto operator[](U const index) -> Vec2<T> &
|
|
||||||
{
|
|
||||||
if (index < 0 || index > 1) {
|
|
||||||
throw std::out_of_range("A box only has two points");
|
|
||||||
}
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
auto first() -> Vec2<T> & { return m_data[0]; }
|
|
||||||
auto second() -> Vec2<T> & { return m_data[1]; }
|
|
||||||
auto x0() -> T & { return m_data[0].x; }
|
|
||||||
auto y0() -> T & { return m_data[0].y; }
|
|
||||||
auto x1() -> T & { return m_data[1].x; }
|
|
||||||
auto y1() -> T & { return m_data[1].y; }
|
|
||||||
auto left() -> T &
|
|
||||||
{
|
|
||||||
if (x0() < x1()) {
|
|
||||||
return x0();
|
|
||||||
}
|
|
||||||
return x1();
|
|
||||||
}
|
|
||||||
auto right() -> T &
|
|
||||||
{
|
|
||||||
if (x0() > x1()) {
|
|
||||||
return x0();
|
|
||||||
}
|
|
||||||
return x1();
|
|
||||||
}
|
|
||||||
auto top() -> T &
|
|
||||||
{
|
|
||||||
if (y0() < y1()) {
|
|
||||||
return y0();
|
|
||||||
}
|
|
||||||
return y1();
|
|
||||||
}
|
|
||||||
auto bottom() -> T &
|
|
||||||
{
|
|
||||||
if (y0() > y1()) {
|
|
||||||
return y0();
|
|
||||||
}
|
|
||||||
return y1();
|
|
||||||
}
|
|
||||||
|
|
||||||
Box() = default;
|
|
||||||
explicit Box(Rect<T> rect)
|
|
||||||
{
|
|
||||||
this->m_data[0] = rect.pos;
|
|
||||||
this->m_data[1] = rect.pos + rect.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::array<Vec2<T>, 2> m_data = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T = int>
|
|
||||||
requires std::is_arithmetic_v<T>
|
|
||||||
auto subtract_rect(Math::Rect<T> const &src, Math::Rect<T> const &clip)
|
|
||||||
-> std::vector<Math::Rect<T>>
|
|
||||||
{
|
|
||||||
std::vector<Math::Rect<T>> result;
|
|
||||||
|
|
||||||
auto sx = src.x();
|
|
||||||
auto sy = src.y();
|
|
||||||
auto sw = src.w();
|
|
||||||
auto sh = src.h();
|
|
||||||
|
|
||||||
auto cx = clip.x();
|
|
||||||
auto cy = clip.y();
|
|
||||||
auto cw = clip.w();
|
|
||||||
auto ch = clip.h();
|
|
||||||
|
|
||||||
T s_right = sx + sw;
|
|
||||||
T s_bottom = sy + sh;
|
|
||||||
|
|
||||||
T c_right = cx + cw;
|
|
||||||
T c_bottom = cy + ch;
|
|
||||||
|
|
||||||
// No overlap → keep src
|
|
||||||
if (c_right <= sx || cx >= s_right || c_bottom <= sy || cy >= s_bottom) {
|
|
||||||
result.push_back(src);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top piece
|
|
||||||
if (cy > sy) {
|
|
||||||
result.emplace_back(sx, sy, sw, cy - sy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bottom piece
|
|
||||||
if (c_bottom < s_bottom) {
|
|
||||||
result.emplace_back(sx, c_bottom, sw, s_bottom - c_bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Middle pieces left and right of clip
|
|
||||||
T middle_top = std::max(sy, cy);
|
|
||||||
T middle_bottom = std::min(s_bottom, c_bottom);
|
|
||||||
T middle_height = middle_bottom - middle_top;
|
|
||||||
|
|
||||||
if (middle_height > 0) {
|
|
||||||
// Left piece
|
|
||||||
if (cx > sx) {
|
|
||||||
result.emplace_back(sx, middle_top, cx - sx, middle_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right piece
|
|
||||||
if (c_right < s_right) {
|
|
||||||
result.emplace_back(
|
|
||||||
c_right, middle_top, s_right - c_right, middle_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T = float>
|
|
||||||
requires std::is_arithmetic_v<T> struct Viewport {
|
|
||||||
Rect<T> rect;
|
|
||||||
Vec2<T> depth_limits;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> constexpr auto deg2rad(T degrees) -> T
|
|
||||||
{
|
|
||||||
return degrees * (std::numbers::pi / 180.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace LunarWM::Math
|
|
||||||
676
src/Util.cppm
676
src/Util.cppm
@@ -1,676 +0,0 @@
|
|||||||
module;
|
|
||||||
|
|
||||||
// NOLINTBEGIN
|
|
||||||
#include <openxr/openxr.h>
|
|
||||||
// NOLINTEND
|
|
||||||
|
|
||||||
export module LunarWM.Util;
|
|
||||||
|
|
||||||
import std;
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<> struct formatter<XrResult, char> {
|
|
||||||
template<class ParseContext> constexpr auto parse(ParseContext &ctx)
|
|
||||||
{
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto to_string(XrResult r) -> std::string_view
|
|
||||||
{
|
|
||||||
switch (r) {
|
|
||||||
case XR_FRAME_DISCARDED:
|
|
||||||
return "XR_FRAME_DISCARDED";
|
|
||||||
case XR_ERROR_VALIDATION_FAILURE:
|
|
||||||
return "XR_ERROR_VALIDATION_FAILURE: The function usage was "
|
|
||||||
"invalid in "
|
|
||||||
"some way.";
|
|
||||||
case XR_ERROR_RUNTIME_FAILURE:
|
|
||||||
return "XR_ERROR_RUNTIME_FAILURE: The runtime failed to handle the "
|
|
||||||
"function in an unexpected way that is not covered by "
|
|
||||||
"another "
|
|
||||||
"error result.";
|
|
||||||
case XR_ERROR_OUT_OF_MEMORY:
|
|
||||||
return "XR_ERROR_OUT_OF_MEMORY: A memory allocation has failed.";
|
|
||||||
case XR_ERROR_API_VERSION_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_API_VERSION_UNSUPPORTED: The runtime does not "
|
|
||||||
"support "
|
|
||||||
"the requested API version.";
|
|
||||||
case XR_ERROR_INITIALIZATION_FAILED:
|
|
||||||
return "XR_ERROR_INITIALIZATION_FAILED: Initialization of object "
|
|
||||||
"could "
|
|
||||||
"not be completed.";
|
|
||||||
case XR_ERROR_FUNCTION_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_FUNCTION_UNSUPPORTED: The requested function was "
|
|
||||||
"not "
|
|
||||||
"found or is otherwise unsupported.";
|
|
||||||
case XR_ERROR_FEATURE_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_FEATURE_UNSUPPORTED: The requested feature is not "
|
|
||||||
"supported.";
|
|
||||||
case XR_ERROR_EXTENSION_NOT_PRESENT:
|
|
||||||
return "XR_ERROR_EXTENSION_NOT_PRESENT: A requested extension is "
|
|
||||||
"not "
|
|
||||||
"supported.";
|
|
||||||
case XR_ERROR_LIMIT_REACHED:
|
|
||||||
return "XR_ERROR_LIMIT_REACHED: The runtime supports no more of "
|
|
||||||
"the "
|
|
||||||
"requested resource.";
|
|
||||||
case XR_ERROR_SIZE_INSUFFICIENT:
|
|
||||||
return "XR_ERROR_SIZE_INSUFFICIENT: The supplied size was smaller "
|
|
||||||
"than "
|
|
||||||
"required.";
|
|
||||||
case XR_ERROR_HANDLE_INVALID:
|
|
||||||
return "XR_ERROR_HANDLE_INVALID: A supplied object handle was "
|
|
||||||
"invalid.";
|
|
||||||
case XR_ERROR_INSTANCE_LOST:
|
|
||||||
return "XR_ERROR_INSTANCE_LOST: The XrInstance was lost or could "
|
|
||||||
"not be "
|
|
||||||
"found. It will need to be destroyed and optionally "
|
|
||||||
"recreated.";
|
|
||||||
case XR_ERROR_SESSION_RUNNING:
|
|
||||||
return "XR_ERROR_SESSION_RUNNING: The session is already running.";
|
|
||||||
case XR_ERROR_SESSION_NOT_RUNNING:
|
|
||||||
return "XR_ERROR_SESSION_NOT_RUNNING: The session is not yet "
|
|
||||||
"running.";
|
|
||||||
case XR_ERROR_SESSION_LOST:
|
|
||||||
return "XR_ERROR_SESSION_LOST: The XrSession was lost. It will "
|
|
||||||
"need to "
|
|
||||||
"be destroyed and optionally recreated.";
|
|
||||||
case XR_ERROR_SYSTEM_INVALID:
|
|
||||||
return "XR_ERROR_SYSTEM_INVALID: The provided XrSystemId was "
|
|
||||||
"invalid.";
|
|
||||||
case XR_ERROR_PATH_INVALID:
|
|
||||||
return "XR_ERROR_PATH_INVALID: The provided XrPath was not valid.";
|
|
||||||
case XR_ERROR_PATH_COUNT_EXCEEDED:
|
|
||||||
return "XR_ERROR_PATH_COUNT_EXCEEDED: The maximum number of "
|
|
||||||
"supported "
|
|
||||||
"semantic paths has been reached.";
|
|
||||||
case XR_ERROR_PATH_FORMAT_INVALID:
|
|
||||||
return "XR_ERROR_PATH_FORMAT_INVALID: The semantic path character "
|
|
||||||
"format "
|
|
||||||
"is invalid.";
|
|
||||||
case XR_ERROR_PATH_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_PATH_UNSUPPORTED: The semantic path is "
|
|
||||||
"unsupported.";
|
|
||||||
case XR_ERROR_LAYER_INVALID:
|
|
||||||
return "XR_ERROR_LAYER_INVALID: The layer was NULL or otherwise "
|
|
||||||
"invalid.";
|
|
||||||
case XR_ERROR_LAYER_LIMIT_EXCEEDED:
|
|
||||||
return "XR_ERROR_LAYER_LIMIT_EXCEEDED: The number of specified "
|
|
||||||
"layers is "
|
|
||||||
"greater than the supported number.";
|
|
||||||
case XR_ERROR_SWAPCHAIN_RECT_INVALID:
|
|
||||||
return "XR_ERROR_SWAPCHAIN_RECT_INVALID: The image rect was "
|
|
||||||
"negatively "
|
|
||||||
"sized or otherwise invalid.";
|
|
||||||
case XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED: The image format is "
|
|
||||||
"not "
|
|
||||||
"supported by the runtime or platform.";
|
|
||||||
case XR_ERROR_ACTION_TYPE_MISMATCH:
|
|
||||||
return "XR_ERROR_ACTION_TYPE_MISMATCH: The API used to retrieve an "
|
|
||||||
"action’s state does not match the action’s type.";
|
|
||||||
case XR_ERROR_SESSION_NOT_READY:
|
|
||||||
return "XR_ERROR_SESSION_NOT_READY: The session is not in the "
|
|
||||||
"ready "
|
|
||||||
"state.";
|
|
||||||
case XR_ERROR_SESSION_NOT_STOPPING:
|
|
||||||
return "XR_ERROR_SESSION_NOT_STOPPING: The session is not in the "
|
|
||||||
"stopping state.";
|
|
||||||
case XR_ERROR_TIME_INVALID:
|
|
||||||
return "XR_ERROR_TIME_INVALID: The provided XrTime was zero, "
|
|
||||||
"negative, "
|
|
||||||
"or out of range.";
|
|
||||||
case XR_ERROR_REFERENCE_SPACE_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_REFERENCE_SPACE_UNSUPPORTED: The specified "
|
|
||||||
"reference "
|
|
||||||
"space is not supported by the runtime or system.";
|
|
||||||
case XR_ERROR_FILE_ACCESS_ERROR:
|
|
||||||
return "XR_ERROR_FILE_ACCESS_ERROR: The file could not be "
|
|
||||||
"accessed.";
|
|
||||||
case XR_ERROR_FILE_CONTENTS_INVALID:
|
|
||||||
return "XR_ERROR_FILE_CONTENTS_INVALID: The file’s contents were "
|
|
||||||
"invalid.";
|
|
||||||
case XR_ERROR_FORM_FACTOR_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_FORM_FACTOR_UNSUPPORTED: The specified form "
|
|
||||||
"factor is "
|
|
||||||
"not supported by the current runtime or platform.";
|
|
||||||
case XR_ERROR_FORM_FACTOR_UNAVAILABLE:
|
|
||||||
return "XR_ERROR_FORM_FACTOR_UNAVAILABLE: The specified form "
|
|
||||||
"factor is "
|
|
||||||
"supported, but the device is currently not available, e.g. "
|
|
||||||
"not "
|
|
||||||
"plugged in or powered off.";
|
|
||||||
case XR_ERROR_API_LAYER_NOT_PRESENT:
|
|
||||||
return "XR_ERROR_API_LAYER_NOT_PRESENT: A requested API layer is "
|
|
||||||
"not "
|
|
||||||
"present or could not be loaded.";
|
|
||||||
case XR_ERROR_CALL_ORDER_INVALID:
|
|
||||||
return "XR_ERROR_CALL_ORDER_INVALID: The call was made without "
|
|
||||||
"having "
|
|
||||||
"made a previously required call.";
|
|
||||||
case XR_ERROR_GRAPHICS_DEVICE_INVALID:
|
|
||||||
return "XR_ERROR_GRAPHICS_DEVICE_INVALID: The given graphics "
|
|
||||||
"device is "
|
|
||||||
"not in a valid state. The graphics device could be lost or "
|
|
||||||
"initialized without meeting graphics requirements.";
|
|
||||||
case XR_ERROR_POSE_INVALID:
|
|
||||||
return "XR_ERROR_POSE_INVALID: The supplied pose was invalid with "
|
|
||||||
"respect to the requirements.";
|
|
||||||
case XR_ERROR_INDEX_OUT_OF_RANGE:
|
|
||||||
return "XR_ERROR_INDEX_OUT_OF_RANGE: The supplied index was "
|
|
||||||
"outside the "
|
|
||||||
"range of valid indices.";
|
|
||||||
case XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED: The "
|
|
||||||
"specified view "
|
|
||||||
"configuration type is not supported by the runtime or "
|
|
||||||
"platform.";
|
|
||||||
case XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED:
|
|
||||||
return "XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED: The specified "
|
|
||||||
"environment blend mode is not supported by the runtime or "
|
|
||||||
"platform.";
|
|
||||||
case XR_ERROR_NAME_DUPLICATED:
|
|
||||||
return "XR_ERROR_NAME_DUPLICATED: The name provided was a "
|
|
||||||
"duplicate of "
|
|
||||||
"an already-existing resource.";
|
|
||||||
case XR_ERROR_NAME_INVALID:
|
|
||||||
return "XR_ERROR_NAME_INVALID: The name provided was invalid.";
|
|
||||||
case XR_ERROR_ACTIONSET_NOT_ATTACHED:
|
|
||||||
return "XR_ERROR_ACTIONSET_NOT_ATTACHED: A referenced action set "
|
|
||||||
"is not "
|
|
||||||
"attached to the session.";
|
|
||||||
case XR_ERROR_ACTIONSETS_ALREADY_ATTACHED:
|
|
||||||
return "XR_ERROR_ACTIONSETS_ALREADY_ATTACHED: The session already "
|
|
||||||
"has "
|
|
||||||
"attached action sets.";
|
|
||||||
case XR_ERROR_LOCALIZED_NAME_DUPLICATED:
|
|
||||||
return "XR_ERROR_LOCALIZED_NAME_DUPLICATED: The localized name "
|
|
||||||
"provided "
|
|
||||||
"was a duplicate of an already-existing resource.";
|
|
||||||
case XR_ERROR_LOCALIZED_NAME_INVALID:
|
|
||||||
return "XR_ERROR_LOCALIZED_NAME_INVALID: The localized name "
|
|
||||||
"provided was "
|
|
||||||
"invalid.";
|
|
||||||
case XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING:
|
|
||||||
return "XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING: The "
|
|
||||||
"xrGetGraphicsRequirements* call was not made before "
|
|
||||||
"calling "
|
|
||||||
"xrCreateSession.";
|
|
||||||
case XR_ERROR_RUNTIME_UNAVAILABLE:
|
|
||||||
return "XR_ERROR_RUNTIME_UNAVAILABLE: The loader was unable to "
|
|
||||||
"find or "
|
|
||||||
"load a runtime.";
|
|
||||||
case XR_ERROR_EXTENSION_DEPENDENCY_NOT_ENABLED:
|
|
||||||
return "XR_ERROR_EXTENSION_DEPENDENCY_NOT_ENABLED: One or more of "
|
|
||||||
"the "
|
|
||||||
"extensions being enabled has dependency on extensions that "
|
|
||||||
"are "
|
|
||||||
"not enabled.";
|
|
||||||
case XR_ERROR_PERMISSION_INSUFFICIENT:
|
|
||||||
return "XR_ERROR_PERMISSION_INSUFFICIENT: Insufficient "
|
|
||||||
"permissions. This "
|
|
||||||
"error is included for use by vendor extensions. The "
|
|
||||||
"precise "
|
|
||||||
"definition of XR_ERROR_PERMISSION_INSUFFICIENT and actions "
|
|
||||||
"possible by the developer or user to resolve it can vary "
|
|
||||||
"by "
|
|
||||||
"platform, extension or function. The developer should "
|
|
||||||
"refer to "
|
|
||||||
"the documentation of the function that returned the error "
|
|
||||||
"code "
|
|
||||||
"and extension it was defined.";
|
|
||||||
case XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR:
|
|
||||||
return "XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR: "
|
|
||||||
"xrSetAndroidApplicationThreadKHR failed as thread id is "
|
|
||||||
"invalid. "
|
|
||||||
"(Added by the XR_KHR_android_thread_settings extension)";
|
|
||||||
case XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR:
|
|
||||||
return "XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR: "
|
|
||||||
"xrSetAndroidApplicationThreadKHR failed setting the thread "
|
|
||||||
"attributes/priority. (Added by the "
|
|
||||||
"XR_KHR_android_thread_settings extension)";
|
|
||||||
case XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT:
|
|
||||||
return "XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT: Spatial anchor "
|
|
||||||
"could "
|
|
||||||
"not be created at that location. (Added by the "
|
|
||||||
"XR_MSFT_spatial_anchor extension)";
|
|
||||||
case XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT:
|
|
||||||
return "XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_"
|
|
||||||
"MSFT: The "
|
|
||||||
"secondary view configuration was not enabled when creating "
|
|
||||||
"the "
|
|
||||||
"session. (Added by the "
|
|
||||||
"XR_MSFT_secondary_view_configuration "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT:
|
|
||||||
return "XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT: The controller "
|
|
||||||
"model "
|
|
||||||
"key is invalid. (Added by the XR_MSFT_controller_model "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT:
|
|
||||||
return "XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT: The "
|
|
||||||
"reprojection "
|
|
||||||
"mode is not supported. (Added by the "
|
|
||||||
"XR_MSFT_composition_layer_reprojection extension)";
|
|
||||||
case XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT:
|
|
||||||
return "XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT: Compute new "
|
|
||||||
"scene "
|
|
||||||
"not completed. (Added by the XR_MSFT_scene_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT:
|
|
||||||
return "XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT: Scene component "
|
|
||||||
"id "
|
|
||||||
"invalid. (Added by the XR_MSFT_scene_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT:
|
|
||||||
return "XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT: Scene "
|
|
||||||
"component "
|
|
||||||
"type mismatch. (Added by the XR_MSFT_scene_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT:
|
|
||||||
return "XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT: Scene mesh "
|
|
||||||
"buffer id "
|
|
||||||
"invalid. (Added by the XR_MSFT_scene_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT:
|
|
||||||
return "XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT: Scene "
|
|
||||||
"compute "
|
|
||||||
"feature incompatible. (Added by the "
|
|
||||||
"XR_MSFT_scene_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT:
|
|
||||||
return "XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT: Scene "
|
|
||||||
"compute "
|
|
||||||
"consistency mismatch. (Added by the "
|
|
||||||
"XR_MSFT_scene_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB:
|
|
||||||
return "XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB: The display "
|
|
||||||
"refresh rate is not supported by the platform. (Added by "
|
|
||||||
"the "
|
|
||||||
"XR_FB_display_refresh_rate extension)";
|
|
||||||
case XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB:
|
|
||||||
return "XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB: The color space is "
|
|
||||||
"not "
|
|
||||||
"supported by the runtime. (Added by the XR_FB_color_space "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB:
|
|
||||||
return "XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB: The component "
|
|
||||||
"type is "
|
|
||||||
"not supported for this space. (Added by the "
|
|
||||||
"XR_FB_spatial_entity "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB:
|
|
||||||
return "XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB: The required "
|
|
||||||
"component "
|
|
||||||
"is not enabled for this space. (Added by the "
|
|
||||||
"XR_FB_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB:
|
|
||||||
return "XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB: A request to "
|
|
||||||
"set the "
|
|
||||||
"component’s status is currently pending. (Added by the "
|
|
||||||
"XR_FB_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB:
|
|
||||||
return "XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB: The "
|
|
||||||
"component is "
|
|
||||||
"already set to the requested value. (Added by the "
|
|
||||||
"XR_FB_spatial_entity extension)";
|
|
||||||
case XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB:
|
|
||||||
return "XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB: The object state "
|
|
||||||
"is "
|
|
||||||
"unexpected for the issued command. (Added by the "
|
|
||||||
"XR_FB_passthrough extension)";
|
|
||||||
case XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB:
|
|
||||||
return "XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB: Trying to "
|
|
||||||
"create an MR feature when one was already created and only "
|
|
||||||
"one "
|
|
||||||
"instance is allowed. (Added by the XR_FB_passthrough "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB:
|
|
||||||
return "XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB: Requested "
|
|
||||||
"functionality requires a feature to be created first. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_FB_passthrough extension)";
|
|
||||||
case XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB:
|
|
||||||
return "XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB: Requested "
|
|
||||||
"functionality "
|
|
||||||
"is not permitted - application is not allowed to perform "
|
|
||||||
"the "
|
|
||||||
"requested operation. (Added by the XR_FB_passthrough "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB:
|
|
||||||
return "XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB: There were "
|
|
||||||
"insufficient resources available to perform an operation. "
|
|
||||||
"(Added "
|
|
||||||
"by the XR_FB_passthrough extension)";
|
|
||||||
case XR_ERROR_UNKNOWN_PASSTHROUGH_FB:
|
|
||||||
return "XR_ERROR_UNKNOWN_PASSTHROUGH_FB: Unknown Passthrough error "
|
|
||||||
"(no "
|
|
||||||
"further details provided). (Added by the XR_FB_passthrough "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_RENDER_MODEL_KEY_INVALID_FB:
|
|
||||||
return "XR_ERROR_RENDER_MODEL_KEY_INVALID_FB: The model key is "
|
|
||||||
"invalid. "
|
|
||||||
"(Added by the XR_FB_render_model extension)";
|
|
||||||
case XR_ERROR_MARKER_NOT_TRACKED_VARJO:
|
|
||||||
return "XR_ERROR_MARKER_NOT_TRACKED_VARJO: Marker tracking is "
|
|
||||||
"disabled "
|
|
||||||
"or the specified marker is not currently tracked. (Added "
|
|
||||||
"by the "
|
|
||||||
"XR_VARJO_marker_tracking extension)";
|
|
||||||
case XR_ERROR_MARKER_ID_INVALID_VARJO:
|
|
||||||
return "XR_ERROR_MARKER_ID_INVALID_VARJO: The specified marker ID "
|
|
||||||
"is not "
|
|
||||||
"valid. (Added by the XR_VARJO_marker_tracking extension)";
|
|
||||||
case XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML:
|
|
||||||
return "XR_ERROR_MARKER_DETECTOR_PERMISSION_DENIED_ML: The "
|
|
||||||
"com.magicleap.permission.MARKER_TRACKING permission was "
|
|
||||||
"denied. "
|
|
||||||
"(Added by the XR_ML_marker_understanding extension)";
|
|
||||||
case XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML:
|
|
||||||
return "XR_ERROR_MARKER_DETECTOR_LOCATE_FAILED_ML: The specified "
|
|
||||||
"marker "
|
|
||||||
"could not be located spatially. (Added by the "
|
|
||||||
"XR_ML_marker_understanding extension)";
|
|
||||||
case XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML:
|
|
||||||
return "XR_ERROR_MARKER_DETECTOR_INVALID_DATA_QUERY_ML: The marker "
|
|
||||||
"queried does not contain data of the requested type. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_ML_marker_understanding extension)";
|
|
||||||
case XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML:
|
|
||||||
return "XR_ERROR_MARKER_DETECTOR_INVALID_CREATE_INFO_ML: "
|
|
||||||
"createInfo "
|
|
||||||
"contains mutually exclusive parameters, such as setting "
|
|
||||||
"XR_MARKER_DETECTOR_CORNER_REFINE_METHOD_APRIL_TAG_ML with "
|
|
||||||
"XR_MARKER_TYPE_ARUCO_ML. (Added by the "
|
|
||||||
"XR_ML_marker_understanding extension)";
|
|
||||||
case XR_ERROR_MARKER_INVALID_ML:
|
|
||||||
return "XR_ERROR_MARKER_INVALID_ML: The marker id passed to the "
|
|
||||||
"function "
|
|
||||||
"was invalid. (Added by the XR_ML_marker_understanding "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_INCOMPATIBLE_ML: The "
|
|
||||||
"localization map "
|
|
||||||
"being imported is not compatible with current OS or mode. "
|
|
||||||
"(Added "
|
|
||||||
"by the XR_ML_localization_map extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_UNAVAILABLE_ML: The localization "
|
|
||||||
"map "
|
|
||||||
"requested is not available. (Added by the "
|
|
||||||
"XR_ML_localization_map "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_FAIL_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_FAIL_ML: The map localization "
|
|
||||||
"service "
|
|
||||||
"failed to fulfill the request, retry later. (Added by the "
|
|
||||||
"XR_ML_localization_map extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_IMPORT_EXPORT_PERMISSION_DENIED_"
|
|
||||||
"ML: "
|
|
||||||
"The com.magicleap.permission.SPACE_IMPORT_EXPORT "
|
|
||||||
"permission was "
|
|
||||||
"denied. (Added by the XR_ML_localization_map extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_PERMISSION_DENIED_ML: The "
|
|
||||||
"com.magicleap.permission.SPACE_MANAGER permission was "
|
|
||||||
"denied. "
|
|
||||||
"(Added by the XR_ML_localization_map extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_ALREADY_EXISTS_ML: The map being "
|
|
||||||
"imported already exists in the system. (Added by the "
|
|
||||||
"XR_ML_localization_map extension)";
|
|
||||||
case XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML:
|
|
||||||
return "XR_ERROR_LOCALIZATION_MAP_CANNOT_EXPORT_CLOUD_MAP_ML: The "
|
|
||||||
"map "
|
|
||||||
"localization service cannot export cloud based maps. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_ML_localization_map extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHORS_PERMISSION_DENIED_ML:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHORS_PERMISSION_DENIED_ML: The "
|
|
||||||
"com.magicleap.permission.SPATIAL_ANCHOR permission was not "
|
|
||||||
"granted. (Added by the XR_ML_spatial_anchors extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHORS_NOT_LOCALIZED_ML:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHORS_NOT_LOCALIZED_ML: Operation "
|
|
||||||
"failed "
|
|
||||||
"because the system is not localized into a localization "
|
|
||||||
"map. "
|
|
||||||
"(Added by the XR_ML_spatial_anchors extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHORS_OUT_OF_MAP_BOUNDS_ML:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHORS_OUT_OF_MAP_BOUNDS_ML: Operation "
|
|
||||||
"failed "
|
|
||||||
"because it is performed outside of the localization map. "
|
|
||||||
"(Added "
|
|
||||||
"by the XR_ML_spatial_anchors extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHORS_SPACE_NOT_LOCATABLE_ML:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHORS_SPACE_NOT_LOCATABLE_ML: Operation "
|
|
||||||
"failed because the space referenced cannot be located. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_ML_spatial_anchors extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHORS_ANCHOR_NOT_FOUND_ML:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHORS_ANCHOR_NOT_FOUND_ML: The anchor "
|
|
||||||
"references was not found. (Added by the "
|
|
||||||
"XR_ML_spatial_anchors_storage extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT: A spatial "
|
|
||||||
"anchor "
|
|
||||||
"was not found associated with the spatial anchor name "
|
|
||||||
"provided "
|
|
||||||
"(Added by the XR_MSFT_spatial_anchor_persistence "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT:
|
|
||||||
return "XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT: The spatial "
|
|
||||||
"anchor "
|
|
||||||
"name provided was not valid (Added by the "
|
|
||||||
"XR_MSFT_spatial_anchor_persistence extension)";
|
|
||||||
case XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB:
|
|
||||||
return "XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB: Anchor import from "
|
|
||||||
"cloud "
|
|
||||||
"or export from device failed. (Added by the "
|
|
||||||
"XR_FB_spatial_entity_sharing extension)";
|
|
||||||
case XR_ERROR_SPACE_LOCALIZATION_FAILED_FB:
|
|
||||||
return "XR_ERROR_SPACE_LOCALIZATION_FAILED_FB: Anchors were "
|
|
||||||
"downloaded "
|
|
||||||
"from the cloud but failed to be imported/aligned on the "
|
|
||||||
"device. "
|
|
||||||
"(Added by the XR_FB_spatial_entity_sharing extension)";
|
|
||||||
case XR_ERROR_SPACE_NETWORK_TIMEOUT_FB:
|
|
||||||
return "XR_ERROR_SPACE_NETWORK_TIMEOUT_FB: Timeout occurred while "
|
|
||||||
"waiting for network request to complete. (Added by the "
|
|
||||||
"XR_FB_spatial_entity_sharing extension)";
|
|
||||||
case XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB:
|
|
||||||
return "XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB: The network "
|
|
||||||
"request "
|
|
||||||
"failed. (Added by the XR_FB_spatial_entity_sharing "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB:
|
|
||||||
return "XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB: Cloud storage is "
|
|
||||||
"required for this operation but is currently disabled. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_FB_spatial_entity_sharing extension)";
|
|
||||||
case XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META:
|
|
||||||
return "XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META: "
|
|
||||||
"The "
|
|
||||||
"provided data buffer did not match the required size. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_META_passthrough_color_lut extension)";
|
|
||||||
case XR_ERROR_RENDER_MODEL_ID_INVALID_EXT:
|
|
||||||
return "XR_ERROR_RENDER_MODEL_ID_INVALID_EXT: The render model ID "
|
|
||||||
"is "
|
|
||||||
"invalid. (Added by the XR_EXT_render_model extension)";
|
|
||||||
case XR_ERROR_RENDER_MODEL_ASSET_UNAVAILABLE_EXT:
|
|
||||||
return "XR_ERROR_RENDER_MODEL_ASSET_UNAVAILABLE_EXT: The render "
|
|
||||||
"model "
|
|
||||||
"asset is unavailable. (Added by the XR_EXT_render_model "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_RENDER_MODEL_GLTF_EXTENSION_REQUIRED_EXT:
|
|
||||||
return "XR_ERROR_RENDER_MODEL_GLTF_EXTENSION_REQUIRED_EXT: A glTF "
|
|
||||||
"extension is required. (Added by the XR_EXT_render_model "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_NOT_INTERACTION_RENDER_MODEL_EXT:
|
|
||||||
return "XR_ERROR_NOT_INTERACTION_RENDER_MODEL_EXT: The provided "
|
|
||||||
"XrRenderModelEXT was not created from a XrRenderModelIdEXT "
|
|
||||||
"from "
|
|
||||||
"[XR_EXT_interaction_render_model] (Added by the "
|
|
||||||
"XR_EXT_interaction_render_model extension)";
|
|
||||||
case XR_ERROR_HINT_ALREADY_SET_QCOM:
|
|
||||||
return "XR_ERROR_HINT_ALREADY_SET_QCOM: Tracking optimization hint "
|
|
||||||
"is "
|
|
||||||
"already set for the domain. (Added by the "
|
|
||||||
"XR_QCOM_tracking_optimization_settings extension)";
|
|
||||||
case XR_ERROR_NOT_AN_ANCHOR_HTC:
|
|
||||||
return "XR_ERROR_NOT_AN_ANCHOR_HTC: The provided space is valid "
|
|
||||||
"but not "
|
|
||||||
"an anchor. (Added by the XR_HTC_anchor extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ENTITY_ID_INVALID_BD:
|
|
||||||
return "XR_ERROR_SPATIAL_ENTITY_ID_INVALID_BD: The spatial entity "
|
|
||||||
"id is "
|
|
||||||
"invalid. (Added by the XR_BD_spatial_sensing extension)";
|
|
||||||
case XR_ERROR_SPATIAL_SENSING_SERVICE_UNAVAILABLE_BD:
|
|
||||||
return "XR_ERROR_SPATIAL_SENSING_SERVICE_UNAVAILABLE_BD: The "
|
|
||||||
"spatial "
|
|
||||||
"sensing service is unavailable. (Added by the "
|
|
||||||
"XR_BD_spatial_sensing extension)";
|
|
||||||
case XR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_ENTITY_BD:
|
|
||||||
return "XR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_ENTITY_BD: The spatial "
|
|
||||||
"entity "
|
|
||||||
"does not support anchor. (Added by the "
|
|
||||||
"XR_BD_spatial_sensing "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SCENE_CAPTURE_FAILURE_BD:
|
|
||||||
return "XR_ERROR_SCENE_CAPTURE_FAILURE_BD: The scene capture is "
|
|
||||||
"failed, "
|
|
||||||
"for example exiting abnormally. (Added by the "
|
|
||||||
"XR_BD_spatial_scene extension)";
|
|
||||||
case XR_ERROR_SPACE_NOT_LOCATABLE_EXT:
|
|
||||||
return "XR_ERROR_SPACE_NOT_LOCATABLE_EXT: The space passed to the "
|
|
||||||
"function was not locatable. (Added by the "
|
|
||||||
"XR_EXT_plane_detection "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT:
|
|
||||||
return "XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT: The "
|
|
||||||
"permission "
|
|
||||||
"for this resource was not granted. (Added by the "
|
|
||||||
"XR_EXT_plane_detection extension)";
|
|
||||||
case XR_ERROR_FUTURE_PENDING_EXT:
|
|
||||||
return "XR_ERROR_FUTURE_PENDING_EXT: Returned by completion "
|
|
||||||
"function to "
|
|
||||||
"indicate future is not ready. (Added by the XR_EXT_future "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_FUTURE_INVALID_EXT:
|
|
||||||
return "XR_ERROR_FUTURE_INVALID_EXT: Returned by completion "
|
|
||||||
"function to "
|
|
||||||
"indicate future is not valid. (Added by the XR_EXT_future "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SYSTEM_NOTIFICATION_PERMISSION_DENIED_ML:
|
|
||||||
return "XR_ERROR_SYSTEM_NOTIFICATION_PERMISSION_DENIED_ML: The "
|
|
||||||
"com.magicleap.permission.SYSTEM_NOTIFICATION permission "
|
|
||||||
"was not "
|
|
||||||
"granted. (Added by the XR_ML_system_notifications "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SYSTEM_NOTIFICATION_INCOMPATIBLE_SKU_ML:
|
|
||||||
return "XR_ERROR_SYSTEM_NOTIFICATION_INCOMPATIBLE_SKU_ML: "
|
|
||||||
"Incompatible "
|
|
||||||
"SKU detected. (Added by the XR_ML_system_notifications "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_WORLD_MESH_DETECTOR_PERMISSION_DENIED_ML:
|
|
||||||
return "XR_ERROR_WORLD_MESH_DETECTOR_PERMISSION_DENIED_ML: The "
|
|
||||||
"world "
|
|
||||||
"mesh detector permission was not granted. (Added by the "
|
|
||||||
"XR_ML_world_mesh_detection extension)";
|
|
||||||
case XR_ERROR_WORLD_MESH_DETECTOR_SPACE_NOT_LOCATABLE_ML:
|
|
||||||
return "XR_ERROR_WORLD_MESH_DETECTOR_SPACE_NOT_LOCATABLE_ML: At "
|
|
||||||
"the time "
|
|
||||||
"of the call the runtime was unable to locate the space and "
|
|
||||||
"cannot fulfill your request. (Added by the "
|
|
||||||
"XR_ML_world_mesh_detection extension)";
|
|
||||||
case XR_ERROR_COLOCATION_DISCOVERY_NETWORK_FAILED_META:
|
|
||||||
return "XR_ERROR_COLOCATION_DISCOVERY_NETWORK_FAILED_META: The "
|
|
||||||
"network "
|
|
||||||
"request failed. (Added by the XR_META_colocation_discovery "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_COLOCATION_DISCOVERY_NO_DISCOVERY_METHOD_META:
|
|
||||||
return "XR_ERROR_COLOCATION_DISCOVERY_NO_DISCOVERY_METHOD_META: "
|
|
||||||
"The "
|
|
||||||
"runtime does not have any methods available to perform "
|
|
||||||
"discovery. (Added by the XR_META_colocation_discovery "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPACE_GROUP_NOT_FOUND_META:
|
|
||||||
return "XR_ERROR_SPACE_GROUP_NOT_FOUND_META: The group UUID was "
|
|
||||||
"not "
|
|
||||||
"found within the runtime (Added by the "
|
|
||||||
"XR_META_spatial_entity_group_sharing extension)";
|
|
||||||
case XR_ERROR_SPATIAL_CAPABILITY_UNSUPPORTED_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_CAPABILITY_UNSUPPORTED_EXT: The specified "
|
|
||||||
"spatial capability is not supported by the runtime or the "
|
|
||||||
"system. (Added by the XR_EXT_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT: The specified "
|
|
||||||
"spatial "
|
|
||||||
"entity id is invalid or an entity with that id does not "
|
|
||||||
"exist in "
|
|
||||||
"the environment. (Added by the XR_EXT_spatial_entity "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPATIAL_BUFFER_ID_INVALID_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_BUFFER_ID_INVALID_EXT: The specified "
|
|
||||||
"spatial "
|
|
||||||
"buffer id is invalid or does not exist in the spatial "
|
|
||||||
"snapshot "
|
|
||||||
"being used to query for the buffer data. (Added by the "
|
|
||||||
"XR_EXT_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPATIAL_COMPONENT_UNSUPPORTED_FOR_CAPABILITY_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_COMPONENT_UNSUPPORTED_FOR_CAPABILITY_EXT: "
|
|
||||||
"The "
|
|
||||||
"specified spatial component is not supported by the "
|
|
||||||
"runtime or "
|
|
||||||
"the system for the given capability. (Added by the "
|
|
||||||
"XR_EXT_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPATIAL_CAPABILITY_CONFIGURATION_INVALID_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_CAPABILITY_CONFIGURATION_INVALID_EXT: The "
|
|
||||||
"specified spatial capability configuration is invalid. "
|
|
||||||
"(Added by "
|
|
||||||
"the XR_EXT_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPATIAL_COMPONENT_NOT_ENABLED_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_COMPONENT_NOT_ENABLED_EXT: The specified "
|
|
||||||
"spatial component is not enabled for the spatial context. "
|
|
||||||
"(Added "
|
|
||||||
"by the XR_EXT_spatial_entity extension)";
|
|
||||||
case XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT: The "
|
|
||||||
"specified spatial persistence scope is not supported by "
|
|
||||||
"the "
|
|
||||||
"runtime or the system. (Added by the "
|
|
||||||
"XR_EXT_spatial_persistence "
|
|
||||||
"extension)";
|
|
||||||
case XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_INCOMPATIBLE_EXT:
|
|
||||||
return "XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_INCOMPATIBLE_EXT: THe "
|
|
||||||
"scope "
|
|
||||||
"configured for the persistence context is incompatible for "
|
|
||||||
"the "
|
|
||||||
"current spatial entity. (Added by the "
|
|
||||||
"XR_EXT_spatial_persistence_operations extension)";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class FmtCtx> auto format(XrResult r, FmtCtx &ctx) const
|
|
||||||
{
|
|
||||||
if (spec == 'd') {
|
|
||||||
return format_to(ctx.out(), "{}", static_cast<int32_t>(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view str = std::formatter<XrResult, char>::to_string(r);
|
|
||||||
if (!str.empty()) {
|
|
||||||
return format_to(ctx.out(), "{}", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
return format_to(ctx.out(), "<0x{:x}>", static_cast<uint32_t>(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char spec { 's' };
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace std
|
|
||||||
6
src/common.h
Normal file
6
src/common.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#define ARRAY_SZ(arr) (sizeof(arr) / sizeof(*arr))
|
||||||
|
|
||||||
|
#endif // COMMON_H
|
||||||
@@ -1,705 +0,0 @@
|
|||||||
#include "dhos_config.h"
|
|
||||||
|
|
||||||
// NOLINTBEGIN
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cctype>
|
|
||||||
#include <charconv>
|
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
|
||||||
#include <print>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace dhos {
|
|
||||||
|
|
||||||
// environment shared across parser and evaluation
|
|
||||||
struct Environment {
|
|
||||||
Environment(Environment *p = nullptr)
|
|
||||||
: parent { p }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
std::unordered_map<std::string, Value> tbl;
|
|
||||||
Environment *parent;
|
|
||||||
bool contains(std::string const &k) const
|
|
||||||
{
|
|
||||||
return tbl.contains(k) || (parent && parent->contains(k));
|
|
||||||
}
|
|
||||||
Value &operator[](std::string const &k)
|
|
||||||
{
|
|
||||||
if (tbl.contains(k))
|
|
||||||
return tbl.at(k);
|
|
||||||
if (parent)
|
|
||||||
return (*parent)[k];
|
|
||||||
throw std::runtime_error(std::format("Undefined variable: {}", k));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// env, lexer, parser
|
|
||||||
|
|
||||||
enum class Tok {
|
|
||||||
End,
|
|
||||||
Id,
|
|
||||||
Num,
|
|
||||||
Str,
|
|
||||||
Path,
|
|
||||||
LPar,
|
|
||||||
RPar,
|
|
||||||
LBr,
|
|
||||||
RBr,
|
|
||||||
LBrk,
|
|
||||||
RBrk,
|
|
||||||
Eq,
|
|
||||||
Dot,
|
|
||||||
Comma
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string Tok_str(Tok t)
|
|
||||||
{
|
|
||||||
if (t == Tok::End)
|
|
||||||
return "End";
|
|
||||||
else if (t == Tok::Id)
|
|
||||||
return "Id";
|
|
||||||
else if (t == Tok::Num)
|
|
||||||
return "Num";
|
|
||||||
else if (t == Tok::Str)
|
|
||||||
return "Str";
|
|
||||||
else if (t == Tok::Path)
|
|
||||||
return "Path";
|
|
||||||
else if (t == Tok::LPar)
|
|
||||||
return "LPar";
|
|
||||||
else if (t == Tok::RPar)
|
|
||||||
return "RPar";
|
|
||||||
else if (t == Tok::LBr)
|
|
||||||
return "LBr";
|
|
||||||
else if (t == Tok::RBr)
|
|
||||||
return "RBr";
|
|
||||||
else if (t == Tok::LBrk)
|
|
||||||
return "LBrk";
|
|
||||||
else if (t == Tok::RBrk)
|
|
||||||
return "RBrk";
|
|
||||||
else if (t == Tok::Eq)
|
|
||||||
return "Eq";
|
|
||||||
else if (t == Tok::Dot)
|
|
||||||
return "Dot";
|
|
||||||
else if (t == Tok::Comma)
|
|
||||||
return "Comma";
|
|
||||||
else
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
struct T {
|
|
||||||
Tok k;
|
|
||||||
std::string t;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Lex {
|
|
||||||
public:
|
|
||||||
explicit Lex(std::string_view s)
|
|
||||||
: src { s }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
T next();
|
|
||||||
|
|
||||||
private:
|
|
||||||
T id();
|
|
||||||
T num();
|
|
||||||
T str();
|
|
||||||
T path();
|
|
||||||
void skip();
|
|
||||||
std::string_view src;
|
|
||||||
std::size_t pos {};
|
|
||||||
};
|
|
||||||
|
|
||||||
T Lex::id()
|
|
||||||
{
|
|
||||||
std::size_t s = pos;
|
|
||||||
while (pos < src.size()
|
|
||||||
&& (std::isalnum((unsigned char)src[pos]) || src[pos] == '_'))
|
|
||||||
++pos;
|
|
||||||
return { Tok::Id, std::string { src.substr(s, pos - s) } };
|
|
||||||
}
|
|
||||||
T Lex::num()
|
|
||||||
{
|
|
||||||
std::size_t s = pos;
|
|
||||||
while (pos < src.size()
|
|
||||||
&& (std::isdigit((unsigned char)src[pos]) || src[pos] == '_'))
|
|
||||||
++pos;
|
|
||||||
if (pos < src.size() && src[pos] == '.') {
|
|
||||||
++pos;
|
|
||||||
while (pos < src.size()
|
|
||||||
&& (std::isdigit((unsigned char)src[pos]) || src[pos] == '_'))
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
return { Tok::Num, std::string { src.substr(s, pos - s) } };
|
|
||||||
}
|
|
||||||
T Lex::str()
|
|
||||||
{
|
|
||||||
char q = src[pos++];
|
|
||||||
std::string o;
|
|
||||||
while (pos < src.size() && src[pos] != q)
|
|
||||||
o.push_back(src[pos++]);
|
|
||||||
if (pos >= src.size())
|
|
||||||
throw std::runtime_error("Unterminated string literal");
|
|
||||||
++pos;
|
|
||||||
return { Tok::Str, o };
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_path_ch(char c)
|
|
||||||
{
|
|
||||||
return std::isalnum((unsigned char)c) || c == '_' || c == '.' || c == '/'
|
|
||||||
|| c == '-' || c == ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
T Lex::path()
|
|
||||||
{
|
|
||||||
std::string out;
|
|
||||||
while (pos < src.size()) {
|
|
||||||
char c = src[pos];
|
|
||||||
if (c == '\\') {
|
|
||||||
++pos;
|
|
||||||
if (pos < src.size()) {
|
|
||||||
out.push_back(src[pos]);
|
|
||||||
++pos;
|
|
||||||
} else {
|
|
||||||
out.push_back('\\');
|
|
||||||
}
|
|
||||||
} else if (is_path_ch(c)) {
|
|
||||||
out.push_back(c);
|
|
||||||
++pos;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { Tok::Path, out };
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lex::skip()
|
|
||||||
{
|
|
||||||
while (pos < src.size()) {
|
|
||||||
if (std::isspace((unsigned char)src[pos])) {
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (src[pos] == '#') {
|
|
||||||
while (pos < src.size() && src[pos] != '\n')
|
|
||||||
++pos;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T Lex::next()
|
|
||||||
{
|
|
||||||
skip();
|
|
||||||
if (pos >= src.size())
|
|
||||||
return { Tok::End, "" };
|
|
||||||
char c = src[pos];
|
|
||||||
|
|
||||||
if (c == '/' // "/foo"
|
|
||||||
|| (c == '.' && pos + 1 < src.size() && src[pos + 1] == '/') // "./foo"
|
|
||||||
|| (c == '.' && pos + 2 < src.size() && src[pos + 1] == '.'
|
|
||||||
&& src[pos + 2] == '/') // "../foo"
|
|
||||||
|| (std::isalpha((unsigned char)c) && pos + 1 < src.size()
|
|
||||||
&& src[pos + 1] == ':')) // "C:/foo"
|
|
||||||
return path();
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case '(':
|
|
||||||
++pos;
|
|
||||||
return { Tok::LPar, "(" };
|
|
||||||
case ')':
|
|
||||||
++pos;
|
|
||||||
return { Tok::RPar, ")" };
|
|
||||||
case '{':
|
|
||||||
++pos;
|
|
||||||
return { Tok::LBr, "{" };
|
|
||||||
case '}':
|
|
||||||
++pos;
|
|
||||||
return { Tok::RBr, "}" };
|
|
||||||
case '[':
|
|
||||||
++pos;
|
|
||||||
return { Tok::LBrk, "[" };
|
|
||||||
case ']':
|
|
||||||
++pos;
|
|
||||||
return { Tok::RBrk, "]" };
|
|
||||||
case '=':
|
|
||||||
++pos;
|
|
||||||
return { Tok::Eq, "=" };
|
|
||||||
case '.':
|
|
||||||
++pos;
|
|
||||||
return { Tok::Dot, "." };
|
|
||||||
case ',':
|
|
||||||
++pos;
|
|
||||||
return { Tok::Comma, "," };
|
|
||||||
case '"':
|
|
||||||
case '\'':
|
|
||||||
return str();
|
|
||||||
case 0:
|
|
||||||
return { Tok::End, "" };
|
|
||||||
default:
|
|
||||||
if (std::isdigit((unsigned char)c))
|
|
||||||
return num();
|
|
||||||
if (std::isalpha((unsigned char)c) || c == '_')
|
|
||||||
return id();
|
|
||||||
std::println("Invalid character: {} ({:d})", c, c);
|
|
||||||
throw std::runtime_error(std::format("Invalid character: {}", c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parser
|
|
||||||
class Parser {
|
|
||||||
public:
|
|
||||||
Parser(std::string_view s, std::shared_ptr<Environment> e)
|
|
||||||
: lx { s }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
adv();
|
|
||||||
}
|
|
||||||
Value parse() { return val(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Lex lx;
|
|
||||||
T cur;
|
|
||||||
std::shared_ptr<Environment> env;
|
|
||||||
void adv() { cur = lx.next(); }
|
|
||||||
bool acc(Tok k)
|
|
||||||
{
|
|
||||||
if (cur.k == k) {
|
|
||||||
adv();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void exp(Tok k)
|
|
||||||
{
|
|
||||||
if (!acc(k)) {
|
|
||||||
std::println("Expected: {}, Got: {}", Tok_str(k), Tok_str(cur.k));
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::format("Syntax error: expected {}, got {}", Tok_str(k),
|
|
||||||
Tok_str(cur.k)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool begins(Tok k)
|
|
||||||
{
|
|
||||||
return k == Tok::Path || k == Tok::Id || k == Tok::Num || k == Tok::Str
|
|
||||||
|| k == Tok::LBr || k == Tok::LBrk || k == Tok::LPar;
|
|
||||||
}
|
|
||||||
std::string id()
|
|
||||||
{
|
|
||||||
std::string s = cur.t;
|
|
||||||
exp(Tok::Id);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value array()
|
|
||||||
{
|
|
||||||
exp(Tok::LBrk);
|
|
||||||
Array a;
|
|
||||||
while (cur.k != Tok::RBrk) {
|
|
||||||
a.push_back(val());
|
|
||||||
acc(Tok::Comma);
|
|
||||||
}
|
|
||||||
exp(Tok::RBrk);
|
|
||||||
return Value { std::move(a), env };
|
|
||||||
}
|
|
||||||
Value block()
|
|
||||||
{
|
|
||||||
exp(Tok::LBr);
|
|
||||||
Object o;
|
|
||||||
while (cur.k != Tok::RBr) {
|
|
||||||
if (acc(Tok::LPar)) {
|
|
||||||
Value inner = val();
|
|
||||||
exp(Tok::RPar);
|
|
||||||
o.insert(inner.obj().begin(), inner.obj().end());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::string k = id();
|
|
||||||
exp(Tok::Eq);
|
|
||||||
o[k] = val();
|
|
||||||
}
|
|
||||||
exp(Tok::RBr);
|
|
||||||
return Value { std::move(o), env };
|
|
||||||
}
|
|
||||||
Value func()
|
|
||||||
{
|
|
||||||
exp(Tok::Id);
|
|
||||||
std::vector<std::string> params;
|
|
||||||
while (cur.k == Tok::Id)
|
|
||||||
params.push_back(id());
|
|
||||||
exp(Tok::Eq);
|
|
||||||
Value body = val();
|
|
||||||
auto f = std::make_shared<Value::Function>();
|
|
||||||
f->params = params;
|
|
||||||
f->body = std::make_shared<Value>(body);
|
|
||||||
return Value { std::move(f), env };
|
|
||||||
}
|
|
||||||
Value call()
|
|
||||||
{
|
|
||||||
std::string name = id();
|
|
||||||
std::vector<Value> args;
|
|
||||||
while (begins(cur.k))
|
|
||||||
args.emplace_back(val());
|
|
||||||
auto c = std::make_shared<Value::Call>();
|
|
||||||
c->name = name;
|
|
||||||
c->args = std::move(args);
|
|
||||||
return Value { std::move(c), env };
|
|
||||||
}
|
|
||||||
Value val()
|
|
||||||
{
|
|
||||||
switch (cur.k) {
|
|
||||||
case Tok::Id:
|
|
||||||
if (cur.t == "fn") {
|
|
||||||
return func();
|
|
||||||
}
|
|
||||||
if (cur.t == "nil") {
|
|
||||||
adv();
|
|
||||||
return Value { env };
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::string idn = cur.t;
|
|
||||||
adv();
|
|
||||||
|
|
||||||
// make the base AST node
|
|
||||||
auto node = std::make_shared<Value::Call>();
|
|
||||||
node->recv = nullptr; // top‐level call
|
|
||||||
node->name = std::move(idn);
|
|
||||||
|
|
||||||
// consume any “.field” chains
|
|
||||||
while (acc(Tok::Dot)) {
|
|
||||||
auto parent = node;
|
|
||||||
std::string fld = id();
|
|
||||||
auto mnode = std::make_shared<Value::Call>();
|
|
||||||
mnode->recv = std::make_shared<Value>(
|
|
||||||
parent, env); // wrap the old AST
|
|
||||||
mnode->name = std::move(fld);
|
|
||||||
node = mnode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// then any args
|
|
||||||
while (begins(cur.k)) {
|
|
||||||
node->args.push_back(val());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Value { node, env };
|
|
||||||
}
|
|
||||||
case Tok::Num: {
|
|
||||||
std::string s = cur.t;
|
|
||||||
s.erase(std::remove(s.begin(), s.end(), '_'), s.end());
|
|
||||||
double n;
|
|
||||||
if (static_cast<int>(
|
|
||||||
std::from_chars(s.data(), s.data() + s.size(), n).ec))
|
|
||||||
throw;
|
|
||||||
adv();
|
|
||||||
return Value { n, env };
|
|
||||||
}
|
|
||||||
case Tok::Str: {
|
|
||||||
Value v { cur.t, env };
|
|
||||||
adv();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
case Tok::Path: {
|
|
||||||
Value v { std::filesystem::path { cur.t }, env };
|
|
||||||
adv();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
case Tok::LBrk:
|
|
||||||
return array();
|
|
||||||
case Tok::LBr:
|
|
||||||
return block();
|
|
||||||
case Tok::LPar:
|
|
||||||
adv();
|
|
||||||
{
|
|
||||||
Value v = val();
|
|
||||||
exp(Tok::RPar);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::format("Unexpected token: {}", Tok_str(cur.k)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// built-ins
|
|
||||||
Value join(Array const &a)
|
|
||||||
{
|
|
||||||
Array r;
|
|
||||||
for (auto &v : a) {
|
|
||||||
if (!v.is_arr())
|
|
||||||
throw;
|
|
||||||
r.insert(r.end(), v.arr().begin(), v.arr().end());
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
Value list_rng(Array const &a)
|
|
||||||
{
|
|
||||||
if (a.size() != 3 || !a[0].is_num() || !a[1].is_num() || !a[2].is_num())
|
|
||||||
throw;
|
|
||||||
double s = a[0].num(), e = a[1].num(), st = a[2].num();
|
|
||||||
if (!st)
|
|
||||||
throw;
|
|
||||||
Array r;
|
|
||||||
if (st > 0)
|
|
||||||
for (double x = s; x <= e; x += st)
|
|
||||||
r.emplace_back(x);
|
|
||||||
else
|
|
||||||
for (double x = s; x >= e; x += st)
|
|
||||||
r.emplace_back(x);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
Value imp(Array const &a)
|
|
||||||
{
|
|
||||||
if (a.empty())
|
|
||||||
throw;
|
|
||||||
std::ifstream f;
|
|
||||||
if (a[0].is_str()) {
|
|
||||||
f = std::ifstream { a[0].str() };
|
|
||||||
} else if (a[0].is_path()) {
|
|
||||||
f = std::ifstream { a[0].path() };
|
|
||||||
} else {
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
if (!f)
|
|
||||||
throw;
|
|
||||||
std::stringstream b;
|
|
||||||
b << f.rdbuf();
|
|
||||||
std::istringstream in { b.str() };
|
|
||||||
return parse_config(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
// serializer
|
|
||||||
void w(std::ostream &o, Value const &v)
|
|
||||||
{
|
|
||||||
if (v.is_nil()) {
|
|
||||||
o << "nil";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_num()) {
|
|
||||||
o << v.num();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_str()) {
|
|
||||||
o << '"' << v.str() << '"';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_path()) {
|
|
||||||
o << v.path().generic_string();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_arr()) {
|
|
||||||
o << "[";
|
|
||||||
bool f = true;
|
|
||||||
for (auto &x : v.arr()) {
|
|
||||||
if (!f)
|
|
||||||
o << ",";
|
|
||||||
w(o, x);
|
|
||||||
f = false;
|
|
||||||
}
|
|
||||||
o << "]";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_obj()) {
|
|
||||||
o << "{";
|
|
||||||
bool f = true;
|
|
||||||
for (auto &[k, x] : v.obj()) {
|
|
||||||
if (!f)
|
|
||||||
o << ",";
|
|
||||||
o << k << "=";
|
|
||||||
w(o, x);
|
|
||||||
f = false;
|
|
||||||
}
|
|
||||||
o << "}";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
o << "fn"; // prints literal token for functions
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// public helpers
|
|
||||||
Value eval(Value const &v, Object const *extra_lib)
|
|
||||||
{
|
|
||||||
static Object base = make_default_lib();
|
|
||||||
Object merged = merge_lib(base, extra_lib);
|
|
||||||
|
|
||||||
if (v.is_call()) {
|
|
||||||
auto const &c = v.call();
|
|
||||||
Value fn;
|
|
||||||
|
|
||||||
// receiver or global
|
|
||||||
if (c.recv && !c.recv->is_nil()) {
|
|
||||||
Value recv = eval(*c.recv, extra_lib);
|
|
||||||
fn = recv[c.name];
|
|
||||||
} else {
|
|
||||||
if (auto it = merged.find(c.name); it != merged.end())
|
|
||||||
fn = it->second;
|
|
||||||
else
|
|
||||||
fn = (*v.env)[c.name];
|
|
||||||
}
|
|
||||||
|
|
||||||
// args
|
|
||||||
Array argv;
|
|
||||||
argv.reserve(c.args.size());
|
|
||||||
for (auto &a : c.args)
|
|
||||||
argv.push_back(eval(a, extra_lib));
|
|
||||||
|
|
||||||
// call
|
|
||||||
if (auto b = std::get_if<Builtin>(&fn.data))
|
|
||||||
return (*b)(argv);
|
|
||||||
|
|
||||||
if (auto fp = std::get_if<std::shared_ptr<Value::Function>>(&fn.data)) {
|
|
||||||
auto child = std::make_shared<Environment>(fn.env.get());
|
|
||||||
for (size_t i = 0; i < (*fp)->params.size(); ++i)
|
|
||||||
child->tbl[(*fp)->params[i]]
|
|
||||||
= i < argv.size() ? argv[i] : Value(child);
|
|
||||||
|
|
||||||
Value body = *(*fp)->body;
|
|
||||||
body.env = child;
|
|
||||||
return eval(body, extra_lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not a call
|
|
||||||
if (!v.is_fn())
|
|
||||||
return v;
|
|
||||||
|
|
||||||
if (auto fp = std::get_if<std::shared_ptr<Value::Function>>(&v.data))
|
|
||||||
return *(*fp)->body;
|
|
||||||
|
|
||||||
return v; // builtin with no args
|
|
||||||
}
|
|
||||||
|
|
||||||
// auto-evaluating operator[] impl
|
|
||||||
static void materialise(Value &v)
|
|
||||||
{
|
|
||||||
auto r = eval(v, nullptr);
|
|
||||||
if (!r.is_fn() && !r.is_call())
|
|
||||||
v = std::move(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value &Value::operator[](std::string const &k)
|
|
||||||
{
|
|
||||||
materialise(*this);
|
|
||||||
if (is_nil())
|
|
||||||
return *this;
|
|
||||||
if (!is_obj())
|
|
||||||
throw std::logic_error("[] on non-object");
|
|
||||||
|
|
||||||
Value &child = obj()[k];
|
|
||||||
materialise(child);
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value &Value::operator[](std::size_t i)
|
|
||||||
{
|
|
||||||
materialise(*this);
|
|
||||||
if (is_nil())
|
|
||||||
return *this;
|
|
||||||
if (!is_arr())
|
|
||||||
throw std::logic_error("[] on non-array");
|
|
||||||
if (i >= arr().size())
|
|
||||||
throw std::out_of_range("index");
|
|
||||||
|
|
||||||
Value &child = arr()[i];
|
|
||||||
materialise(child);
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value const &Value::operator[](std::string const &k) const
|
|
||||||
{
|
|
||||||
return const_cast<Value *>(this)->operator[](k);
|
|
||||||
}
|
|
||||||
Value const &Value::operator[](std::size_t i) const
|
|
||||||
{
|
|
||||||
return const_cast<Value *>(this)->operator[](i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse/write
|
|
||||||
Value parse_config(std::istream &in)
|
|
||||||
{
|
|
||||||
std::stringstream b;
|
|
||||||
b << in.rdbuf();
|
|
||||||
std::string src = b.str();
|
|
||||||
auto env = std::make_shared<Environment>();
|
|
||||||
env->tbl = make_default_lib();
|
|
||||||
Parser p { src, env };
|
|
||||||
return p.parse();
|
|
||||||
}
|
|
||||||
inline void resolve_paths(Value &v, std::filesystem::path const &base)
|
|
||||||
{
|
|
||||||
if (v.is_path()) {
|
|
||||||
auto &p = v.path();
|
|
||||||
if (p.is_relative())
|
|
||||||
p = base / p;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_arr()) {
|
|
||||||
for (auto &x : v.arr())
|
|
||||||
resolve_paths(x, base);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_obj()) {
|
|
||||||
for (auto &[_, x] : v.obj())
|
|
||||||
resolve_paths(x, base);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (v.is_call()) {
|
|
||||||
for (auto &x : v.call().args)
|
|
||||||
resolve_paths(x, base);
|
|
||||||
}
|
|
||||||
if (std::holds_alternative<std::shared_ptr<Value::Function>>(v.data)) {
|
|
||||||
resolve_paths(
|
|
||||||
*std::get<std::shared_ptr<Value::Function>>(v.data)->body, base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value parse_config(std::filesystem::path const &f)
|
|
||||||
{
|
|
||||||
std::ifstream in { f };
|
|
||||||
if (!in)
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::format("Failed to open configuration file: {}", f.string()));
|
|
||||||
Value v = parse_config(in);
|
|
||||||
resolve_paths(v, f.parent_path());
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
void write_config(Value const &v, std::filesystem::path const &o)
|
|
||||||
{
|
|
||||||
std::ofstream f { o };
|
|
||||||
if (!f)
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::format("Failed to write configuration file: {}", o.string()));
|
|
||||||
w(f, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// default lib
|
|
||||||
Object make_default_lib();
|
|
||||||
Object merge_lib(Object const &base, Object const *extra)
|
|
||||||
{
|
|
||||||
Object out = base;
|
|
||||||
if (extra)
|
|
||||||
out.insert(extra->begin(), extra->end());
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_env_tbl(Environment *env) -> std::unordered_map<std::string, Value> &
|
|
||||||
{
|
|
||||||
return env->tbl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object make_default_lib()
|
|
||||||
{
|
|
||||||
Object l;
|
|
||||||
l["join"] = Builtin { join };
|
|
||||||
l["list_from_range"] = Builtin { list_rng };
|
|
||||||
l["import"] = Builtin { imp };
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dhos
|
|
||||||
|
|
||||||
// NOLINTEND
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// NOLINTBEGIN
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <functional>
|
|
||||||
#include <istream>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace dhos {
|
|
||||||
|
|
||||||
struct Environment;
|
|
||||||
struct Value;
|
|
||||||
|
|
||||||
using Array = std::vector<Value>;
|
|
||||||
using Object = std::unordered_map<std::string, Value>;
|
|
||||||
using Builtin = std::function<Value(Array const &)>;
|
|
||||||
|
|
||||||
struct Value {
|
|
||||||
using EnvPtr = std::shared_ptr<Environment>;
|
|
||||||
|
|
||||||
struct Function {
|
|
||||||
std::vector<std::string> params;
|
|
||||||
std::shared_ptr<Value> body;
|
|
||||||
};
|
|
||||||
struct Call {
|
|
||||||
std::string name;
|
|
||||||
Array args;
|
|
||||||
std::shared_ptr<Value> recv;
|
|
||||||
};
|
|
||||||
using Data = std::variant<std::monostate, double, std::string,
|
|
||||||
std::filesystem::path, Array, Object, std::shared_ptr<Function>,
|
|
||||||
Builtin, std::shared_ptr<Call>>;
|
|
||||||
Data data {};
|
|
||||||
EnvPtr env {};
|
|
||||||
|
|
||||||
Value() = default;
|
|
||||||
explicit Value(EnvPtr e)
|
|
||||||
: env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(double n, EnvPtr e = {})
|
|
||||||
: data { n }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(std::string const &s, EnvPtr e = {})
|
|
||||||
: data { s }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(char const *s, EnvPtr e = {})
|
|
||||||
: data { std::string { s } }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(std::filesystem::path const &p, EnvPtr e = {})
|
|
||||||
: data { p }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(Array a, EnvPtr e = {})
|
|
||||||
: data { std::move(a) }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(Object o, EnvPtr e = {})
|
|
||||||
: data { std::move(o) }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(std::shared_ptr<Function> f, EnvPtr e = {})
|
|
||||||
: data { std::move(f) }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(Builtin b, EnvPtr e = {})
|
|
||||||
: data { std::move(b) }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Value(std::shared_ptr<Call> c, EnvPtr e = {})
|
|
||||||
: data { std::move(c) }
|
|
||||||
, env { std::move(e) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_nil() const { return std::holds_alternative<std::monostate>(data); }
|
|
||||||
bool is_num() const { return std::holds_alternative<double>(data); }
|
|
||||||
bool is_str() const { return std::holds_alternative<std::string>(data); }
|
|
||||||
bool is_path() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<std::filesystem::path>(data);
|
|
||||||
}
|
|
||||||
bool is_arr() const { return std::holds_alternative<Array>(data); }
|
|
||||||
bool is_obj() const { return std::holds_alternative<Object>(data); }
|
|
||||||
bool is_fn() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<std::shared_ptr<Function>>(data)
|
|
||||||
|| std::holds_alternative<Builtin>(data);
|
|
||||||
}
|
|
||||||
bool is_call() const
|
|
||||||
{
|
|
||||||
return std::holds_alternative<std::shared_ptr<Call>>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
double num() const { return std::get<double>(data); }
|
|
||||||
std::string const &str() const { return std::get<std::string>(data); }
|
|
||||||
Array &arr() { return std::get<Array>(data); }
|
|
||||||
Array const &arr() const { return std::get<Array>(data); }
|
|
||||||
Object &obj() { return std::get<Object>(data); }
|
|
||||||
Object const &obj() const { return std::get<Object>(data); }
|
|
||||||
std::filesystem::path &path()
|
|
||||||
{
|
|
||||||
return std::get<std::filesystem::path>(data);
|
|
||||||
}
|
|
||||||
std::filesystem::path const &path() const
|
|
||||||
{
|
|
||||||
return std::get<std::filesystem::path>(data);
|
|
||||||
}
|
|
||||||
Call &call() { return *std::get<std::shared_ptr<Call>>(data); }
|
|
||||||
Call const &call() const { return *std::get<std::shared_ptr<Call>>(data); }
|
|
||||||
|
|
||||||
// auto-evaluating nlohmann-style access
|
|
||||||
Value &operator[](std::string const &k);
|
|
||||||
Value &operator[](std::size_t i);
|
|
||||||
Value const &operator[](std::string const &k) const;
|
|
||||||
Value const &operator[](std::size_t i) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
// pure evaluation helper (never mutates its argument)
|
|
||||||
Value eval(Value const &v, Object const *extra_lib = nullptr);
|
|
||||||
|
|
||||||
Value parse_config(std::istream &in);
|
|
||||||
Value parse_config(std::filesystem::path const &f);
|
|
||||||
void write_config(Value const &v, std::filesystem::path const &out);
|
|
||||||
|
|
||||||
Object make_default_lib();
|
|
||||||
Object merge_lib(Object const &base, Object const *extra);
|
|
||||||
|
|
||||||
auto get_env_tbl(Environment *env) -> std::unordered_map<std::string, Value> &;
|
|
||||||
|
|
||||||
} // namespace dhos
|
|
||||||
|
|
||||||
// NOLINTEND
|
|
||||||
16
src/main.c
Normal file
16
src/main.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "LunarWM.h"
|
||||||
|
|
||||||
|
LunarWM g_wm = {};
|
||||||
|
|
||||||
|
void sigint_handler(int) { LunarWM_terminate(&g_wm); }
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
assert(LunarWM_init(&g_wm));
|
||||||
|
signal(SIGINT, sigint_handler);
|
||||||
|
LunarWM_run(&g_wm);
|
||||||
|
LunarWM_destroy(&g_wm);
|
||||||
|
}
|
||||||
30
src/main.cpp
30
src/main.cpp
@@ -1,30 +0,0 @@
|
|||||||
// NOLINTBEGIN
|
|
||||||
#include <cassert>
|
|
||||||
#include <csignal>
|
|
||||||
|
|
||||||
#include <cpptrace/cpptrace.hpp>
|
|
||||||
#include <cpptrace/from_current.hpp>
|
|
||||||
// NOLINTEND
|
|
||||||
|
|
||||||
import std;
|
|
||||||
|
|
||||||
import LunarWM.LunarWM;
|
|
||||||
|
|
||||||
static std::unique_ptr<LunarWM::LunarWM> g_comp;
|
|
||||||
|
|
||||||
auto main() noexcept -> int // NOLINT(bugprone-exception-escape)
|
|
||||||
{
|
|
||||||
CPPTRACE_TRY
|
|
||||||
{
|
|
||||||
g_comp = std::make_unique<LunarWM::LunarWM>();
|
|
||||||
g_comp->init();
|
|
||||||
assert(
|
|
||||||
std::signal(SIGINT, [](int) { g_comp->terminate(); }) != SIG_ERR);
|
|
||||||
g_comp->run();
|
|
||||||
}
|
|
||||||
CPPTRACE_CATCH(std::exception const &e)
|
|
||||||
{
|
|
||||||
std::println(std::cerr, "Uncaught exception: {}", e.what());
|
|
||||||
cpptrace::from_current_exception().print();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
148
src/vec.c
Normal file
148
src/vec.c
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2024, Mashpoe
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vec.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
vec_size_t size;
|
||||||
|
vec_size_t capacity;
|
||||||
|
unsigned char data[];
|
||||||
|
} vector_header;
|
||||||
|
|
||||||
|
vector_header* vector_get_header(vector vec) { return &((vector_header*)vec)[-1]; }
|
||||||
|
|
||||||
|
vector vector_create(void)
|
||||||
|
{
|
||||||
|
vector_header* h = (vector_header*)malloc(sizeof(vector_header));
|
||||||
|
h->capacity = 0;
|
||||||
|
h->size = 0;
|
||||||
|
|
||||||
|
return &h->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vector_free(vector vec) { free(vector_get_header(vec)); }
|
||||||
|
|
||||||
|
vec_size_t vector_size(vector vec) { return vector_get_header(vec)->size; }
|
||||||
|
|
||||||
|
vec_size_t vector_capacity(vector vec) { return vector_get_header(vec)->capacity; }
|
||||||
|
|
||||||
|
vector_header* vector_realloc(vector_header* h, vec_type_t type_size)
|
||||||
|
{
|
||||||
|
vec_size_t new_capacity = (h->capacity == 0) ? 1 : h->capacity * 2;
|
||||||
|
vector_header* new_h = (vector_header*)realloc(h, sizeof(vector_header) + new_capacity * type_size);
|
||||||
|
new_h->capacity = new_capacity;
|
||||||
|
|
||||||
|
return new_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vector_has_space(vector_header* h)
|
||||||
|
{
|
||||||
|
return h->capacity - h->size > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* _vector_add_dst(vector* vec_addr, vec_type_t type_size)
|
||||||
|
{
|
||||||
|
vector_header* h = vector_get_header(*vec_addr);
|
||||||
|
|
||||||
|
if (!vector_has_space(h))
|
||||||
|
{
|
||||||
|
h = vector_realloc(h, type_size);
|
||||||
|
*vec_addr = h->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &h->data[type_size * h->size++];
|
||||||
|
}
|
||||||
|
|
||||||
|
void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos)
|
||||||
|
{
|
||||||
|
vector_header* h = vector_get_header(*vec_addr);
|
||||||
|
|
||||||
|
vec_size_t new_length = h->size + 1;
|
||||||
|
|
||||||
|
// make sure there is enough room for the new element
|
||||||
|
if (!vector_has_space(h))
|
||||||
|
{
|
||||||
|
h = vector_realloc(h, type_size);
|
||||||
|
*vec_addr = h->data;
|
||||||
|
}
|
||||||
|
// move trailing elements
|
||||||
|
memmove(&h->data[(pos + 1) * type_size],
|
||||||
|
&h->data[pos * type_size],
|
||||||
|
(h->size - pos) * type_size);
|
||||||
|
|
||||||
|
h->size = new_length;
|
||||||
|
|
||||||
|
return &h->data[pos * type_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vector_erase(vector vec, vec_type_t type_size, vec_size_t pos, vec_size_t len)
|
||||||
|
{
|
||||||
|
vector_header* h = vector_get_header(vec);
|
||||||
|
memmove(&h->data[pos * type_size],
|
||||||
|
&h->data[(pos + len) * type_size],
|
||||||
|
(h->size - pos - len) * type_size);
|
||||||
|
|
||||||
|
h->size -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vector_remove(vector vec, vec_type_t type_size, vec_size_t pos)
|
||||||
|
{
|
||||||
|
_vector_erase(vec, type_size, pos, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vector_pop(vector vec) { --vector_get_header(vec)->size; }
|
||||||
|
|
||||||
|
void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity)
|
||||||
|
{
|
||||||
|
vector_header* h = vector_get_header(*vec_addr);
|
||||||
|
if (h->capacity >= capacity)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = (vector_header*)realloc(h, sizeof(vector_header) + capacity * type_size);
|
||||||
|
h->capacity = capacity;
|
||||||
|
*vec_addr = &h->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector _vector_copy(vector vec, vec_type_t type_size)
|
||||||
|
{
|
||||||
|
vector_header* h = vector_get_header(vec);
|
||||||
|
size_t alloc_size = sizeof(vector_header) + h->size * type_size;
|
||||||
|
vector_header* copy_h = (vector_header*)malloc(alloc_size);
|
||||||
|
memcpy(copy_h, h, alloc_size);
|
||||||
|
copy_h->capacity = copy_h->size;
|
||||||
|
|
||||||
|
return ©_h->data;
|
||||||
|
}
|
||||||
127
src/vec.h
Normal file
127
src/vec.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2024, Mashpoe
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef vec_h
|
||||||
|
#define vec_h
|
||||||
|
|
||||||
|
#ifdef __cpp_decltype
|
||||||
|
#include <type_traits>
|
||||||
|
#define typeof(T) std::remove_reference<std::add_lvalue_reference<decltype(T)>::type>::type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// generic type for internal use
|
||||||
|
typedef void* vector;
|
||||||
|
// number of elements in a vector
|
||||||
|
typedef size_t vec_size_t;
|
||||||
|
// number of bytes for a type
|
||||||
|
typedef size_t vec_type_t;
|
||||||
|
|
||||||
|
// TODO: more rigorous check for typeof support with different compilers
|
||||||
|
#if _MSC_VER == 0 || __STDC_VERSION__ >= 202311L || defined __cpp_decltype
|
||||||
|
|
||||||
|
// shortcut defines
|
||||||
|
|
||||||
|
// vec_addr is a vector* (aka type**)
|
||||||
|
#define vector_add_dst(vec_addr)\
|
||||||
|
((typeof(*vec_addr))(\
|
||||||
|
_vector_add_dst((vector*)vec_addr, sizeof(**vec_addr))\
|
||||||
|
))
|
||||||
|
#define vector_insert_dst(vec_addr, pos)\
|
||||||
|
((typeof(*vec_addr))(\
|
||||||
|
_vector_insert_dst((vector*)vec_addr, sizeof(**vec_addr), pos)))
|
||||||
|
|
||||||
|
#define vector_add(vec_addr, value)\
|
||||||
|
(*vector_add_dst(vec_addr) = value)
|
||||||
|
#define vector_insert(vec_addr, pos, value)\
|
||||||
|
(*vector_insert_dst(vec_addr, pos) = value)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define vector_add_dst(vec_addr, type)\
|
||||||
|
((type*)_vector_add_dst((vector*)vec_addr, sizeof(type)))
|
||||||
|
#define vector_insert_dst(vec_addr, type, pos)\
|
||||||
|
((type*)_vector_insert_dst((vector*)vec_addr, sizeof(type), pos))
|
||||||
|
|
||||||
|
#define vector_add(vec_addr, type, value)\
|
||||||
|
(*vector_add_dst(vec_addr, type) = value)
|
||||||
|
#define vector_insert(vec_addr, type, pos, value)\
|
||||||
|
(*vector_insert_dst(vec_addr, type, pos) = value)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vec is a vector (aka type*)
|
||||||
|
#define vector_erase(vec, pos, len)\
|
||||||
|
(_vector_erase((vector)vec, sizeof(*vec), pos, len))
|
||||||
|
#define vector_remove(vec, pos)\
|
||||||
|
(_vector_remove((vector)vec, sizeof(*vec), pos))
|
||||||
|
|
||||||
|
#define vector_reserve(vec_addr, capacity)\
|
||||||
|
(_vector_reserve((vector*)vec_addr, sizeof(**vec_addr), capacity))
|
||||||
|
|
||||||
|
#define vector_copy(vec)\
|
||||||
|
(_vector_copy((vector)vec, sizeof(*vec)))
|
||||||
|
|
||||||
|
vector vector_create(void);
|
||||||
|
|
||||||
|
void vector_free(vector vec);
|
||||||
|
|
||||||
|
void* _vector_add_dst(vector* vec_addr, vec_type_t type_size);
|
||||||
|
|
||||||
|
void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos);
|
||||||
|
|
||||||
|
void _vector_erase(vector vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t len);
|
||||||
|
|
||||||
|
void _vector_remove(vector vec_addr, vec_type_t type_size, vec_size_t pos);
|
||||||
|
|
||||||
|
void vector_pop(vector vec);
|
||||||
|
|
||||||
|
void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity);
|
||||||
|
|
||||||
|
vector _vector_copy(vector vec, vec_type_t type_size);
|
||||||
|
|
||||||
|
vec_size_t vector_size(vector vec);
|
||||||
|
|
||||||
|
vec_size_t vector_capacity(vector vec);
|
||||||
|
|
||||||
|
// closing bracket for extern "C"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* vec_h */
|
||||||
Reference in New Issue
Block a user