Commit 5609a84d authored by Hanspeter Portner's avatar Hanspeter Portner

migrate so sandbox_ui.

parent 8da79f8b
language: c
os: linux
sudo: required
dist: trusty
language:
- c
os:
- linux
compiler:
- gcc
- clang
# - clang
before_install:
- wget http://lv2plug.in/spec/lv2-1.12.0.tar.bz2
- tar xjf lv2-1.12.0.tar.bz2
- wget http://download.drobilla.net/serd-0.22.0.tar.bz2
- wget http://download.drobilla.net/sord-0.14.0.tar.bz2
- wget http://download.drobilla.net/sratom-0.4.6.tar.bz2
- wget http://download.drobilla.net/lilv-0.22.0.tar.bz2
- wget https://github.com/nanomsg/nanomsg/releases/download/0.8-beta/nanomsg-0.8-beta.tar.gz
- tar xjf lv2-1.12.0.tar.bz2
- tar xjf serd-0.22.0.tar.bz2
- tar xjf sord-0.14.0.tar.bz2
- tar xjf sratom-0.4.6.tar.bz2
- tar xjf lilv-0.22.0.tar.bz2
- tar xzf nanomsg-0.8-beta.tar.gz
- wget https://github.com/libuv/libuv/archive/v1.7.5.tar.gz
- tar xzf v1.7.5.tar.gz
- if [ "$CC" = "clang" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm-upper; fi
......@@ -16,8 +30,13 @@ before_install:
install:
- if [ "$CC" = "clang" ]; then sudo apt-get install -y clang-3.6 libstdc++-5-dev; fi
- if [ "$CC" = "gcc" ]; then sudo apt-get install -y gcc-5 g++-5; fi
- sudo apt-get install -y libefl-dev libelementary-dev cmake=2.8.12.2-3
- pushd lv2-1.12.0 && ./waf configure && ./waf build && sudo ./waf install && popd
- sudo apt-get install -y libefl-dev cmake
- pushd lv2-1.12.0 && ./waf configure --no-plugins --prefix=/usr && ./waf build && sudo ./waf install && popd
- pushd serd-0.22.0 && ./waf configure --no-utils --prefix=/usr && ./waf build && sudo ./waf install && popd
- pushd sord-0.14.0 && ./waf configure --no-utils --prefix=/usr && ./waf build && sudo ./waf install && popd
- pushd sratom-0.4.6 && ./waf configure --prefix=/usr && ./waf build && sudo ./waf install && popd
- pushd lilv-0.22.0 && ./waf configure --no-utils --prefix=/usr && ./waf build && sudo ./waf install && popd
- pushd nanomsg-0.8-beta && ./configure --prefix=/usr && make && sudo make install && popd
- pushd libuv-1.7.5 && sh autogen.sh && ./configure --prefix=/usr && make && sudo make install && popd
before_script:
- if [ "$CC" = "clang" ]; then export CXX="clang++-3.6" CC="clang-3.6" CFLAGS="-ffreestanding"; fi
......
......@@ -4,7 +4,8 @@ project(moony.lv2)
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/tlsf-3.0)
include_directories(${PROJECT_SOURCE_DIR}/eo_ui.lv2)
include_directories(${PROJECT_SOURCE_DIR}/sandbox_ui.lv2)
include_directories(${PROJECT_SOURCE_DIR}/symap)
include_directories(${PROJECT_SOURCE_DIR}/osc.lv2)
include_directories(${PROJECT_SOURCE_DIR}/timely.lv2)
include_directories(${PROJECT_SOURCE_DIR}/xpress.lv2)
......@@ -43,7 +44,6 @@ if(NOT DEFINED PLUGIN_DEST)
endif()
find_package(PkgConfig) # ${PKG_CONFIG_FOUND}
find_package(FLEX)
pkg_search_module(LV2 REQUIRED lv2>=1.10)
include_directories(${LV2_INCLUDE_DIRS})
......@@ -59,39 +59,60 @@ cmake_dependent_option(USE_FS_EVENT "Use filesystem notify events" ON "BUILD_SIM
if(BUILD_COMMON_UI)
pkg_search_module(ELM REQUIRED elementary>=1.8)
include_directories(${ELM_INCLUDE_DIRS})
set(LIBS_UI ${LIBS_UI} ${ELM_LDFLAGS})
pkg_search_module(ECORE_X OPTIONAL ecore-x)
pkg_search_module(NANOMSG REQUIRED libnanomsg>=2.0)
include_directories(${NANOMSG_INCLUDE_DIRS})
if((${ELM_VERSION} VERSION_EQUAL "1.9.0") OR (${ELM_VERSION} VERSION_GREATER "1.9.0"))
add_definitions("-DELM_1_9")
pkg_search_module(SRATOM REQUIRED sratom-0>=0.4.0)
include_directories(${SRATOM_INCLUDE_DIRS})
pkg_search_module(LILV REQUIRED lilv-0>=0.20.0)
include_directories(${LILV_INCLUDE_DIRS})
if((${LILV_VERSION} VERSION_EQUAL "0.22.0") OR (${LILV_VERSION} VERSION_GREATER "0.22.0"))
add_definitions("-DLILV_0_22")
endif()
if((DEFINED ECORE_X_FOUND) AND ((${ELM_VERSION} VERSION_EQUAL "1.13.0") OR (${ELM_VERSION} VERSION_GREATER "1.13.0")))
message(STATUS "X11 UI wrap enabled")
set(X11_UI_WRAP "")
add_definitions("-DX11_UI_WRAP")
else()
message(STATUS "X11 UI wrap disabled")
set(X11_UI_WRAP "#")
if((${ELM_VERSION} VERSION_EQUAL "1.9.0") OR (${ELM_VERSION} VERSION_GREATER "1.9.0"))
add_definitions("-DELM_1_9")
endif()
find_package(FLEX)
flex_target(encoder ${PROJECT_SOURCE_DIR}/ui/encoder.l ${PROJECT_BINARY_DIR}/encoder.c
COMPILE_FLAGS "--header-file=${PROJECT_BINARY_DIR}/encoder.h --prefix=enc")
add_library(moony_ui MODULE
ui/moony_ui.c
ui/common_ui.c
${FLEX_encoder_OUTPUTS})
target_link_libraries(moony_ui ${LIBS_UI})
${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_ui.c
${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_master.c
${PROJECT_SOURCE_DIR}/ui/moony_ui.c)
target_link_libraries(moony_ui
${NANOMSG_LDFLAGS}
${SRATOM_LDFLAGS})
set_target_properties(moony_ui PROPERTIES PREFIX "")
install(TARGETS moony_ui DESTINATION ${PLUGIN_DEST})
add_library(moony_eo MODULE
${PROJECT_SOURCE_DIR}/ui/moony_eo.c
${PROJECT_SOURCE_DIR}/ui/common_ui.c
${FLEX_encoder_OUTPUTS})
target_link_libraries(moony_eo
${ELM_LDFLAGS})
set_target_properties(moony_eo PROPERTIES PREFIX "")
install(TARGETS moony_eo DESTINATION ${PLUGIN_DEST})
add_executable(sandbox_efl
${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_slave.c
${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_efl.c
${PROJECT_SOURCE_DIR}/symap/symap.c)
target_link_libraries(sandbox_efl
${ELM_LDFLAGS}
${NANOMSG_LDFLAGS}
${LILV_LDFLAGS})
install(TARGETS sandbox_efl DESTINATION ${PLUGIN_DEST})
install(FILES ${PROJECT_SOURCE_DIR}/ui/omk_logo_256x256.png DESTINATION ${PLUGIN_DEST})
else()
set(EO_UI_WRAP "#")
set(UI_UI_WRAP "#")
set(X11_UI_WRAP "#")
set(KX_UI_WRAP "#")
set(COMMON_WRAP "#")
endif()
if(BUILD_SIMPLE_UI)
......@@ -114,8 +135,7 @@ if(BUILD_SIMPLE_UI)
set_target_properties(moony_simple PROPERTIES PREFIX "")
install(TARGETS moony_simple DESTINATION ${PLUGIN_DEST})
else()
set(UI_SIMPLE_WRAP "#")
set(KX_SIMPLE_WRAP "#")
set(SIMPLE_WRAP "#")
endif()
if(BUILD_WEB_UI)
......@@ -147,8 +167,7 @@ if(BUILD_WEB_UI)
install(FILES ${PROJECT_SOURCE_DIR}/web_ui/keybinding-vim.js DESTINATION ${PLUGIN_DEST}/web_ui)
install(FILES ${PROJECT_SOURCE_DIR}/web_ui/keybinding-emacs.js DESTINATION ${PLUGIN_DEST}/web_ui)
else()
set(UI_WEB_WRAP "#")
set(KX_WEB_WRAP "#")
set(WEB_WRAP "#")
endif()
add_library(lua OBJECT
......@@ -223,6 +242,7 @@ install(TARGETS moony DESTINATION ${PLUGIN_DEST})
configure_file(${PROJECT_SOURCE_DIR}/plugin/manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl)
install(FILES ${PROJECT_BINARY_DIR}/manifest.ttl DESTINATION ${PLUGIN_DEST})
install(FILES ${PROJECT_SOURCE_DIR}/plugin/moony.ttl DESTINATION ${PLUGIN_DEST})
install(FILES ${PROJECT_SOURCE_DIR}/plugin/moony_ui.ttl DESTINATION ${PLUGIN_DEST})
install(FILES ${PROJECT_SOURCE_DIR}/plugin/presets.ttl DESTINATION ${PLUGIN_DEST})
include(CTest)
......
......@@ -65,16 +65,15 @@
#define MOONY_TRACE_URI MOONY_URI"#trace"
#define MOONY_STATE_URI MOONY_URI"#state"
#define MOONY_COMMON_UI_URI MOONY_URI"#ui5_common_ui"
#define MOONY_COMMON_KX_URI MOONY_URI"#ui6_common_kx"
#define MOONY_COMMON_X11_URI MOONY_URI"#ui7_common_x11"
#define MOONY_COMMON_EO_URI MOONY_URI"#ui8_common_eo"
#define MOONY_COMMON_UI_URI MOONY_URI"#ui_3_common_1_ui"
#define MOONY_COMMON_KX_URI MOONY_URI"#ui_3_common_2_kx"
#define MOONY_COMMON_EO_URI MOONY_URI"#ui_3_common_3_eo"
#define MOONY_SIMPLE_UI_URI MOONY_URI"#ui3_simple_ui"
#define MOONY_SIMPLE_KX_URI MOONY_URI"#ui4_simple_kx"
#define MOONY_SIMPLE_UI_URI MOONY_URI"#ui_2_simple_1_ui"
#define MOONY_SIMPLE_KX_URI MOONY_URI"#ui_2_simple_2_kx"
#define MOONY_WEB_UI_URI MOONY_URI"#ui1_web_ui"
#define MOONY_WEB_KX_URI MOONY_URI"#ui2_web_kx"
#define MOONY_WEB_UI_URI MOONY_URI"#ui_1_web_1_ui"
#define MOONY_WEB_KX_URI MOONY_URI"#ui_1_web_2_kx"
#define MOONY_C1XC1_URI MOONY_URI"#c1xc1"
#define MOONY_C2XC2_URI MOONY_URI"#c2xc2"
......@@ -102,7 +101,6 @@ extern const LV2_Descriptor c4a1xc4a1;
extern const LV2UI_Descriptor common_eo;
extern const LV2UI_Descriptor common_ui;
extern const LV2UI_Descriptor common_x11;
extern const LV2UI_Descriptor common_kx;
extern const LV2UI_Descriptor simple_ui;
......
This diff is collapsed.
This diff is collapsed.
# Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
#
# This is free software: you can redistribute it and/or modify
# it under the terms of the Artistic License 2.0 as published by
# The Perl Foundation.
#
# This source is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Artistic License 2.0 for more details.
#
# You should have received a copy of the Artistic License 2.0
# along the source as a COPYING file. If not, obtain it from
# http://www.perlfoundation.org/artistic_license_2_0.
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@prefix kx: <http://kxstudio.sf.net/ns/lv2ext/external-ui#> .
@prefix moony: <http://open-music-kontrollers.ch/lv2/moony#> .
# Web UI
moony:ui_1_web_1_ui
a ui:UI ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map, urid:unmap ;
lv2:extensionData ui:idleInterface, ui:showInterface .
moony:ui_1_web_2_kx
a kx:Widget ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature kx:Host, ui:portMap, urid:map, urid:unmap .
# Simple UI
moony:ui_2_simple_1_ui
a ui:UI ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map ;
lv2:extensionData ui:idleInterface, ui:showInterface .
moony:ui_2_simple_2_kx
a kx:Widget ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature kx:Host, ui:portMap, urid:map .
# Common UI
moony:ui_3_common_1_ui
a ui:UI ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map ;
lv2:extensionData ui:idleInterface, ui:showInterface .
moony:ui_3_common_2_kx
a kx:Widget ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature kx:Host, ui:portMap, urid:map .
moony:ui_3_common_3_eo
a ui:EoUI ;
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature ui:portMap, urid:map .
/*
Copyright 2011-2014 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "symap.h"
/**
@file symap.c Implementation of Symap, a basic symbol map (string interner).
This implementation is primitive, but has some desirable qualities: good
(O(lg(n)) lookup performance for already-mapped symbols, minimal space
overhead, extremely fast (O(1)) reverse mapping (ID to string), simple code,
no dependencies.
The tradeoff is that mapping new symbols may be quite slow. In other words,
this implementation is ideal for use cases with a relatively limited set of
symbols, or where most symbols are mapped early. It will not fare so well
with very dynamic sets of symbols. For that, you're better off with a
tree-based implementation (and the associated space cost, especially if you
need reverse mapping).
*/
struct SymapImpl {
/**
Unsorted array of strings, such that the symbol for ID i is found
at symbols[i - 1].
*/
char** symbols;
/**
Array of IDs, sorted by corresponding string in `symbols`.
*/
uint32_t* index;
/**
Number of symbols (number of items in `symbols` and `index`).
*/
uint32_t size;
};
Symap*
symap_new(void)
{
Symap* map = (Symap*)malloc(sizeof(Symap));
map->symbols = NULL;
map->index = NULL;
map->size = 0;
return map;
}
void
symap_free(Symap* map)
{
for (uint32_t i = 0; i < map->size; ++i) {
free(map->symbols[i]);
}
free(map->symbols);
free(map->index);
free(map);
}
static char*
symap_strdup(const char* str)
{
const size_t len = strlen(str);
char* copy = (char*)malloc(len + 1);
memcpy(copy, str, len + 1);
return copy;
}
/**
Return the index into map->index (not the ID) corresponding to `sym`,
or the index where a new entry for `sym` should be inserted.
*/
static uint32_t
symap_search(const Symap* map, const char* sym, bool* exact)
{
*exact = false;
if (map->size == 0) {
return 0; // Empty map, insert at 0
} else if (strcmp(map->symbols[map->index[map->size - 1] - 1], sym) < 0) {
return map->size; // Greater than last element, append
}
uint32_t lower = 0;
uint32_t upper = map->size - 1;
uint32_t i = upper;
int cmp;
while (upper >= lower) {
i = lower + ((upper - lower) / 2);
cmp = strcmp(map->symbols[map->index[i] - 1], sym);
if (cmp == 0) {
*exact = true;
return i;
} else if (cmp > 0) {
if (i == 0) {
break; // Avoid underflow
}
upper = i - 1;
} else {
lower = ++i;
}
}
assert(!*exact || strcmp(map->symbols[map->index[i] - 1], sym) > 0);
return i;
}
uint32_t
symap_try_map(Symap* map, const char* sym)
{
bool exact;
const uint32_t index = symap_search(map, sym, &exact);
if (exact) {
assert(!strcmp(map->symbols[map->index[index]], sym));
return map->index[index];
}
return 0;
}
uint32_t
symap_map(Symap* map, const char* sym)
{
bool exact;
const uint32_t index = symap_search(map, sym, &exact);
if (exact) {
assert(!strcmp(map->symbols[map->index[index] - 1], sym));
return map->index[index];
}
const uint32_t id = ++map->size;
char* const str = symap_strdup(sym);
/* Append new symbol to symbols array */
map->symbols = (char**)realloc(map->symbols, map->size * sizeof(str));
map->symbols[id - 1] = str;
/* Insert new index element into sorted index */
map->index = (uint32_t*)realloc(map->index, map->size * sizeof(uint32_t));
if (index < map->size - 1) {
memmove(map->index + index + 1,
map->index + index,
(map->size - index - 1) * sizeof(uint32_t));
}
map->index[index] = id;
return id;
}
const char*
symap_unmap(Symap* map, uint32_t id)
{
if (id == 0) {
return NULL;
} else if (id <= map->size) {
return map->symbols[id - 1];
}
return NULL;
}
#ifdef STANDALONE
#include <stdio.h>
static void
symap_dump(Symap* map)
{
fprintf(stderr, "{\n");
for (uint32_t i = 0; i < map->size; ++i) {
fprintf(stderr, "\t%u = %s\n",
map->index[i], map->symbols[map->index[i] - 1]);
}
fprintf(stderr, "}\n");
}
int
main()
{
#define N_SYMS 5
char* syms[N_SYMS] = {
"hello", "bonjour", "goodbye", "aloha", "salut"
};
Symap* map = symap_new();
for (int i = 0; i < N_SYMS; ++i) {
if (symap_try_map(map, syms[i])) {
fprintf(stderr, "error: Symbol already mapped\n");
return 1;