C++, BYE BYE!! BYE BYE!!!

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-08-10 06:38:23 +03:00
parent d154db1422
commit 4e23877697
14 changed files with 2049 additions and 3901 deletions

File diff suppressed because one or more lines are too long

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

173
src/LunarWM.h Normal file
View 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

View File

@@ -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

View File

@@ -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 "
"actions state does not match the actions 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 files 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 "
"components 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
View File

@@ -0,0 +1,6 @@
#ifndef COMMON_H
#define COMMON_H
#define ARRAY_SZ(arr) (sizeof(arr) / sizeof(*arr))
#endif // COMMON_H

View File

@@ -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; // toplevel 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

View File

@@ -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
View 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);
}

View File

@@ -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
View 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 &copy_h->data;
}

127
src/vec.h Normal file
View 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 */