diff --git a/gen-lib/CMakeLists.txt b/gen-lib/CMakeLists.txt deleted file mode 100644 index 421b3b4..0000000 --- a/gen-lib/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -set(CMAKE_TOOLCHAIN_FILE arduino-esp32.cmake) - -project(libmapper) - -set(LIBLO_SRCS liblo/src/address.c liblo/src/blob.c liblo/src/bundle.c liblo/src/message.c liblo/src/method.c liblo/src/pattern_match.c liblo/src/send.c liblo/src/server.c liblo/src/server_thread.c liblo/src/timetag.c liblo/src/version.c) -set(LIBMAPPER_SRCS libmapper/src/device.c libmapper/src/expression.c libmapper/src/graph.c libmapper/src/link.c libmapper/src/list.c libmapper/src/map.c libmapper/src/network.c libmapper/src/object.c libmapper/src/properties.c libmapper/src/router.c libmapper/src/signal.c libmapper/src/slot.c libmapper/src/table.c libmapper/src/time.c libmapper/src/value.c) -set(COMPAT_SRCS compat-idf/src/gai_strerror.c compat-idf/src/gethostname.c compat-idf/src/getnameinfo.c compat-idf/src/ifaddrs.c) -set(ZLIB_SRCS zlib/crc32.c) - -set(SRCS ${COMPAT_SRCS} ${LIBLO_SRCS} ${LIBMAPPER_SRCS} ${ZLIB_SRCS}) - -include_directories(libmapper/include liblo compat-idf/include zlib) - -add_library(mapper STATIC ${SRCS}) - -get_filename_component(COMPAT_H compat-idf/include/compat.h ABSOLUTE) -target_compile_options(mapper PRIVATE -DHAVE_CONFIG_H -include${COMPAT_H}) - -add_custom_command(OUTPUT liblo/config.h - COMMAND cp liblo_config.h liblo/config.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -add_custom_command(OUTPUT liblo/lo/lo.h - COMMAND cp lo.h liblo/lo/lo.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -add_custom_command(OUTPUT liblo/lo/lo_endian.h - COMMAND cp lo_endian.h liblo/lo/lo_endian.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -add_custom_command(OUTPUT libmapper/src/config.h - COMMAND cp libmapper_config.h libmapper/src/config.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - -add_custom_target(libmapper_config_headers DEPENDS liblo/config.h liblo/lo/lo.h liblo/lo/lo_endian.h libmapper/src/config.h) -add_dependencies(mapper libmapper_config_headers) -add_custom_command(TARGET mapper POST_BUILD COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/genlib.sh) - -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Arduino/libmapper DESTINATION ${ARDUINO_LIBRARY_PATH}) -install(TARGETS mapper DESTINATION ${ARDUINO_LIBRARY_PATH}/libmapper/src/esp32) diff --git a/gen-lib/Makefile b/gen-lib/Makefile deleted file mode 100644 index 7454eb4..0000000 --- a/gen-lib/Makefile +++ /dev/null @@ -1,120 +0,0 @@ -COMPILER_PATH := $(HOME)/Library/Arduino15/packages/esp32/tools/xtensa-esp32-elf-gcc/1.22.0-80-g6c4433a-5.2.0/bin -SDK := $(HOME)/Library/Arduino15/packages/esp32/hardware/esp32/1.0.4/tools/sdk -SDK_INCLUDE := $(SDK)/include -CC := $(COMPILER_PATH)/xtensa-esp32-elf-gcc -AR := $(COMPILER_PATH)/xtensa-esp32-elf-ar - -BUILD_DIR := ./build -OUTPUT_DIR := $(BUILD_DIR)/Arduino/libmapper -OUTPUT_SRC_DIR := $(OUTPUT_DIR)/src -OUTPUT_LIB_DIR := $(OUTPUT_SRC_DIR)/esp32 - -INCLUDES := -I"$(SDK_INCLUDE)/config" -I"$(SDK_INCLUDE)/app_trace" -I"$(SDK_INCLUDE)/app_update" -I"$(SDK_INCLUDE)/asio" -I"$(SDK_INCLUDE)/bootloader_support" -I"$(SDK_INCLUDE)/bt" -I"$(SDK_INCLUDE)/coap" -I"$(SDK_INCLUDE)/console" -I"$(SDK_INCLUDE)/driver" -I"$(SDK_INCLUDE)/esp-tls" -I"$(SDK_INCLUDE)/esp32" -I"$(SDK_INCLUDE)/esp_adc_cal" -I"$(SDK_INCLUDE)/esp_event" -I"$(SDK_INCLUDE)/esp_http_client" -I"$(SDK_INCLUDE)/esp_http_server" -I"$(SDK_INCLUDE)/esp_https_ota" -I"$(SDK_INCLUDE)/esp_ringbuf" -I"$(SDK_INCLUDE)/ethernet" -I"$(SDK_INCLUDE)/expat" -I"$(SDK_INCLUDE)/fatfs" -I"$(SDK_INCLUDE)/freemodbus" -I"$(SDK_INCLUDE)/freertos" -I"$(SDK_INCLUDE)/heap" -I"$(SDK_INCLUDE)/idf_test" -I"$(SDK_INCLUDE)/jsmn" -I"$(SDK_INCLUDE)/json" -I"$(SDK_INCLUDE)/libsodium" -I"$(SDK_INCLUDE)/log" -I"$(SDK_INCLUDE)/lwip" -I"$(SDK_INCLUDE)/mbedtls" -I"$(SDK_INCLUDE)/mdns" -I"$(SDK_INCLUDE)/micro-ecc" -I"$(SDK_INCLUDE)/mqtt" -I"$(SDK_INCLUDE)/newlib" -I"$(SDK_INCLUDE)/nghttp" -I"$(SDK_INCLUDE)/nvs_flash" -I"$(SDK_INCLUDE)/openssl" -I"$(SDK_INCLUDE)/protobuf-c" -I"$(SDK_INCLUDE)/protocomm" -I"$(SDK_INCLUDE)/pthread" -I"$(SDK_INCLUDE)/sdmmc" -I"$(SDK_INCLUDE)/smartconfig_ack" -I"$(SDK_INCLUDE)/soc" -I"$(SDK_INCLUDE)/spi_flash" -I"$(SDK_INCLUDE)/spiffs" -I"$(SDK_INCLUDE)/tcp_transport" -I"$(SDK_INCLUDE)/tcpip_adapter" -I"$(SDK_INCLUDE)/ulp" -I"$(SDK_INCLUDE)/vfs" -I"$(SDK_INCLUDE)/wear_levelling" -I"$(SDK_INCLUDE)/wifi_provisioning" -I"$(SDK_INCLUDE)/wpa_supplicant" -I"$(SDK_INCLUDE)/xtensa-debug-module" -I"$(SDK_INCLUDE)/esp-face" -I"$(SDK_INCLUDE)/esp32-camera" -I"$(SDK_INCLUDE)/esp-face" -I"$(SDK_INCLUDE)/fb_gfx" -WARNING_FLAGS := -w -Wpointer-arith -Wno-maybe-uninitialized -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-variable -Wno-deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -Wno-old-style-declaration -CFLAGS := -DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H -DGCC_NOT_5_2_0=0 -DWITH_POSIX -std=gnu99 -Os -g3 -fstack-protector -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib $(WARNING_FLAGS) -MMD - -# Compat lib -COMPAT_SRCS_DIR := ./compat/src -COMPAT_INCLUDE_DIR := compat/include -COMPAT_FLAGS := $(CFLAGS) -I$(COMPAT_INCLUDE_DIR) $(INCLUDES) -COMPAT_OBJ_DIR := $(BUILD_DIR)/compat -COMPAT_OBJS := $(addprefix $(COMPAT_OBJ_DIR)/,gai_strerror.o gethostname.o getnameinfo.o ifaddrs.o) - -# zlib -ZLIB_SRCS_DIR := ./zlib -ZLIB_INCLUDE_DIR := ./zlib -ZLIB_FLAGS := $(CFLAGS) $(INCLUDES) -ZLIB_OBJ_DIR := $(BUILD_DIR)/zlib -ZLIB_OBJS := $(addprefix $(ZLIB_OBJ_DIR)/,crc32.o) - -# liblo -LIBLO_SRCS_DIR := ./liblo/src -LIBLO_INCLUDE_DIR := ./liblo -LIBLO_FLAGS := $(CFLAGS) -include $(COMPAT_INCLUDE_DIR)/compat.h -I$(LIBLO_INCLUDE_DIR) -I$(COMPAT_INCLUDE_DIR) $(INCLUDES) -LIBLO_OBJ_DIR := $(BUILD_DIR)/liblo -LIBLO_OBJS := $(addprefix $(LIBLO_OBJ_DIR)/,address.o blob.o bundle.o message.o method.o pattern_match.o send.o server.o server_thread.o timetag.o version.o) -LIBLO_CONFIGURED := $(shell [ -f liblo/config.h ] && echo "TRUE" || echo "FALSE") - -# libmapper -LIBMAPPER_SRCS_DIR := ./libmapper/src -LIBMAPPER_INCLUDE_DIR := ./libmapper/include -LIBMAPPER_FLAGS := -DDEBUG $(CFLAGS) -include $(COMPAT_INCLUDE_DIR)/compat.h -I$(LIBMAPPER_INCLUDE_DIR) -I$(COMPAT_INCLUDE_DIR) -I$(LIBLO_INCLUDE_DIR) -I$(ZLIB_INCLUDE_DIR) $(INCLUDES) -LIBMAPPER_OBJ_DIR := $(BUILD_DIR)/libmapper -LIBMAPPER_OBJS := $(addprefix $(LIBMAPPER_OBJ_DIR)/,database.o device.o expression.o link.o list.o map.o network.o properties.o router.o signal.o slot.o table.o timetag.o) -LIBMAPPER_CONFIGURED := $(shell [ -f libmapper/src/config.h ] && echo "TRUE" || echo "FALSE") - -$(COMPAT_OBJ_DIR)/%.o : $(COMPAT_SRCS_DIR)/%.c - @echo Building $< - @$(CC) $(COMPAT_FLAGS) -c $< -o $@ - -$(ZLIB_OBJ_DIR)/%.o : $(ZLIB_SRCS_DIR)/%.c - @echo Building $< - @$(CC) $(ZLIB_FLAGS) -c $< -o $@ - -$(LIBLO_OBJ_DIR)/%.o : $(LIBLO_SRCS_DIR)/%.c - @echo Building $< - @$(CC) $(LIBLO_FLAGS) -c $< -o $@ - -$(LIBMAPPER_OBJ_DIR)/%.o : $(LIBMAPPER_SRCS_DIR)/%.c - @echo Building $< - @$(CC) $(LIBMAPPER_FLAGS) -c $< -o $@ - -all : $(COMPAT_OBJS) $(ZLIB_OBJS) $(LIBLO_OBJS) $(LIBMAPPER_OBJS) - @mkdir -p $(OUTPUT_LIB_DIR) - @rm $(OUTPUT_LIB_DIR)/libmapper.a || true - @echo Linking $(OUTPUT_LIB_DIR)/libmapper.a - @$(AR) cru $(OUTPUT_LIB_DIR)/libmapper.a $^ - cp library.properties $(OUTPUT_DIR)/library.properties - cp -R examples $(OUTPUT_DIR) - cp mapper.h $(OUTPUT_SRC_DIR)/mapper.h - mkdir -p $(OUTPUT_SRC_DIR)/mapper - find $(LIBMAPPER_INCLUDE_DIR)/mapper -name "*.h" -exec cp -prv {} $(OUTPUT_SRC_DIR)/mapper/ ";" - mkdir -p $(OUTPUT_SRC_DIR)/lo - find $(LIBLO_INCLUDE_DIR)/lo -name "*.h" -exec cp -prv {} $(OUTPUT_SRC_DIR)/lo/ ";" - -$(COMPAT_OBJS) : | $(COMPAT_OBJ_DIR) - -$(COMPAT_OBJ_DIR) : - mkdir -p $(COMPAT_OBJ_DIR) - -$(ZLIB_OBJS): | $(ZLIB_OBJ_DIR) - -$(ZLIB_OBJ_DIR): - mkdir -p $(ZLIB_OBJ_DIR) - -$(LIBLO_OBJS) : | $(LIBLO_OBJ_DIR) configure-liblo - -$(LIBLO_OBJ_DIR) : - mkdir -p $(LIBLO_OBJ_DIR) - -$(LIBMAPPER_OBJS) : | $(LIBMAPPER_OBJ_DIR) configure-libmapper - -$(LIBMAPPER_OBJ_DIR): - mkdir -p $(LIBMAPPER_OBJ_DIR) - -.PHONY: configure-liblo -configure-liblo : -ifeq ($(LIBLO_CONFIGURED), TRUE) - @echo liblo: config.h was found -else - @echo Configuring liblo... - @cd liblo && ./autogen.sh -endif - -.PHONY: configure-libmapper -configure-libmapper : -ifeq ($(LIBMAPPER_CONFIGURED), TRUE) - @echo libmapper: config.h was found -else - @echo Configuring libmapper... - @cd libmapper && ./autogen.sh -endif - -.PHONY : install -install : - mkdir -p $(HOME)/Documents/Arduino/libraries/libmapper - cp -R $(OUTPUT_DIR)/. $(HOME)/Documents/Arduino/libraries/libmapper - -.PHONY : clean -clean : - -rm $(COMPAT_OBJS) $(ZLIB_OBJS) $(LIBLO_OBJS) $(LIBMAPPER_OBJS) \ No newline at end of file diff --git a/gen-lib/arduino-esp32.cmake b/gen-lib/arduino-esp32.cmake deleted file mode 100644 index 7852eb7..0000000 --- a/gen-lib/arduino-esp32.cmake +++ /dev/null @@ -1,22 +0,0 @@ -if(APPLE) - set(ARDUINO_ROOT "$ENV{HOME}/Documents/Arduino/hardware/espressif/esp32") - set(ARDUINO_LIBRARY_PATH "$ENV{HOME}/Documents/Arduino/libraries") -elseif(UNIX) - set(ARDUINO_ROOT "$ENV{HOME}/.arduino15/packages/esp32") - set(ARDUINO_LIBRARY_PATH "$ENV{HOME}/Arduino/libraries") -else() - message(FATAL_ERROR "Toolchain not implemented on this host OS. Please modify arduino-esp32.cmake.") -endif() -set(SDK ${ARDUINO_ROOT}/tools/sdk) -set(tools ${ARDUINO_ROOT}/tools/xtensa-esp32-elf) -set(SDK_INCLUDE ${SDK}/include) -set(ARDUINO_COMPILE_FLAGS "-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE=${SDK}/mbedtls/esp_config.h -DHAVE_CONFIG_H -DGCC_NOT_5_2_0=0 -DWITH_POSIX -std=gnu99 -Os -g3 -fstack-protector -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -MMD -I${SDK_INCLUDE}/config -I${SDK_INCLUDE}/app_trace -I${SDK_INCLUDE}/app_update -I${SDK_INCLUDE}/asio -I${SDK_INCLUDE}/bootloader_support -I${SDK_INCLUDE}/bt -I${SDK_INCLUDE}/coap -I${SDK_INCLUDE}/console -I${SDK_INCLUDE}/driver -I${SDK_INCLUDE}/esp-tls -I${SDK_INCLUDE}/esp32 -I${SDK_INCLUDE}/esp_adc_cal -I${SDK_INCLUDE}/esp_event -I${SDK_INCLUDE}/esp_http_client -I${SDK_INCLUDE}/esp_http_server -I${SDK_INCLUDE}/esp_https_ota -I${SDK_INCLUDE}/esp_ringbuf -I${SDK_INCLUDE}/ethernet -I${SDK_INCLUDE}/expat -I${SDK_INCLUDE}/fatfs -I${SDK_INCLUDE}/freemodbus -I${SDK_INCLUDE}/freertos -I${SDK_INCLUDE}/heap -I${SDK_INCLUDE}/idf_test -I${SDK_INCLUDE}/jsmn -I${SDK_INCLUDE}/json -I${SDK_INCLUDE}/libsodium -I${SDK_INCLUDE}/log -I${SDK_INCLUDE}/lwip -I${SDK_INCLUDE}/mbedtls -I${SDK_INCLUDE}/mdns -I${SDK_INCLUDE}/micro-ecc -I${SDK_INCLUDE}/mqtt -I${SDK_INCLUDE}/newlib -I${SDK_INCLUDE}/nghttp -I${SDK_INCLUDE}/nvs_flash -I${SDK_INCLUDE}/openssl -I${SDK_INCLUDE}/protobuf-c -I${SDK_INCLUDE}/protocomm -I${SDK_INCLUDE}/pthread -I${SDK_INCLUDE}/sdmmc -I${SDK_INCLUDE}/smartconfig_ack -I${SDK_INCLUDE}/soc -I${SDK_INCLUDE}/spi_flash -I${SDK_INCLUDE}/spiffs -I${SDK_INCLUDE}/tcp_transport -I${SDK_INCLUDE}/tcpip_adapter -I${SDK_INCLUDE}/ulp -I${SDK_INCLUDE}/vfs -I${SDK_INCLUDE}/wear_levelling -I${SDK_INCLUDE}/wifi_provisioning -I${SDK_INCLUDE}/wpa_supplicant -I${SDK_INCLUDE}/xtensa-debug-module -I${SDK_INCLUDE}/esp-face -I${SDK_INCLUDE}/esp32-camera -I${SDK_INCLUDE}/esp-face -I${SDK_INCLUDE}/fb_gfx") - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER ${tools}/bin/xtensa-esp32-elf-gcc) -set(CMAKE_CXX_COMPILER ${tools}/bin/xtensa-esp32-elf-g++) -set(CMAKE_ASM_COMPILER ${tools}/bin/xtensa-esp32-elf-gcc) - -set(CMAKE_C_FLAGS ${ARDUINO_COMPILE_FLAGS} CACHE STRING "C Compiler Base Flags") -set(CMAKE_CXX_FLAGS ${ARDUINO_COMPILE_FLAGS} CACHE STRING "C++ Compiler Base Flags") diff --git a/gen-lib/genlib.sh b/gen-lib/genlib.sh deleted file mode 100755 index 6da25cf..0000000 --- a/gen-lib/genlib.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -SRC_DIR=../ -OUTPUT_DIR=Arduino/libmapper -OUTPUT_SRC_DIR=$OUTPUT_DIR/src -mkdir -p $OUTPUT_DIR -cp $SRC_DIR/library.properties $OUTPUT_DIR/library.properties -cp -R $SRC_DIR/examples $OUTPUT_DIR -cp $SRC_DIR/mapper.h $OUTPUT_SRC_DIR/mapper.h -mkdir -p $OUTPUT_SRC_DIR/mapper -find $SRC_DIR/libmapper/include -name "*.h" -exec cp -prv {} $OUTPUT_SRC_DIR/mapper/ ";" -mkdir -p $OUTPUT_SRC_DIR/lo -find $SRC_DIR/liblo/lo -name "*.h" -exec cp -prv {} $OUTPUT_SRC_DIR/lo/ ";" diff --git a/gen-lib/liblo_config.h b/gen-lib/liblo_config.h deleted file mode 100644 index 801e257..0000000 --- a/gen-lib/liblo_config.h +++ /dev/null @@ -1,141 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - -/* Define this to enable ipv6. */ -/* #undef ENABLE_IPV6 */ - -/* Define this to enable network tests. */ -#define ENABLE_NETWORK_TESTS 1 - -/* Define this to enable threads. */ -#define ENABLE_THREADS 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the `getifaddrs' function. */ -#define HAVE_GETIFADDRS 1 - -/* Define to 1 if inet_pton() is available. */ -#define HAVE_INET_PTON 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `m' library (-lm). */ -/* #undef HAVE_LIBM */ - -/* Define to use the pthread library for threading. */ -#define HAVE_LIBPTHREAD 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if poll() is available. */ -#define HAVE_POLL 1 - -/* Define to 1 if select() is available. */ -#define HAVE_SELECT 1 - -/* Define to 1 if setvbuf() is available. */ -#define HAVE_SETVBUF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if the system has the type `uintptr_t'. */ -#define HAVE_UINTPTR_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to use the win32 library for threading. */ -/* #undef HAVE_WIN32_THREADS */ - -/* If machine is bigendian */ -#define LO_BIGENDIAN "0" - -/* Libtool compatibility version */ -#define LO_SO_VERSION {11, 1, 4} - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "liblo" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "liblo-devel@lists.sourceforge.net" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "liblo" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "liblo 0.31" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "liblo" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.31" - -/* printf code for type long long int */ -#define PRINTF_LL "ll" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.31" - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to the type of an unsigned integer type wide enough to hold a - pointer, if such a type exists, and if the system does not define it. */ -/* #undef uintptr_t */ diff --git a/gen-lib/libmapper_config.h b/gen-lib/libmapper_config.h deleted file mode 100644 index 4f15801..0000000 --- a/gen-lib/libmapper_config.h +++ /dev/null @@ -1,129 +0,0 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* src/config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if getifaddrs() is available. */ -#define HAVE_GETIFADDRS /**/ - -/* Define if gettimeofday() is available. */ -#define HAVE_GETTIMEOFDAY /**/ - -/* Define if inet_ptoa() is available. */ -/* #undef HAVE_INET_PTOA */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define if iphlpapi library is available. (Windows) */ -/* #undef HAVE_LIBIPHLPAPI */ - -/* Define to enable Open Sound Control support with liblo */ -#define HAVE_LIBLO /**/ - -/* Define to use lo_bundle_count function in liblo. */ -#define HAVE_LIBLO_BUNDLE_COUNT /**/ - -/* Define to use lo_servers_recv_noblock function in liblo. */ -#define HAVE_LIBLO_SERVERS_RECV_NOBLOCK /**/ - -/* Define to use lo_server_new_multicast_iface function in liblo. */ -#define HAVE_LIBLO_SERVER_IFACE /**/ - -/* Define to use lo_address_set_iface function in liblo. */ -#define HAVE_LIBLO_SET_IFACE /**/ - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define if you have POSIX threads libraries and header files. */ -#define HAVE_PTHREAD 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TERMIOS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINSOCK2_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ZLIB_H 1 - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "libmapper" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "dot_mapper@googlegroups.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libmapper" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libmapper 1.2-155-ge732a23f" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libmapper" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "http://libmapper.org" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.2-155-ge732a23f" - -/* printf code for type long long int */ -#define PRINTF_LL "ll" - -/* Define to necessary symbol if this constant uses a non-standard name on - your system. */ -/* #undef PTHREAD_CREATE_JOINABLE */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "1.2-155-ge732a23f" - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ diff --git a/gen-lib/library.properties b/gen-lib/library.properties deleted file mode 100644 index 5462056..0000000 --- a/gen-lib/library.properties +++ /dev/null @@ -1,11 +0,0 @@ -name=libmapper -version=0.2 -author=Mathias Bredholt -maintainer=Mathias Bredholt -sentence=A library for connecting things. -paragraph=This library is a system for representing input and output signals on a network and allowing arbitrary "mappings" to be dynamically created between them. -category=Communication -url=http://libmapper.github.io/ -architectures=esp32 -precompiled=true -includes=mapper.h diff --git a/gen-lib/lo.h b/gen-lib/lo.h deleted file mode 100644 index 9032838..0000000 --- a/gen-lib/lo.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program 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 - * GNU Lesser General Public License for more details. - * - * $Id$ - */ - -#ifndef LO_H -#define LO_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \file lo.h The liblo main headerfile and high-level API functions. - */ - -#include "lo/lo_endian.h" -#include "lo/lo_types.h" -#include "lo/lo_osc_types.h" -#include "lo/lo_errors.h" -#include "lo/lo_lowlevel.h" -#include "lo/lo_serverthread.h" - -/** - * \defgroup liblo High-level OSC API - * - * Defines the high-level API functions necessary to implement OSC support. - * Should be adequate for most applications, but if you require lower level - * control you can use the functions defined in lo_lowlevel.h - * @{ - */ - -/** - * \brief Declare an OSC destination, given IP address and port number. - * Same as lo_address_new_with_proto(), but using UDP. - * - * \param host An IP address or number, or NULL for the local machine. - * \param port a decimal port number or service name. - * - * The lo_address object may be used as the target of OSC messages. - * - * Note: if you wish to receive replies from the target of this - * address, you must first create a lo_server_thread or lo_server - * object which will receive the replies. The last lo_server(_thread) - * object craeted will be the receiver. - */ -lo_address lo_address_new(const char *host, const char *port); - -/** - * \brief Declare an OSC destination, given IP address and port number, - * specifying protocol. - * - * \param proto The protocol to use, must be one of LO_UDP, LO_TCP or LO_UNIX. - * \param host An IP address or number, or NULL for the local machine. - * \param port a decimal port number or service name. - * - * The lo_address object may be used as the target of OSC messages. - * - * Note: if you wish to receive replies from the target of this - * address, you must first create a lo_server_thread or lo_server - * object which will receive the replies. The last lo_server(_thread) - * object created will be the receiver. - */ -lo_address lo_address_new_with_proto(int proto, const char *host, const char *port); - -/** - * \brief Create a lo_address object from an OSC URL. - * - * example: \c "osc.udp://localhost:4444/my/path/" - */ -lo_address lo_address_new_from_url(const char *url); - -/** - * \brief Free the memory used by the lo_address object - */ -void lo_address_free(lo_address t); - -/** - * \brief Set the Time-to-Live value for a given target address. - * - * This is required for sending multicast UDP messages. A value of 1 - * (the usual case) keeps the message within the subnet, while 255 - * means a global, unrestricted scope. - * - * \param t An OSC address. - * \param ttl An integer specifying the scope of a multicast UDP message. - */ -void lo_address_set_ttl(lo_address t, int ttl); - -/** - * \brief Get the Time-to-Live value for a given target address. - * - * \param t An OSC address. - * \return An integer specifying the scope of a multicast UDP message. - */ -int lo_address_get_ttl(lo_address t); - -/** - * \brief Send a OSC formatted message to the address specified. - * - * \param targ The target OSC address - * \param path The OSC path the message will be delivered to - * \param type The types of the data items in the message, types are defined in - * lo_osc_types.h - * \param ... The data values to be transmitted. The types of the arguments - * passed here must agree with the types specified in the type parameter. - * - * example: - * \code - * lo_send(t, "/foo/bar", "ff", 0.1f, 23.0f); - * \endcode - * - * \return -1 on failure. - */ -int lo_send(lo_address targ, const char *path, const char *type, ...); - -/** - * \brief Send a OSC formatted message to the address specified, - * from the same socket as the specified server. - * - * \param targ The target OSC address - * \param from The server to send message from (can be NULL to use new socket) - * \param ts The OSC timetag timestamp at which the message will be processed - * (can be LO_TT_IMMEDIATE if you don't want to attach a timetag) - * \param path The OSC path the message will be delivered to - * \param type The types of the data items in the message, types are defined in - * lo_osc_types.h - * \param ... The data values to be transmitted. The types of the arguments - * passed here must agree with the types specified in the type parameter. - * - * example: - * \code - * serv = lo_server_new(NULL, err); - * lo_server_add_method(serv, "/reply", "ss", reply_handler, NULL); - * lo_send_from(t, serv, LO_TT_IMMEDIATE, "/foo/bar", "ff", 0.1f, 23.0f); - * \endcode - * - * \return on success, the number of bytes sent, or -1 on failure. - */ -int lo_send_from(lo_address targ, lo_server from, lo_timetag ts, - const char *path, const char *type, ...); - -/** - * \brief Send a OSC formatted message to the address specified, scheduled to - * be dispatch at some time in the future. - * - * \param targ The target OSC address - * \param ts The OSC timetag timestamp at which the message will be processed - * \param path The OSC path the message will be delivered to - * \param type The types of the data items in the message, types are defined in - * lo_osc_types.h - * \param ... The data values to be transmitted. The types of the arguments - * passed here must agree with the types specified in the type parameter. - * - * example: - * \code - * lo_timetag now;
- * lo_timetag_now(&now);
- * lo_send_timestamped(t, now, "/foo/bar", "ff", 0.1f, 23.0f); - * \endcode - * - * \return on success, the number of bytes sent, or -1 on failure. - */ -int lo_send_timestamped(lo_address targ, lo_timetag ts, const char *path, - const char *type, ...); - -/** - * \brief Return the error number from the last failed lo_send() or - * lo_address_new() call - */ -int lo_address_errno(lo_address a); - -/** - * \brief Return the error string from the last failed lo_send() or - * lo_address_new() call - */ -const char *lo_address_errstr(lo_address a); - -/** - * \brief Create a new OSC blob type. - * - * \param size The amount of space to allocate in the blob structure. - * \param data The data that will be used to initialise the blob, should be - * size bytes long. - */ -lo_blob lo_blob_new(int32_t size, const void *data); - -/** - * \brief Free the memory taken by a blob - */ -void lo_blob_free(lo_blob b); - -/** - * \brief Return the amount of valid data in a lo_blob object. - * - * If you want to know the storage size, use lo_arg_size(). - */ -uint32_t lo_blob_datasize(lo_blob b); - -/** - * \brief Return a pointer to the start of the blob data to allow contents to - * be changed. - */ -void *lo_blob_dataptr(lo_blob b); - -/** - * \brief Get information on the version of liblo current in use. - * - * All parameters are optional and can be given the value of 0 if that - * information is not desired. For example, to get just the version - * as a string, call lo_version(str, size, 0, 0, 0, 0, 0, 0, 0); - * - * The "lt" fields, called the ABI version, corresponds to libtool's - * versioning system for binary interface compatibility, and is not - * related to the library version number. This information is usually - * encoded in the filename of the shared library. - * - * Typically the string returned in 'verstr' should correspond with - * $major.$minor$extra, e.g., "0.28rc". If no 'extra' information is - * present, e.g., "0.28", extra will given the null string. - * - * \param verstr A buffer to receive a string describing the - * library version. - * \param verstr_size Size of the buffer pointed to by string. - * \param major Location to receive the library major version. - * \param minor Location to receive the library minor version. - * \param extra Location to receive the library version extra string. - * \param extra_size Size of the buffer pointed to by extra. - * \param lt_major Location to receive the ABI major version. - * \param lt_minor Location to receive the ABI minor version. - * \param lt_bug Location to receive the ABI 'bugfix' version. - */ -void lo_version(char *verstr, int verstr_size, - int *major, int *minor, char *extra, int extra_size, - int *lt_major, int *lt_minor, int *lt_bug); - -/** @} */ - -#include "lo/lo_macros.h" - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/gen-lib/lo_endian.h b/gen-lib/lo_endian.h deleted file mode 100644 index 0ff26f9..0000000 --- a/gen-lib/lo_endian.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program 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 - * GNU Lesser General Public License for more details. - * - * $Id$ - */ - -#ifndef LO_ENDIAN_H -#define LO_ENDIAN_H - -#include -#include - -#if defined(WIN32) || defined(_MSC_VER) -#include -#include -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define lo_swap16(x) htons(x) - -#define lo_swap32(x) htonl(x) - -/* These macros come from the Linux kernel */ - -#ifndef lo_swap16 -#define lo_swap16(x) \ -({ \ - uint16_t __x = (x); \ - ((uint16_t)( \ - (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ - (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ -}) -#warning USING UNOPTIMISED ENDIAN STUFF -#endif - -#ifndef lo_swap32 -#define lo_swap32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) -#endif - -#if 0 -#ifndef lo_swap64 -#define lo_swap64(x) \ -({ \ - uint64_t __x = (x); \ - ((uint64_t)( \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ -}) -#endif -#else - -typedef union { - uint64_t all; - struct { - uint32_t a; - uint32_t b; - } part; -} lo_split64; - -#ifdef _MSC_VER -#define LO_INLINE __inline -#else -#define LO_INLINE inline -#endif -static LO_INLINE uint64_t lo_swap64(uint64_t x) -{ - lo_split64 in, out; - - in.all = x; - out.part.a = lo_swap32(in.part.b); - out.part.b = lo_swap32(in.part.a); - - return out.all; -} -#undef LO_INLINE -#endif - -/* When compiling for an Apple universal build, allow compile-time - * macros to override autoconf endianness settings. */ -#ifdef LO_BIGENDIAN -#undef LO_BIGENDIAN -#endif -#if 0 == 2 -#ifdef __BIG_ENDIAN__ -#define LO_BIGENDIAN 1 -#else -#ifdef __LITTLE_ENDIAN__ -#define LO_BIGENDIAN 0 -#else -#error Unknown endianness during Apple universal build. -#endif -#endif -#else -#define LO_BIGENDIAN 0 -#endif - -/* Host to OSC and OSC to Host conversion macros */ -#if LO_BIGENDIAN -#define lo_htoo16(x) (x) -#define lo_htoo32(x) (x) -#define lo_htoo64(x) (x) -#define lo_otoh16(x) (x) -#define lo_otoh32(x) (x) -#define lo_otoh64(x) (x) -#else -#define lo_htoo16 lo_swap16 -#define lo_htoo32 lo_swap32 -#define lo_htoo64 lo_swap64 -#define lo_otoh16 lo_swap16 -#define lo_otoh32 lo_swap32 -#define lo_otoh64 lo_swap64 -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/* vi:set ts=8 sts=4 sw=4: */ diff --git a/gen-lib/mapper.h b/gen-lib/mapper.h deleted file mode 100644 index 4cade71..0000000 --- a/gen-lib/mapper.h +++ /dev/null @@ -1 +0,0 @@ -#include "mapper/mapper.h" \ No newline at end of file diff --git a/library.properties b/library.properties index ec93bbf..0aa929d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=libmapper -version=0.2 +version=0.3 author=Mathias Bredholt maintainer=Mathias Bredholt sentence=A library for connecting things. diff --git a/mapper.h b/mapper.h new file mode 100644 index 0000000..7acecf8 --- /dev/null +++ b/mapper.h @@ -0,0 +1 @@ +#include "mapper/mapper.h" diff --git a/src/compat.h b/src/compat.h index b608a08..9b25da4 100644 --- a/src/compat.h +++ b/src/compat.h @@ -17,13 +17,7 @@ */ -#ifndef COMPAT_H -#define COMPAT_H - -#include - const char *gai_strerror(int); -int gethostname(char *name, size_t len); #ifndef EAI_BADFLAGS #define EAI_BADFLAGS 205 @@ -52,10 +46,3 @@ int gethostname(char *name, size_t len); #ifndef PF_UNIX #define PF_UNIX AF_UNIX #endif - -#ifndef HAVE_CONFIG_H -#define HAVE_CONFIG_H -#endif - -#endif - diff --git a/src/lo/address.c b/src/lo/address.c index e9fa734..5189136 100644 --- a/src/lo/address.c +++ b/src/lo/address.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/blob.c b/src/lo/blob.c index f310dcd..fab4261 100644 --- a/src/lo/blob.c +++ b/src/lo/blob.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/bundle.c b/src/lo/bundle.c index 7e63957..8d3bdba 100644 --- a/src/lo/bundle.c +++ b/src/lo/bundle.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/lo.h b/src/lo/lo.h index 9032838..f640b47 100644 --- a/src/lo/lo.h +++ b/src/lo/lo.h @@ -51,9 +51,13 @@ extern "C" { * The lo_address object may be used as the target of OSC messages. * * Note: if you wish to receive replies from the target of this - * address, you must first create a lo_server_thread or lo_server - * object which will receive the replies. The last lo_server(_thread) - * object craeted will be the receiver. + * address, you must either supply a lo_server by using lo_send_from() + * or lo_send_message_from() to send your message, otherwise the last + * lo_server or lo_server_thread that was created will be used as the + * reply socket. The remote receiver may get the reply address by + * calling lo_message_get_source() in the message handler. See + * example_tcp_echo_server.c for an example of how to establish + * bidirectional communication. */ lo_address lo_address_new(const char *host, const char *port); @@ -129,6 +133,13 @@ int lo_send(lo_address targ, const char *path, const char *type, ...); * \brief Send a OSC formatted message to the address specified, * from the same socket as the specified server. * + * If a liblo server is receiving this message, it can reply by + * getting the server's address by calling lo_message_get_source() in + * the message handler, passing the \ref lo_message provided as an + * argument to the \ref lo_method_handler. By this mechanism + * bidirectional communication can be established by setting up a \ref + * lo_server or \ref lo_server_thread on both sides. + * * \param targ The target OSC address * \param from The server to send message from (can be NULL to use new socket) * \param ts The OSC timetag timestamp at which the message will be processed @@ -146,6 +157,9 @@ int lo_send(lo_address targ, const char *path, const char *type, ...); * lo_send_from(t, serv, LO_TT_IMMEDIATE, "/foo/bar", "ff", 0.1f, 23.0f); * \endcode * + * See \ref example_tcp_echo_server.c for an example of how to use + * lo_message_get_source() as described. + * * \return on success, the number of bytes sent, or -1 on failure. */ int lo_send_from(lo_address targ, lo_server from, lo_timetag ts, diff --git a/src/lo/lo_cpp.h b/src/lo/lo_cpp.h index 5effadf..3e9bfc6 100644 --- a/src/lo/lo_cpp.h +++ b/src/lo/lo_cpp.h @@ -11,7 +11,9 @@ #include #include #include -#include +#if __cplusplus >= 201703L +#include +#endif #include #ifndef LO_USE_EXCEPTIONS #include @@ -77,20 +79,30 @@ namespace lo { // "std::string", and "int". class string_type { public: + string_type(const string_type& s) { _s = s._s; } string_type(const char *s=0) { _s = s; } string_type(const std::string &s) { _s = s.c_str(); } +#if __cplusplus >= 201703L + string_type(const std::string_view& s) { + if (s[s.length()]==0) _s = s.data(); + else { _p.reset(new std::string(s)); _s = _p->c_str(); } + } +#endif operator const char*() const { return _s; } std::string s() const { return _s?_s:""; } const char *_s; + std::unique_ptr _p; }; class num_string_type : public string_type { public: - num_string_type(const char *s) : string_type(s) {} - num_string_type(const std::string &s) : string_type(s) {} - num_string_type(int n) { std::ostringstream ss; ss << n; - _p.reset(new std::string(ss.str())); _s = _p->c_str(); } - std::unique_ptr _p; + num_string_type(const char *s) : string_type(s) {} + num_string_type(const std::string &s) : string_type(s) {} +#if __cplusplus >= 201703L + num_string_type(const std::string_view& s) : string_type(s) {} +#endif + num_string_type(int n) + {_p.reset(new std::string(std::to_string(n))); _s = _p->c_str(); } }; /* diff --git a/src/lo/lo_lowlevel.h b/src/lo/lo_lowlevel.h index 2dd656c..22ccfa5 100644 --- a/src/lo/lo_lowlevel.h +++ b/src/lo/lo_lowlevel.h @@ -31,6 +31,7 @@ extern "C" { #include #include #ifdef _MSC_VER +#include typedef SSIZE_T ssize_t; #endif #include diff --git a/src/lo/lo_types.h b/src/lo/lo_types.h index bc240e9..967011c 100644 --- a/src/lo/lo_types.h +++ b/src/lo/lo_types.h @@ -42,14 +42,14 @@ extern "C" { * * Created by calls to lo_address_new() or lo_address_new_from_url(). */ -typedef struct lo_address_ {} *lo_address; +typedef struct lo_address_ *lo_address; /** * \brief A object to store an opaque binary data object. * * Can be passed over OSC using the 'b' type. Created by calls to lo_blob_new(). */ -typedef struct lo_blob_ {} *lo_blob; +typedef struct lo_blob_ *lo_blob; /** * \brief A low-level object used to represent messages passed over OSC. @@ -57,7 +57,7 @@ typedef struct lo_blob_ {} *lo_blob; * Created by calls to lo_message_new(), arguments can be added with calls to * lo_message_add_*(). */ -typedef struct lo_message_ {} *lo_message; +typedef struct lo_message_ *lo_message; /** * \brief A low-level object used to represent bundles of messages passed over @@ -66,7 +66,7 @@ typedef struct lo_message_ {} *lo_message; * Created by calls to lo_bundle_new(), messages can be added with calls to * lo_bundle_add_message(). */ -typedef struct lo_bundle_ {} *lo_bundle; +typedef struct lo_bundle_ *lo_bundle; /** * \brief An object representing an method on a server. @@ -74,7 +74,7 @@ typedef struct lo_bundle_ {} *lo_bundle; * Returned by calls to lo_server_thread_add_method() and * lo_server_add_method(). */ -typedef struct lo_method_ {} *lo_method; +typedef struct lo_method_ *lo_method; /** * \brief An object representing an instance of an OSC server. @@ -82,14 +82,14 @@ typedef struct lo_method_ {} *lo_method; * Created by calls to lo_server_new(). If you wish to have the server * operate in a background thread, use lo_server_thread instead. */ -typedef struct lo_server_ {} *lo_server; +typedef struct lo_server_ *lo_server; /** * \brief An object representing a thread containing an OSC server. * * Created by calls to lo_server_thread_new(). */ -typedef struct lo_server_thread_ {} *lo_server_thread; +typedef struct lo_server_thread_ *lo_server_thread; /** * \brief A callback function to receive notification of an error in a server or diff --git a/src/lo/message.c b/src/lo/message.c index b6d36a6..2c875d3 100644 --- a/src/lo/message.c +++ b/src/lo/message.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * @@ -529,7 +529,7 @@ static void *lo_message_add_data(lo_message m, size_t s) int lo_strsize(const char *s) { - return 4 * (strlen(s) / 4 + 1); + return (NULL != s)? (4 * (strlen(s) / 4 + 1)) : 0; } size_t lo_arg_size(lo_type type, void *data) diff --git a/src/lo/method.c b/src/lo/method.c index 7379ac4..d8142ff 100644 --- a/src/lo/method.c +++ b/src/lo/method.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/pattern_match.c b/src/lo/pattern_match.c index efe16eb..661a425 100644 --- a/src/lo/pattern_match.c +++ b/src/lo/pattern_match.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/send.c b/src/lo/send.c index 500df44..41fd6a9 100644 --- a/src/lo/send.c +++ b/src/lo/send.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * @@ -333,7 +333,7 @@ static int is_local_broadcast(struct addrinfo *ai){ // loop over all network interfaces for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family==AF_INET) { + if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET) { // get this machine's address for the current interface (ie. 192.168.1.6) uint32_t cur_addr = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr; // get the subnet mask for the current interface (ie. 255.255.0.0) diff --git a/src/lo/server.c b/src/lo/server.c index 4962cfd..064e8ed 100644 --- a/src/lo/server.c +++ b/src/lo/server.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * @@ -1974,7 +1974,7 @@ static void dispatch_method(lo_server s, const char *path, to others. */ pptr = path; - if (it->path) + if (it->path && !it->has_pattern) pptr = it->path; ret = it->handler(pptr, types, msg->argv, argc, msg, it->user_data); diff --git a/src/lo/server_thread.c b/src/lo/server_thread.c index ff3b847..e0927a7 100644 --- a/src/lo/server_thread.c +++ b/src/lo/server_thread.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/subtest.c b/src/lo/subtest.c deleted file mode 100644 index fb9a057..0000000 --- a/src/lo/subtest.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "compat.h" -/* - * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - * - * This program 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 - * GNU Lesser General Public License for more details. - * - * $Id$ - */ - -#include -#include -#include -#ifndef _MSC_VER -#include -#endif - -#include "lo/lo.h" - -static int subtest_count = 0; - -int subtest_handler(const char *path, const char *types, lo_arg ** argv, - int argc, lo_message data, void *user_data); - -int main(int argc, char *argv[]) -{ - lo_server_thread st; - lo_address t; - int tries; - - printf("entered subtest\n"); - - st = lo_server_thread_new(NULL, NULL); - - if (argc != 2) { - fprintf(stderr, "Usage: subtest \n"); - - return 1; - } - - lo_server_thread_add_method(st, NULL, "i", subtest_handler, NULL); - lo_server_thread_start(st); - - printf("subtest: creating new address `%s'\n", argv[1]); - t = lo_address_new_from_url(argv[1]); - lo_send(t, "/subtest", "i", 0xf00); - - tries = 400; - while (subtest_count == 0 && (--tries > 0)) { -#if defined(WIN32) || defined(_MSC_VER) - Sleep(10); -#else - usleep(10000); -#endif - } - - if (tries == 0) { - printf("subtest: too many tries\n"); - exit(1); - } - - return 0; -} - -int subtest_handler(const char *path, const char *types, lo_arg ** argv, - int argc, lo_message data, void *user_data) -{ - int i; - lo_address a = lo_message_get_source(data); - static char *uri = NULL; - - printf("subtest: got reply (%s)\n", path); - - if (!uri) { - uri = lo_address_get_url(a); - } else { - char *new_uri = lo_address_get_url(a); - - if (strcmp(uri, new_uri)) { - printf("ERROR: %s != %s\n", uri, new_uri); - - exit(1); - } - free(new_uri); - } - - lo_send(a, "/subtest-reply", "i", 0xbaa); - - if (lo_address_errno(a)) { - fprintf(stderr, "subtest error %d: %s\n", lo_address_errno(a), - lo_address_errstr(a)); - - exit(1); - } - - for (i = 0; i < 10; i++) { - lo_send(a, "/subtest-reply", "i", 0xbaa + i); -#if defined(WIN32) || defined(_MSC_VER) - Sleep(2); -#else - usleep(2000); -#endif - } - - subtest_count ++; - - return 0; -} - -/* vi:set ts=8 sts=4 sw=4: */ diff --git a/src/lo/timetag.c b/src/lo/timetag.c index 2aca6ef..ff73ecc 100644 --- a/src/lo/timetag.c +++ b/src/lo/timetag.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/lo/version.c b/src/lo/version.c index 963cf10..dad0a81 100644 --- a/src/lo/version.c +++ b/src/lo/version.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include /* * Copyright (C) 2014 Steve Harris et al. (see AUTHORS) * diff --git a/src/mapper.h b/src/mapper.h index 4cade71..7acecf8 100644 --- a/src/mapper.h +++ b/src/mapper.h @@ -1 +1 @@ -#include "mapper/mapper.h" \ No newline at end of file +#include "mapper/mapper.h" diff --git a/src/mapper/config.h b/src/mapper/config.h index 4f15801..8cf6048 100644 --- a/src/mapper/config.h +++ b/src/mapper/config.h @@ -98,7 +98,7 @@ #define PACKAGE_NAME "libmapper" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libmapper 1.2-155-ge732a23f" +#define PACKAGE_STRING "libmapper 1.2-301-g67458aad" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libmapper" @@ -107,7 +107,7 @@ #define PACKAGE_URL "http://libmapper.org" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.2-155-ge732a23f" +#define PACKAGE_VERSION "1.2-301-g67458aad" /* printf code for type long long int */ #define PRINTF_LL "ll" @@ -120,7 +120,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.2-155-ge732a23f" +#define VERSION "1.2-301-g67458aad" /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ diff --git a/src/mapper/device.c b/src/mapper/device.c index 6fab03e..dacbd71 100644 --- a/src/mapper/device.c +++ b/src/mapper/device.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -20,24 +20,18 @@ extern const char* net_msg_strings[NUM_MSG_STRINGS]; -#define DEV_SERVER_FUNC(FUNC, ...) \ -{ \ - lo_server_ ## FUNC(net->server.udp, __VA_ARGS__); \ - lo_server_ ## FUNC(net->server.tcp, __VA_ARGS__); \ -} - -// prototypes -void mpr_dev_start_servers(mpr_dev dev); -static void mpr_dev_remove_idmap(mpr_dev dev, int group, mpr_id_map rem); -static inline int mpr_dev_process_outputs_internal(mpr_dev dev, int idx); -static inline int fetch_and_add_bundle_idx(mpr_dev dev); +/* prototypes */ +void mpr_dev_start_servers(mpr_local_dev dev); +static void mpr_dev_remove_idmap(mpr_local_dev dev, int group, mpr_id_map rem); +MPR_INLINE static int _process_outgoing_maps(mpr_local_dev dev); mpr_time ts = {0,1}; static int cmp_qry_linked(const void *ctx, mpr_dev dev) { + int i; mpr_dev self = *(mpr_dev*)ctx; - for (int i = 0; i < self->num_linked; i++) { + for (i = 0; i < self->num_linked; i++) { if (!self->linked[i] || self->linked[i]->obj.id == dev->obj.id) return 1; } @@ -47,25 +41,26 @@ static int cmp_qry_linked(const void *ctx, mpr_dev dev) static int cmp_qry_dev_sigs(const void *context_data, mpr_sig sig) { mpr_id dev_id = *(mpr_id*)context_data; - int dir = *(int*)(context_data + sizeof(mpr_id)); + int dir = *(int*)((char*)context_data + sizeof(mpr_id)); return ((dir & sig->dir) && (dev_id == sig->dev->obj.id)); } void init_dev_prop_tbl(mpr_dev dev) { - dev->obj.props.mask = 0; + int mod = dev->is_local ? NON_MODIFIABLE : MODIFIABLE; + mpr_tbl tbl; + mpr_list qry; + dev->obj.props.synced = mpr_tbl_new(); - if (!dev->loc) + if (!dev->is_local) dev->obj.props.staged = mpr_tbl_new(); - int mod = dev->loc ? NON_MODIFIABLE : MODIFIABLE; - mpr_tbl tbl = dev->obj.props.synced; + tbl = dev->obj.props.synced; - // these properties need to be added in alphabetical order + /* these properties need to be added in alphabetical order */ mpr_tbl_link(tbl, PROP(DATA), 1, MPR_PTR, &dev->obj.data, LOCAL_MODIFY | INDIRECT | LOCAL_ACCESS_ONLY); mpr_tbl_link(tbl, PROP(ID), 1, MPR_INT64, &dev->obj.id, mod); - mpr_list qry = mpr_list_new_query((const void**)&dev->obj.graph->devs, - cmp_qry_linked, "v", &dev); + qry = mpr_list_new_query((const void**)&dev->obj.graph->devs, (void*)cmp_qry_linked, "v", &dev); mpr_tbl_link(tbl, PROP(LINKED), 1, MPR_LIST, qry, NON_MODIFIABLE | PROP_OWNED); mpr_tbl_link(tbl, PROP(NAME), 1, MPR_STR, &dev->name, mod | INDIRECT | LOCAL_ACCESS_ONLY); mpr_tbl_link(tbl, PROP(NUM_MAPS_IN), 1, MPR_INT32, &dev->num_maps_in, mod); @@ -73,18 +68,18 @@ void init_dev_prop_tbl(mpr_dev dev) mpr_tbl_link(tbl, PROP(NUM_SIGS_IN), 1, MPR_INT32, &dev->num_inputs, mod); mpr_tbl_link(tbl, PROP(NUM_SIGS_OUT), 1, MPR_INT32, &dev->num_outputs, mod); mpr_tbl_link(tbl, PROP(ORDINAL), 1, MPR_INT32, &dev->ordinal, mod); - if (!dev->loc) { - qry = mpr_list_new_query((const void**)&dev->obj.graph->sigs, - cmp_qry_dev_sigs, "hi", dev->obj.id, MPR_DIR_ANY); + if (!dev->is_local) { + qry = mpr_list_new_query((const void**)&dev->obj.graph->sigs, (void*)cmp_qry_dev_sigs, + "hi", dev->obj.id, MPR_DIR_ANY); mpr_tbl_link(tbl, PROP(SIG), 1, MPR_LIST, qry, NON_MODIFIABLE | PROP_OWNED); } mpr_tbl_link(tbl, PROP(STATUS), 1, MPR_INT32, &dev->status, mod | LOCAL_ACCESS_ONLY); mpr_tbl_link(tbl, PROP(SYNCED), 1, MPR_TIME, &dev->synced, mod | LOCAL_ACCESS_ONLY); mpr_tbl_link(tbl, PROP(VERSION), 1, MPR_INT32, &dev->obj.version, mod); - if (dev->loc) + if (dev->is_local) mpr_tbl_set(tbl, PROP(LIBVER), NULL, 1, MPR_STR, PACKAGE_VERSION, NON_MODIFIABLE); - mpr_tbl_set(tbl, PROP(IS_LOCAL), NULL, 1, MPR_BOOL, &dev->loc, + mpr_tbl_set(tbl, PROP(IS_LOCAL), NULL, 1, MPR_BOOL, &dev->is_local, LOCAL_ACCESS_ONLY | NON_MODIFIABLE); } @@ -92,7 +87,8 @@ void init_dev_prop_tbl(mpr_dev dev) * mpr_dev, not to create a representation of remote devices. */ mpr_dev mpr_dev_new(const char *name_prefix, mpr_graph g) { - RETURN_UNLESS(name_prefix, 0); + mpr_local_dev dev; + RETURN_ARG_UNLESS(name_prefix, 0); if (name_prefix[0] == '/') ++name_prefix; TRACE_RETURN_UNLESS(!strchr(name_prefix, '/'), NULL, "error: character '/' " @@ -102,78 +98,82 @@ mpr_dev mpr_dev_new(const char *name_prefix, mpr_graph g) g->own = 0; } - mpr_dev dev = (mpr_dev)mpr_list_add_item((void**)&g->devs, sizeof(mpr_dev_t)); + dev = (mpr_local_dev)mpr_list_add_item((void**)&g->devs, sizeof(mpr_local_dev_t)); dev->obj.type = MPR_DEV; dev->obj.graph = g; - dev->loc = (mpr_local_dev)calloc(1, sizeof(mpr_local_dev_t)); + dev->is_local = 1; - init_dev_prop_tbl(dev); + init_dev_prop_tbl((mpr_dev)dev); dev->prefix = strdup(name_prefix); mpr_dev_start_servers(dev); - if (!g->net.server.udp || !g->net.server.tcp) { - mpr_dev_free(dev); + if (!g->net.servers[SERVER_UDP] || !g->net.servers[SERVER_TCP]) { + mpr_dev_free((mpr_dev)dev); return NULL; } g->net.rtr = (mpr_rtr)calloc(1, sizeof(mpr_rtr_t)); g->net.rtr->dev = dev; - dev->loc->ordinal.val = 1; - dev->loc->idmaps.active = (mpr_id_map*) malloc(sizeof(mpr_id_map)); - dev->loc->idmaps.active[0] = 0; - dev->loc->num_sig_groups = 1; + dev->ordinal_allocator.val = 1; + dev->idmaps.active = (mpr_id_map*) malloc(sizeof(mpr_id_map)); + dev->idmaps.active[0] = 0; + dev->num_sig_groups = 1; mpr_net_add_dev(&g->net, dev); dev->status = MPR_STATUS_STAGED; - return dev; + return (mpr_dev)dev; } -//! Free resources used by a mpr device. +/*! Free resources used by a mpr device. */ void mpr_dev_free(mpr_dev dev) { - RETURN_UNLESS(dev && dev->loc); + mpr_graph gph; + mpr_net net; + mpr_local_dev ldev; + mpr_list list; + int i; + RETURN_UNLESS(dev && dev->is_local); if (!dev->obj.graph) { free(dev); return; } - mpr_graph gph = dev->obj.graph; - mpr_net net = &gph->net; + ldev = (mpr_local_dev)dev; + gph = dev->obj.graph; + net = &gph->net; - // free any queued graph messages without sending + /* free any queued graph messages without sending */ mpr_net_free_msgs(net); - // remove OSC handlers associated with this device - mpr_net_remove_dev_methods(net, dev); + /* remove OSC handlers associated with this device */ + mpr_net_remove_dev_methods(net, ldev); - // remove subscribers - mpr_subscriber sub; - while (dev->loc->subscribers) { - sub = dev->loc->subscribers; + /* remove subscribers */ + while (ldev->subscribers) { + mpr_subscriber sub = ldev->subscribers; FUNC_IF(lo_address_free, sub->addr); - dev->loc->subscribers = sub->next; + ldev->subscribers = sub->next; free(sub); } - int i; - mpr_list sigs = mpr_dev_get_sigs(dev, MPR_DIR_ANY); - while (sigs) { - mpr_sig sig = (mpr_sig)*sigs; - sigs = mpr_list_get_next(sigs); - if (sig->loc) { - // release active instances - for (i = 0; i < sig->loc->idmap_len; i++) { - if (sig->loc->idmaps[i].inst) + list = mpr_dev_get_sigs(dev, MPR_DIR_ANY); + while (list) { + mpr_local_sig sig = (mpr_local_sig)*list; + list = mpr_list_get_next(list); + if (sig->is_local) { + /* release active instances */ + for (i = 0; i < sig->idmap_len; i++) { + if (sig->idmaps[i].inst) mpr_sig_release_inst_internal(sig, i); } } - mpr_sig_free(sig); + mpr_sig_free((mpr_sig)sig); } - if (dev->loc->registered) { - // A registered device must tell the network it is leaving. + if (ldev->registered) { + /* A registered device must tell the network it is leaving. */ NEW_LO_MSG(msg, ;) if (msg) { mpr_net_use_bus(net); @@ -183,35 +183,28 @@ void mpr_dev_free(mpr_dev dev) } } - // Release links to other devices - int idx = fetch_and_add_bundle_idx(dev); - mpr_list links = mpr_dev_get_links(dev, MPR_DIR_ANY); - while (links) { - mpr_link link = (mpr_link)*links; - links = mpr_list_get_next(links); - while (idx != (dev->loc->bundle_idx % NUM_BUNDLES)) { - if (!mpr_dev_process_outputs_internal(dev, idx)) - break; - idx = (idx + 1) % NUM_BUNDLES; - } - dev->loc->polling = 0; + /* Release links to other devices */ + list = mpr_dev_get_links(dev, MPR_DIR_ANY); + while (list) { + mpr_link link = (mpr_link)*list; + list = mpr_list_get_next(list); + _process_outgoing_maps(ldev); mpr_graph_remove_link(gph, link, MPR_OBJ_REM); } - // Release device id maps - mpr_id_map map; - for (i = 0; i < dev->loc->num_sig_groups; i++) { - while (dev->loc->idmaps.active[i]) { - map = dev->loc->idmaps.active[i]; - dev->loc->idmaps.active[i] = map->next; + /* Release device id maps */ + for (i = 0; i < ldev->num_sig_groups; i++) { + while (ldev->idmaps.active[i]) { + mpr_id_map map = ldev->idmaps.active[i]; + ldev->idmaps.active[i] = map->next; free(map); } } - free(dev->loc->idmaps.active); + free(ldev->idmaps.active); - while (dev->loc->idmaps.reserve) { - map = dev->loc->idmaps.reserve; - dev->loc->idmaps.reserve = map->next; + while (ldev->idmaps.reserve) { + mpr_id_map map = ldev->idmaps.reserve; + ldev->idmaps.reserve = map->next; free(map); } @@ -224,47 +217,46 @@ void mpr_dev_free(mpr_dev dev) free(net->rtr); } - FUNC_IF(lo_server_free, net->server.udp); - FUNC_IF(lo_server_free, net->server.tcp); + FUNC_IF(lo_server_free, net->servers[SERVER_UDP]); + FUNC_IF(lo_server_free, net->servers[SERVER_TCP]); FUNC_IF(free, dev->prefix); - free(dev->loc); mpr_graph_remove_dev(gph, dev, MPR_OBJ_REM, 1); if (!gph->own) mpr_graph_free(gph); + + mpr_expr_free_buffers(); } -void mpr_dev_on_registered(mpr_dev dev) +void mpr_dev_on_registered(mpr_local_dev dev) { int i; + mpr_list qry; /* Add unique device id to locally-activated signal instances. */ - mpr_list sigs = mpr_dev_get_sigs(dev, MPR_DIR_ANY); + mpr_list sigs = mpr_dev_get_sigs((mpr_dev)dev, MPR_DIR_ANY); while (sigs) { - mpr_sig sig = (mpr_sig)*sigs; + mpr_local_sig sig = (mpr_local_sig)*sigs; sigs = mpr_list_get_next(sigs); - if (sig->loc) { - for (i = 0; i < sig->loc->idmap_len; i++) { - mpr_id_map idmap = sig->loc->idmaps[i].map; - if (idmap && !(idmap->GID >> 32)) - idmap->GID |= dev->obj.id; - } - sig->obj.id |= dev->obj.id; + for (i = 0; i < sig->idmap_len; i++) { + mpr_id_map idmap = sig->idmaps[i].map; + if (idmap && !(idmap->GID >> 32)) + idmap->GID |= dev->obj.id; } + sig->obj.id |= dev->obj.id; } - mpr_list qry = mpr_list_new_query((const void**)&dev->obj.graph->sigs, - cmp_qry_dev_sigs, "hi", dev->obj.id, MPR_DIR_ANY); + qry = mpr_list_new_query((const void**)&dev->obj.graph->sigs, (void*)cmp_qry_dev_sigs, + "hi", dev->obj.id, MPR_DIR_ANY); mpr_tbl_set(dev->obj.props.synced, PROP(SIG), NULL, 1, MPR_LIST, qry, NON_MODIFIABLE | PROP_OWNED); - dev->loc->registered = 1; - dev->ordinal = dev->loc->ordinal.val; + dev->registered = 1; + dev->ordinal = dev->ordinal_allocator.val; dev->status = MPR_STATUS_READY; } -static inline int check_types(const mpr_type *types, int len, mpr_type type, - int vector_len) +MPR_INLINE static int check_types(const mpr_type *types, int len, mpr_type type, int vector_len) { int i, vals = 0; - RETURN_UNLESS(len >= vector_len, -1); + RETURN_ARG_UNLESS(len >= vector_len, -1); for (i = 0; i < len; i++) { if (types[i] == type) ++vals; @@ -299,28 +291,30 @@ int mpr_dev_bundle_start(lo_timetag t, void *data) int mpr_dev_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *data) { - mpr_sig sig = (mpr_sig)data; - mpr_dev dev; + mpr_local_sig sig = (mpr_local_sig)data; + mpr_local_dev dev; + mpr_sig_inst si; mpr_rtr rtr = sig->obj.graph->net.rtr; - int i, val_len = 0, vals; - int idmap_idx, slot_idx = -1, map_manages_inst = 0; + int i, val_len = 0, vals, size, all; + int idmap_idx, inst_idx, slot_idx = -1, map_manages_inst = 0; mpr_id GID = 0; mpr_id_map idmap; - mpr_map map = 0; - mpr_slot slot = 0; + mpr_local_map map = 0; + mpr_local_slot slot = 0; + float diff; - TRACE_RETURN_UNLESS(sig && (dev = sig->dev), 0, "error in mpr_dev_handler, " - "cannot retrieve user data\n"); + TRACE_RETURN_UNLESS(sig && (dev = sig->dev), 0, + "error in mpr_dev_handler, cannot retrieve user data\n"); TRACE_DEV_RETURN_UNLESS(sig->num_inst, 0, "signal '%s' has no instances.\n", sig->name); - RETURN_UNLESS(argc, 0); + RETURN_ARG_UNLESS(argc, 0); - // We need to consider that there may be properties appended to the msg - // check length and find properties if any + /* We need to consider that there may be properties appended to the msg + * check length and find properties if any */ while (val_len < argc && types[val_len] != MPR_STR) ++val_len; i = val_len; while (i < argc) { - // Parse any attached properties (instance ids, slot number) + /* Parse any attached properties (instance ids, slot number) */ TRACE_DEV_RETURN_UNLESS(types[i] == MPR_STR, 0, "error in " "mpr_dev_handler: unexpected argument type.\n") if ((strcmp(&argv[i]->s, "@in") == 0) && argc >= i + 2) { @@ -344,113 +338,120 @@ int mpr_dev_handler(const char *path, const char *types, lo_arg **argv, int argc } if (slot_idx >= 0) { - // retrieve mapping associated with this slot + /* retrieve mapping associated with this slot */ slot = mpr_rtr_get_slot(rtr, sig, slot_idx); TRACE_DEV_RETURN_UNLESS(slot, 0, "error in mpr_dev_handler: slot %d not found.\n", slot_idx); map = slot->map; TRACE_DEV_RETURN_UNLESS(map->status >= MPR_STATUS_READY, 0, "error in mpr_dev_handler: " "mapping not yet ready.\n"); - TRACE_DEV_RETURN_UNLESS(map->loc->expr, 0, "error in mpr_dev_handler: missing expression.\n"); - if (map->process_loc == MPR_LOC_DST) { + if (map->expr && !map->is_local_only) { vals = check_types(types, val_len, slot->sig->type, slot->sig->len); - map_manages_inst = mpr_expr_get_manages_inst(map->loc->expr); + map_manages_inst = mpr_expr_get_manages_inst(map->expr); } else { - // value has already been processed at source device + /* value has already been processed at source device */ map = 0; vals = check_types(types, val_len, sig->type, sig->len); } } else vals = check_types(types, val_len, sig->type, sig->len); - RETURN_UNLESS(vals >= 0, 0); + RETURN_ARG_UNLESS(vals >= 0, 0); - // TODO: optionally discard out-of-order messages - // requires timebase sync for many-to-one mappings or local updates - // if (sig->discard_out_of_order && out_of_order(si->time, t)) - // return 0; + /* TODO: optionally discard out-of-order messages + * requires timebase sync for many-to-one mappings or local updates + * if (sig->discard_out_of_order && out_of_order(si->time, t)) + * return 0; + */ if (GID) { idmap_idx = mpr_sig_get_idmap_with_GID(sig, GID, RELEASED_LOCALLY, ts, 0); if (idmap_idx < 0) { - // no instance found with this map - // Don't activate instance just to release it again - RETURN_UNLESS(vals, 0); + /* No instance found with this map – don't activate instance just to release it again */ + RETURN_ARG_UNLESS(vals && sig->dir == MPR_DIR_IN, 0); if (map_manages_inst && vals == slot->sig->len) { /* special case: do a dry-run to check whether this map will * cause a release. If so, don't bother stealing an instance. */ - mpr_value_buffer_t b = {argv[0], 0, -1}; - mpr_value_t v = {&b, val_len, 1, slot->sig->type, 1}; - mpr_value src[map->num_src]; + mpr_value *src; + mpr_value_t v = {0, 0, 1, 0, 1}; + mpr_value_buffer_t b = {0, 0, -1}; + b.samps = argv[0]; + v.inst = &b; + v.vlen = val_len; + v.type = slot->sig->type; + src = alloca(map->num_src * sizeof(mpr_value)); for (i = 0; i < map->num_src; i++) - src[i] = (i == slot->obj.id) ? &v : 0; - int status = mpr_expr_eval(map->loc->expr, src, 0, 0, &ts, 0, 0); - if (status & EXPR_RELEASE_BEFORE_UPDATE) + src[i] = (i == slot->id) ? &v : 0; + if (mpr_expr_eval(map->expr, src, 0, 0, 0, 0, 0) & EXPR_RELEASE_BEFORE_UPDATE) return 0; } - // otherwise try to init reserved/stolen instance with device map + /* otherwise try to init reserved/stolen instance with device map */ idmap_idx = mpr_sig_get_idmap_with_GID(sig, GID, 0, ts, 1); - TRACE_DEV_RETURN_UNLESS(idmap_idx >= 0, 0, "no instances available" - " for GUID %"PR_MPR_ID" (1)\n", GID); + TRACE_DEV_RETURN_UNLESS(idmap_idx >= 0, 0, + "no instances available for GUID %"PR_MPR_ID" (1)\n", GID); } - else if (sig->loc->idmaps[idmap_idx].status & RELEASED_LOCALLY) { + else if (sig->idmaps[idmap_idx].status & RELEASED_LOCALLY) { /* map was already released locally, we are only interested in release messages */ if (0 == vals) { - // we can clear signal's reference to map - idmap = sig->loc->idmaps[idmap_idx].map; - sig->loc->idmaps[idmap_idx].map = 0; - mpr_dev_GID_decref(dev, sig->loc->group, idmap); + /* we can clear signal's reference to map */ + idmap = sig->idmaps[idmap_idx].map; + sig->idmaps[idmap_idx].map = 0; + mpr_dev_GID_decref(dev, sig->group, idmap); } return 0; } - TRACE_DEV_RETURN_UNLESS(sig->loc->idmaps[idmap_idx].inst, 0, "error in mpr_dev_handler: " - "missing instance!\n"); + TRACE_DEV_RETURN_UNLESS(sig->idmaps[idmap_idx].inst, 0, + "error in mpr_dev_handler: missing instance!\n"); } else { - // use the first available instance + /* use the first available instance */ idmap_idx = 0; - if (!sig->loc->idmaps[0].inst) - idmap_idx = mpr_sig_get_idmap_with_LID(sig, sig->loc->inst[0]->id, 1, ts, 1); - RETURN_UNLESS(idmap_idx >= 0, 0); + if (!sig->idmaps[0].inst) + idmap_idx = mpr_sig_get_idmap_with_LID(sig, sig->inst[0]->id, 1, ts, 1); + RETURN_ARG_UNLESS(idmap_idx >= 0, 0); } - mpr_sig_inst si = sig->loc->idmaps[idmap_idx].inst; - int inst_idx = si->idx; - float diff = mpr_time_get_diff(ts, si->time); - idmap = sig->loc->idmaps[idmap_idx].map; - - int size = mpr_type_get_size(slot ? slot->sig->type : sig->type); + si = sig->idmaps[idmap_idx].inst; + inst_idx = si->idx; + diff = mpr_time_get_diff(ts, si->time); + idmap = sig->idmaps[idmap_idx].map; + size = mpr_type_get_size(map ? slot->sig->type : sig->type); if (vals == 0) { if (GID) { - // TODO: mark SLOT status as remotely released rather than map - sig->loc->idmaps[idmap_idx].status |= RELEASED_REMOTELY; - mpr_dev_GID_decref(dev, sig->loc->group, idmap); + /* TODO: mark SLOT status as remotely released rather than map */ + sig->idmaps[idmap_idx].status |= RELEASED_REMOTELY; + mpr_dev_GID_decref(dev, sig->group, idmap); if (!sig->use_inst) { - // clear signal's reference to idmap - mpr_dev_LID_decref(dev, sig->loc->group, idmap); - sig->loc->idmaps[idmap_idx].map = 0; - sig->loc->idmaps[idmap_idx].inst->active = 0; - sig->loc->idmaps[idmap_idx].inst = 0; + /* clear signal's reference to idmap */ + mpr_dev_LID_decref(dev, sig->group, idmap); + sig->idmaps[idmap_idx].map = 0; + sig->idmaps[idmap_idx].inst->active = 0; + sig->idmaps[idmap_idx].inst = 0; return 0; } } - RETURN_UNLESS(sig->use_inst && (!map || map->use_inst), 0); + RETURN_ARG_UNLESS(sig->use_inst && (!map || map->use_inst), 0); /* Try to release instance, but do not call mpr_rtr_process_sig() here, since we don't * know if the local signal instance will actually be released. */ - int evt = MPR_SIG_REL_UPSTRM & sig->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE; - mpr_sig_call_handler(sig, evt, idmap->LID, 0, 0, &ts, diff); + if (sig->dir == MPR_DIR_IN) { + int evt = (MPR_SIG_REL_UPSTRM & sig->event_flags) ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE; + mpr_sig_call_handler(sig, evt, idmap->LID, 0, 0, &ts, diff); + } + else if (MPR_SIG_REL_DNSTRM & sig->event_flags) + mpr_sig_call_handler(sig, MPR_SIG_REL_DNSTRM, idmap->LID, 0, 0, &ts, diff); - RETURN_UNLESS(map && MPR_LOC_DST == map->process_loc, 0); + RETURN_ARG_UNLESS(map && MPR_LOC_DST == map->process_loc && sig->dir == MPR_DIR_IN, 0); /* Reset memory for corresponding source slot. */ - mpr_local_slot lslot = slot->loc; - // TODO: make a function (reset) - mpr_value_reset_inst(&lslot->val, inst_idx); + /* TODO: make a function (reset) */ + mpr_value_reset_inst(&slot->val, inst_idx); return 0; } + else if (sig->dir == MPR_DIR_OUT) + return 0; /* Partial vector updates are not allowed in convergent maps since the slot value mirrors the * remote signal value. */ @@ -462,113 +463,71 @@ int mpr_dev_handler(const char *path, const char *types, lo_arg **argv, int argc return 0; } - int all = !GID; + all = !GID; if (map) { /* Or if this signal slot is non-instanced but the map has other instanced * sources we will need to update all of the map instances. */ - all |= !map->use_inst || (!slot->sig->use_inst && map->num_src > 1 && map->loc->num_inst > 1); + all |= !map->use_inst || (!slot->sig->use_inst && map->num_src > 1 && map->num_inst > 1); } if (all) idmap_idx = 0; - for (; idmap_idx < sig->loc->idmap_len; idmap_idx++) { - // check if map instance is active - if (all && !(si = sig->loc->idmaps[idmap_idx].inst)) - continue; - - inst_idx = sig->loc->idmaps[idmap_idx].inst->idx; - idmap = sig->loc->idmaps[idmap_idx].map; - - int status = MPR_SIG_UPDATE; - mpr_type *typestring = 0; - if (map) { - mpr_local_slot lslot = slot->loc; - - /* TODO: would be more efficient not to allocate memory for multiple - * instances if slot is single-instance. */ - mpr_value_set_sample(&lslot->val, inst_idx, argv[0], ts); - if (!slot->causes_update) - continue; - typestring = alloca(map->dst->sig->len * sizeof(mpr_type)); - status = mpr_map_perform(map, typestring, &ts, inst_idx); - if (!map->use_inst || !sig->use_inst) - status &= EXPR_UPDATE; - } - - if (status & EXPR_RELEASE_BEFORE_UPDATE) { - // TODO: release map-tracked instance - /* Try to release instance, but do not call mpr_rtr_process_sig() here, since we don't - * know if the local signal instance will actually be released. */ - int evt = MPR_SIG_REL_UPSTRM & sig->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE; - mpr_sig_call_handler(sig, evt, idmap->LID, 0, 0, &ts, diff); + if (map) { + for (; idmap_idx < sig->idmap_len; idmap_idx++) { + /* check if map instance is active */ + if ((si = sig->idmaps[idmap_idx].inst)) { + inst_idx = si->idx; + /* Setting to local timestamp here */ + /* TODO: jitter mitigation etc. */ + mpr_value_set_sample(&slot->val, inst_idx, argv[0], dev->time); + set_bitflag(map->updated_inst, inst_idx); + map->updated = 1; + dev->receiving = 1; + } + if (!all) + break; } + return 0; + } - if (status & EXPR_UPDATE) { - if (map) { - void *result = mpr_value_get_samp(&map->dst->loc->val, inst_idx); - // TODO: create new map->idmap -// if (map_manages_inst) { -// if (!idmap) { -// // create an id_map and store it in the map -// mpr_id GID = mpr_dev_generate_unique_id(sig->dev); -// idmap = map->idmap = mpr_dev_add_idmap(sig->dev, sig->loc->group, 0, GID); -// } -// } - for (i = 0; i < sig->len; i++) { - if (typestring[i] == MPR_NULL) - continue; - memcpy(si->val + i * size, result + i * size, size); - si->has_val_flags[i / 8] |= 1 << (i % 8); - } + for (; idmap_idx < sig->idmap_len; idmap_idx++) { + /* check if instance is active */ + if ((si = sig->idmaps[idmap_idx].inst)) { + idmap = sig->idmaps[idmap_idx].map; + for (i = 0; i < sig->len; i++) { + if (types[i] == MPR_NULL) + continue; + memcpy((char*)si->val + i * size, argv[i], size); + set_bitflag(si->has_val_flags, i); } - else { - for (i = 0; i < sig->len; i++) { - if (types[i] == MPR_NULL) - continue; - memcpy(si->val + i * size, argv[i], size); - si->has_val_flags[i / 8] |= 1 << (i % 8); - } - } - - if (memcmp(si->has_val_flags, sig->loc->vec_known, sig->len / 8 + 1)==0) + if (!compare_bitflags(si->has_val_flags, sig->vec_known, sig->len)) si->has_val = 1; if (si->has_val) { memcpy(&si->time, &ts, sizeof(mpr_time)); mpr_sig_call_handler(sig, MPR_SIG_UPDATE, idmap->LID, sig->len, si->val, &ts, diff); - // check if instance was released - if (si->active) { - // TODO: only call next line if sig was not updated in handler - // TODO: package outgoing updates in a bundle - if (!(sig->dir & MPR_DIR_OUT)) - mpr_rtr_process_sig(rtr, sig, idmap_idx, si->val, ts); + /* Pass this update downstream if signal is an input and was not updated in handler. */ + if ( !(sig->dir & MPR_DIR_OUT) + && !get_bitflag(sig->updated_inst, si->idx)) { + mpr_rtr_process_sig(rtr, sig, idmap_idx, si->val, ts); + /* TODO: ensure update is propagated within this poll cycle */ } } } - - if (status & EXPR_RELEASE_AFTER_UPDATE) { - // TODO: release map-tracked instance - /* Try to release instance, but do not call mpr_rtr_process_sig() here, since we don't - * know if the local signal instance will actually be released. */ - int evt = MPR_SIG_REL_UPSTRM & sig->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE; - mpr_sig_call_handler(sig, evt, idmap->LID, 0, 0, &ts, diff); - } - if (!all) break; } - return 0; } -mpr_id mpr_dev_get_unused_sig_id(mpr_dev dev) +mpr_id mpr_dev_get_unused_sig_id(mpr_local_dev dev) { int done = 0; mpr_id id; while (!done) { + mpr_list l = mpr_dev_get_sigs((mpr_dev)dev, MPR_DIR_ANY); + id = mpr_dev_generate_unique_id((mpr_dev)dev); + /* check if input signal exists with this id */ done = 1; - id = mpr_dev_generate_unique_id(dev); - // check if input signal exists with this id - mpr_list l = mpr_dev_get_sigs(dev, MPR_DIR_ANY); while (l) { if ((*l)->id == id) { done = 0; @@ -581,40 +540,48 @@ mpr_id mpr_dev_get_unused_sig_id(mpr_dev dev) return id; } -void mpr_dev_add_sig_methods(mpr_dev dev, mpr_sig sig) +void mpr_dev_add_sig_methods(mpr_local_dev dev, mpr_local_sig sig) { - RETURN_UNLESS(sig && sig->loc); - mpr_net net = &dev->obj.graph->net; - DEV_SERVER_FUNC(add_method, sig->path, NULL, mpr_dev_handler, (void*)sig); - ++dev->loc->n_output_callbacks; + mpr_net net; + RETURN_UNLESS(sig && sig->is_local); + net = &dev->obj.graph->net; + lo_server_add_method(net->servers[SERVER_UDP], sig->path, NULL, mpr_dev_handler, (void*)sig); + lo_server_add_method(net->servers[SERVER_TCP], sig->path, NULL, mpr_dev_handler, (void*)sig); + ++dev->n_output_callbacks; } -void mpr_dev_remove_sig_methods(mpr_dev dev, mpr_sig sig) +void mpr_dev_remove_sig_methods(mpr_local_dev dev, mpr_local_sig sig) { - RETURN_UNLESS(sig && sig->loc); - mpr_net net = &dev->obj.graph->net; + mpr_net net; char *path = 0; - int len = (int)strlen(sig->path) + 5; + int len; + RETURN_UNLESS(sig && sig->is_local); + net = &dev->obj.graph->net; + len = (int)strlen(sig->path) + 5; path = (char*)realloc(path, len); snprintf(path, len, "%s%s", sig->path, "/get"); - DEV_SERVER_FUNC(del_method, path, NULL); + lo_server_del_method(net->servers[SERVER_UDP], path, NULL); + lo_server_del_method(net->servers[SERVER_TCP], path, NULL); free(path); - DEV_SERVER_FUNC(del_method, sig->path, NULL); - --dev->loc->n_output_callbacks; + lo_server_del_method(net->servers[SERVER_UDP], sig->path, NULL); + lo_server_del_method(net->servers[SERVER_TCP], sig->path, NULL); + --dev->n_output_callbacks; } mpr_list mpr_dev_get_sigs(mpr_dev dev, mpr_dir dir) { - RETURN_UNLESS(dev && dev->obj.graph->sigs, 0); - mpr_list qry = mpr_list_new_query((const void**)&dev->obj.graph->sigs, - cmp_qry_dev_sigs, "hi", dev->obj.id, dir); + mpr_list qry; + RETURN_ARG_UNLESS(dev && dev->obj.graph->sigs, 0); + qry = mpr_list_new_query((const void**)&dev->obj.graph->sigs, + (void*)cmp_qry_dev_sigs, "hi", dev->obj.id, dir); return mpr_list_start(qry); } mpr_sig mpr_dev_get_sig_by_name(mpr_dev dev, const char *sig_name) { - RETURN_UNLESS(dev, 0); - mpr_list sigs = mpr_list_from_data(dev->obj.graph->sigs); + mpr_list sigs; + RETURN_ARG_UNLESS(dev, 0); + sigs = mpr_list_from_data(dev->obj.graph->sigs); while (sigs) { mpr_sig sig = (mpr_sig)*sigs; if ((sig->dev == dev) && strcmp(sig->name, skip_slash(sig_name))==0) @@ -627,35 +594,36 @@ mpr_sig mpr_dev_get_sig_by_name(mpr_dev dev, const char *sig_name) static int cmp_qry_dev_maps(const void *context_data, mpr_map map) { mpr_id dev_id = *(mpr_id*)context_data; - mpr_dir dir = *(int*)(context_data + sizeof(mpr_id)); + mpr_dir dir = *(int*)((char*)context_data + sizeof(mpr_id)); int i; if (dir == MPR_DIR_BOTH) { - RETURN_UNLESS(map->dst->sig->dev->obj.id == dev_id, 0); + RETURN_ARG_UNLESS(map->dst->sig->dev->obj.id == dev_id, 0); for (i = 0; i < map->num_src; i++) - RETURN_UNLESS(map->src[i]->sig->dev->obj.id == dev_id, 0); + RETURN_ARG_UNLESS(map->src[i]->sig->dev->obj.id == dev_id, 0); return 1; } if (dir & MPR_DIR_OUT) { for (i = 0; i < map->num_src; i++) - RETURN_UNLESS(map->src[i]->sig->dev->obj.id != dev_id, 1); + RETURN_ARG_UNLESS(map->src[i]->sig->dev->obj.id != dev_id, 1); } if (dir & MPR_DIR_IN) - RETURN_UNLESS(map->dst->sig->dev->obj.id != dev_id, 1); + RETURN_ARG_UNLESS(map->dst->sig->dev->obj.id != dev_id, 1); return 0; } mpr_list mpr_dev_get_maps(mpr_dev dev, mpr_dir dir) { - RETURN_UNLESS(dev && dev->obj.graph->maps, 0); - mpr_list qry = mpr_list_new_query((const void**)&dev->obj.graph->maps, - cmp_qry_dev_maps, "hi", dev->obj.id, dir); + mpr_list qry; + RETURN_ARG_UNLESS(dev && dev->obj.graph->maps, 0); + qry = mpr_list_new_query((const void**)&dev->obj.graph->maps, + (void*)cmp_qry_dev_maps, "hi", dev->obj.id, dir); return mpr_list_start(qry); } static int cmp_qry_dev_links(const void *context_data, mpr_link link) { mpr_id dev_id = *(mpr_id*)context_data; - mpr_dir dir = *(int*)(context_data + sizeof(mpr_id)); + mpr_dir dir = *(int*)((char*)context_data + sizeof(mpr_id)); if (link->devs[0]->obj.id == dev_id) { switch (dir) { case MPR_DIR_BOTH: return link->num_maps[0] && link->num_maps[1]; @@ -677,81 +645,107 @@ static int cmp_qry_dev_links(const void *context_data, mpr_link link) mpr_list mpr_dev_get_links(mpr_dev dev, mpr_dir dir) { - RETURN_UNLESS(dev && dev->obj.graph->links, 0); - mpr_list qry = mpr_list_new_query((const void**)&dev->obj.graph->links, - cmp_qry_dev_links, "hi", dev->obj.id, dir); + mpr_list qry; + RETURN_ARG_UNLESS(dev && dev->obj.graph->links, 0); + qry = mpr_list_new_query((const void**)&dev->obj.graph->links, + (void*)cmp_qry_dev_links, "hi", dev->obj.id, dir); return mpr_list_start(qry); } -mpr_link mpr_dev_get_link_by_remote(mpr_dev dev, mpr_dev remote) +mpr_link mpr_dev_get_link_by_remote(mpr_local_dev dev, mpr_dev remote) { - RETURN_UNLESS(dev, 0); - mpr_list links = mpr_list_from_data(dev->obj.graph->links); + mpr_list links; + RETURN_ARG_UNLESS(dev, 0); + links = mpr_list_from_data(dev->obj.graph->links); while (links) { mpr_link link = (mpr_link)*links; - if (link->devs[0] == dev && link->devs[1] == remote) + if (link->devs[0] == (mpr_dev)dev && link->devs[1] == remote) return link; - if (link->devs[1] == dev && link->devs[0] == remote) + if (link->devs[1] == (mpr_dev)dev && link->devs[0] == remote) return link; links = mpr_list_get_next(links); } return 0; } -// TODO: handle interrupt-driven updates that omit call to this function -static inline int mpr_dev_process_outputs_internal(mpr_dev dev, int idx) +/* TODO: handle interrupt-driven updates that omit call to this function */ +MPR_INLINE static void _process_incoming_maps(mpr_local_dev dev) { - mpr_list links = mpr_list_from_data(dev->obj.graph->links); - int msgs = 0; - while (links) { - msgs += mpr_link_process_bundles((mpr_link)*links, dev->loc->time, idx); - links = mpr_list_get_next(links); + mpr_graph graph; + mpr_list maps; + RETURN_UNLESS(dev->receiving); + graph = dev->obj.graph; + /* process and send updated maps */ + /* TODO: speed this up! */ + dev->receiving = 0; + maps = mpr_list_from_data(graph->maps); + while (maps) { + mpr_local_map map = *(mpr_local_map*)maps; + maps = mpr_list_get_next(maps); + if (map->is_local && map->updated && map->expr && !map->muted) + mpr_map_receive(map, dev->time); } - return msgs ? 1 : 0; } -// increase bundle idx and return previous index -static inline int fetch_and_add_bundle_idx(mpr_dev dev) +/* TODO: handle interrupt-driven updates that omit call to this function */ +MPR_INLINE static int _process_outgoing_maps(mpr_local_dev dev) { - // is it possible to simultaneously add to bundle idx and clear "updated" flag? - int idx = __sync_fetch_and_add(&dev->loc->bundle_idx, dev->loc->updated); - dev->loc->updated = 0; - return idx % NUM_BUNDLES; + int msgs = 0; + mpr_list list; + mpr_graph graph; + RETURN_ARG_UNLESS(dev->sending, 0); + + graph = dev->obj.graph; + /* process and send updated maps */ + /* TODO: speed this up! */ + list = mpr_list_from_data(graph->maps); + while (list) { + mpr_local_map map = *(mpr_local_map*)list; + list = mpr_list_get_next(list); + if (map->is_local && map->updated && map->expr && !map->muted) + mpr_map_send(map, dev->time); + } + dev->sending = 0; + list = mpr_list_from_data(graph->links); + while (list) { + msgs += mpr_link_process_bundles((mpr_link)*list, dev->time, 0); + list = mpr_list_get_next(list); + } + return msgs ? 1 : 0; } -void mpr_dev_process_outputs(mpr_dev dev) { - RETURN_UNLESS(dev && dev->loc); - int idx = fetch_and_add_bundle_idx(dev); - dev->loc->time_is_stale = 1; - if (!dev->loc->polling) - mpr_dev_process_outputs_internal(dev, idx); +void mpr_dev_update_maps(mpr_dev dev) { + RETURN_UNLESS(dev && dev->is_local); + ((mpr_local_dev)dev)->time_is_stale = 1; + if (!((mpr_local_dev)dev)->polling) + _process_outgoing_maps((mpr_local_dev)dev); } int mpr_dev_poll(mpr_dev dev, int block_ms) { - RETURN_UNLESS(dev && dev->loc, 0); - int admin_count = 0, device_count = 0, status[4]; - mpr_net net = &dev->obj.graph->net; + mpr_net net; + RETURN_ARG_UNLESS(dev && dev->is_local, 0); + net = &dev->obj.graph->net; mpr_net_poll(net); - if (!dev->loc->registered) { - if (lo_servers_recv_noblock(net->server.admin, status, 2, block_ms)) { + if (!((mpr_local_dev)dev)->registered) { + if (lo_servers_recv_noblock(&net->servers[SERVER_ADMIN], status, 2, block_ms)) { admin_count = (status[0] > 0) + (status[1] > 0); net->msgs_recvd |= admin_count; } - dev->loc->bundle_idx = 1; + ((mpr_local_dev)dev)->bundle_idx = 1; return admin_count; } - dev->loc->polling = 1; - int idx = fetch_and_add_bundle_idx(dev); - dev->loc->time_is_stale = 1; - idx = (idx + mpr_dev_process_outputs_internal(dev, idx)) % NUM_BUNDLES; - dev->loc->polling = 0; + ((mpr_local_dev)dev)->polling = 1; + ((mpr_local_dev)dev)->time_is_stale = 1; + mpr_dev_get_time(dev); + _process_outgoing_maps((mpr_local_dev)dev); + ((mpr_local_dev)dev)->polling = 0; if (!block_ms) { - if (lo_servers_recv_noblock(net->server.all, status, 4, 0)) { + if (lo_servers_recv_noblock(net->servers, status, 4, 0)) { admin_count = (status[0] > 0) + (status[1] > 0); device_count = (status[2] > 0) + (status[3] > 0); net->msgs_recvd |= admin_count; @@ -761,21 +755,18 @@ int mpr_dev_poll(mpr_dev dev, int block_ms) double then = mpr_get_current_time(); int left_ms = block_ms, elapsed, checked_admin = 0; while (left_ms > 0) { - // set timeout to a maximum of 100ms + /* set timeout to a maximum of 100ms */ if (left_ms > 100) left_ms = 100; - dev->loc->polling = 1; - if (lo_servers_recv_noblock(net->server.all, status, 4, left_ms)) { + ((mpr_local_dev)dev)->polling = 1; + if (lo_servers_recv_noblock(net->servers, status, 4, left_ms)) { admin_count += (status[0] > 0) + (status[1] > 0); device_count += (status[2] > 0) + (status[3] > 0); } - // check if any signal update bundles need to be sent - while (idx != (dev->loc->bundle_idx % NUM_BUNDLES)) { - if (!mpr_dev_process_outputs_internal(dev, idx)) - break; - idx = (idx + 1) % NUM_BUNDLES; - } - dev->loc->polling = 0; + /* check if any signal update bundles need to be sent */ + _process_incoming_maps((mpr_local_dev)dev); + _process_outgoing_maps((mpr_local_dev)dev); + ((mpr_local_dev)dev)->polling = 0; elapsed = (mpr_get_current_time() - then) * 1000; if ((elapsed - checked_admin) > 100) { @@ -790,22 +781,19 @@ int mpr_dev_poll(mpr_dev dev, int block_ms) * proportion of the number of input signals. Arbitrarily choosing 1 for * now, but perhaps could be a heuristic based on a recent number of * messages per channel per poll. */ - while (device_count < (dev->num_inputs + dev->loc->n_output_callbacks)*1 - && (lo_servers_recv_noblock(net->server.dev, &status[2], 2, 0))) + while (device_count < (dev->num_inputs + ((mpr_local_dev)dev)->n_output_callbacks)*1 + && (lo_servers_recv_noblock(&net->servers[SERVER_DEVICE], &status[2], 2, 0))) device_count += (status[2] > 0) + (status[3] > 0); - // process any outputs cached during interrupts - dev->loc->polling = 1; - while (idx != (dev->loc->bundle_idx % NUM_BUNDLES)) { - if (!mpr_dev_process_outputs_internal(dev, idx)) - break; - idx = (idx + 1) % NUM_BUNDLES; - } - dev->loc->polling = 0; + /* process incoming maps */ + ((mpr_local_dev)dev)->polling = 1; + _process_incoming_maps((mpr_local_dev)dev); + ((mpr_local_dev)dev)->polling = 0; - if (dev->obj.props.synced->dirty && mpr_dev_get_is_ready(dev) && dev->loc->subscribers) { - // inform device subscribers of changed properties - mpr_net_use_subscribers(net, dev, MPR_DEV); + if (dev->obj.props.synced->dirty && mpr_dev_get_is_ready(dev) + && ((mpr_local_dev)dev)->subscribers) { + /* inform device subscribers of changed properties */ + mpr_net_use_subscribers(net, (mpr_local_dev)dev, MPR_DEV); mpr_dev_send_state(dev, MSG_DEV); } @@ -815,60 +803,61 @@ int mpr_dev_poll(mpr_dev dev, int block_ms) mpr_time mpr_dev_get_time(mpr_dev dev) { - RETURN_UNLESS(dev && dev->loc, MPR_NOW); - if (dev->loc->time_is_stale) + RETURN_ARG_UNLESS(dev && dev->is_local, MPR_NOW); + if (((mpr_local_dev)dev)->time_is_stale) mpr_dev_set_time(dev, MPR_NOW); - return dev->loc->time; + return ((mpr_local_dev)dev)->time; } void mpr_dev_set_time(mpr_dev dev, mpr_time time) { - RETURN_UNLESS(dev && dev->loc && memcmp(&time, &dev->loc->time, sizeof(mpr_time))); - mpr_time_set(&dev->loc->time, time); - dev->loc->time_is_stale = 0; - if (!dev->loc->polling) - mpr_dev_process_outputs_internal(dev, fetch_and_add_bundle_idx(dev)); + RETURN_UNLESS(dev && dev->is_local + && memcmp(&time, &((mpr_local_dev)dev)->time, sizeof(mpr_time))); + mpr_time_set(&((mpr_local_dev)dev)->time, time); + ((mpr_local_dev)dev)->time_is_stale = 0; + if (!((mpr_local_dev)dev)->polling) + _process_outgoing_maps((mpr_local_dev)dev); } -void mpr_dev_reserve_idmap(mpr_dev dev) +void mpr_dev_reserve_idmap(mpr_local_dev dev) { mpr_id_map map; map = (mpr_id_map)calloc(1, sizeof(mpr_id_map_t)); - map->next = dev->loc->idmaps.reserve; - dev->loc->idmaps.reserve = map; + map->next = dev->idmaps.reserve; + dev->idmaps.reserve = map; } -mpr_id_map mpr_dev_add_idmap(mpr_dev dev, int group, mpr_id LID, mpr_id GID) +mpr_id_map mpr_dev_add_idmap(mpr_local_dev dev, int group, mpr_id LID, mpr_id GID) { - if (!dev->loc->idmaps.reserve) + mpr_id_map map; + if (!dev->idmaps.reserve) mpr_dev_reserve_idmap(dev); - - mpr_id_map map = dev->loc->idmaps.reserve; + map = dev->idmaps.reserve; map->LID = LID; - map->GID = GID; + map->GID = GID ? GID : mpr_dev_generate_unique_id((mpr_dev)dev); map->LID_refcount = 1; map->GID_refcount = 0; - dev->loc->idmaps.reserve = map->next; - map->next = dev->loc->idmaps.active[group]; - dev->loc->idmaps.active[group] = map; + dev->idmaps.reserve = map->next; + map->next = dev->idmaps.active[group]; + dev->idmaps.active[group] = map; return map; } -static void mpr_dev_remove_idmap(mpr_dev dev, int group, mpr_id_map rem) +static void mpr_dev_remove_idmap(mpr_local_dev dev, int group, mpr_id_map rem) { - mpr_id_map *map = &dev->loc->idmaps.active[group]; + mpr_id_map *map = &dev->idmaps.active[group]; while (*map) { if ((*map) == rem) { *map = (*map)->next; - rem->next = dev->loc->idmaps.reserve; - dev->loc->idmaps.reserve = rem; + rem->next = dev->idmaps.reserve; + dev->idmaps.reserve = rem; break; } map = &(*map)->next; } } -int mpr_dev_LID_decref(mpr_dev dev, int group, mpr_id_map map) +int mpr_dev_LID_decref(mpr_local_dev dev, int group, mpr_id_map map) { --map->LID_refcount; if (map->LID_refcount <= 0) { @@ -881,7 +870,7 @@ int mpr_dev_LID_decref(mpr_dev dev, int group, mpr_id_map map) return 0; } -int mpr_dev_GID_decref(mpr_dev dev, int group, mpr_id_map map) +int mpr_dev_GID_decref(mpr_local_dev dev, int group, mpr_id_map map) { --map->GID_refcount; if (map->GID_refcount <= 0) { @@ -894,9 +883,9 @@ int mpr_dev_GID_decref(mpr_dev dev, int group, mpr_id_map map) return 0; } -mpr_id_map mpr_dev_get_idmap_by_LID(mpr_dev dev, int group, mpr_id LID) +mpr_id_map mpr_dev_get_idmap_by_LID(mpr_local_dev dev, int group, mpr_id LID) { - mpr_id_map map = dev->loc->idmaps.active[group]; + mpr_id_map map = dev->idmaps.active[group]; while (map) { if (map->LID == LID) return map; @@ -905,9 +894,9 @@ mpr_id_map mpr_dev_get_idmap_by_LID(mpr_dev dev, int group, mpr_id LID) return 0; } -mpr_id_map mpr_dev_get_idmap_by_GID(mpr_dev dev, int group, mpr_id GID) +mpr_id_map mpr_dev_get_idmap_by_GID(mpr_local_dev dev, int group, mpr_id GID) { - mpr_id_map map = dev->loc->idmaps.active[group]; + mpr_id_map map = dev->idmaps.active[group]; while (map) { if (map->GID == GID) return map; @@ -922,59 +911,63 @@ static void handler_error(int num, const char *msg, const char *where) trace_net("[libmapper] liblo server error %d in path %s: %s\n", num, where, msg); } -void mpr_dev_start_servers(mpr_dev dev) +void mpr_dev_start_servers(mpr_local_dev dev) { + int portnum; + char port[16], *pport = 0, *url, *host; mpr_net net = &dev->obj.graph->net; - RETURN_UNLESS(!net->server.udp && !net->server.tcp); - - char port[16], *pport = 0; - while (!(net->server.udp = lo_server_new(pport, handler_error))) + mpr_list sigs; + RETURN_UNLESS(!net->servers[SERVER_UDP] && !net->servers[SERVER_TCP]); + while (!(net->servers[SERVER_UDP] = lo_server_new(pport, handler_error))) pport = 0; - snprintf(port, 16, "%d", lo_server_get_port(net->server.udp)); + snprintf(port, 16, "%d", lo_server_get_port(net->servers[SERVER_UDP])); pport = port; - while (!(net->server.tcp = lo_server_new_with_proto(pport, LO_TCP, handler_error))) + while (!(net->servers[SERVER_TCP] = lo_server_new_with_proto(pport, LO_TCP, handler_error))) pport = 0; - // Disable liblo message queueing - DEV_SERVER_FUNC(enable_queue, 0, 1); + /* Disable liblo message queueing */ + lo_server_enable_queue(net->servers[SERVER_UDP], 0, 1); + lo_server_enable_queue(net->servers[SERVER_TCP], 0, 1); - // Add bundle handlers - DEV_SERVER_FUNC(add_bundle_handlers, mpr_dev_bundle_start, NULL, (void*)dev); + /* Add bundle handlers */ + lo_server_add_bundle_handlers(net->servers[SERVER_UDP], mpr_dev_bundle_start, NULL, (void*)dev); + lo_server_add_bundle_handlers(net->servers[SERVER_TCP], mpr_dev_bundle_start, NULL, (void*)dev); - int portnum = lo_server_get_port(net->server.udp); - mpr_tbl_set(dev->obj.props.synced, PROP(PORT), NULL, 1, MPR_INT32, &portnum, - NON_MODIFIABLE); + portnum = lo_server_get_port(net->servers[SERVER_UDP]); + mpr_tbl_set(dev->obj.props.synced, PROP(PORT), NULL, 1, MPR_INT32, &portnum, NON_MODIFIABLE); trace_dev(dev, "bound to UDP port %i\n", portnum); - trace_dev(dev, "bound to TCP port %i\n", lo_server_get_port(net->server.tcp)); + trace_dev(dev, "bound to TCP port %i\n", lo_server_get_port(net->servers[SERVER_TCP])); - char *url = lo_server_get_url(net->server.udp); - char *host = lo_url_get_hostname(url); - mpr_tbl_set(dev->obj.props.synced, PROP(HOST), NULL, 1, MPR_STR, host, - NON_MODIFIABLE); + url = lo_server_get_url(net->servers[SERVER_UDP]); + host = lo_url_get_hostname(url); + mpr_tbl_set(dev->obj.props.synced, PROP(HOST), NULL, 1, MPR_STR, host, NON_MODIFIABLE); free(host); free(url); - // add signal methods - mpr_list sigs = mpr_dev_get_sigs(dev, MPR_DIR_ANY); + /* add signal methods */ + sigs = mpr_dev_get_sigs((mpr_dev)dev, MPR_DIR_ANY); while (sigs) { - mpr_sig sig = (mpr_sig)*sigs; + mpr_local_sig sig = (mpr_local_sig)*sigs; sigs = mpr_list_get_next(sigs); - if (sig->loc->handler) - DEV_SERVER_FUNC(add_method, sig->path, NULL, mpr_dev_handler, - (void*)sig); + if (sig->handler) { + lo_server_add_method(net->servers[SERVER_UDP], sig->path, NULL, mpr_dev_handler, (void*)sig); + lo_server_add_method(net->servers[SERVER_TCP], sig->path, NULL, mpr_dev_handler, (void*)sig); + } } } const char *mpr_dev_get_name(mpr_dev dev) { - RETURN_UNLESS(!dev->loc || (dev->loc->registered && dev->loc->ordinal.locked), 0); + unsigned int len; + RETURN_ARG_UNLESS(!dev->is_local || ( ((mpr_local_dev)dev)->registered + && ((mpr_local_dev)dev)->ordinal_allocator.locked), 0); if (dev->name) return dev->name; - unsigned int len = strlen(dev->prefix) + 6; + len = strlen(dev->prefix) + 6; dev->name = (char*)malloc(len); dev->name[0] = 0; - snprintf(dev->name, len, "%s.%d", dev->prefix, dev->loc->ordinal.val); + snprintf(dev->name, len, "%s.%d", dev->prefix, ((mpr_local_dev)dev)->ordinal_allocator.val); return dev->name; } @@ -985,25 +978,25 @@ int mpr_dev_get_is_ready(mpr_dev dev) mpr_id mpr_dev_generate_unique_id(mpr_dev dev) { - RETURN_UNLESS(dev, 0); - mpr_id id = ++dev->obj.graph->resource_counter; - if (dev->loc && dev->loc->registered) + mpr_id id; + RETURN_ARG_UNLESS(dev, 0); + id = ++dev->obj.graph->resource_counter; + if (dev->is_local && ((mpr_local_dev)dev)->registered) id |= dev->obj.id; return id; } void mpr_dev_send_state(mpr_dev dev, net_msg_t cmd) { - RETURN_UNLESS(dev); + mpr_net net = &dev->obj.graph->net; NEW_LO_MSG(msg, return); /* device name */ - lo_message_add_string(msg, mpr_dev_get_name(dev)); + lo_message_add_string(msg, mpr_dev_get_name((mpr_dev)dev)); /* properties */ - mpr_tbl_add_to_msg(dev->loc ? dev->obj.props.synced : 0, dev->obj.props.staged, msg); + mpr_tbl_add_to_msg(dev->is_local ? dev->obj.props.synced : 0, dev->obj.props.staged, msg); - mpr_net net = &dev->obj.graph->net; if (cmd == MSG_DEV_MOD) { char str[1024]; snprintf(str, 1024, "/%s/modify", dev->name); @@ -1024,7 +1017,7 @@ int mpr_dev_add_link(mpr_dev dev, mpr_dev rem) return 0; } - // not found - add a new linked device + /* not found - add a new linked device */ i = ++dev->num_linked; dev->linked = realloc(dev->linked, i * sizeof(mpr_dev)); dev->linked[i-1] = rem; @@ -1051,15 +1044,15 @@ static int mpr_dev_update_linked(mpr_dev dev, mpr_msg_atom a) int i, j, updated = 0, num = a->len; lo_arg **link_list = a->vals; if (link_list && *link_list) { + const char *name; if (num == 1 && strcmp(&link_list[0]->s, "none")==0) num = 0; - const char *name; - // Remove any old links that are missing + /* Remove any old links that are missing */ for (i = 0; ; i++) { + int found = 0; if (i >= dev->num_linked) break; - int found = 0; for (j = 0; j < num; j++) { name = &link_list[j]->s; name = name[0] == '/' ? name + 1 : name; @@ -1077,9 +1070,9 @@ static int mpr_dev_update_linked(mpr_dev dev, mpr_msg_atom a) } if (updated) dev->linked = realloc(dev->linked, dev->num_linked * sizeof(mpr_dev)); - // Add any new links - mpr_dev rem; + /* Add any new links */ for (i = 0; i < num; i++) { + mpr_dev rem; if ((rem = mpr_graph_add_dev(dev->obj.graph, &link_list[i]->s, 0))) updated += mpr_dev_add_link(dev, rem); } @@ -1090,14 +1083,13 @@ static int mpr_dev_update_linked(mpr_dev dev, mpr_msg_atom a) /*! Update information about a device record based on message properties. */ int mpr_dev_set_from_msg(mpr_dev dev, mpr_msg m) { - RETURN_UNLESS(m, 0); int i, updated = 0; - mpr_msg_atom a; + RETURN_ARG_UNLESS(m, 0); for (i = 0; i < m->num_atoms; i++) { - a = &m->atoms[i]; + mpr_msg_atom a = &m->atoms[i]; switch (MASK_PROP_BITFLAGS(a->prop)) { case PROP(LINKED): - if (mpr_type_get_is_str(a->types[0])) + if (!dev->is_local && mpr_type_get_is_str(a->types[0])) updated += mpr_dev_update_linked(dev, a); break; default: @@ -1108,9 +1100,9 @@ int mpr_dev_set_from_msg(mpr_dev dev, mpr_msg m) return updated; } -static int mpr_dev_send_sigs(mpr_dev dev, mpr_dir dir) +static int mpr_dev_send_sigs(mpr_local_dev dev, mpr_dir dir) { - mpr_list l = mpr_dev_get_sigs(dev, dir); + mpr_list l = mpr_dev_get_sigs((mpr_dev)dev, dir); while (l) { mpr_sig_send_state((mpr_sig)*l, MSG_SIG); l = mpr_list_get_next(l); @@ -1118,9 +1110,9 @@ static int mpr_dev_send_sigs(mpr_dev dev, mpr_dir dir) return 0; } -static int mpr_dev_send_maps(mpr_dev dev, mpr_dir dir) +static int mpr_dev_send_maps(mpr_local_dev dev, mpr_dir dir) { - mpr_list l = mpr_dev_get_maps(dev, dir); + mpr_list l = mpr_dev_get_maps((mpr_dev)dev, dir); while (l) { mpr_map_send_state((mpr_map)*l, -1, MSG_MAPPED); l = mpr_list_get_next(l); @@ -1128,42 +1120,42 @@ static int mpr_dev_send_maps(mpr_dev dev, mpr_dir dir) return 0; } -// Add/renew/remove a subscription. -void mpr_dev_manage_subscriber(mpr_dev dev, lo_address addr, int flags, +/* Add/renew/remove a subscription. */ +void mpr_dev_manage_subscriber(mpr_local_dev dev, lo_address addr, int flags, int timeout_sec, int revision) { - mpr_subscriber *s = &dev->loc->subscribers; + mpr_time t; + mpr_net net; + mpr_subscriber *s = &dev->subscribers; const char *ip = lo_address_get_hostname(addr); const char *port = lo_address_get_port(addr); RETURN_UNLESS(ip && port); - - mpr_time t; mpr_time_set(&t, MPR_NOW); while (*s) { const char *s_ip = lo_address_get_hostname((*s)->addr); const char *s_port = lo_address_get_port((*s)->addr); if (strcmp(ip, s_ip)==0 && strcmp(port, s_port)==0) { - // subscriber already exists + /* subscriber already exists */ if (!flags || !timeout_sec) { - trace_dev(dev, "removing subscription from %s:%s\n", s_ip, s_port); - // remove subscription + /* remove subscription */ mpr_subscriber temp = *s; int prev_flags = temp->flags; + trace_dev(dev, "removing subscription from %s:%s\n", s_ip, s_port); *s = temp->next; FUNC_IF(lo_address_free, temp->addr); free(temp); RETURN_UNLESS(flags && (flags &= ~prev_flags)); } else { - // reset timeout + /* reset timeout */ + int temp = flags; #ifdef DEBUG trace_dev(dev, "renewing subscription from %s:%s for %d seconds" "with flags ", s_ip, s_port, timeout_sec); print_subscription_flags(flags); #endif (*s)->lease_exp = t.sec + timeout_sec; - int temp = flags; flags &= ~(*s)->flags; (*s)->flags = temp; } @@ -1175,7 +1167,7 @@ void mpr_dev_manage_subscriber(mpr_dev dev, lo_address addr, int flags, RETURN_UNLESS(flags); if (!(*s) && timeout_sec) { - // add new subscriber + /* add new subscriber */ #ifdef DEBUG trace_dev(dev, "adding new subscription from %s:%s with flags ", ip, port); print_subscription_flags(flags); @@ -1184,14 +1176,14 @@ void mpr_dev_manage_subscriber(mpr_dev dev, lo_address addr, int flags, sub->addr = lo_address_new(ip, port); sub->lease_exp = t.sec + timeout_sec; sub->flags = flags; - sub->next = dev->loc->subscribers; - dev->loc->subscribers = sub; + sub->next = dev->subscribers; + dev->subscribers = sub; } - // bring new subscriber up to date - mpr_net net = &dev->obj.graph->net; + /* bring new subscriber up to date */ + net = &dev->obj.graph->net; mpr_net_use_mesh(net, addr); - mpr_dev_send_state(dev, MSG_DEV); + mpr_dev_send_state((mpr_dev)dev, MSG_DEV); mpr_net_send(net); if (flags & MPR_SIG) { diff --git a/src/mapper/expression.c b/src/mapper/expression.c index 7e6b127..02c3a50 100644 --- a/src/mapper/expression.c +++ b/src/mapper/expression.c @@ -1,133 +1,307 @@ -#include "compat.h" +#include #include #include #include #include #include +#include +#include #include "mapper_internal.h" #define MAX_HIST_SIZE 100 -#define STACK_SIZE 128 +#define STACK_SIZE 64 #define N_USER_VARS 16 #ifdef DEBUG - #define TRACING 0 /* Set non-zero to see trace during parse & eval. */ + #define TRACE_PARSE 0 /* Set non-zero to see trace during parse. */ + #define TRACE_EVAL 0 /* Set non-zero to see trace during evaluation. */ #else - #define TRACING 0 + #define TRACE_PARSE 0 /* Set non-zero to see trace during parse. */ + #define TRACE_EVAL 0 /* Set non-zero to see trace during evaluation. */ #endif #define lex_error trace -#define PARSE_ERROR(ret, ...) { trace(__VA_ARGS__); return ret; } -typedef union _mpr_val { +typedef union _mpr_expr_val { float f; double d; int i; } mpr_expr_val_t, *mpr_expr_val; +/* could we use mpr_value here instead, with stack idx instead of history idx? + * pro: vectors, commonality with I/O + * con: timetags wasted + * option: create version with unallocated timetags */ +mpr_expr_val stk = 0; +uint8_t *dims = 0; +int stk_size = 0; + #define EXTREMA_FUNC(NAME, TYPE, OP) \ static TYPE NAME(TYPE x, TYPE y) { return (x OP y) ? x : y; } -EXTREMA_FUNC(maxi, int, >); -EXTREMA_FUNC(mini, int, <); -EXTREMA_FUNC(maxf, float, >); -EXTREMA_FUNC(minf, float, <); -EXTREMA_FUNC(maxd, double, >); -EXTREMA_FUNC(mind, double, <); - -#define CONST_FUNC(NAME, TYPE, VALUE) static TYPE NAME() { return VALUE; } -CONST_FUNC(pif, float, M_PI); -CONST_FUNC(pid, double, M_PI); -CONST_FUNC(ef, float, M_E); -CONST_FUNC(ed, double, M_E); +EXTREMA_FUNC(maxi, int, >) +EXTREMA_FUNC(mini, int, <) +EXTREMA_FUNC(maxf, float, >) +EXTREMA_FUNC(minf, float, <) +EXTREMA_FUNC(maxd, double, >) +EXTREMA_FUNC(mind, double, <) #define UNARY_FUNC(TYPE, NAME, SUFFIX, CALC) \ static TYPE NAME##SUFFIX(TYPE x) { return CALC; } #define FLOAT_OR_DOUBLE_UNARY_FUNC(NAME, CALC) \ UNARY_FUNC(float, NAME, f, CALC) \ UNARY_FUNC(double, NAME, d, CALC) -FLOAT_OR_DOUBLE_UNARY_FUNC(midiToHz, 440. * pow(2.0, (x - 69) / 12.0)); -FLOAT_OR_DOUBLE_UNARY_FUNC(hzToMidi, 69. + 12. * log2(x / 440.)); -FLOAT_OR_DOUBLE_UNARY_FUNC(uniform, rand() / (RAND_MAX + 1.0) * x); -UNARY_FUNC(int, sign, i, x >= 0 ? 1 : -1); -FLOAT_OR_DOUBLE_UNARY_FUNC(sign, x >= 0 ? 1.0 : -1.0); - -#define TEST_VEC(OP, CMP, RET, EL) \ - for (int i = 0; i < len; i++) { \ - if (val[i].EL OP CMP) \ - return RET; \ - } \ - return 1 - RET; -#define TEST_VEC_TYPED(NAME, TYPE, OP, CMP, RET, EL) \ - static TYPE NAME##EL(mpr_expr_val val, int len) { \ - TEST_VEC(OP, CMP, RET, EL) \ - } -TEST_VEC_TYPED(all, int, ==, 0, 0, i) -TEST_VEC_TYPED(any, int, !=, 0, 1, i) -TEST_VEC_TYPED(all, float, ==, 0.f, 0, f) -TEST_VEC_TYPED(any, float, !=, 0.f, 1, f) -TEST_VEC_TYPED(all, double, ==, 0., 0, d) -TEST_VEC_TYPED(any, double, !=, 0., 1, d) - -#define SUM_FUNC(TYPE, EL) \ - static TYPE sum##EL(mpr_expr_val val, int len) \ - { \ - TYPE aggregate = 0; \ - for (int i = 0; i < len; i++) \ - aggregate += val[i].EL; \ - return aggregate; \ - } -SUM_FUNC(int, i) -SUM_FUNC(float, f) -SUM_FUNC(double, d) +FLOAT_OR_DOUBLE_UNARY_FUNC(midiToHz, 440. * pow(2.0, (x - 69) / 12.0)) +FLOAT_OR_DOUBLE_UNARY_FUNC(hzToMidi, 69. + 12. * log2(x / 440.)) +FLOAT_OR_DOUBLE_UNARY_FUNC(uniform, rand() / (RAND_MAX + 1.0) * x) +UNARY_FUNC(int, sign, i, x >= 0 ? 1 : -1) +FLOAT_OR_DOUBLE_UNARY_FUNC(sign, x >= 0 ? 1.0 : -1.0) + +#define TEST_VEC_TYPED(NAME, TYPE, OP, CMP, RET, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + register TYPE ret = 1 - RET; \ + mpr_expr_val val = stk + idx * inc; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) { \ + if (val[i].T OP CMP) { \ + ret = RET; \ + break; \ + } \ + } \ + val[0].T = ret; \ +} +TEST_VEC_TYPED(valli, int, ==, 0, 0, i) +TEST_VEC_TYPED(vallf, float, ==, 0.f, 0, f) +TEST_VEC_TYPED(valld, double, ==, 0., 0, d) +TEST_VEC_TYPED(vanyi, int, !=, 0, 1, i) +TEST_VEC_TYPED(vanyf, float, !=, 0.f, 1, f) +TEST_VEC_TYPED(vanyd, double, !=, 0., 1, d) + +#define SUM_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + register TYPE aggregate = 0; \ + mpr_expr_val val = stk + idx * inc; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) \ + aggregate += val[i].T; \ + val[0].T = aggregate; \ +} +SUM_VFUNC(vsumi, int, i) +SUM_VFUNC(vsumf, float, f) +SUM_VFUNC(vsumd, double, d) -static float meanf(mpr_expr_val val, int len) -{ - return sumf(val, len) / (float)len; +#define MEAN_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + register TYPE mean = 0; \ + mpr_expr_val val = stk + idx * inc; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) \ + mean += val[i].T; \ + val[0].T = mean / len; \ } +MEAN_VFUNC(vmeanf, float, f) +MEAN_VFUNC(vmeand, double, d) -static double meand(mpr_expr_val val, int len) -{ - return sumd(val, len) / (double)len; +#define CENTER_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + mpr_expr_val val = stk + idx * inc; \ + register TYPE max = val[0].T, min = max; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) { \ + if (val[i].T > max) \ + max = val[i].T; \ + if (val[i].T < min) \ + min = val[i].T; \ + } \ + val[0].T = (max + min) * 0.5; \ +} +CENTER_VFUNC(vcenterf, float, f) +CENTER_VFUNC(vcenterd, double, d) + +#define EXTREMA_VFUNC(NAME, OP, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + mpr_expr_val val = stk + idx * inc; \ + register TYPE extrema = val[0].T; \ + int i, len = dim[idx]; \ + for (i = 1; i < len; i++) { \ + if (val[i].T OP extrema) \ + extrema = val[i].T; \ + } \ + val[0].T = extrema; \ +} +EXTREMA_VFUNC(vmaxi, >, int, i) +EXTREMA_VFUNC(vmini, <, int, i) +EXTREMA_VFUNC(vmaxf, >, float, f) +EXTREMA_VFUNC(vminf, <, float, f) +EXTREMA_VFUNC(vmaxd, >, double, d) +EXTREMA_VFUNC(vmind, <, double, d) + +#define powd pow +#define sqrtd sqrt +#define acosd acos + +#define NORM_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + mpr_expr_val val = stk + idx * inc; \ + register TYPE tmp = 0; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) \ + tmp += pow##T(val[i].T, 2); \ + val[0].T = sqrt##T(tmp); \ +} +NORM_VFUNC(vnormf, float, f) +NORM_VFUNC(vnormd, double, d) + +#define DOT_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + register TYPE dot = 0; \ + mpr_expr_val a = stk + idx * inc, b = a + inc; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) \ + dot += a[i].T * b[i].T; \ + a[0].T = dot; \ +} +DOT_VFUNC(vdoti, int, i) +DOT_VFUNC(vdotf, float, f) +DOT_VFUNC(vdotd, double, d) + +/* TODO: should we handle multidimensional angles as well? Problem with sign... + * should probably have separate function for signed and unsigned: angle vs. rotation */ +/* TODO: quaternion functions */ + +#define atan2d atan2 +#define ANGLE_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + register TYPE theta; \ + mpr_expr_val a = stk + idx * inc, b = a + inc; \ + theta = atan2##T(a[1].T, a[0].T) - atan2##T(b[1].T, b[0].T); \ + a[0].T = theta; \ } +ANGLE_VFUNC(vanglef, float, f) +ANGLE_VFUNC(vangled, double, d) -#define EXTREMA_VFUNC(NAME, OP, TYPE, EL) \ -static TYPE NAME(mpr_expr_val val, int len) \ -{ \ - TYPE extrema = val[0].EL; \ - for (int i = 1; i < len; i++) { \ - if (val[i].EL OP extrema) \ - extrema = val[i].EL; \ - } \ - return extrema; \ +#define MAXMIN_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + mpr_expr_val max = stk+idx*inc, min = max+inc, new = min+inc; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) { \ + if (new[i].T > max[i].T) \ + max[i].T = new[i].T; \ + if (new[i].T < min[i].T) \ + min[i].T = new[i].T; \ + } \ +} +MAXMIN_VFUNC(vmaxmini, int, i) +MAXMIN_VFUNC(vmaxminf, float, f) +MAXMIN_VFUNC(vmaxmind, double, d) + +#define SUMNUM_VFUNC(NAME, TYPE, T) \ +static void NAME(mpr_expr_val stk, uint8_t *dim, int idx, int inc) \ +{ \ + mpr_expr_val sum = stk+idx*inc, num = sum+inc, new = num+inc; \ + int i, len = dim[idx]; \ + for (i = 0; i < len; i++) { \ + sum[i].T += new[i].T; \ + num[i].T += 1; \ + } \ } -EXTREMA_VFUNC(vmaxi, >, int, i); -EXTREMA_VFUNC(vmini, <, int, i); -EXTREMA_VFUNC(vmaxf, >, float, f); -EXTREMA_VFUNC(vminf, <, float, f); -EXTREMA_VFUNC(vmaxd, >, double, d); -EXTREMA_VFUNC(vmind, <, double, d); - -#define TYPED_EMA(TYPE, SUFFIX) \ -static TYPE ema##SUFFIX(TYPE memory, TYPE val, TYPE weight) \ +SUMNUM_VFUNC(vsumnumi, int, i) +SUMNUM_VFUNC(vsumnumf, float, f) +SUMNUM_VFUNC(vsumnumd, double, d) + +#define TYPED_EMA(TYPE, T) \ +static TYPE ema##T(TYPE memory, TYPE val, TYPE weight) \ { return val * weight + memory * (1 - weight); } TYPED_EMA(float, f) TYPED_EMA(double, d) -#define TYPED_SCHMITT(TYPE, SUFFIX) \ -static TYPE schmitt##SUFFIX(TYPE memory, TYPE val, TYPE low, TYPE high) \ +#define TYPED_SCHMITT(TYPE, T) \ +static TYPE schmitt##T(TYPE memory, TYPE val, TYPE low, TYPE high) \ { return memory ? val > low : val >= high; } TYPED_SCHMITT(float, f) TYPED_SCHMITT(double, d) typedef enum { - VAR_UNKNOWN=-1, - VAR_Y=N_USER_VARS, + VAR_UNKNOWN = -1, + VAR_Y = N_USER_VARS, VAR_X, N_VARS } expr_var_t; typedef enum { - FN_UNKNOWN=-1, - FN_ABS=0, + OP_UNKNOWN = -1, + OP_LOGICAL_NOT, + OP_MULTIPLY, + OP_DIVIDE, + OP_MODULO, + OP_ADD, + OP_SUBTRACT, + OP_LEFT_BIT_SHIFT, + OP_RIGHT_BIT_SHIFT, + OP_IS_GREATER_THAN, + OP_IS_GREATER_THAN_OR_EQUAL, + OP_IS_LESS_THAN, + OP_IS_LESS_THAN_OR_EQUAL, + OP_IS_EQUAL, + OP_IS_NOT_EQUAL, + OP_BITWISE_AND, + OP_BITWISE_XOR, + OP_BITWISE_OR, + OP_LOGICAL_AND, + OP_LOGICAL_OR, + OP_IF, + OP_IF_ELSE, + OP_IF_THEN_ELSE +} expr_op_t; + +#define NONE 0x0 +#define GET_ZERO 0x1 +#define GET_ONE 0x2 +#define GET_OPER 0x4 +#define BAD_EXPR 0x8 + +static struct { + const char *name; + uint8_t arity; + uint8_t precedence; + uint16_t optimize_const_ops; +} op_tbl[] = { +/* left==0 | right==0 | left==1 | right==1 */ + { "!", 1, 11, GET_ONE | GET_ONE <<4 | GET_ZERO <<8 | GET_ZERO <<12 }, + { "*", 2, 10, GET_ZERO | GET_ZERO <<4 | GET_OPER <<8 | GET_OPER <<12 }, + { "/", 2, 10, GET_ZERO | BAD_EXPR <<4 | NONE <<8 | GET_OPER <<12 }, + { "%", 2, 10, GET_ZERO | GET_OPER <<4 | GET_ONE <<8 | GET_OPER <<12 }, + { "+", 2, 9, GET_OPER | GET_OPER <<4 | NONE <<8 | NONE <<12 }, + { "-", 2, 9, NONE | GET_OPER <<4 | NONE <<8 | NONE <<12 }, + { "<<", 2, 8, GET_ZERO | GET_OPER <<4 | NONE <<8 | NONE <<12 }, + { ">>", 2, 8, GET_ZERO | GET_OPER <<4 | NONE <<8 | NONE <<12 }, + { ">", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { ">=", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "<", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "<=", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "==", 2, 6, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "!=", 2, 6, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "&", 2, 5, GET_ZERO | GET_ZERO <<4 | NONE <<8 | NONE <<12 }, + { "^", 2, 4, GET_OPER | GET_OPER <<4 | NONE <<8 | NONE <<12 }, + { "|", 2, 3, GET_OPER | GET_OPER <<4 | GET_ONE <<8 | GET_ONE <<12 }, + { "&&", 2, 2, GET_ZERO | GET_ZERO <<4 | NONE <<8 | NONE <<12 }, + { "||", 2, 1, GET_OPER | GET_OPER <<4 | GET_ONE <<8 | GET_ONE <<12 }, + /* TODO: handle optimization of ternary operator */ + { "IFTHEN", 2, 0, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "IFELSE", 2, 0, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + { "IFTHENELSE", 3, 0, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, +}; + +typedef enum { + FN_UNKNOWN = -1, + FN_ABS = 0, FN_ACOS, FN_ACOSH, FN_ASIN, @@ -139,7 +313,6 @@ typedef enum { FN_CEIL, FN_COS, FN_COSH, - FN_E, FN_EMA, FN_EXP, FN_EXP2, @@ -153,7 +326,6 @@ typedef enum { FN_MAX, FN_MIDITOHZ, FN_MIN, - FN_PI, FN_POW, FN_ROUND, FN_SCHMITT, @@ -172,141 +344,125 @@ typedef enum { static struct { const char *name; - const char arity; - const char memory; + uint8_t arity; + uint8_t memory; void *fn_int; void *fn_flt; void *fn_dbl; } fn_tbl[] = { - { "abs", 1, 0, abs, fabsf, fabs }, - { "acos", 1, 0, 0, acosf, acos }, - { "acosh", 1, 0, 0, acoshf, acosh }, - { "asin", 1, 0, 0, asinf, asin }, - { "asinh", 1, 0, 0, asinhf, asinh }, - { "atan", 1, 0, 0, atanf, atan }, - { "atan2", 2, 0, 0, atan2f, atan2 }, - { "atanh", 1, 0, 0, atanhf, atanh }, - { "cbrt", 1, 0, 0, cbrtf, cbrt }, - { "ceil", 1, 0, 0, ceilf, ceil }, - { "cos", 1, 0, 0, cosf, cos }, - { "cosh", 1, 0, 0, coshf, cosh }, - { "e", 0, 0, 0, ef, ed }, - { "ema", 3, 1, 0, emaf, emad }, - { "exp", 1, 0, 0, expf, exp }, - { "exp2", 1, 0, 0, exp2f, exp2 }, - { "floor", 1, 0, 0, floorf, floor }, - { "hypot", 2, 0, 0, hypotf, hypot }, - { "hzToMidi", 1, 0, 0, hzToMidif, hzToMidid }, - { "log", 1, 0, 0, logf, log }, - { "log10", 1, 0, 0, log10f, log10 }, - { "log2", 1, 0, 0, log2f, log2 }, - { "logb", 1, 0, 0, logbf, logb }, - { "max", 2, 0, maxi, maxf, maxd }, - { "midiToHz", 1, 0, 0, midiToHzf, midiToHzd }, - { "min", 2, 0, mini, minf, mind }, - { "pi", 0, 0, 0, pif, pid }, - { "pow", 2, 0, 0, powf, pow }, - { "round", 1, 0, 0, roundf, round }, - { "schmitt", 4, 1, 0, schmittf, schmittd }, - { "sign", 1, 0, signi, signf, signd }, - { "sin", 1, 0, 0, sinf, sin }, - { "sinh", 1, 0, 0, sinhf, sinh }, - { "sqrt", 1, 0, 0, sqrtf, sqrt }, - { "tan", 1, 0, 0, tanf, tan }, - { "tanh", 1, 0, 0, tanhf, tanh }, - { "trunc", 1, 0, 0, truncf, trunc }, + { "abs", 1, 0, (void*)abs, (void*)fabsf, (void*)fabs }, + { "acos", 1, 0, 0, (void*)acosf, (void*)acos }, + { "acosh", 1, 0, 0, (void*)acoshf, (void*)acosh }, + { "asin", 1, 0, 0, (void*)asinf, (void*)asin }, + { "asinh", 1, 0, 0, (void*)asinhf, (void*)asinh }, + { "atan", 1, 0, 0, (void*)atanf, (void*)atan }, + { "atan2", 2, 0, 0, (void*)atan2f, (void*)atan2 }, + { "atanh", 1, 0, 0, (void*)atanhf, (void*)atanh }, + { "cbrt", 1, 0, 0, (void*)cbrtf, (void*)cbrt }, + { "ceil", 1, 0, 0, (void*)ceilf, (void*)ceil }, + { "cos", 1, 0, 0, (void*)cosf, (void*)cos }, + { "cosh", 1, 0, 0, (void*)coshf, (void*)cosh }, + { "ema", 3, 1, 0, (void*)emaf, (void*)emad }, + { "exp", 1, 0, 0, (void*)expf, (void*)exp }, + { "exp2", 1, 0, 0, (void*)exp2f, (void*)exp2 }, + { "floor", 1, 0, 0, (void*)floorf, (void*)floor }, + { "hypot", 2, 0, 0, (void*)hypotf, (void*)hypot }, + { "hzToMidi", 1, 0, 0, (void*)hzToMidif, (void*)hzToMidid }, + { "log", 1, 0, 0, (void*)logf, (void*)log }, + { "log10", 1, 0, 0, (void*)log10f, (void*)log10 }, + { "log2", 1, 0, 0, (void*)log2f, (void*)log2 }, + { "logb", 1, 0, 0, (void*)logbf, (void*)logb }, + { "max", 2, 0, (void*)maxi, (void*)maxf, (void*)maxd }, + { "midiToHz", 1, 0, 0, (void*)midiToHzf, (void*)midiToHzd }, + { "min", 2, 0, (void*)mini, (void*)minf, (void*)mind }, + { "pow", 2, 0, 0, (void*)powf, (void*)pow }, + { "round", 1, 0, 0, (void*)roundf, (void*)round }, + { "schmitt", 4, 1, 0, (void*)schmittf, (void*)schmittd }, + { "sign", 1, 0, (void*)signi, (void*)signf, (void*)signd }, + { "sin", 1, 0, 0, (void*)sinf, (void*)sin }, + { "sinh", 1, 0, 0, (void*)sinhf, (void*)sinh }, + { "sqrt", 1, 0, 0, (void*)sqrtf, (void*)sqrt }, + { "tan", 1, 0, 0, (void*)tanf, (void*)tan }, + { "tanh", 1, 0, 0, (void*)tanhf, (void*)tanh }, + { "trunc", 1, 0, 0, (void*)truncf, (void*)trunc }, /* place functions which should never be precomputed below this point */ - { "delay", 1, 0, (void*)1, 0, 0, }, - { "uniform", 1, 0, 0, uniformf, uniformd }, + { "delay", 1, 0, (void*)1, 0, 0, }, + { "uniform", 1, 0, 0, (void*)uniformf, (void*)uniformd }, }; typedef enum { - VFN_UNKNOWN=-1, - VFN_ALL=0, + VFN_UNKNOWN = -1, + VFN_ALL = 0, VFN_ANY, - VFN_MEAN, - VFN_SUM, + VFN_CENTER, VFN_MAX, + VFN_MEAN, VFN_MIN, + VFN_SUM, + /* function names above this line are also found in pfn_table */ + VFN_NORM, + VFN_MAXMIN, + VFN_SUMNUM, + VFN_ANGLE, + VFN_DOT, N_VFN } expr_vfn_t; static struct { const char *name; - unsigned int arity; - void *fn_int; - void *fn_flt; - void *fn_dbl; + uint8_t arity; + uint8_t reduce; /* TODO: use bitflags */ + uint8_t dot_notation; + void (*fn_int)(mpr_expr_val, uint8_t*, int, int); + void (*fn_flt)(mpr_expr_val, uint8_t*, int, int); + void (*fn_dbl)(mpr_expr_val, uint8_t*, int, int); } vfn_tbl[] = { - { "all", 1, alli, allf, alld }, - { "any", 1, anyi, anyf, anyd }, - { "mean", 1, 0, meanf, meand }, - { "sum", 1, sumi, sumf, sumd }, - { "max", 1, vmaxi, vmaxf, vmaxd }, - { "min", 1, vmini, vminf, vmind }, + { "all", 1, 1, 1, valli, vallf, valld }, + { "any", 1, 1, 1, vanyi, vanyf, vanyd }, + { "center", 1, 1, 1, 0, vcenterf, vcenterd }, + { "max", 1, 1, 1, vmaxi, vmaxf, vmaxd }, + { "mean", 1, 1, 1, 0, vmeanf, vmeand }, + { "min", 1, 1, 1, vmini, vminf, vmind }, + { "sum", 1, 1, 1, vsumi, vsumf, vsumd }, + { "norm", 1, 1, 1, 0, vnormf, vnormd }, + { "maxmin", 3, 0, 0, vmaxmini, vmaxminf, vmaxmind }, + { "sumnum", 3, 0, 0, vsumnumi, vsumnumf, vsumnumd }, + { "angle", 2, 1, 0, 0, vanglef, vangled }, + { "dot", 2, 1, 0, vdoti, vdotf, vdotd }, }; typedef enum { - OP_LOGICAL_NOT, - OP_MULTIPLY, - OP_DIVIDE, - OP_MODULO, - OP_ADD, - OP_SUBTRACT, - OP_LEFT_BIT_SHIFT, - OP_RIGHT_BIT_SHIFT, - OP_IS_GREATER_THAN, - OP_IS_GREATER_THAN_OR_EQUAL, - OP_IS_LESS_THAN, - OP_IS_LESS_THAN_OR_EQUAL, - OP_IS_EQUAL, - OP_IS_NOT_EQUAL, - OP_BITWISE_AND, - OP_BITWISE_XOR, - OP_BITWISE_OR, - OP_LOGICAL_AND, - OP_LOGICAL_OR, - OP_IF, - OP_IF_ELSE, - OP_IF_THEN_ELSE, -} expr_op_t; - -#define NONE 0x0 -#define GET_ZERO 0x1 -#define GET_ONE 0x2 -#define GET_OPER 0x4 -#define BAD_EXPR 0x8 + PFN_UNKNOWN = -1, + PFN_ALL = 0, + PFN_ANY, + PFN_CENTER, + PFN_MAX, + PFN_MEAN, + PFN_MIN, + PFN_SUM, + /* function names above this line are also found in vfn_table */ + PFN_COUNT, + PFN_POOL, + PFN_SIZE, + N_PFN +} expr_pfn_t; static struct { const char *name; - char arity; - char precedence; - uint16_t optimize_const_operands; -} op_tbl[] = { -/* left==0 | right==0 | left==1 | right==1 */ - { "!", 1, 11, GET_ONE | GET_ONE <<4 | GET_ZERO <<8 | GET_ZERO <<12 }, - { "*", 2, 10, GET_ZERO | GET_ZERO <<4 | GET_OPER <<8 | GET_OPER <<12 }, - { "/", 2, 10, GET_ZERO | BAD_EXPR <<4 | NONE <<8 | GET_OPER <<12 }, - { "%", 2, 10, GET_ZERO | GET_OPER <<4 | GET_ONE <<8 | GET_OPER <<12 }, - { "+", 2, 9, GET_OPER | GET_OPER <<4 | NONE <<8 | NONE <<12 }, - { "-", 2, 9, NONE | GET_OPER <<4 | NONE <<8 | NONE <<12 }, - { "<<", 2, 8, GET_ZERO | GET_OPER <<4 | NONE <<8 | NONE <<12 }, - { ">>", 2, 8, GET_ZERO | GET_OPER <<4 | NONE <<8 | NONE <<12 }, - { ">", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { ">=", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "<", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "<=", 2, 7, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "==", 2, 6, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "!=", 2, 6, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "&", 2, 5, GET_ZERO | GET_ZERO <<4 | NONE <<8 | NONE <<12 }, - { "^", 2, 4, GET_OPER | GET_OPER <<4 | NONE <<8 | NONE <<12 }, - { "|", 2, 3, GET_OPER | GET_OPER <<4 | GET_ONE <<8 | GET_ONE <<12 }, - { "&&", 2, 2, GET_ZERO | GET_ZERO <<4 | NONE <<8 | NONE <<12 }, - { "||", 2, 1, GET_OPER | GET_OPER <<4 | GET_ONE <<8 | GET_ONE <<12 }, - // TODO: handle optimization of ternary operator - { "IFTHEN", 2, 0, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "IFELSE", 2, 0, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, - { "IFTHENELSE", 3, 0, NONE | NONE <<4 | NONE <<8 | NONE <<12 }, + unsigned int arity; + expr_op_t op; + expr_vfn_t vfn; +} pfn_tbl[] = { + { "all", 2, OP_LOGICAL_AND, VFN_UNKNOWN }, + { "any", 2, OP_LOGICAL_OR, VFN_UNKNOWN }, + { "center", 0, OP_UNKNOWN, VFN_MAXMIN }, + { "max", 2, OP_UNKNOWN, VFN_MAX }, + { "mean", 3, OP_UNKNOWN, VFN_SUMNUM }, + { "min", 2, OP_UNKNOWN, VFN_MIN }, + { "sum", 2, OP_ADD, VFN_UNKNOWN }, + { "count", 0, OP_ADD, VFN_UNKNOWN }, + { "pool", 0, OP_UNKNOWN, VFN_UNKNOWN }, /* replaced during parsing */ + { "size", 0, OP_UNKNOWN, VFN_MAXMIN }, }; typedef int fn_int_arity0(); @@ -324,59 +480,110 @@ typedef double fn_dbl_arity1(double); typedef double fn_dbl_arity2(double,double); typedef double fn_dbl_arity3(double,double,double); typedef double fn_dbl_arity4(double,double,double,double); -typedef int vfn_int_arity1(mpr_expr_val, int); -typedef float vfn_flt_arity1(mpr_expr_val, int); -typedef double vfn_dbl_arity1(mpr_expr_val, int); +typedef void vfn_template(mpr_expr_val, uint8_t*, int, int); + +#define CONST_MINVAL 0x0001 +#define CONST_MAXVAL 0x0002 +#define CONST_PI 0x0003 +#define CONST_E 0x0004 +#define CONST_SPECIAL 0x000F +#define CLEAR_STACK 0x0010 +#define VAR_MUTED 0x0020 +#define VAR_DELAY 0x0040 +#define VEC_LEN_LOCKED 0x0080 + +enum toktype { + TOK_LITERAL = 0x000001, + TOK_NEGATE = 0x000002, + TOK_FN = 0x000004, + TOK_VFN = 0x000008, + TOK_VFN_DOT = 0x000010, + TOK_PFN = 0x000020, + TOK_OPEN_PAREN = 0x000040, + TOK_MUTED = 0x000080, + TOK_PUBLIC = 0x000100, + TOK_OPEN_SQUARE = 0x000200, + TOK_OPEN_CURLY = 0x000400, + TOK_CLOSE_PAREN = 0x000800, + TOK_CLOSE_SQUARE = 0x001000, + TOK_CLOSE_CURLY = 0x002000, + TOK_VAR = 0x004000, + TOK_OP = 0x008000, + TOK_COMMA = 0x010000, + TOK_COLON = 0x020000, + TOK_SEMICOLON = 0x040000, + TOK_VECTORIZE = 0x080000, + TOK_POOL = 0x100000, + TOK_ASSIGN = 0x200000, + TOK_ASSIGN_USE, + TOK_ASSIGN_CONST, + TOK_ASSIGN_TT, + TOK_TT = 0x400000, + TOK_CACHE_INIT_INST, + TOK_BRANCH_NEXT_INST, + TOK_SP_ADD, + TOK_END = 0x800000 +}; + +struct generic_type { + enum toktype toktype; + mpr_type datatype; + mpr_type casttype; + uint8_t vec_len; + uint8_t flags; +}; -typedef struct _token { +struct literal_type { + enum toktype toktype; + mpr_type datatype; + mpr_type casttype; + uint8_t vec_len; + uint8_t flags; union { float f; int i; double d; - expr_var_t var; - expr_op_t op; - expr_fn_t fn; - expr_vfn_t vfn; - }; - enum { - TOK_CONST = 0x000001, - TOK_NEGATE = 0x000002, - TOK_FN = 0x000004, - TOK_VFN = 0x000008, - TOK_OPEN_PAREN = 0x000010, - TOK_MUTED = 0x000020, - TOK_PUBLIC = 0x000040, - TOK_OPEN_SQUARE = 0x000080, - TOK_OPEN_CURLY = 0x000100, - TOK_CLOSE_PAREN = 0x000200, - TOK_CLOSE_SQUARE = 0x000400, - TOK_CLOSE_CURLY = 0x000800, - TOK_VAR = 0x001000, - TOK_OP = 0x002000, - TOK_COMMA = 0x004000, - TOK_COLON = 0x008000, - TOK_SEMICOLON = 0x010000, - TOK_VECTORIZE = 0x020000, - TOK_ASSIGN = 0x040000, - TOK_ASSIGN_USE, - TOK_ASSIGN_CONST, - TOK_ASSIGN_TT, - TOK_TT = 0x080000, - TOK_END = 0x100000, - } toktype; - union { - mpr_type casttype; - uint8_t offset; - }; + } val; +}; + +struct operator_type { + enum toktype toktype; mpr_type datatype; + mpr_type casttype; + uint8_t vec_len; + uint8_t flags; + expr_op_t idx; +}; + +struct variable_type { + enum toktype toktype; + mpr_type datatype; + mpr_type casttype; + uint8_t vec_len; + uint8_t flags; + expr_var_t idx; + uint8_t offset; /* only used by TOK_ASSIGN* */ + uint8_t vec_idx; /* only used by TOK_VAR and TOK_ASSIGN* */ +}; + +struct function_type { + enum toktype toktype; + mpr_type datatype; + mpr_type casttype; uint8_t vec_len; -// union { - uint8_t vec_idx; - uint8_t arity; -// }; - int8_t hist; // TODO switch to bitflags - char vec_len_locked; // TODO switch to bitflags - char muted; // TODO switch to bitflags + uint8_t flags; + int idx; + uint8_t arity; /* used by TOK_FN, TOK_VFN, TOK_VECTORIZE */ + uint8_t inst_cache_pos; /* only used by TOK_BRANCH* */ +}; + +typedef union _token { + enum toktype toktype; + struct generic_type gen; + struct literal_type lit; + struct operator_type op; + struct variable_type var; + struct function_type fn; } mpr_token_t, *mpr_token; typedef struct _var { @@ -394,37 +601,32 @@ static int strncmp_lc(const char *a, const char *b, int len) int i; for (i = 0; i < len; i++) { int diff = tolower(a[i]) - tolower(b[i]); - RETURN_UNLESS(0 == diff, diff); + RETURN_ARG_UNLESS(0 == diff, diff); } return 0; } -#define FN_LOOKUP(LC, UC) \ -static expr_##LC##_t LC##_lookup(const char *s, int len) \ -{ \ - int i, j; \ - for (i=0; itoktype = TOK_TT; s += 2; len -= 2; - tok->var = VAR_X; + tok->var.idx = VAR_X; } else tok->toktype = TOK_VAR; if (*s == 'y' && 1 == len) - tok->var = VAR_Y; + tok->var.idx = VAR_Y; else if ('x' == *s) { if (1 == len) - tok->var = VAR_X; + tok->var.idx = VAR_X; else { int i, ordinal = 1; for (i = 1; i < len; i++) { @@ -449,29 +651,42 @@ static void var_lookup(mpr_token_t *tok, const char *s, int len) break; } } - tok->var = ordinal ? VAR_X + atoi(s+1) : VAR_UNKNOWN; + tok->var.idx = ordinal ? VAR_X + atoi(s+1) : VAR_UNKNOWN; } } else - tok->var = VAR_UNKNOWN; + tok->var.idx = VAR_UNKNOWN; +} + +static int const_lookup(mpr_token_t *tok, const char *s, int len) +{ + if (len == 2 && 'p' == *s && 'i' == *(s+1)) + tok->gen.flags |= CONST_PI; + else if (len == 1 && *s == 'e') + tok->gen.flags |= CONST_E; + else + return 1; + tok->toktype = TOK_LITERAL; + tok->gen.datatype = MPR_FLT; + return 0; } static int const_tok_is_zero(mpr_token_t tok) { - switch (tok.datatype) { - case MPR_INT32: return tok.i == 0; - case MPR_FLT: return tok.f == 0.f; - case MPR_DBL: return tok.d == 0.0; + switch (tok.gen.datatype) { + case MPR_INT32: return tok.lit.val.i == 0; + case MPR_FLT: return tok.lit.val.f == 0.f; + case MPR_DBL: return tok.lit.val.d == 0.0; } return 0; } static int const_tok_is_one(mpr_token_t tok) { - switch (tok.datatype) { - case MPR_INT32: return tok.i == 1; - case MPR_FLT: return tok.f == 1.f; - case MPR_DBL: return tok.d == 1.0; + switch (tok.gen.datatype) { + case MPR_INT32: return tok.lit.val.i == 1; + case MPR_FLT: return tok.lit.val.f == 1.f; + case MPR_DBL: return tok.lit.val.d == 1.0; } return 0; } @@ -479,10 +694,17 @@ static int const_tok_is_one(mpr_token_t tok) static int tok_arity(mpr_token_t tok) { switch (tok.toktype) { - case TOK_OP: return op_tbl[tok.op].arity; - case TOK_FN: return fn_tbl[tok.fn].arity; - case TOK_VFN: return vfn_tbl[tok.fn].arity; - case TOK_VECTORIZE: return tok.arity; + case TOK_VAR: + case TOK_TT: + case TOK_ASSIGN: + case TOK_ASSIGN_CONST: + case TOK_ASSIGN_USE: + case TOK_ASSIGN_TT: return tok.gen.flags & VAR_DELAY ? 1 : 0; + case TOK_OP: return op_tbl[tok.op.idx].arity; + case TOK_FN: return fn_tbl[tok.fn.idx].arity; + case TOK_PFN: return pfn_tbl[tok.fn.idx].arity; + case TOK_VFN: return vfn_tbl[tok.fn.idx].arity; + case TOK_VECTORIZE: return tok.fn.arity; default: return 0; } return 0; @@ -490,18 +712,18 @@ static int tok_arity(mpr_token_t tok) #define SET_TOK_OPTYPE(TYPE) \ tok->toktype = TOK_OP; \ - tok->op = TYPE; + tok->op.idx = TYPE; static int expr_lex(const char *str, int idx, mpr_token_t *tok) { - tok->datatype = MPR_INT32; - tok->casttype = 0; - tok->vec_len = 1; - tok->vec_idx = 0; - tok->vec_len_locked = 0; int n=idx, i=idx; char c = str[idx]; int integer_found = 0; + tok->gen.datatype = MPR_INT32; + tok->gen.casttype = 0; + tok->gen.vec_len = 1; + tok->var.vec_idx = 0; + tok->gen.flags = 0; if (c==0) { tok->toktype = TOK_END; @@ -518,9 +740,9 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) n = atoi(str+i); integer_found = 1; if (c!='.' && c!='e') { - tok->i = n; - tok->toktype = TOK_CONST; - tok->datatype = MPR_INT32; + tok->lit.val.i = n; + tok->toktype = TOK_LITERAL; + tok->lit.datatype = MPR_INT32; return idx; } } @@ -528,32 +750,43 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) switch (c) { case '.': c = str[++idx]; - if (!isdigit(c) && c!='e' && integer_found) { - tok->toktype = TOK_CONST; - tok->f = (float)n; - tok->datatype = MPR_FLT; - return idx; + if (!isdigit(c) && c!='e') { + if (integer_found) { + tok->toktype = TOK_LITERAL; + tok->lit.val.f = (float)n; + tok->lit.datatype = MPR_FLT; + return idx; + } + while (c && (isalpha(c) || c == '.')) + c = str[++idx]; + ++i; + if ((tok->fn.idx = vfn_lookup(str+i, idx-i)) != VFN_UNKNOWN) + tok->toktype = TOK_VFN_DOT; + else if ((tok->fn.idx = pfn_lookup(str+i, idx-i)) != PFN_UNKNOWN) + tok->toktype = TOK_PFN; + else + break; + return idx+2; } - if (!isdigit(c) && c!='e') - break; do { c = str[++idx]; } while (c && isdigit(c)); if (c!='e') { - tok->d = atof(str+i); - tok->toktype = TOK_CONST; - tok->datatype = MPR_DBL; + tok->lit.val.f = atof(str+i); + tok->toktype = TOK_LITERAL; + tok->lit.datatype = MPR_FLT; return idx; } + /* continue to next case 'e' */ case 'e': if (!integer_found) { while (c && (isalpha(c) || isdigit(c) || c == '_')) c = str[++idx]; - if ((tok->fn = fn_lookup(str+i, idx-i)) != FN_UNKNOWN) + if ((tok->fn.idx = fn_lookup(str+i, idx-i)) != FN_UNKNOWN) tok->toktype = TOK_FN; - else if ((tok->vfn = vfn_lookup(str+i, idx-i)) != VFN_UNKNOWN) + else if ((tok->fn.idx = vfn_lookup(str+i, idx-i)) != VFN_UNKNOWN) tok->toktype = TOK_VFN; - else + else if (const_lookup(tok, str+i, idx-i)) var_lookup(tok, str+i, idx-i); return idx; } @@ -566,17 +799,17 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) c = str[++idx]; while (c && isdigit(c)) c = str[++idx]; - tok->toktype = TOK_CONST; - tok->datatype = MPR_DBL; - tok->d = atof(str+i); + tok->toktype = TOK_LITERAL; + tok->lit.datatype = MPR_DBL; + tok->lit.val.d = atof(str+i); return idx; case '+': SET_TOK_OPTYPE(OP_ADD); return ++idx; case '-': - // could be either subtraction or negation - i = idx-1; - // back up one character + /* could be either subtraction or negation */ + i = idx - 1; + /* back up one character */ while (i && strchr(" \t\r\n", str[i])) --i; if (isalpha(str[i]) || isdigit(str[i]) || strchr(")]}", str[i])) { @@ -595,7 +828,7 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) SET_TOK_OPTYPE(OP_MODULO); return ++idx; case '=': - // could be '=', '==' + /* could be '=', '==' */ c = str[++idx]; if (c == '=') { SET_TOK_OPTYPE(OP_IS_EQUAL); @@ -605,61 +838,61 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) tok->toktype = TOK_ASSIGN; return idx; case '<': - // could be '<', '<=', '<<' + /* could be '<', '<=', '<<' */ SET_TOK_OPTYPE(OP_IS_LESS_THAN); c = str[++idx]; if (c == '=') { - tok->op = OP_IS_LESS_THAN_OR_EQUAL; + tok->op.idx = OP_IS_LESS_THAN_OR_EQUAL; ++idx; } else if (c == '<') { - tok->op = OP_LEFT_BIT_SHIFT; + tok->op.idx = OP_LEFT_BIT_SHIFT; ++idx; } return idx; case '>': - // could be '>', '>=', '>>' + /* could be '>', '>=', '>>' */ SET_TOK_OPTYPE(OP_IS_GREATER_THAN); c = str[++idx]; if (c == '=') { - tok->op = OP_IS_GREATER_THAN_OR_EQUAL; + tok->op.idx = OP_IS_GREATER_THAN_OR_EQUAL; ++idx; } else if (c == '>') { - tok->op = OP_RIGHT_BIT_SHIFT; + tok->op.idx = OP_RIGHT_BIT_SHIFT; ++idx; } return idx; case '!': - // could be '!', '!=' - // TODO: handle factorial case + /* could be '!', '!=' */ + /* TODO: handle factorial case */ SET_TOK_OPTYPE(OP_LOGICAL_NOT); c = str[++idx]; if (c == '=') { - tok->op = OP_IS_NOT_EQUAL; + tok->op.idx = OP_IS_NOT_EQUAL; ++idx; } return idx; case '&': - // could be '&', '&&' + /* could be '&', '&&' */ SET_TOK_OPTYPE(OP_BITWISE_AND); c = str[++idx]; if (c == '&') { - tok->op = OP_LOGICAL_AND; + tok->op.idx = OP_LOGICAL_AND; ++idx; } return idx; case '|': - // could be '|', '||' + /* could be '|', '||' */ SET_TOK_OPTYPE(OP_BITWISE_OR); c = str[++idx]; if (c == '|') { - tok->op = OP_LOGICAL_OR; + tok->op.idx = OP_LOGICAL_OR; ++idx; } return idx; case '^': - // bitwise XOR + /* bitwise XOR */ SET_TOK_OPTYPE(OP_BITWISE_XOR); return ++idx; case '(': @@ -690,11 +923,11 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) tok->toktype = TOK_COMMA; return ++idx; case '?': - // conditional + /* conditional */ SET_TOK_OPTYPE(OP_IF); c = str[++idx]; if (c == ':') { - tok->op = OP_IF_ELSE; + tok->op.idx = OP_IF_ELSE; ++idx; } return idx; @@ -717,11 +950,11 @@ static int expr_lex(const char *str, int idx, mpr_token_t *tok) } while (c && (isalpha(c) || isdigit(c) || c == '_')) c = str[++idx]; - if ((tok->fn = fn_lookup(str+i, idx-i)) != FN_UNKNOWN) + if ((tok->fn.idx = fn_lookup(str+i, idx-i)) != FN_UNKNOWN) tok->toktype = TOK_FN; - else if ((tok->vfn = vfn_lookup(str+i, idx-i)) != VFN_UNKNOWN) + else if ((tok->fn.idx = vfn_lookup(str+i, idx-i)) != VFN_UNKNOWN) tok->toktype = TOK_VFN; - else + else if (const_lookup(tok, str+i, idx-i)) var_lookup(tok, str+i, idx-i); return idx; } @@ -734,13 +967,15 @@ struct _mpr_expr mpr_token start; mpr_var vars; uint8_t offset; - uint8_t len; - uint8_t vec_size; + uint8_t n_tokens; + uint8_t stack_size; + uint8_t vec_len; uint8_t *in_hist_size; uint8_t out_hist_size; uint8_t n_vars; int8_t inst_ctl; int8_t mute_ctl; + int8_t n_ins; }; void mpr_expr_free(mpr_expr expr) @@ -756,122 +991,153 @@ void mpr_expr_free(mpr_expr expr) free(expr); } -#ifdef DEBUG +void mpr_expr_free_buffers() +{ + if (stk) { + free(stk); + stk = 0; + } + if (dims) { + free(dims); + dims = 0; + } +} + +#ifdef TRACE_PARSE static void printtoken(mpr_token_t t, mpr_var_t *vars) { - int i, len = 64; - char s[len]; + int i, len = 64, delay = t.gen.flags & VAR_DELAY; + char s[64]; switch (t.toktype) { - case TOK_CONST: - switch (t.datatype) { - case MPR_FLT: snprintf(s, len, "%f", t.f); break; - case MPR_DBL: snprintf(s, len, "%f", t.d); break; - case MPR_INT32: snprintf(s, len, "%d", t.i); break; - } break; - case TOK_OP: snprintf(s, len, "%s", op_tbl[t.op].name); break; - case TOK_OPEN_CURLY: snprintf(s, len, "{"); break; - case TOK_OPEN_PAREN: snprintf(s, len, "("); break; - case TOK_OPEN_SQUARE: snprintf(s, len, "["); break; - case TOK_CLOSE_CURLY: snprintf(s, len, "}"); break; - case TOK_CLOSE_PAREN: snprintf(s, len, ")"); break; - case TOK_CLOSE_SQUARE: snprintf(s, len, "]"); break; + case TOK_LITERAL: + switch (t.gen.flags & CONST_SPECIAL) { + case CONST_MAXVAL: snprintf(s, len, "max%c", t.lit.datatype); break; + case CONST_MINVAL: snprintf(s, len, "min%c", t.lit.datatype); break; + case CONST_PI: snprintf(s, len, "pi%c", t.lit.datatype); break; + case CONST_E: snprintf(s, len, "e%c", t.lit.datatype); break; + default: + switch (t.gen.datatype) { + case MPR_FLT: snprintf(s, len, "%g", t.lit.val.f); break; + case MPR_DBL: snprintf(s, len, "%g", t.lit.val.d); break; + case MPR_INT32: snprintf(s, len, "%d", t.lit.val.i); break; + } break; + } + break; + case TOK_OP: snprintf(s, len, "op.%s", op_tbl[t.op.idx].name); break; + case TOK_OPEN_CURLY: snprintf(s, len, "{"); break; + case TOK_OPEN_PAREN: snprintf(s, len, "( arity %d", t.fn.arity); break; + case TOK_OPEN_SQUARE: snprintf(s, len, "["); break; + case TOK_CLOSE_CURLY: snprintf(s, len, "}"); break; + case TOK_CLOSE_PAREN: snprintf(s, len, ")"); break; + case TOK_CLOSE_SQUARE: snprintf(s, len, "]"); break; case TOK_VAR: - if (t.var == VAR_Y) - snprintf(s, len, "y%s[%u]", t.hist ? "{N}" : "", t.vec_idx); - else if (t.var >= VAR_X) - snprintf(s, len, "x%d%s[%u]", t.var-VAR_X, t.hist ? "{N}" : "", t.vec_idx); + if (t.var.idx == VAR_Y) + snprintf(s, len, "var.y%s[%u]", delay ? "{N}" : "", t.var.vec_idx); + else if (t.var.idx >= VAR_X) + snprintf(s, len, "var.x%d%s[%u]", t.var.idx - VAR_X, delay ? "{N}" : "", t.var.vec_idx); else - snprintf(s, len, "%s%s[%u]", vars[t.var].name, t.hist ? "{N}" : "", t.vec_idx); + snprintf(s, len, "var.%s%s[%u/%u]", vars ? vars[t.var.idx].name : "?", + delay ? "{N}" : "", t.var.vec_idx, vars ? vars[t.var.idx].vec_len : 0); break; case TOK_TT: - if (t.var == VAR_Y) - snprintf(s, len, "t_y%s", t.hist ? "{N}" : ""); - else if (t.var >= VAR_X) - snprintf(s, len, "t_x%d%s", t.var-VAR_X, t.hist ? "{N}" : ""); + if (t.var.idx == VAR_Y) + snprintf(s, len, "tt.y%s", delay ? "{N}" : ""); + else if (t.var.idx >= VAR_X) + snprintf(s, len, "tt.x%d%s", t.var.idx - VAR_X, delay ? "{N}" : ""); else - snprintf(s, len, "t_%s%s", vars[t.var].name, t.hist ? "{N}" : ""); + snprintf(s, len, "tt.%s%s", vars ? vars[t.var.idx].name : "?", delay ? "{N}" : ""); break; - case TOK_FN: snprintf(s, len, "%s(arity %d)", fn_tbl[t.fn].name, t.arity); break; - case TOK_COMMA: snprintf(s, len, ","); break; - case TOK_COLON: snprintf(s, len, ":"); break; - case TOK_VECTORIZE: snprintf(s, len, "VECT(%d)", t.arity); break; - case TOK_NEGATE: snprintf(s, len, "-"); break; - case TOK_VFN: snprintf(s, len, "%s()", vfn_tbl[t.fn].name); break; + case TOK_FN: snprintf(s, len, "fn.%s(arity %d)", fn_tbl[t.fn.idx].name, t.fn.arity); break; + case TOK_COMMA: snprintf(s, len, ","); break; + case TOK_COLON: snprintf(s, len, ":"); break; + case TOK_VECTORIZE: snprintf(s, len, "VECT(%d)", t.fn.arity); break; + case TOK_NEGATE: snprintf(s, len, "-"); break; + case TOK_VFN: + case TOK_VFN_DOT: snprintf(s, len, "vfn.%s(arity %d)", vfn_tbl[t.fn.idx].name, t.fn.arity); break; + case TOK_PFN: snprintf(s, len, "pfn.%s(arity %d)", pfn_tbl[t.fn.idx].name, t.fn.arity); break; + case TOK_POOL: snprintf(s, len, "pool()"); break; case TOK_ASSIGN: case TOK_ASSIGN_CONST: case TOK_ASSIGN_USE: - if (t.var == VAR_Y) - snprintf(s, len, "ASSIGN_TO:y%s[%u]->[%u]%s", t.hist ? "{N}" : "", t.offset, - t.vec_idx, t.toktype == TOK_ASSIGN_CONST ? " (const) " : ""); + if (t.var.idx == VAR_Y) + snprintf(s, len, "ASSIGN_TO:y%s[%u]->[%u]%s", delay ? "{N}" : "", t.var.offset, + t.var.vec_idx, t.toktype == TOK_ASSIGN_CONST ? " (const) " : ""); else - snprintf(s, len, "ASSIGN_TO:%s%s[%u]->[%u]%s", vars[t.var].name, - t.hist ? "{N}" : "", t.offset, t.vec_idx, + snprintf(s, len, "ASSIGN_TO:%s%s[%u]->[%u]%s", vars ? vars[t.var.idx].name : "?", + delay ? "{N}" : "", t.var.offset, t.var.vec_idx, t.toktype == TOK_ASSIGN_CONST ? " (const) " : ""); break; case TOK_ASSIGN_TT: - snprintf(s, len, "ASSIGN_TO:t_y%s->[%u]", t.hist ? "{N}" : "", t.vec_idx); + snprintf(s, len, "ASSIGN_TO:t_y%s->[%u]", delay ? "{N}" : "", t.var.vec_idx); break; - case TOK_END: printf("END\n"); return; - default: printf("(unknown token)\n"); return; + case TOK_CACHE_INIT_INST: snprintf(s, len, ""); break; + case TOK_BRANCH_NEXT_INST: snprintf(s, len, "", + t.lit.val.i, t.fn.inst_cache_pos); break; + case TOK_SP_ADD: snprintf(s, len, "", t.lit.val.i); break; + case TOK_SEMICOLON: snprintf(s, len, "semicolon"); break; + case TOK_END: printf("END\n"); return; + default: printf("(unknown token)\n"); return; } printf("%s", s); - // indent + /* indent */ len = strlen(s); for (i = len; i < 40; i++) printf(" "); - printf("%c[%u]", t.datatype, t.vec_len); - if (t.toktype < TOK_ASSIGN && t.casttype) - printf("->%c", t.casttype); + printf("%c%u", t.gen.datatype, t.gen.vec_len); + if (t.toktype != TOK_LITERAL && t.toktype < TOK_ASSIGN && t.gen.casttype) + printf("->%c", t.gen.casttype); else printf(" "); - if (t.vec_len_locked) + if (t.gen.flags & VEC_LEN_LOCKED) printf(" locked"); + if (t.gen.flags & CLEAR_STACK) + printf(" clear"); printf("\n"); } -static void printstack(const char *s, mpr_token_t *stk, int top, - mpr_var_t *vars, int show_init_line) +static void printstack(const char *s, mpr_token_t *stk, int sp, mpr_var_t *vars, int show_init_line) { int i, j, indent = 0, can_advance = 1; printf("%s ", s); if (s) indent = strlen(s) + 1; - if (top < 0) { + if (sp < 0) { printf("EMPTY\n"); return; } - for (i=0; i<=top; i++) { + for (i = 0; i <= sp; i++) { if (i != 0) { - for (j=0; j ---\n"); can_advance = 0; break; } break; + case TOK_PFN: case TOK_VAR: - if (stk[i].var >= VAR_X) + if (stk[i].var.idx >= VAR_X) can_advance = 0; break; default: @@ -885,17 +1151,19 @@ static void printstack(const char *s, mpr_token_t *stk, int top, void printexpr(const char *s, mpr_expr e) { - printstack(s, e->tokens, e->len-1, e->vars, 1); + printstack(s, e->tokens, e->n_tokens - 1, e->vars, 1); } -#endif // DEBUG +#endif /* TRACE_PARSE */ static mpr_type compare_token_datatype(mpr_token_t tok, mpr_type type) { - // return the higher datatype - if (tok.datatype == MPR_DBL || type == MPR_DBL) + if (tok.toktype >= TOK_CACHE_INIT_INST) + return type; + /* return the higher datatype */ + if (tok.gen.datatype == MPR_DBL || type == MPR_DBL) return MPR_DBL; - else if (tok.datatype == MPR_FLT || type == MPR_FLT) + else if (tok.gen.datatype == MPR_FLT || type == MPR_FLT) return MPR_FLT; else return MPR_INT32; @@ -903,97 +1171,182 @@ static mpr_type compare_token_datatype(mpr_token_t tok, mpr_type type) static mpr_type promote_token_datatype(mpr_token_t *tok, mpr_type type) { - tok->casttype = 0; + if (tok->toktype >= TOK_CACHE_INIT_INST) + return type; + + tok->gen.casttype = 0; - if (tok->datatype == type) + if (tok->gen.datatype == type) return type; if (tok->toktype >= TOK_ASSIGN) { - if (tok->var >= VAR_Y) { - // typecasting is not possible - return tok->datatype; + if (tok->var.idx >= VAR_Y) { + /* typecasting is not possible */ + return tok->var.datatype; } else { - // user-defined variable, can typecast - tok->casttype = type; + /* user-defined variable, can typecast */ + tok->var.casttype = type; return type; } } - if (tok->toktype == TOK_CONST) { - // constants can be cast immediately - if (tok->datatype == MPR_INT32) { + if (tok->toktype == TOK_LITERAL) { + /* constants can be cast immediately */ + if (tok->lit.datatype == MPR_INT32) { if (type == MPR_FLT) { - tok->f = (float)tok->i; - tok->datatype = type; + tok->lit.val.f = (float)tok->lit.val.i; + tok->lit.datatype = type; } else if (type == MPR_DBL) { - tok->d = (double)tok->i; - tok->datatype = type; + tok->lit.val.d = (double)tok->lit.val.i; + tok->lit.datatype = type; } } - else if (tok->datatype == MPR_FLT) { + else if (tok->lit.datatype == MPR_FLT) { if (type == MPR_DBL) { - tok->d = (double)tok->f; - tok->datatype = type; + tok->lit.val.d = (double)tok->lit.val.f; + tok->lit.datatype = type; } else if (type == MPR_INT32) - tok->casttype = type; + tok->lit.casttype = type; } else - tok->casttype = type; + tok->lit.casttype = type; return type; } - else if (tok->toktype == TOK_VAR) { - // we need to cast at runtime - tok->casttype = type; + else if (tok->toktype == TOK_VAR || tok->toktype == TOK_PFN) { + /* we need to cast at runtime */ + tok->gen.casttype = type; return type; } else { - if (tok->datatype == MPR_INT32 || type == MPR_DBL) { - tok->datatype = type; + if (tok->gen.datatype == MPR_INT32 || type == MPR_DBL) { + tok->gen.datatype = type; return type; } else { - tok->casttype = type; - return tok->datatype; + tok->gen.casttype = type; + return tok->gen.datatype; } } return type; } -static void lock_vec_len(mpr_token_t *stk, int top) +static void lock_vec_len(mpr_token_t *stk, int sp) { - int i=top, arity=1; + int i = sp, arity = 1; while ((i >= 0) && arity--) { - stk[i].vec_len_locked = 1; + stk[i].gen.flags |= VEC_LEN_LOCKED; switch (stk[i].toktype) { - case TOK_OP: arity += op_tbl[stk[i].op].arity; break; - case TOK_FN: arity += fn_tbl[stk[i].fn].arity; break; - case TOK_VECTORIZE: arity += stk[i].arity; break; - default: break; + case TOK_OP: arity += op_tbl[stk[i].op.idx].arity; break; + case TOK_FN: arity += fn_tbl[stk[i].fn.idx].arity; break; + case TOK_VECTORIZE: arity += stk[i].fn.arity; break; + default: break; } --i; } } +static int replace_special_constants(mpr_token_t *stk, int sp) +{ + while (sp >= 0) { + if (stk[sp].toktype != TOK_LITERAL || !(stk[sp].gen.flags & CONST_SPECIAL)) { + --sp; + continue; + } + switch (stk[sp].gen.flags & CONST_SPECIAL) { + case CONST_MAXVAL: + switch (stk[sp].lit.datatype) { + case MPR_INT32: stk[sp].lit.val.i = INT_MAX; break; + case MPR_FLT: stk[sp].lit.val.f = FLT_MAX; break; + case MPR_DBL: stk[sp].lit.val.d = DBL_MAX; break; + default: goto error; + } + break; + case CONST_MINVAL: + switch (stk[sp].lit.datatype) { + case MPR_INT32: stk[sp].lit.val.i = INT_MIN; break; + case MPR_FLT: stk[sp].lit.val.f = FLT_MIN; break; + case MPR_DBL: stk[sp].lit.val.d = DBL_MIN; break; + default: goto error; + } + break; + case CONST_PI: + switch (stk[sp].lit.datatype) { + case MPR_FLT: stk[sp].lit.val.f = M_PI; break; + case MPR_DBL: stk[sp].lit.val.d = M_PI; break; + default: goto error; + } + break; + case CONST_E: + switch (stk[sp].lit.datatype) { + case MPR_FLT: stk[sp].lit.val.f = M_E; break; + case MPR_DBL: stk[sp].lit.val.d = M_E; break; + default: goto error; + } + break; + default: + continue; + } + stk[sp].gen.flags &= ~CONST_SPECIAL; + --sp; + } + return 0; +error: +#if TRACE_PARSE + printf("Illegal type found when replacing special constants.\n"); +#endif + return -1; +} + +static void expr_stack_realloc(int num_samps) { + /* Reallocate evaluation stack if necessary. */ + if (num_samps > stk_size) { + stk_size = num_samps; + if (stk) + stk = realloc(stk, stk_size * sizeof(mpr_expr_val_t)); + else + stk = malloc(stk_size * sizeof(mpr_expr_val_t)); + if (dims) + dims = realloc(dims, stk_size * sizeof(uint8_t)); + else + dims = malloc(stk_size * sizeof(uint8_t)); + } +} + static int precompute(mpr_token_t *stk, int len, int vec_len) { - struct _mpr_expr e = {0, stk, 0, 0, len, vec_len, 0, 0, 0, -1, -1}; - void *s = malloc(mpr_type_get_size(stk[len-1].datatype) * vec_len); - mpr_value_buffer_t b = {s, 0, -1}; - mpr_value_t v = {&b, vec_len, 1, stk[len-1].datatype, 1}; + int i; + struct _mpr_expr e = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1}; + mpr_value_t v = {0, 0, 1, 0, 1}; + mpr_value_buffer_t b = {0, 0, -1}; + void *s; + + if (replace_special_constants(stk, len-1)) + return 0; + e.start = stk; + e.n_tokens = e.stack_size = len; + e.vec_len = vec_len; + + s = b.samps = malloc(mpr_type_get_size(stk[len - 1].gen.datatype) * vec_len); + + v.inst = &b; + v.vlen = vec_len; + v.type = stk[len - 1].gen.datatype; + + expr_stack_realloc(len * vec_len); + if (!(mpr_expr_eval(&e, 0, 0, &v, 0, 0, 0) & 1)) { free(s); return 0; } - int i; switch (v.type) { -#define TYPED_CASE(MTYPE, TYPE, EL) \ - case MTYPE: \ - for (i = 0; i < vec_len; i++) \ - stk[i].EL = ((TYPE*)s)[i]; \ +#define TYPED_CASE(MTYPE, TYPE, T) \ + case MTYPE: \ + for (i = 0; i < vec_len; i++) \ + stk[i].lit.val.T = ((TYPE*)s)[i]; \ break; TYPED_CASE(MPR_INT32, int, i) TYPED_CASE(MPR_FLT, float, f) @@ -1005,93 +1358,95 @@ static int precompute(mpr_token_t *stk, int len, int vec_len) break; } for (i = 0; i < vec_len; i++) { - stk[i].toktype = TOK_CONST; - stk[i].datatype = stk[len-1].datatype; + stk[i].toktype = TOK_LITERAL; + stk[i].gen.flags &= ~CONST_SPECIAL; + stk[i].gen.datatype = stk[len - 1].gen.datatype; } free(s); - return len-1; + return len - 1; } -static int check_type_and_len(mpr_token_t *stk, int top, mpr_var_t *vars) +static int check_type(mpr_token_t *stk, int sp, mpr_var_t *vars, int enable_optimize) { - // TODO: allow precomputation of const-only vectors + /* TODO: enable precomputation of const-only vectors */ int i, arity, can_precompute = 1, optimize = NONE; - mpr_type type = stk[top].datatype; - uint8_t vec_len = stk[top].vec_len; - switch (stk[top].toktype) { + mpr_type type = stk[sp].gen.datatype; + uint8_t vec_len = stk[sp].gen.vec_len; + switch (stk[sp].toktype) { case TOK_OP: - if (stk[top].op == OP_IF) - PARSE_ERROR(-1, "Ternary operator is missing operand.\n"); - arity = op_tbl[stk[top].op].arity; + if (stk[sp].op.idx == OP_IF) { + trace("Ternary operator is missing operand.\n"); + return -1; + } + arity = op_tbl[stk[sp].op.idx].arity; break; case TOK_FN: - arity = fn_tbl[stk[top].fn].arity; - if (stk[top].fn >= FN_DELAY) + arity = fn_tbl[stk[sp].fn.idx].arity; + if (stk[sp].fn.idx >= FN_DELAY) can_precompute = 0; break; case TOK_VFN: - arity = vfn_tbl[stk[top].fn].arity; + arity = vfn_tbl[stk[sp].fn.idx].arity; break; case TOK_VECTORIZE: - arity = stk[top].arity; + arity = stk[sp].fn.arity; can_precompute = 0; break; case TOK_ASSIGN: case TOK_ASSIGN_CONST: case TOK_ASSIGN_TT: case TOK_ASSIGN_USE: - arity = stk[top].hist ? 2 : 1; + arity = stk[sp].gen.flags & VAR_DELAY ? 2 : 1; can_precompute = 0; break; default: - return top; + return sp; } if (arity) { - // find operator or function inputs - i = top; + /* find operator or function inputs */ int skip = 0; int depth = arity; int operand = 0; - // last arg of op or func is at top-1 - type = compare_token_datatype(stk[top-1], type); - if (stk[top-1].vec_len > vec_len) - vec_len = stk[top-1].vec_len; + i = sp; - // Walk down stack distance of arity, checking types and vector lengths. + /* Walk down stack distance of arity, checking types. */ while (--i >= 0) { - if (stk[i].toktype == TOK_FN && fn_tbl[stk[i].fn].arity) - can_precompute = 0; - else if (stk[i].toktype != TOK_CONST) + if (stk[i].toktype >= TOK_CACHE_INIT_INST) { + can_precompute = enable_optimize = 0; + continue; + } + + if (stk[i].toktype == TOK_FN) { + if (fn_tbl[stk[i].fn.idx].arity) + can_precompute = 0; + } + else if (stk[i].toktype > TOK_LITERAL) can_precompute = 0; if (skip == 0) { - if (stk[i].toktype == TOK_CONST && stk[top].toktype == TOK_OP - && depth <= op_tbl[stk[top].op].arity) { + if (enable_optimize && stk[i].toktype == TOK_LITERAL && stk[sp].toktype == TOK_OP + && depth <= op_tbl[stk[sp].op.idx].arity) { if (const_tok_is_zero(stk[i])) { - // mask and bitshift, depth == 1 or 2 - optimize = (op_tbl[stk[top].op].optimize_const_operands - >>(depth-1)*4) & 0xF; + /* mask and bitshift, depth == 1 or 2 */ + optimize = (op_tbl[stk[sp].op.idx].optimize_const_ops >> (depth - 1) * 4) & 0xF; } else if (const_tok_is_one(stk[i])) { - optimize = (op_tbl[stk[top].op].optimize_const_operands - >>(depth+1)*4) & 0xF; + optimize = (op_tbl[stk[sp].op.idx].optimize_const_ops >> (depth + 1) * 4) & 0xF; } if (optimize == GET_OPER) { - if (i == top-1) { - // optimize immediately without moving other operand - return top-2; + if (i == sp - 1) { + /* optimize immediately without moving other operand */ + return sp - 2; } else { - // store position of non-zero operand - operand = top-1; + /* store position of non-zero operand */ + operand = sp - 1; } } } type = compare_token_datatype(stk[i], type); - if (stk[i].toktype == TOK_VFN) - stk[i].vec_len = vec_len; - else if (stk[i].vec_len > vec_len) - vec_len = stk[i].vec_len; + if (stk[i].gen.vec_len > vec_len) + vec_len = stk[i].gen.vec_len; --depth; if (depth == 0) break; @@ -1100,117 +1455,112 @@ static int check_type_and_len(mpr_token_t *stk, int top, mpr_var_t *vars) --skip; switch (stk[i].toktype) { - case TOK_OP: skip += op_tbl[stk[i].op].arity; break; - case TOK_FN: skip += fn_tbl[stk[i].fn].arity; break; - case TOK_VFN: skip += vfn_tbl[stk[i].fn].arity; break; - case TOK_VECTORIZE: skip += stk[i].arity; break; - case TOK_ASSIGN_USE: ++skip; break; - case TOK_VAR: skip += stk[i].hist ? 1 : 0; break; - default: break; + case TOK_OP: skip += op_tbl[stk[i].op.idx].arity; break; + case TOK_FN: skip += fn_tbl[stk[i].fn.idx].arity; break; + case TOK_VFN: + skip += vfn_tbl[stk[i].fn.idx].arity; + if (VFN_MAXMIN == stk[i].fn.idx || VFN_SUMNUM == stk[i].fn.idx) + --skip; /* these functions have 2 outputs */ + break; + case TOK_VECTORIZE: skip += stk[i].fn.arity; break; + case TOK_ASSIGN_USE: ++skip; break; + case TOK_VAR: skip += stk[i].gen.flags & VAR_DELAY ? 1 : 0; break; + default: break; } } if (depth) return -1; - if (!can_precompute) { + if (enable_optimize && !can_precompute) { switch (optimize) { case BAD_EXPR: - PARSE_ERROR(-1, "Operator '%s' cannot have zero operand.\n", - op_tbl[stk[top].op].name); + trace("Operator '%s' cannot have zero operand.\n", op_tbl[stk[sp].op.idx].name); + return -1; case GET_ZERO: case GET_ONE: { - // finish walking down compound arity + /* finish walking down compound arity */ int _arity = 0; while ((_arity += tok_arity(stk[i])) && i >= 0) { --_arity; --i; } - stk[i].toktype = TOK_CONST; - stk[i].datatype = MPR_INT32; - stk[i].i = optimize == GET_ZERO ? 0 : 1; - stk[i].vec_len = vec_len; - stk[i].vec_len_locked = 0; - stk[i].casttype = 0; + stk[i].toktype = TOK_LITERAL; + stk[i].gen.datatype = MPR_INT32; + stk[i].lit.val.i = optimize == GET_ZERO ? 0 : 1; + stk[i].gen.casttype = 0; return i; } case GET_OPER: - // copy tokens for non-zero operand + /* copy tokens for non-zero operand */ for (; i < operand; i++) - memcpy(stk+i, stk+i+1, sizeof(mpr_token_t)); - // we may need to promote vector length, so do not return yet - top = operand-1; + memcpy(stk + i, stk + i + 1, sizeof(mpr_token_t)); + return i; default: break; } } - // walk down stack distance of arity again, promoting types and lengths - i = top; - switch (stk[top].toktype) { - case TOK_VECTORIZE: skip = stk[top].arity; depth = 0; break; - case TOK_VFN: - case TOK_ASSIGN_USE: skip = 1; depth = 0; break; - case TOK_VAR: skip = stk[top].hist ? 1 : 0; depth = 0; break; - default: skip = 0; depth = arity; break; + /* walk down stack distance of arity again, promoting types + * this time we will also touch sub-arguments */ + i = sp; + switch (stk[sp].toktype) { + case TOK_VECTORIZE: skip = stk[sp].fn.arity; depth = 0; break; + case TOK_ASSIGN_USE: skip = 1; depth = 0; break; + case TOK_VAR: skip = stk[sp].gen.flags & VAR_DELAY ? 1 : 0; depth = 0; break; + default: skip = 0; depth = arity; break; } type = promote_token_datatype(&stk[i], type); while (--i >= 0) { - // we will promote types within range of compound arity - if ((stk[i+1].toktype != TOK_VAR && stk[i+1].toktype != TOK_TT) || !stk[i+1].hist) { - // don't promote type of history indices + if (stk[i].toktype >= TOK_CACHE_INIT_INST) + continue; + /* we will promote types within range of compound arity */ + if ((stk[i+1].toktype != TOK_VAR && stk[i+1].toktype != TOK_TT) + || !(stk[i+1].gen.flags & VAR_DELAY)) { + /* don't promote type of history indices */ type = promote_token_datatype(&stk[i], type); } if (skip <= 0) { - // also check/promote vector length - if (!stk[i].vec_len_locked) { - if (stk[i].toktype == TOK_VFN) { - if (stk[i].vec_len != vec_len) - PARSE_ERROR(-1, "Vector length mismatch (1) %u != %u\n", - stk[i].vec_len, vec_len); - } - else if (stk[i].toktype == TOK_VAR && stk[i].var < VAR_Y) { - uint8_t *vec_len_ptr = &vars[stk[i].var].vec_len; - *vec_len_ptr = vec_len; - stk[i].vec_len = vec_len; - stk[i].vec_len_locked = 1; - } - else - stk[i].vec_len = vec_len; + --depth; + if (!(stk[i].gen.flags & VEC_LEN_LOCKED) && stk[i].toktype == TOK_VAR + && stk[i].var.idx < VAR_Y) { + vars[stk[i].var.idx].vec_len = stk[i].var.vec_len = vec_len; + stk[i].gen.flags |= VEC_LEN_LOCKED; } - else if (stk[i].vec_len != vec_len) - PARSE_ERROR(-1, "Vector length mismatch (2) %u != %u\n", - stk[i].vec_len, vec_len); + else + stk[i].gen.vec_len = vec_len; } switch (stk[i].toktype) { case TOK_OP: if (skip > 0) - skip += op_tbl[stk[i].op].arity; + skip += op_tbl[stk[i].op.idx].arity; else - depth += op_tbl[stk[i].op].arity; + depth += op_tbl[stk[i].op.idx].arity; break; case TOK_FN: if (skip > 0) - skip += fn_tbl[stk[i].fn].arity; + skip += fn_tbl[stk[i].fn.idx].arity; else - depth += fn_tbl[stk[i].fn].arity; + depth += fn_tbl[stk[i].fn.idx].arity; break; case TOK_VFN: - skip = 2; + skip += vfn_tbl[stk[i].fn.idx].arity + 1; break; case TOK_VECTORIZE: - skip = stk[i].arity + 1; + skip = stk[i].fn.arity + 1; break; case TOK_ASSIGN_USE: ++skip; ++depth; break; case TOK_VAR: - if (stk[i].hist) { - ++skip; - ++depth; + if (stk[i].gen.flags & VAR_DELAY) { + if (skip > 0) + ++skip; + else + ++depth; } break; default: @@ -1219,73 +1569,64 @@ static int check_type_and_len(mpr_token_t *stk, int top, mpr_var_t *vars) if (skip > 0) --skip; - else - --depth; if (depth <= 0 && skip <= 0) break; } + } - if (!stk[top].vec_len_locked) { - if (stk[top].toktype != TOK_VFN) - stk[top].vec_len = vec_len; - } - else if (stk[top].vec_len != vec_len) - PARSE_ERROR(-1, "Vector length mismatch (3) %u != %u\n", - stk[top].vec_len, vec_len); + if (!(stk[sp].gen.flags & VEC_LEN_LOCKED)) { + if (stk[sp].toktype != TOK_VFN) + stk[sp].gen.vec_len = vec_len; } + /* if stack within bounds of arity was only constants, we're ok to compute */ + if (enable_optimize && can_precompute) + return sp - precompute(&stk[sp - arity], arity + 1, vec_len); else - stk[top].datatype = MPR_DBL; - // if stack within bounds of arity was only constants, we're ok to compute - if (can_precompute) - return top - precompute(&stk[top-arity], arity+1, vec_len); - else - return top; + return sp; } -static int check_assign_type_and_len(mpr_token_t *stk, int top, mpr_var_t *vars) +static int check_assign_type_and_len(mpr_token_t *stk, int sp, mpr_var_t *vars) { - int i = top; + int i = sp, optimize = 1, expr_len; uint8_t vec_len = 0; - expr_var_t var = stk[top].var; + expr_var_t var = stk[sp].var.idx; - while (i >= 0 && (stk[i].toktype & TOK_ASSIGN) && (stk[i].var == var)) { - vec_len += stk[i].vec_len; + while (i >= 0 && (stk[i].toktype & TOK_ASSIGN) && (stk[i].var.idx == var)) { + vec_len += stk[i].gen.vec_len; --i; } - if (i < 0) - PARSE_ERROR(-1, "Malformed expression (1)\n"); - if (stk[i].vec_len != vec_len) - PARSE_ERROR(-1, "Vector length mismatch (4) %u != %u\n", - stk[i].vec_len, vec_len); - promote_token_datatype(&stk[i], stk[top].datatype); - if (check_type_and_len(stk, i, vars) == -1) + /* skip branch instruction if any */ + if (i >= 0 && TOK_BRANCH_NEXT_INST == stk[i].toktype) { + --i; + optimize = 0; + } + if (i < 0) { + trace("Malformed expression (1)\n"); return -1; - promote_token_datatype(&stk[i], stk[top].datatype); - - if (stk[top].hist == 0 || i == 0) - return 0; - - // Move assignment expression to beginning of stack - int j = 0, expr_len = top - i + (stk[top].hist ? 2 : 1); - if (stk[i].toktype == TOK_VECTORIZE) - expr_len += stk[i].arity; - - mpr_token_t temp[expr_len]; - for (i = top-expr_len+1; i <= top; i++) - memcpy(&temp[j++], &stk[i], sizeof(mpr_token_t)); - - for (i = top-expr_len; i >= 0; i--) - memcpy(&stk[i+expr_len], &stk[i], sizeof(mpr_token_t)); - - for (i = 0; i < expr_len; i++) - memcpy(&stk[i], &temp[i], sizeof(mpr_token_t)); - + } + promote_token_datatype(&stk[i], stk[sp].gen.datatype); + if (check_type(stk, i, vars, optimize) == -1) + return -1; + promote_token_datatype(&stk[i], stk[sp].gen.datatype); + + if (i > 0 && (stk[sp].gen.flags & VAR_DELAY)) { + /* Move assignment expression to beginning of stack */ + mpr_token_t *temp; + expr_len = sp - i + 2; + if (stk[i].toktype == TOK_VECTORIZE) + expr_len += stk[i].fn.arity; + + temp = alloca(expr_len * sizeof(mpr_token_t)); + memcpy(temp, stk + sp - expr_len + 1, expr_len * sizeof(mpr_token_t)); + memcpy(stk + expr_len, stk, (sp - expr_len + 1) * sizeof(mpr_token_t)); + memcpy(stk, temp, expr_len * sizeof(mpr_token_t)); + } return 0; } static int find_var_by_name(mpr_var_t *vars, int n_vars, const char *str, int len) { - // check if variable name matches known variable + /* check if variable name matches known variable */ int i; for (i = 0; i < n_vars; i++) { if (strlen(vars[i].name) == len && strncmp(vars[i].name, str, len)==0) @@ -1294,33 +1635,100 @@ static int find_var_by_name(mpr_var_t *vars, int n_vars, const char *str, int le return -1; } +static int _get_num_input_slots(mpr_expr expr) +{ + /* actually need to return highest numbered input slot */ + int i, count = -1; + mpr_token_t *tok = expr->tokens; + for (i = 0; i < expr->n_tokens; i++) { + if (tok[i].toktype == TOK_VAR && tok[i].var.idx > count) + count = tok[i].var.idx; + } + return count >= VAR_X ? count - VAR_X + 1 : 0; +} + +static int substack_len(mpr_token_t *stk, int sp) +{ + int idx = sp, arity = tok_arity(stk[sp]); + while (arity > 0 && idx > 0) { + --idx; + --arity; + arity += tok_arity(stk[idx]); + } + return sp - idx + 1; +} + +static int _eval_stack_size(mpr_token_t *token_stack, int token_stack_len) +{ + int i = 0, sp = 0, eval_stack_len = 0; + mpr_token_t *tok = token_stack; + while (i < token_stack_len && tok->toktype != TOK_END) { + switch (tok->toktype) { + case TOK_CACHE_INIT_INST: + case TOK_LITERAL: + case TOK_VAR: + case TOK_TT: if (!(tok->gen.flags & VAR_DELAY)) ++sp; break; + case TOK_OP: sp -= op_tbl[tok->op.idx].arity - 1; break; + case TOK_FN: sp -= fn_tbl[tok->fn.idx].arity - 1; break; + case TOK_VFN: sp -= vfn_tbl[tok->fn.idx].arity - 1; break; + case TOK_SP_ADD: sp += tok->lit.val.i; break; + case TOK_BRANCH_NEXT_INST: --sp; break; + case TOK_VECTORIZE: sp -= tok->fn.arity - 1; break; + case TOK_ASSIGN: + case TOK_ASSIGN_USE: + case TOK_ASSIGN_CONST: + case TOK_ASSIGN_TT: + if (tok->gen.flags & VAR_DELAY) + --sp; + if (tok->toktype != TOK_ASSIGN_USE) + --sp; + break; + default: + return -1; + } + if (sp > eval_stack_len) + eval_stack_len = sp; + ++tok; + ++i; + } + return eval_stack_len; +} + /* Macros to help express stack operations in parser. */ #define FAIL(msg) { \ while (--n_vars >= 0) \ free(vars[n_vars].name); \ - PARSE_ERROR(0, "%s\n", msg); \ + trace("%s\n", msg); \ + return 0; \ } #define FAIL_IF(condition, msg) \ if (condition) {FAIL(msg)} #define PUSH_TO_OUTPUT(x) \ { \ - {FAIL_IF(++out_idx >= STACK_SIZE, "Stack size exceeded.");} \ + {FAIL_IF(++out_idx >= STACK_SIZE, "Stack size exceeded. (1)");} \ if (x.toktype == TOK_ASSIGN_CONST && !is_const) \ x.toktype = TOK_ASSIGN; \ memcpy(out + out_idx, &x, sizeof(mpr_token_t)); \ } +#define PUSH_INT_TO_OUTPUT(x) \ +{ \ + tok.toktype = TOK_LITERAL; \ + tok.lit.datatype = MPR_INT32; \ + tok.lit.val.i = x; \ + PUSH_TO_OUTPUT(tok); \ +} #define POP_OUTPUT() ( out_idx-- ) #define PUSH_TO_OPERATOR(x) \ { \ - {FAIL_IF(++op_idx >= STACK_SIZE, "Stack size exceeded.");} \ + {FAIL_IF(++op_idx >= STACK_SIZE, "Stack size exceeded. (2)");} \ memcpy(op + op_idx, &x, sizeof(mpr_token_t)); \ } #define POP_OPERATOR() ( op_idx-- ) #define POP_OPERATOR_TO_OUTPUT() \ { \ PUSH_TO_OUTPUT(op[op_idx]); \ - out_idx = check_type_and_len(out, out_idx, vars); \ - {FAIL_IF(out_idx < 0, "Malformed expression (2).");} \ + out_idx = check_type(out, out_idx, vars, 1); \ + {FAIL_IF(out_idx < 0, "Malformed expression (3).");} \ POP_OPERATOR(); \ } #define GET_NEXT_TOKEN(x) \ @@ -1329,55 +1737,61 @@ static int find_var_by_name(mpr_var_t *vars, int n_vars, const char *str, int le {FAIL_IF(!lex_idx, "Error in lexer.");} \ } +#define ASSIGN_MASK (TOK_VAR | TOK_OPEN_SQUARE | TOK_COMMA | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY \ + | TOK_OPEN_CURLY | TOK_PUBLIC | TOK_NEGATE | TOK_LITERAL) +#define OBJECT_TOKENS (TOK_VAR | TOK_LITERAL | TOK_FN | TOK_VFN | TOK_MUTED | TOK_PUBLIC \ + | TOK_NEGATE | TOK_OPEN_PAREN | TOK_OPEN_SQUARE | TOK_OP | TOK_TT) + /*! Use Dijkstra's shunting-yard algorithm to parse expression into RPN stack. */ -mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, - const mpr_type *in_types, const int *in_vec_lens, - mpr_type out_type, int out_vec_len) +mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, const mpr_type *in_types, + const int *in_vec_lens, mpr_type out_type, int out_vec_len) { - RETURN_UNLESS(str && n_ins && in_types && in_vec_lens, 0); mpr_token_t out[STACK_SIZE]; mpr_token_t op[STACK_SIZE]; int i, lex_idx = 0, out_idx = -1, op_idx = -1; - int oldest_in[n_ins], oldest_out = 0, max_vector = 1; - for (i = 0; i < n_ins; i++) - oldest_in[i] = 0; + int oldest_in[MAX_NUM_MAP_SRC], oldest_out = 0, max_vector = 1; - int assigning = 0; - int out_assigned = 0; - int vectorizing = 0; + /* TODO: use bitflags instead? */ + uint8_t assigning = 0, is_const = 1, out_assigned = 0, muted = 0, public = 0, vectorizing = 0; int var_flags = 0; - int allow_toktype = 0xFFFF; - int is_const = 1; + int allow_toktype = 0x2FFFFF; int in_vec_len = 0; - int muted = 0; - int public = 0; mpr_var_t vars[N_USER_VARS]; int n_vars = 0; int inst_ctl = -1; int mute_ctl = -1; - int assign_mask = (TOK_VAR | TOK_OPEN_SQUARE | TOK_COMMA | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY - | TOK_OPEN_CURLY | TOK_PUBLIC | TOK_NEGATE | TOK_CONST); - int OBJECT_TOKENS = (TOK_VAR | TOK_CONST | TOK_FN | TOK_VFN | TOK_MUTED - | TOK_PUBLIC | TOK_NEGATE | TOK_OPEN_PAREN - | TOK_OPEN_SQUARE | TOK_OP | TOK_TT); mpr_token_t tok; + mpr_type var_type; + mpr_expr expr; + + RETURN_ARG_UNLESS(str && n_ins && in_types && in_vec_lens, 0); + for (i = 0; i < n_ins; i++) + oldest_in[i] = 0; - // ignoring spaces at start of expression + /* ignoring spaces at start of expression */ while (str[lex_idx] == ' ') ++lex_idx; {FAIL_IF(!str[lex_idx], "No expression found.");} assigning = 1; allow_toktype = TOK_VAR | TOK_TT | TOK_OPEN_SQUARE | TOK_MUTED | TOK_PUBLIC; -#if TRACING + var_type = out_type; + for (i = 0; i < n_ins; i++) { + if (var_type == in_types[i]) + continue; + if (MPR_INT32 == var_type || MPR_DBL == in_types[i]) + var_type = in_types[i]; + } + +#if TRACE_PARSE printf("parsing expression '%s'\n", str); #endif while (str[lex_idx]) { GET_NEXT_TOKEN(tok); if (assigning) { - {FAIL_IF(tok.toktype < TOK_ASSIGN && !(tok.toktype & allow_toktype & assign_mask), + {FAIL_IF(tok.toktype < TOK_ASSIGN && !(tok.toktype & allow_toktype & ASSIGN_MASK), "Illegal token sequence. (1)");} } else if (!(tok.toktype & allow_toktype)) @@ -1402,182 +1816,339 @@ mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, public = 1; allow_toktype = TOK_VAR | TOK_TT; break; - case TOK_CONST: - // push to output stack + case TOK_LITERAL: + /* push to output stack */ PUSH_TO_OUTPUT(tok); allow_toktype = (TOK_OP | TOK_CLOSE_PAREN | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY | TOK_COMMA | TOK_COLON | TOK_SEMICOLON); break; case TOK_VAR: case TOK_TT: - if (tok.var >= VAR_X) { - int slot = tok.var-VAR_X; + if (tok.var.idx >= VAR_X) { + int slot = tok.var.idx - VAR_X; {FAIL_IF(slot >= n_ins, "Input slot index > number of sources.");} - tok.datatype = in_types[slot]; - tok.vec_len = (TOK_VAR == tok.toktype) ? in_vec_lens[slot] : 1; - in_vec_len = tok.vec_len; - tok.vec_len_locked = 1; + tok.gen.datatype = in_types[slot]; + tok.gen.vec_len = (TOK_VAR == tok.toktype) ? in_vec_lens[slot] : 1; + in_vec_len = tok.gen.vec_len; + tok.gen.flags |= VEC_LEN_LOCKED; is_const = 0; } - else if (tok.var == VAR_Y) { - tok.datatype = out_type; - tok.vec_len = (TOK_VAR == tok.toktype) ? out_vec_len : 1; - tok.vec_len_locked = 1; + else if (tok.var.idx == VAR_Y) { + tok.gen.datatype = out_type; + tok.gen.vec_len = (TOK_VAR == tok.toktype) ? out_vec_len : 1; + tok.gen.flags |= VEC_LEN_LOCKED; } else { - // get name of variable - int idx = lex_idx-1; + /* get name of variable */ + int len, idx = lex_idx - 1; char c = str[idx]; while (idx >= 0 && c && (isalpha(c) || isdigit(c))) { if (--idx >= 0) c = str[idx]; } - int len = lex_idx-idx-1; - int i = find_var_by_name(vars, n_vars, str+idx+1, len); + len = lex_idx - idx - 1; + i = find_var_by_name(vars, n_vars, str+idx+1, len); if (i >= 0) { - tok.var = i; - tok.datatype = vars[i].datatype; - tok.vec_len = vars[i].vec_len; - if (tok.vec_len) - tok.vec_len_locked = 1; + tok.var.idx = i; + tok.gen.datatype = vars[i].datatype; + tok.gen.vec_len = vars[i].vec_len; + if (tok.gen.vec_len) + tok.gen.flags |= VEC_LEN_LOCKED; if (public) vars[i].public = 1; } else { {FAIL_IF(n_vars >= N_USER_VARS, "Maximum number of variables exceeded.");} - // need to store new variable - vars[n_vars].name = malloc(lex_idx-idx); - snprintf(vars[n_vars].name, lex_idx-idx, "%s", str+idx+1); - vars[n_vars].datatype = MPR_DBL; + /* need to store new variable */ + vars[n_vars].name = malloc(lex_idx - idx); + snprintf(vars[n_vars].name, lex_idx - idx, "%s", str+idx+1); + vars[n_vars].datatype = var_type; vars[n_vars].vec_len = 0; vars[n_vars].assigned = 0; vars[n_vars].public = public; -#if TRACING - printf("Stored new variable '%s' at index %i\n", - vars[n_vars].name, n_vars); +#if TRACE_PARSE + printf("Stored new variable '%s' at index %i\n", vars[n_vars].name, n_vars); #endif - tok.var = n_vars; - tok.datatype = MPR_DBL; - // special case: 'alive' tracks instance lifetime + tok.var.idx = n_vars; + tok.var.datatype = var_type; + /* special case: 'alive' tracks instance lifetime */ if (strcmp(vars[n_vars].name, "alive")==0) { inst_ctl = n_vars; - tok.vec_len = 1; - tok.vec_len_locked = 1; + tok.gen.vec_len = 1; + tok.gen.flags |= VEC_LEN_LOCKED; + tok.gen.datatype = MPR_INT32; } else if (strcmp(vars[n_vars].name, "muted")==0) { mute_ctl = n_vars; - tok.vec_len = 1; - tok.vec_len_locked = 1; + tok.gen.vec_len = 1; + tok.gen.flags |= VEC_LEN_LOCKED; + tok.gen.datatype = MPR_INT32; } else - tok.vec_len = 0; + tok.gen.vec_len = 0; ++n_vars; } } - tok.hist = 0; - tok.vec_idx = 0; - tok.muted = muted; - // timetag tokens have type double + tok.var.vec_idx = 0; + if (muted) + tok.gen.flags |= VAR_MUTED; + /* timetag tokens have type double */ if (tok.toktype == TOK_TT) - tok.datatype = MPR_DBL; + tok.gen.datatype = MPR_DBL; PUSH_TO_OUTPUT(tok); - // variables can have vector and history indices + /* variables can have vector and history indices */ var_flags = TOK_OPEN_SQUARE | TOK_OPEN_CURLY; allow_toktype = (var_flags | (assigning ? TOK_ASSIGN | TOK_ASSIGN_TT : 0)); - if (tok.var != VAR_Y || out_assigned > 1) + if (TOK_VAR == tok.toktype) + allow_toktype |= TOK_VFN_DOT | TOK_PFN; + if (tok.var.idx != VAR_Y || out_assigned > 1) allow_toktype |= (TOK_OP | TOK_CLOSE_PAREN | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY | TOK_COMMA | TOK_COLON | TOK_SEMICOLON); muted = 0; public = 0; break; - case TOK_FN: - tok.datatype = fn_tbl[tok.fn].fn_int ? MPR_INT32 : MPR_DBL; - tok.arity = fn_tbl[tok.fn].arity; + case TOK_FN: { mpr_token_t newtok; - if (fn_tbl[tok.fn].memory) { - // add assignment token - {FAIL_IF(n_vars >= N_USER_VARS, "Maximum number of variables exceeded.");} + tok.gen.datatype = fn_tbl[tok.fn.idx].fn_int ? MPR_INT32 : MPR_FLT; + tok.fn.arity = fn_tbl[tok.fn.idx].arity; + if (fn_tbl[tok.fn.idx].memory) { + /* add assignment token */ char varname[6]; int varidx = n_vars; + {FAIL_IF(n_vars >= N_USER_VARS, "Maximum number of variables exceeded.");} do { snprintf(varname, 6, "var%d", varidx++); } while (find_var_by_name(vars, n_vars, varname, 6) >= 0); - // need to store new variable + /* need to store new variable */ vars[n_vars].name = strdup(varname); - vars[n_vars].datatype = MPR_DBL; + vars[n_vars].datatype = var_type; vars[n_vars].vec_len = 1; vars[n_vars].assigned = 1; newtok.toktype = TOK_ASSIGN_USE; - newtok.var = n_vars; + newtok.var.idx = n_vars; ++n_vars; - newtok.datatype = MPR_DBL; - newtok.vec_len = 1; - newtok.vec_len_locked = 0; - newtok.hist = 0; - newtok.vec_idx = 0; - newtok.offset = 0; + newtok.gen.datatype = var_type; + newtok.gen.vec_len = 1; + newtok.gen.flags = 0; + newtok.var.vec_idx = 0; + newtok.var.offset = 0; is_const = 0; PUSH_TO_OPERATOR(newtok); } PUSH_TO_OPERATOR(tok); - if (fn_tbl[tok.fn].arity) + if (fn_tbl[tok.fn.idx].arity) allow_toktype = TOK_OPEN_PAREN; else { POP_OPERATOR_TO_OUTPUT(); allow_toktype = (TOK_OP | TOK_CLOSE_PAREN | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY | TOK_COMMA | TOK_COLON | TOK_SEMICOLON); } - if (tok.fn >= FN_DELAY) + if (tok.fn.idx >= FN_DELAY) is_const = 0; - if (fn_tbl[tok.fn].memory) { + if (fn_tbl[tok.fn.idx].memory) { newtok.toktype = TOK_VAR; - newtok.hist = 0; + newtok.gen.flags = 0; PUSH_TO_OUTPUT(newtok); } break; + } + case TOK_PFN: { + int pre, sslen; + expr_pfn_t pfn; + {FAIL_IF(PFN_POOL != tok.fn.idx, "Instance reduce functions must start with 'pool()'.");} + GET_NEXT_TOKEN(tok); + {FAIL_IF(TOK_PFN != tok.toktype && TOK_VFN_DOT != tok.toktype, + "pool() must be followed by a reduce function.");} + /* get compound arity of last token */ + sslen = substack_len(out, out_idx); + pfn = tok.fn.idx; + switch (pfn) { + case PFN_MEAN: case PFN_CENTER: case PFN_SIZE: pre = 3; break; + default: pre = 2; break; + } + + {FAIL_IF(out_idx + pre > STACK_SIZE, "Stack size exceeded. (3)");} + /* copy substack to after prefix */ + out_idx = out_idx - sslen + 1; + memcpy(out + out_idx + pre, out + out_idx, sizeof(mpr_token_t) * sslen); + --out_idx; + + /* all instance reduce functions require this token */ + tok.toktype = TOK_CACHE_INIT_INST; + PUSH_TO_OUTPUT(tok); + + switch (pfn) { + case PFN_CENTER: + case PFN_MAX: + case PFN_SIZE: + /* some reduce functions need init with the value from first iteration */ + tok.toktype = TOK_LITERAL; + tok.gen.flags = CONST_MINVAL; + PUSH_TO_OUTPUT(tok); + if (PFN_MAX == pfn) + break; + tok.toktype = TOK_LITERAL; + tok.gen.flags = CONST_MAXVAL; + PUSH_TO_OUTPUT(tok); + break; + case PFN_MIN: + tok.toktype = TOK_LITERAL; + tok.gen.flags = CONST_MAXVAL; + PUSH_TO_OUTPUT(tok); + break; + case PFN_ALL: + case PFN_ANY: + case PFN_COUNT: + case PFN_MEAN: + case PFN_SUM: + PUSH_INT_TO_OUTPUT(PFN_ALL == pfn); + if (PFN_COUNT == pfn || PFN_MEAN == pfn) + PUSH_INT_TO_OUTPUT(PFN_COUNT == pfn); + break; + default: + break; + } + + /* skip to after substack */ + if (PFN_COUNT != pfn) + out_idx += sslen; + + if (OP_UNKNOWN != pfn_tbl[pfn].op) { + tok.toktype = TOK_OP; + tok.op.idx = pfn_tbl[pfn].op; + /* don't use macro here since we don't want to optimize away initialization args */ + PUSH_TO_OUTPUT(tok); + out_idx = check_type(out, out_idx, vars, 0); + {FAIL_IF(out_idx < 0, "Malformed expression (11).");} + } + if (VFN_UNKNOWN != pfn_tbl[pfn].vfn) { + tok.toktype = TOK_VFN; + tok.fn.idx = pfn_tbl[pfn].vfn; + if (VFN_MAX == tok.fn.idx || VFN_MIN == tok.fn.idx) { + /* we don't want vector reduce version here */ + tok.toktype = TOK_FN; + tok.fn.idx = (VFN_MAX == tok.fn.idx) ? FN_MAX : FN_MIN; + tok.fn.arity = fn_tbl[tok.fn.idx].arity; + } + else + tok.fn.arity = vfn_tbl[tok.fn.idx].arity; + PUSH_TO_OPERATOR(tok); + POP_OPERATOR_TO_OUTPUT(); + } + + if (PFN_CENTER == pfn || PFN_MEAN == pfn || PFN_SIZE == pfn) { + tok.toktype = TOK_SP_ADD; + tok.lit.val.i = 1; + PUSH_TO_OUTPUT(tok); + } + + /* all instance reduce functions require these tokens */ + tok.toktype = TOK_BRANCH_NEXT_INST; + if (PFN_CENTER == pfn || PFN_MEAN == pfn || PFN_SIZE == pfn) { + tok.lit.val.i = -3 - sslen; + tok.fn.inst_cache_pos = 2; + } + else { + tok.lit.val.i = -2 - sslen; + tok.fn.inst_cache_pos = 1; + } + tok.fn.arity = 0; + PUSH_TO_OUTPUT(tok); + + if (PFN_CENTER == pfn) { + tok.toktype = TOK_OP; + tok.op.idx = OP_ADD; + PUSH_TO_OPERATOR(tok); + POP_OPERATOR_TO_OUTPUT(); + tok.toktype = TOK_LITERAL; + tok.gen.flags &= ~CONST_SPECIAL; + tok.gen.datatype = MPR_FLT; + tok.lit.val.f = 0.5; + PUSH_TO_OUTPUT(tok); + tok.toktype = TOK_OP; + tok.op.idx = OP_MULTIPLY; + PUSH_TO_OPERATOR(tok); + POP_OPERATOR_TO_OUTPUT(); + } + else if (PFN_MEAN == pfn) { + tok.toktype = TOK_OP; + tok.op.idx = OP_DIVIDE; + PUSH_TO_OPERATOR(tok); + POP_OPERATOR_TO_OUTPUT(); + } + else if (PFN_SIZE == pfn) { + tok.toktype = TOK_OP; + tok.op.idx = OP_SUBTRACT; + PUSH_TO_OPERATOR(tok); + POP_OPERATOR_TO_OUTPUT(); + } + allow_toktype = (TOK_OP | TOK_CLOSE_PAREN | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY + | TOK_COMMA | TOK_COLON | TOK_SEMICOLON); + break; + } case TOK_VFN: - tok.datatype = vfn_tbl[tok.fn].fn_int ? MPR_INT32 : MPR_FLT; + tok.toktype = TOK_VFN; + tok.gen.datatype = vfn_tbl[tok.fn.idx].fn_int ? MPR_INT32 : MPR_FLT; + tok.fn.arity = vfn_tbl[tok.fn.idx].arity; + tok.gen.vec_len = 1; PUSH_TO_OPERATOR(tok); allow_toktype = TOK_OPEN_PAREN; break; + case TOK_VFN_DOT: + tok.toktype = TOK_VFN; + tok.gen.datatype = vfn_tbl[tok.fn.idx].fn_int ? MPR_INT32 : MPR_FLT; + tok.fn.arity = vfn_tbl[tok.fn.idx].arity; + tok.gen.vec_len = 1; + PUSH_TO_OPERATOR(tok); + POP_OPERATOR_TO_OUTPUT(); + allow_toktype = (TOK_OP | TOK_CLOSE_PAREN | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY + | TOK_COMMA | TOK_COLON | TOK_SEMICOLON | TOK_PFN); + break; case TOK_OPEN_PAREN: - tok.arity = 1; + if (TOK_FN == op[op_idx].toktype && fn_tbl[op[op_idx].fn.idx].memory) + tok.fn.arity = 2; + else + tok.fn.arity = 1; PUSH_TO_OPERATOR(tok); allow_toktype = OBJECT_TOKENS; break; case TOK_CLOSE_CURLY: - case TOK_CLOSE_PAREN: - // pop from operator stack to output until left parenthesis found + case TOK_CLOSE_PAREN: { + int arity; + /* pop from operator stack to output until left parenthesis found */ while (op_idx >= 0 && op[op_idx].toktype != TOK_OPEN_PAREN) POP_OPERATOR_TO_OUTPUT(); {FAIL_IF(op_idx < 0, "Unmatched parentheses or misplaced comma.");} - int arity = op[op_idx].arity; - // remove left parenthesis from operator stack + arity = op[op_idx].fn.arity; + /* remove left parenthesis from operator stack */ POP_OPERATOR(); - allow_toktype = (TOK_OP | TOK_COLON | TOK_SEMICOLON | TOK_COMMA - | TOK_CLOSE_PAREN | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY); + allow_toktype = (TOK_OP | TOK_COLON | TOK_SEMICOLON | TOK_COMMA | TOK_CLOSE_PAREN + | TOK_CLOSE_SQUARE | TOK_CLOSE_CURLY); if (tok.toktype == TOK_CLOSE_CURLY) allow_toktype |= TOK_OPEN_SQUARE; + else + allow_toktype |= (TOK_VFN_DOT | TOK_PFN); if (op_idx < 0) break; - // if operator stack[top] is tok_fn or tok_vfn, pop to output + /* if operator stack[sp] is tok_fn or tok_vfn, pop to output */ if (op[op_idx].toktype == TOK_FN) { - if (FN_DELAY == op[op_idx].fn) { + if (FN_DELAY == op[op_idx].fn.idx) { int buffer_size = 0; switch (arity) { case 2: - // max delay should be at the top of output stack - {FAIL_IF(out[out_idx].toktype != TOK_CONST, "non-constant max history.");} - switch (out[out_idx].datatype) { -#define TYPED_CASE(MTYPE, EL) \ - case MTYPE: \ - buffer_size = (int)out[out_idx].EL; \ + /* max delay should be at the top of output stack */ + {FAIL_IF(out[out_idx].toktype != TOK_LITERAL, + "non-constant max history.");} + switch (out[out_idx].gen.datatype) { +#define TYPED_CASE(MTYPE, T) \ + case MTYPE: \ + buffer_size = (int)out[out_idx].lit.val.T; \ break; TYPED_CASE(MPR_INT32, i) TYPED_CASE(MPR_FLT, f) @@ -1593,12 +2164,12 @@ mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, {FAIL_IF(out[out_idx].toktype != TOK_VAR && out[out_idx].toktype != TOK_TT, "delay on non-variable token.");} if (!buffer_size) { - {FAIL_IF(out[out_idx-1].toktype != TOK_CONST, + {FAIL_IF(out[out_idx - 1].toktype != TOK_LITERAL, "variable history indices must include maximum value.");} - switch (out[out_idx-1].datatype) { -#define TYPED_CASE(MTYPE, EL) \ - case MTYPE: \ - buffer_size = (int)out[out_idx-1].EL; \ + switch (out[out_idx - 1].gen.datatype) { +#define TYPED_CASE(MTYPE, T) \ + case MTYPE: \ + buffer_size = (int)out[out_idx - 1].lit.val.T; \ break; TYPED_CASE(MPR_INT32, i) TYPED_CASE(MPR_FLT, f) @@ -1611,153 +2182,178 @@ mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, "Illegal history index.");} } if (!buffer_size) { - // remove zero delay - memcpy(&out[out_idx-1], &out[out_idx], sizeof(mpr_token_t)); + /* remove zero delay */ + memcpy(&out[out_idx - 1], &out[out_idx], sizeof(mpr_token_t)); POP_OUTPUT(); POP_OPERATOR(); break; } - if (out[out_idx].var == VAR_Y && buffer_size < oldest_out) + if (out[out_idx].var.idx == VAR_Y && buffer_size < oldest_out) oldest_out = buffer_size; - else if ( out[out_idx].var >= VAR_X - && buffer_size < oldest_in[out[out_idx].var-VAR_X]) { - oldest_in[out[out_idx].var-VAR_X] = buffer_size; + else if ( out[out_idx].var.idx >= VAR_X + && buffer_size < oldest_in[out[out_idx].var.idx - VAR_X]) { + oldest_in[out[out_idx].var.idx - VAR_X] = buffer_size; } - // TODO: disable non-const assignment to past values of output - out[out_idx].hist = 1; + /* TODO: disable non-const assignment to past values of output */ + out[out_idx].gen.flags |= VAR_DELAY; POP_OPERATOR(); - // cast history index to int if necessary - // TODO: consider adding support for interpolation - if (out[out_idx-1].datatype != MPR_INT32) - out[out_idx-1].casttype = MPR_INT32; break; default: {FAIL("Illegal arity for variable delay.");} } } else { - // check for overloaded functions - if (arity == 1) { - if (op[op_idx].fn == FN_MIN) { + if (arity != fn_tbl[op[op_idx].fn.idx].arity) { + /* check for overloaded functions */ + if (arity != 1) + {FAIL("Function arity mismatch.");} + if (op[op_idx].fn.idx == FN_MIN) { op[op_idx].toktype = TOK_VFN; - op[op_idx].vfn = VFN_MIN; + op[op_idx].fn.idx = VFN_MIN; } - else if (op[op_idx].fn == FN_MAX) { + else if (op[op_idx].fn.idx == FN_MAX) { op[op_idx].toktype = TOK_VFN; - op[op_idx].vfn = VFN_MAX; + op[op_idx].fn.idx = VFN_MAX; } + else + {FAIL("Function arity mismatch.");} } POP_OPERATOR_TO_OUTPUT(); } + } - else if (op[op_idx].toktype == TOK_VFN) + else if (op[op_idx].toktype == TOK_VFN) { + /* check arity */ + {FAIL_IF(arity != vfn_tbl[op[op_idx].fn.idx].arity, "VFN arity mismatch.");} POP_OPERATOR_TO_OUTPUT(); - // special case: if stack[top] is tok_assign, pop to output + } + /* special case: if top of stack is tok_assign_use, pop to output */ if (op_idx >= 0 && op[op_idx].toktype == TOK_ASSIGN_USE) POP_OPERATOR_TO_OUTPUT(); break; + } case TOK_COMMA: - // pop from operator stack to output until left parenthesis or TOK_VECTORIZE found + /* pop from operator stack to output until left parenthesis or TOK_VECTORIZE found */ while (op_idx >= 0 && op[op_idx].toktype != TOK_OPEN_PAREN && op[op_idx].toktype != TOK_VECTORIZE) { POP_OPERATOR_TO_OUTPUT(); } - {FAIL_IF(op_idx < 0, "Malformed expression (3).");} + {FAIL_IF(op_idx < 0, "Malformed expression (4).");} if (op[op_idx].toktype == TOK_VECTORIZE) { - ++op[op_idx].vec_idx; - op[op_idx].vec_len += out[out_idx].vec_len; + switch (out[out_idx].toktype) { + case TOK_BRANCH_NEXT_INST: + op[op_idx].gen.vec_len += out[out_idx-1].gen.vec_len; + ++op[op_idx].fn.arity; + break; + case TOK_LITERAL: + if (out_idx >= 1 && TOK_LITERAL == out[out_idx - 1].toktype + && out[out_idx].gen.datatype == out[out_idx - 1].gen.datatype + && out[out_idx].lit.val.i == out[out_idx - 1].lit.val.i) { +#if TRACE_EVAL + printf("Squashing vector. (1)\n"); +#endif + ++out[out_idx - 1].gen.vec_len; + ++op[op_idx].gen.vec_len; + POP_OUTPUT(); + break; + } + default: + op[op_idx].gen.vec_len += out[out_idx].gen.vec_len; + ++op[op_idx].fn.arity; + } lock_vec_len(out, out_idx); } - ++op[op_idx].arity; + else + ++op[op_idx].fn.arity; allow_toktype = OBJECT_TOKENS; break; case TOK_COLON: - // pop from operator stack to output until conditional found - while (op_idx >= 0 && (op[op_idx].toktype != TOK_OP || - op[op_idx].op != OP_IF)) { + /* pop from operator stack to output until conditional found */ + while (op_idx >= 0 && (op[op_idx].toktype != TOK_OP || op[op_idx].op.idx != OP_IF)) { POP_OPERATOR_TO_OUTPUT(); } {FAIL_IF(op_idx < 0, "Unmatched colon.");} - op[op_idx].op = OP_IF_THEN_ELSE; + op[op_idx].op.idx = OP_IF_THEN_ELSE; allow_toktype = OBJECT_TOKENS; break; - case TOK_SEMICOLON: - // finish popping operators to output, check for unbalanced parentheses + case TOK_SEMICOLON: { + int var_idx; + /* finish popping operators to output, check for unbalanced parentheses */ while (op_idx >= 0 && op[op_idx].toktype < TOK_ASSIGN) { if (op[op_idx].toktype == TOK_OPEN_PAREN) {FAIL("Unmatched parentheses or misplaced comma.");} POP_OPERATOR_TO_OUTPUT(); } - int var_idx = op[op_idx].var; + var_idx = op[op_idx].var.idx; if (var_idx < VAR_Y) { if (!vars[var_idx].vec_len) - vars[var_idx].vec_len = out[out_idx].vec_len; - // update and lock vector length of assigned variable - op[op_idx].vec_len = vars[var_idx].vec_len; - op[op_idx].vec_len_locked = 1; + vars[var_idx].vec_len = out[out_idx].gen.vec_len; + /* update and lock vector length of assigned variable */ + op[op_idx].gen.vec_len = vars[var_idx].vec_len; + op[op_idx].gen.flags |= VEC_LEN_LOCKED; } - // pop assignment operators to output + /* pop assignment operators to output */ while (op_idx >= 0) { if (!op_idx && op[op_idx].toktype < TOK_ASSIGN) - {FAIL("Malformed expression (4)");} + {FAIL("Malformed expression (5)");} PUSH_TO_OUTPUT(op[op_idx]); if (out[out_idx].toktype == TOK_ASSIGN_USE && check_assign_type_and_len(out, out_idx, vars) == -1) - {FAIL("Malformed expression (5)");} + {FAIL("Malformed expression (6)");} POP_OPERATOR(); } - // check vector length and type + /* mark last assignment token to clear eval stack */ + out[out_idx].gen.flags |= CLEAR_STACK; + + /* check vector length and type */ if (check_assign_type_and_len(out, out_idx, vars) == -1) - {FAIL("Malformed expression (6)");} - // start another sub-expression + {FAIL("Malformed expression (7)");} + + /* start another sub-expression */ assigning = 1; allow_toktype = TOK_VAR | TOK_TT | TOK_PUBLIC; break; + } case TOK_OP: - // check precedence of operators on stack + /* check precedence of operators on stack */ while (op_idx >= 0 && op[op_idx].toktype == TOK_OP - && (op_tbl[op[op_idx].op].precedence >= - op_tbl[tok.op].precedence)) { + && (op_tbl[op[op_idx].op.idx].precedence >= + op_tbl[tok.op.idx].precedence)) { POP_OPERATOR_TO_OUTPUT(); } PUSH_TO_OPERATOR(tok); allow_toktype = OBJECT_TOKENS; break; case TOK_OPEN_SQUARE: - if (var_flags & TOK_OPEN_SQUARE) { // vector index not set + if (var_flags & TOK_OPEN_SQUARE) { /* vector index not set */ GET_NEXT_TOKEN(tok); - {FAIL_IF(tok.toktype != TOK_CONST || tok.datatype != MPR_INT32, + {FAIL_IF(tok.toktype != TOK_LITERAL || tok.gen.datatype != MPR_INT32, "Non-integer vector index.");} - if (out[out_idx].var == VAR_Y) { - {FAIL_IF(tok.i >= out_vec_len, - "Index exceeds output vector length. (1)");} - } + if (out[out_idx].var.idx == VAR_Y) + {FAIL_IF(tok.lit.val.i >= out_vec_len, "Index exceeds output vector length. (1)");} else - {FAIL_IF(tok.i >= in_vec_len, "Index exceeds input vector length. (1)");} - out[out_idx].vec_idx = tok.i; - out[out_idx].vec_len = 1; - out[out_idx].vec_len_locked = 1; + {FAIL_IF(tok.lit.val.i >= in_vec_len, "Index exceeds input vector length. (1)");} + out[out_idx].var.vec_idx = tok.lit.val.i; + out[out_idx].gen.vec_len = 1; + out[out_idx].gen.flags |= VEC_LEN_LOCKED; GET_NEXT_TOKEN(tok); if (tok.toktype == TOK_COLON) { - // index is range A:B + /* index is range A:B */ GET_NEXT_TOKEN(tok); - {FAIL_IF(tok.toktype != TOK_CONST || tok.datatype != MPR_INT32, + {FAIL_IF(tok.toktype != TOK_LITERAL || tok.gen.datatype != MPR_INT32, "Malformed vector index.");} - if (out[out_idx].var == VAR_Y) { - {FAIL_IF(tok.i >= out_vec_len, + if (out[out_idx].var.idx == VAR_Y) + {FAIL_IF(tok.lit.val.i >= out_vec_len, "Index exceeds output vector length. (2)");} - } else - {FAIL_IF(tok.i >= in_vec_len, + {FAIL_IF(tok.lit.val.i >= in_vec_len, "Index exceeds input vector length. (2)");} - {FAIL_IF(tok.i < out[out_idx].vec_idx, - "Malformed vector index.");} - out[out_idx].vec_len = - tok.i - out[out_idx].vec_idx + 1; + {FAIL_IF(tok.lit.val.i < out[out_idx].var.vec_idx, "Malformed vector index.");} + out[out_idx].gen.vec_len = tok.lit.val.i - out[out_idx].var.vec_idx + 1; GET_NEXT_TOKEN(tok); } {FAIL_IF(tok.toktype != TOK_CLOSE_SQUARE, "Unmatched bracket.");} - // vector index set + /* vector index set */ var_flags &= ~TOK_OPEN_SQUARE; allow_toktype = (TOK_OP | TOK_COMMA | TOK_CLOSE_PAREN | TOK_CLOSE_CURLY | TOK_CLOSE_SQUARE | TOK_COLON | TOK_SEMICOLON @@ -1766,47 +2362,66 @@ mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, else { {FAIL_IF(vectorizing, "Nested (multidimensional) vectors not allowed.");} tok.toktype = TOK_VECTORIZE; - tok.vec_len = 0; - tok.arity = 0; + tok.gen.vec_len = 0; + tok.fn.arity = 0; PUSH_TO_OPERATOR(tok); vectorizing = 1; allow_toktype = OBJECT_TOKENS & ~TOK_OPEN_SQUARE; } break; case TOK_CLOSE_SQUARE: - // pop from operator stack to output until TOK_VECTORIZE found + /* pop from operator stack to output until TOK_VECTORIZE found */ while (op_idx >= 0 && op[op_idx].toktype != TOK_VECTORIZE) { POP_OPERATOR_TO_OUTPUT(); } {FAIL_IF(op_idx < 0, "Unmatched brackets or misplaced comma.");} - if (op[op_idx].vec_len) { - op[op_idx].vec_len_locked = 1; - ++op[op_idx].arity; - op[op_idx].vec_len += out[out_idx].vec_len; + if (op[op_idx].gen.vec_len) { + op[op_idx].gen.flags |= VEC_LEN_LOCKED; + + switch (out[out_idx].toktype) { + case TOK_BRANCH_NEXT_INST: + op[op_idx].gen.vec_len += out[out_idx-1].gen.vec_len; + ++op[op_idx].fn.arity; + break; + case TOK_LITERAL: + if (out_idx >= 1 && TOK_LITERAL == out[out_idx - 1].toktype + && out[out_idx].gen.datatype == out[out_idx - 1].gen.datatype + && out[out_idx].lit.val.i == out[out_idx - 1].lit.val.i) { + trace("Squashing vector. (2)\n"); + ++out[out_idx - 1].gen.vec_len; + ++op[op_idx].gen.vec_len; + POP_OUTPUT(); + break; + } + default: + op[op_idx].gen.vec_len += out[out_idx].gen.vec_len; + ++op[op_idx].fn.arity; + } lock_vec_len(out, out_idx); - POP_OPERATOR_TO_OUTPUT(); } + if (op[op_idx].fn.arity > 1) + { POP_OPERATOR_TO_OUTPUT(); } else { - // we do not need vectorizer token if vector length == 1 + /* we do not need vectorizer token if vector length == 1 */ POP_OPERATOR(); } vectorizing = 0; allow_toktype = (TOK_OP | TOK_CLOSE_PAREN | TOK_CLOSE_CURLY | TOK_COMMA - | TOK_COLON | TOK_SEMICOLON); + | TOK_COLON | TOK_SEMICOLON | TOK_VFN_DOT); break; case TOK_OPEN_CURLY: - // push a FN_DELAY to operator stack + /* push a FN_DELAY to operator stack */ tok.toktype = TOK_FN; - tok.fn = FN_DELAY; - tok.arity = 1; + tok.fn.idx = FN_DELAY; + tok.fn.arity = 1; PUSH_TO_OPERATOR(tok); - // also push an open parenthesis + /* also push an open parenthesis */ tok.toktype = TOK_OPEN_PAREN; PUSH_TO_OPERATOR(tok); - // move variable from output to operator stack + /* move variable from output to operator stack */ PUSH_TO_OPERATOR(out[out_idx]); POP_OUTPUT(); @@ -1815,173 +2430,189 @@ mpr_expr mpr_expr_new_from_str(const char *str, int n_ins, allow_toktype = OBJECT_TOKENS; break; case TOK_NEGATE: - // push '-1' to output stack, and '*' to operator stack - tok.toktype = TOK_CONST; - tok.datatype = MPR_INT32; - tok.i = -1; + /* push '-1' to output stack, and '*' to operator stack */ + tok.toktype = TOK_LITERAL; + tok.gen.datatype = MPR_INT32; + tok.lit.val.i = -1; PUSH_TO_OUTPUT(tok); tok.toktype = TOK_OP; - tok.op = OP_MULTIPLY; + tok.op.idx = OP_MULTIPLY; PUSH_TO_OPERATOR(tok); - allow_toktype = TOK_CONST | TOK_VAR | TOK_TT | TOK_FN | TOK_VFN; + allow_toktype = TOK_LITERAL | TOK_VAR | TOK_TT | TOK_FN; break; case TOK_ASSIGN: var_flags = 0; - // assignment to variable + /* assignment to variable */ {FAIL_IF(!assigning, "Misplaced assignment operator.");} - {FAIL_IF(op_idx >= 0 || out_idx < 0, - "Malformed expression left of assignment.");} + {FAIL_IF(op_idx >= 0 || out_idx < 0, "Malformed expression left of assignment.");} if (out[out_idx].toktype == TOK_VAR) { - int var = out[out_idx].var; + int var = out[out_idx].var.idx; if (var >= VAR_X) {FAIL("Cannot assign to input variable 'x'.");} - else if (var == VAR_Y) { - if (out[out_idx].hist == 0) + if (!(out[out_idx].gen.flags & VAR_DELAY)) { + if (var == VAR_Y) ++out_assigned; + else + vars[var].assigned = 1; } - else if (out[out_idx].hist == 0) - vars[var].assigned = 1; - // nothing extraordinary, continue as normal + /* nothing extraordinary, continue as normal */ out[out_idx].toktype = is_const ? TOK_ASSIGN_CONST : TOK_ASSIGN; - out[out_idx].offset = 0; + out[out_idx].var.offset = 0; PUSH_TO_OPERATOR(out[out_idx]); --out_idx; } else if (out[out_idx].toktype == TOK_TT) { - // assignment to timetag - // for now we will only allow assigning to output t_y - FAIL_IF(out[out_idx].var != VAR_Y, "Only output timetag is writable."); - // disable writing to current timetag for now - FAIL_IF(out[out_idx].hist == 0, "Only past samples of output timetag are writable."); + /* assignment to timetag */ + /* for now we will only allow assigning to output t_y */ + FAIL_IF(out[out_idx].var.idx != VAR_Y, "Only output timetag is writable."); + /* disable writing to current timetag for now */ + FAIL_IF(!(out[out_idx].gen.flags & VAR_DELAY), + "Only past samples of output timetag are writable."); out[out_idx].toktype = TOK_ASSIGN_TT; - out[out_idx].datatype = MPR_DBL; + out[out_idx].gen.datatype = MPR_DBL; PUSH_TO_OPERATOR(out[out_idx]); --out_idx; } else if (out[out_idx].toktype == TOK_VECTORIZE) { - // out token is vectorizer + int var, idx, vec_count = 0;; + /* out token is vectorizer */ --out_idx; {FAIL_IF(out[out_idx].toktype != TOK_VAR, "Illegal tokens left of assignment.");} - int var = out[out_idx].var; + var = out[out_idx].var.idx; if (var >= VAR_X) {FAIL("Cannot assign to input variable 'x'.");} else if (var == VAR_Y) { - if (out[out_idx].hist == 0) + if (!(out[out_idx].gen.flags & VAR_DELAY)) ++out_assigned; } - else if (out[out_idx].hist == 0) + else if (!(out[out_idx].gen.flags & VAR_DELAY)) vars[var].assigned = 1; while (out_idx >= 0) { if (out[out_idx].toktype != TOK_VAR) {FAIL("Illegal tokens left of assignment.");} - else if (out[out_idx].var != var) + else if (out[out_idx].var.idx != var) {FAIL("Cannot mix variables in vector assignment.");} out[out_idx].toktype = is_const ? TOK_ASSIGN_CONST : TOK_ASSIGN; PUSH_TO_OPERATOR(out[out_idx]); --out_idx; } - int idx = op_idx, vec_count = 0; + idx = op_idx; while (idx >= 0) { - op[idx].offset = vec_count; - vec_count += op[idx].vec_len; + op[idx].var.offset = vec_count; + vec_count += op[idx].gen.vec_len; --idx; } } else {FAIL("Malformed expression left of assignment.");} assigning = 0; - allow_toktype = 0xFFFFF; + allow_toktype = (TOK_VAR | TOK_LITERAL | TOK_FN | TOK_VFN | TOK_MUTED | TOK_PUBLIC + | TOK_NEGATE | TOK_OPEN_PAREN | TOK_OPEN_SQUARE | TOK_OP | TOK_TT); break; default: {FAIL("Unknown token type.");} break; } -#if (TRACING && DEBUG) +#if (TRACE_PARSE) printstack("OUTPUT STACK: ", out, out_idx, vars, 0); printstack("OPERATOR STACK:", op, op_idx, vars, 0); #endif } - {FAIL_IF(allow_toktype & TOK_CONST || !out_assigned, - "Expression has no output assignment.");} + {FAIL_IF(allow_toktype & TOK_LITERAL || !out_assigned, "Expression has no output assignment.");} - // check that all used-defined variables were assigned + /* check that all used-defined variables were assigned */ for (i = 0; i < n_vars; i++) { {FAIL_IF(!vars[i].assigned, "User-defined variable not assigned.");} } - // finish popping operators to output, check for unbalanced parentheses + /* finish popping operators to output, check for unbalanced parentheses */ while (op_idx >= 0 && op[op_idx].toktype < TOK_ASSIGN) { - {FAIL_IF(op[op_idx].toktype == TOK_OPEN_PAREN, - "Unmatched parentheses or misplaced comma.");} + {FAIL_IF(op[op_idx].toktype == TOK_OPEN_PAREN, "Unmatched parentheses or misplaced comma.");} POP_OPERATOR_TO_OUTPUT(); } if (op_idx >= 0) { - int var_idx = op[op_idx].var; + int var_idx = op[op_idx].var.idx; if (var_idx < VAR_Y) { if (!vars[var_idx].vec_len) - vars[var_idx].vec_len = out[out_idx].vec_len; - // update and lock vector length of assigned variable - op[op_idx].vec_len = vars[var_idx].vec_len; - op[op_idx].vec_len_locked = 1; + vars[var_idx].vec_len = out[out_idx].gen.vec_len; + /* update and lock vector length of assigned variable */ + op[op_idx].gen.vec_len = vars[var_idx].vec_len; + op[op_idx].gen.flags |= VEC_LEN_LOCKED; } } - // pop assignment operator(s) to output + /* pop assignment operator(s) to output */ while (op_idx >= 0) { - {FAIL_IF(!op_idx && op[op_idx].toktype < TOK_ASSIGN, - "Malformed expression (7).");} + {FAIL_IF(!op_idx && op[op_idx].toktype < TOK_ASSIGN, "Malformed expression (8).");} PUSH_TO_OUTPUT(op[op_idx]); - // check vector length and type + /* check vector length and type */ {FAIL_IF(out[out_idx].toktype == TOK_ASSIGN_USE && check_assign_type_and_len(out, out_idx, vars) == -1, - "Malformed expression (8).");} + "Malformed expression (9).");} POP_OPERATOR(); } - // check vector length and type - {FAIL_IF(check_assign_type_and_len(out, out_idx, vars) == -1, - "Malformed expression (9).");} + /* mark last assignment token to clear eval stack */ + out[out_idx].gen.flags |= CLEAR_STACK; + + /* promote unlocked variable token vector lengths */ + for (i = 0; i < out_idx; i++) { + if (TOK_VAR == out[i].toktype && out[i].var.idx < N_USER_VARS + && !(out[i].gen.flags & VEC_LEN_LOCKED)) + out[i].gen.vec_len = vars[tok.var.idx].vec_len; + } + + /* check vector length and type */ + {FAIL_IF(check_assign_type_and_len(out, out_idx, vars) == -1, "Malformed expression (10).");} -#if (TRACING && DEBUG) + {FAIL_IF(replace_special_constants(out, out_idx), "Error replacing special constants."); } + +#if (TRACE_PARSE) printstack("--->OUTPUT STACK: ", out, out_idx, vars, 0); printstack("--->OPERATOR STACK:", op, op_idx, vars, 0); #endif - // Check for maximum vector length used in stack + /* Check for maximum vector length used in stack */ for (i = 0; i < out_idx; i++) { - if (out[i].vec_len > max_vector) - max_vector = out[i].vec_len; + if (out[i].gen.vec_len > max_vector) + max_vector = out[i].gen.vec_len; } - mpr_expr expr = malloc(sizeof(struct _mpr_expr)); - expr->len = out_idx + 1; + expr = malloc(sizeof(struct _mpr_expr)); + expr->n_tokens = out_idx + 1; + expr->stack_size = _eval_stack_size(out, out_idx); expr->offset = 0; expr->inst_ctl = inst_ctl; expr->mute_ctl = mute_ctl; - // copy tokens - expr->tokens = malloc(sizeof(struct _token) * expr->len); - memcpy(expr->tokens, &out, sizeof(struct _token) * expr->len); + /* copy tokens */ + expr->tokens = malloc(sizeof(union _token) * expr->n_tokens); + memcpy(expr->tokens, &out, sizeof(union _token) * expr->n_tokens); expr->start = expr->tokens; - expr->vec_size = max_vector; + expr->vec_len = max_vector; expr->out_hist_size = -oldest_out+1; expr->in_hist_size = malloc(sizeof(uint8_t) * n_ins); for (i = 0; i < n_ins; i++) expr->in_hist_size[i] = -oldest_in[i] + 1; if (n_vars) { - // copy user-defined variables - expr->vars = malloc(sizeof(mpr_var_t)*n_vars); - memcpy(expr->vars, vars, sizeof(mpr_var_t)*n_vars); + /* copy user-defined variables */ + expr->vars = malloc(sizeof(mpr_var_t) * n_vars); + memcpy(expr->vars, vars, sizeof(mpr_var_t) * n_vars); } else expr->vars = NULL; expr->n_vars = n_vars; -#if TRACING + /* TODO: is this the same as n_ins arg passed to this function? */ + expr->n_ins = _get_num_input_slots(expr); + + expr_stack_realloc(expr->stack_size * expr->vec_len); + +#if TRACE_PARSE printf("expression allocated and initialized\n"); #endif return expr; @@ -2004,7 +2635,7 @@ int mpr_expr_get_num_vars(mpr_expr expr) int mpr_expr_get_var_is_public(mpr_expr expr, int idx) { - return 1;//(idx >= 0 && idx < expr->n_vars) ? expr->vars[idx].public : 0; + return 1;/*(idx >= 0 && idx < expr->n_vars) ? expr->vars[idx].public : 0; */ } const char *mpr_expr_get_var_name(mpr_expr expr, int idx) @@ -2017,14 +2648,19 @@ int mpr_expr_get_var_vec_len(mpr_expr expr, int idx) return (idx >= 0 && idx < expr->n_vars) ? expr->vars[idx].vec_len : 0; } +int mpr_expr_get_var_type(mpr_expr expr, int idx) +{ + return (idx >= 0 && idx < expr->n_vars) ? expr->vars[idx].datatype : 0; +} + int mpr_expr_get_src_is_muted(mpr_expr expr, int idx) { - int i, found = 0, muted = 1; + int i, found = 0, muted = VAR_MUTED; mpr_token_t *tok = expr->tokens; - for (i = 0; i < expr->len; i++) { - if (tok[i].toktype == TOK_VAR && tok[i].var == idx + VAR_X) { + for (i = 0; i < expr->n_tokens; i++) { + if (tok[i].toktype == TOK_VAR && tok[i].var.idx == idx + VAR_X) { found = 1; - muted &= tok[i].muted; + muted &= tok[i].gen.flags; } } return found && muted; @@ -2032,14 +2668,7 @@ int mpr_expr_get_src_is_muted(mpr_expr expr, int idx) int mpr_expr_get_num_input_slots(mpr_expr expr) { - // actually need to return highest numbered input slot - int i, count = -1; - mpr_token_t *tok = expr->tokens; - for (i = 0; i < expr->len; i++) { - if (tok[i].toktype == TOK_VAR && tok[i].var > count) - count = tok[i].var; - } - return count >= VAR_X ? count - VAR_X + 1 : 0; + return expr ? expr->n_ins : 0; } int mpr_expr_get_manages_inst(mpr_expr expr) @@ -2047,21 +2676,21 @@ int mpr_expr_get_manages_inst(mpr_expr expr) return expr ? expr->inst_ctl >= 0 : 0; } -#if TRACING +#if TRACE_EVAL static void print_stack_vec(mpr_expr_val stk, mpr_type type, int vec_len) { int i; if (vec_len > 1) printf("["); switch (type) { -#define TYPED_CASE(MTYPE, STR, EL) \ +#define TYPED_CASE(MTYPE, STR, T) \ case MTYPE: \ for (i = 0; i < vec_len; i++) \ - printf(STR, stk[i].EL); \ + printf(STR, stk[i].T); \ break; TYPED_CASE(MPR_INT32, "%d, ", i) - TYPED_CASE(MPR_FLT, "%f, ", f) - TYPED_CASE(MPR_DBL, "%f, ", d) + TYPED_CASE(MPR_FLT, "%g, ", f) + TYPED_CASE(MPR_DBL, "%g, ", d) #undef TYPED_CASE default: break; @@ -2073,7 +2702,7 @@ static void print_stack_vec(mpr_expr_val stk, mpr_type type, int vec_len) } #endif -#if TRACING +#if TRACE_EVAL static const char *type_name(const mpr_type type) { switch (type) { @@ -2085,31 +2714,31 @@ static const char *type_name(const mpr_type type) } #endif -#define UNARY_OP_CASE(OP, SYM, EL) \ +#define UNARY_OP_CASE(OP, SYM, T) \ case OP: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL SYM stk[top][i].EL; \ + for (i = sp; i < sp + dims[dp]; i++) \ + stk[i].T SYM stk[i].T; \ break; -#define BINARY_OP_CASE(OP, SYM, EL) \ +#define BINARY_OP_CASE(OP, SYM, T) \ case OP: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = stk[top][i].EL SYM stk[top+1][i].EL; \ + for (i = 0, j = sp; i < dims[dp]; i++, j++) \ + stk[j].T = stk[j].T SYM stk[sp + vlen + i % rdim].T; \ break; -#define CONDITIONAL_CASES(EL) \ +#define CONDITIONAL_CASES(T) \ case OP_IF_ELSE: \ - for (i = 0; i < tok->vec_len; i++) { \ - if (!stk[top][i].EL) \ - stk[top][i].EL = stk[top+1][i].EL; \ + for (i = 0, j = sp; i < dims[dp]; i++, j++) { \ + if (!stk[j].T) \ + stk[j].T = stk[sp + vlen + i % rdim].T; \ } \ break; \ case OP_IF_THEN_ELSE: \ - for (i = 0; i < tok->vec_len; i++) { \ - if (stk[top][i].EL) \ - stk[top][i].EL = stk[top+1][i].EL; \ + for (i = 0, j = sp; i < dims[dp]; i++, j++) { \ + if (stk[j].T) \ + stk[j].T = stk[sp + vlen + i % rdim].T; \ else \ - stk[top][i].EL = stk[top+2][i].EL; \ + stk[j].T = stk[sp + 2 * vlen + i % dims[dp + 2]].T; \ } \ break; @@ -2117,7 +2746,6 @@ static const char *type_name(const mpr_type type) BINARY_OP_CASE(OP_ADD, +, EL); \ BINARY_OP_CASE(OP_SUBTRACT, -, EL); \ BINARY_OP_CASE(OP_MULTIPLY, *, EL); \ - BINARY_OP_CASE(OP_DIVIDE, /, EL); \ BINARY_OP_CASE(OP_IS_EQUAL, ==, EL); \ BINARY_OP_CASE(OP_IS_NOT_EQUAL, !=, EL); \ BINARY_OP_CASE(OP_IS_LESS_THAN, <, EL); \ @@ -2126,90 +2754,145 @@ static const char *type_name(const mpr_type type) BINARY_OP_CASE(OP_IS_GREATER_THAN_OR_EQUAL, >=, EL); \ BINARY_OP_CASE(OP_LOGICAL_AND, &&, EL); \ BINARY_OP_CASE(OP_LOGICAL_OR, ||, EL); \ - UNARY_OP_CASE(OP_LOGICAL_NOT, =!, EL) \ - CONDITIONAL_CASES(EL) + UNARY_OP_CASE(OP_LOGICAL_NOT, =!, EL); \ + CONDITIONAL_CASES(EL); -#define COPY_TYPED(MTYPE, TYPE, EL) \ +#define COPY_TYPED(MTYPE, TYPE, T) \ case MTYPE: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = ((TYPE*)a)[i+tok->vec_idx]; \ + for (i = 0, j = sp; i < tok->gen.vec_len; i++, j++) \ + stk[j].T = ((TYPE*)a)[i + tok->var.vec_idx]; \ break; -#define COPY_TO_STACK(SRC) \ - if (!tok->hist) \ - ++top; \ - dims[top] = tok->vec_len; \ - mpr_value_buffer b = &SRC->inst[inst_idx % SRC->num_inst]; \ - idx = ((b->pos + SRC->mlen + (tok->hist ? stk[top][0].i : 0)) % SRC->mlen); \ - if (idx < 0) idx = SRC->mlen + idx; \ - void *a = (b->samps + idx * SRC->vlen * mpr_type_get_size(SRC->type)); \ - switch (SRC->type) { \ - COPY_TYPED(MPR_INT32, int, i) \ - COPY_TYPED(MPR_FLT, float, f) \ - COPY_TYPED(MPR_DBL, double, d) \ - default: \ - goto error; \ - } + +#define WEIGHTED_ADD(MTYPE, TYPE, T) \ + case MTYPE: \ + for (i = 0, j = sp; i < tok->gen.vec_len; i++, j++) \ + stk[j].T = stk[j].T * weight + ((TYPE*)a)[i + tok->var.vec_idx] * (1 - weight); \ + break; + +#define COPY_TO_STACK(VAL) \ + if (!(tok->gen.flags & VAR_DELAY)) { \ + sp += vlen; \ + ++dp; \ + } \ + else { \ + switch (last_type) { \ + case MPR_INT32: \ + hidx = stk[sp].i; \ + break; \ + case MPR_FLT: \ + hidx = (int)stk[sp].f; \ + weight = fabsf(stk[sp].f - hidx); \ + break; \ + case MPR_DBL: \ + hidx = (int)stk[sp].d; \ + weight = fabs(stk[sp].d - hidx); \ + break; \ + default: \ + goto error; \ + } \ + } \ + dims[dp] = tok->gen.vec_len; \ + a = mpr_value_get_samp_hist(VAL, inst_idx % VAL->num_inst, hidx); \ + switch (VAL->type) { \ + COPY_TYPED(MPR_INT32, int, i) \ + COPY_TYPED(MPR_FLT, float, f) \ + COPY_TYPED(MPR_DBL, double, d) \ + default: \ + goto error; \ + } \ + if (weight) { \ + a = mpr_value_get_samp_hist(VAL, inst_idx % VAL->num_inst, hidx-1); \ + switch (VAL->type) { \ + WEIGHTED_ADD(MPR_INT32, int, i) \ + WEIGHTED_ADD(MPR_FLT, float, f) \ + WEIGHTED_ADD(MPR_DBL, double, d) \ + default: \ + goto error; \ + } \ + } \ + +MPR_INLINE static int _max(int a, int b) +{ + return a > b ? a : b; +} int mpr_expr_eval(mpr_expr expr, mpr_value *v_in, mpr_value *v_vars, - mpr_value v_out, mpr_time *t, mpr_type *types, int inst_idx) + mpr_value v_out, mpr_time *time, mpr_type *types, int inst_idx) { + mpr_token_t *tok, *end; + int status = 1 | EXPR_EVAL_DONE, cache = 0, vlen; + int i, j, sp, dp = -1; + uint8_t alive = 1, muted = 0, can_advance = 1; + mpr_type last_type = 0; + mpr_value_buffer b_out; + mpr_value x = NULL; + if (!expr) { -#if TRACING +#if TRACE_EVAL printf(" no expression to evaluate!\n"); #endif return 0; } - mpr_token_t *tok = expr->start; - int len = expr->len; - int status = 1, alive = 1, muted = 0; - mpr_value_buffer b_out = v_out ? &v_out->inst[inst_idx] : 0; + sp = -expr->vec_len; + vlen = expr->vec_len; + tok = expr->start; + end = expr->start + expr->n_tokens; + b_out = v_out ? &v_out->inst[inst_idx] : 0; if (v_out && b_out->pos >= 0) { tok += expr->offset; - len -= expr->offset; } if (v_vars) { if (expr->inst_ctl >= 0) { - // recover instance state + /* recover instance state */ mpr_value v = *v_vars + expr->inst_ctl; - double *d = v->inst[inst_idx].samps; - alive = (0 != d[0]); + int *vi = v->inst[inst_idx].samps; + alive = (0 != vi[0]); } if (expr->mute_ctl >= 0) { - // recover mute state + /* recover mute state */ mpr_value v = *v_vars + expr->mute_ctl; - double *d = v->inst[inst_idx].samps; - muted = (0 != d[0]); + int *vi = v->inst[inst_idx].samps; + muted = (0 != vi[0]); } } - mpr_expr_val_t stk[len][expr->vec_size]; - int dims[len]; - - int i, j, k, top = -1, count = 0, can_advance = 1; - if (v_out) { - // init types + /* init types */ if (types) memset(types, MPR_NULL, v_out->vlen); /* Increment index position of output data structure. */ b_out->pos = (b_out->pos + 1) % v_out->mlen; } + /* choose one input to represent active instances + * or now we will choose the input with the highest instance count + * TODO: consider alternatives */ + if (v_in) { + x = v_in[0]; + for (i = 1; i < expr->n_ins; i++) { + if (v_in[i]->num_inst > x->num_inst) + x = v_in[i]; + } + } + for (i = 0; i < expr->n_vars; i++) expr->vars[i].assigned = 0; - while (count < len && tok->toktype != TOK_END) { + while (tok < end) { + repeat: switch (tok->toktype) { - case TOK_CONST: - ++top; - dims[top] = tok->vec_len; - switch (tok->datatype) { -#define TYPED_CASE(MTYPE, EL) \ - case MTYPE: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = tok->EL; \ + case TOK_LITERAL: + sp += vlen; + ++dp; + dims[dp] = tok->gen.vec_len; + /* TODO: remove vector building? */ + switch (tok->gen.datatype) { +#define TYPED_CASE(MTYPE, T) \ + case MTYPE: \ + for (i = sp; i < sp + tok->gen.vec_len; i++)\ + stk[i].T = tok->lit.val.T; \ break; TYPED_CASE(MPR_INT32, i) TYPED_CASE(MPR_FLT, f) @@ -2218,168 +2901,260 @@ int mpr_expr_eval(mpr_expr expr, mpr_value *v_in, mpr_value *v_vars, default: goto error; } -#if TRACING +#if TRACE_EVAL printf("loading constant "); - print_stack_vec(stk[top], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp, tok->gen.datatype, tok->gen.vec_len); printf("\n"); #endif break; case TOK_VAR: { - int idx; - if (tok->var == VAR_Y) { + int hidx = 0; + float weight = 0.f; +#if TRACE_EVAL + int mlen = 0; + if (tok->var.idx == VAR_Y) { + printf("loading variable y"); + mlen = v_out->mlen; + } + else if (tok->var.idx >= VAR_X) { + printf("loading variable x%d", tok->var.idx - VAR_X); + mlen = v_in ? v_in[tok->var.idx - VAR_X]->mlen : 0; + } + else if (expr->vars) + printf("loading variable %s", expr->vars[tok->var.idx].name); + else + printf("loading variable vars[%d]", tok->var.idx); + + if (tok->gen.flags & VAR_DELAY) { + switch (last_type) { + case MPR_INT32: + printf("{N=%d}", mlen ? stk[sp].i % mlen : stk[sp].i); + break; + case MPR_FLT: + printf("{N=%g}", mlen ? fmodf(stk[sp].f, (float)mlen) : stk[sp].f); + break; + case MPR_DBL: + printf("{N=%g}", mlen ? fmod(stk[sp].d, (double)mlen) : stk[sp].d); + break; + default: + goto error; + } + } + printf("[%u] ", tok->var.vec_idx); +#endif + if (tok->var.idx == VAR_Y) { + void *a; if (!v_out) return status; -#if TRACING - if (tok->hist) - printf("loading variable y{N=%d}[%u] ", stk[top][0].i, tok->vec_idx); - else - printf("loading variable y[%u] ", tok->vec_idx); -#endif COPY_TO_STACK(v_out); -#if TRACING - print_stack_vec(stk[top], tok->datatype, tok->vec_len); - printf(" \n"); -#endif } - else if (tok->var >= VAR_X) { + else if (tok->var.idx >= VAR_X) { + mpr_value v; + void *a; if (!v_in) return status; - mpr_value v = v_in[tok->var-VAR_X]; -#if TRACING - if (tok->hist) - printf("loading variable x%d{N=%d}[%u] ", tok->var-VAR_X, stk[top][0].i, - tok->vec_idx); - else - printf("loading variable x%d[%u] ", tok->var-VAR_X, tok->vec_idx); -#endif + v = v_in[tok->var.idx - VAR_X]; COPY_TO_STACK(v); -#if TRACING - print_stack_vec(stk[top], tok->datatype, tok->vec_len); - printf(" \n"); -#endif + if (!cache) + status &= ~EXPR_EVAL_DONE; } else if (v_vars) { - // TODO: allow other data types? -#if TRACING - printf("loading variable %s{%d}[%u] ", expr->vars[tok->var].name, - tok->hist ? stk[top][0].i : 0, tok->vec_idx); -#endif - if (!tok->hist) - ++top; - dims[top] = tok->vec_len; - mpr_value v = *v_vars + tok->var; - double *d = v->inst[inst_idx].samps; - for (i = 0; i < tok->vec_len; i++) - stk[top][i].d = d[i+tok->vec_idx]; -#if TRACING - print_stack_vec(stk[top], tok->datatype, tok->vec_len); - printf(" \n"); -#endif + mpr_value v = *v_vars + tok->var.idx; + if (!(tok->gen.flags & VAR_DELAY)) { + sp += vlen; + ++dp; + } + dims[dp] = tok->gen.vec_len; + switch (v->type) { +#define TYPED_CASE(MTYPE, TYPE, T) \ + case MTYPE: { \ + TYPE *vt = v->inst[inst_idx].samps; \ + for (i = 0, j = sp; i < tok->gen.vec_len; i++, j++) \ + stk[j].T = vt[i + tok->var.vec_idx]; \ + break; \ + } + TYPED_CASE(MPR_INT32, int, i) + TYPED_CASE(MPR_FLT, float, f) + TYPED_CASE(MPR_DBL, double, d) +#undef TYPED_CASE + } } else goto error; +#if TRACE_EVAL + print_stack_vec(stk + sp, tok->gen.datatype, tok->gen.vec_len); + printf(" \n"); +#endif break; } case TOK_TT: { - int idx; - if (!tok->hist) - ++top; - dims[top] = tok->vec_len; - mpr_value_buffer b; - if (tok->var == VAR_Y) { - if (!v_out) - return status; - b = b_out; - idx = (b->pos + v_out->mlen + (tok->hist ? stk[top][0].i : 0)) % v_out->mlen; -#if TRACING - printf("loading timetag t_y{%d}", tok->hist ? stk[top][0].i : 0); + int hidx = 0; + double weight = 0.0; + double t_d; + if (!(tok->gen.flags & VAR_DELAY)) { + sp += vlen; + ++dp; + } + dims[dp] = tok->gen.vec_len; +#if TRACE_EVAL + if (tok->var.idx == VAR_Y) + printf("loading timetag t_y"); + else if (tok->var.idx >= VAR_X) + printf("loading timetag t_x%d", tok->var.idx - VAR_X); + else if (v_vars) + printf("loading timetag t_%s", expr->vars[tok->var.idx].name); + + if (tok->gen.flags & VAR_DELAY) { + switch (last_type) { + case MPR_INT32: printf("{N=%d}", stk[sp].i); break; + case MPR_FLT: printf("{N=%g}", stk[sp].f); break; + case MPR_DBL: printf("{N=%g}", stk[sp].d); break; + default: goto error; + } + } #endif + if (tok->gen.flags & VAR_DELAY) { + switch (last_type) { + case MPR_INT32: + hidx = stk[sp].i; + break; + case MPR_FLT: + hidx = (int)stk[sp].f; + weight = fabsf(stk[sp].f - hidx); + break; + case MPR_DBL: + hidx = (int)stk[sp].d; + weight = fabs(stk[sp].d - hidx); + break; + default: + goto error; + } } - else if (tok->var >= VAR_X) { - if (!v_in) - return status; - mpr_value v = v_in[tok->var-VAR_X]; + if (tok->var.idx == VAR_Y) { + int idx; + mpr_value_buffer b; + RETURN_ARG_UNLESS(v_out, status); + b = b_out; + idx = (b->pos + v_out->mlen + hidx) % v_out->mlen; + t_d = mpr_time_as_dbl(b->times[idx]); + if (weight) + t_d = t_d * weight + ((b->pos + v_out->mlen + hidx - 1) % v_out->mlen) * (1 - weight); + } + else if (tok->var.idx >= VAR_X) { + mpr_value v; + mpr_value_buffer b; + RETURN_ARG_UNLESS(v_in, status); + v = v_in[tok->var.idx - VAR_X]; b = &v->inst[inst_idx % v->num_inst]; - idx = (b->pos + v->mlen + (tok->hist ? stk[top][0].i : 0)) % v->mlen; -#if TRACING - printf("loading timetag t_x%d{%d}", tok->var-VAR_X, tok->hist ? stk[top][0].i : 0); -#endif + /* TODO: ensure buffer overrun is not possible here amd similar */ + t_d = mpr_time_as_dbl(b->times[(b->pos + v->mlen + hidx) % v->mlen]); + if (weight) + t_d = t_d * weight + ((b->pos + v->mlen + hidx - 1) % v->mlen) * (1 - weight); } else if (v_vars) { - mpr_value v = *v_vars + tok->var; - b = &v->inst[inst_idx]; - idx = 0; -#if TRACING - printf("loading timetag t_%s{%d}", expr->vars[tok->var].name, - tok->hist ? stk[top][0].i : 0); -#endif + mpr_value v = *v_vars + tok->var.idx; + mpr_value_buffer b = &v->inst[inst_idx]; + t_d = mpr_time_as_dbl(b->times[0]); } else goto error; - double t_d = mpr_time_as_dbl(b->times[idx]); -#if TRACING - printf(" as double %f\n", t_d); +#if TRACE_EVAL + printf(" as double %g\n", t_d); #endif - for (i = 0; i < tok->vec_len; i++) - stk[top][i].d = t_d; + for (i = sp; i < sp + tok->gen.vec_len; i++) + stk[i].d = t_d; break; } - case TOK_OP: - top -= op_tbl[tok->op].arity-1; - dims[top] = tok->vec_len; -#if TRACING - if (tok->op == OP_IF_THEN_ELSE || tok->op == OP_IF_ELSE) { + case TOK_OP: { + int maxlen, diff; + unsigned int rdim; + dp -= (op_tbl[tok->op.idx].arity - 1); + sp = dp * vlen; +#if TRACE_EVAL + if (tok->op.idx == OP_IF_THEN_ELSE || tok->op.idx == OP_IF_ELSE) { printf("IF "); - print_stack_vec(stk[top], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); printf(" THEN "); - if (tok->op == OP_IF_ELSE) { - print_stack_vec(stk[top], tok->datatype, tok->vec_len); + if (tok->op.idx == OP_IF_ELSE) { + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); printf(" ELSE "); - print_stack_vec(stk[top+1], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp + vlen, tok->gen.datatype, dims[dp + 1]); } else { - print_stack_vec(stk[top+1], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp + vlen, tok->gen.datatype, dims[dp + 1]); printf(" ELSE "); - print_stack_vec(stk[top+2], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp + 2 * vlen, tok->gen.datatype, dims[dp + 2]); } } else { - print_stack_vec(stk[top], tok->datatype, tok->vec_len); - printf(" %s%c ", op_tbl[tok->op].name, tok->datatype); - print_stack_vec(stk[top+1], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); + printf(" %s%c ", op_tbl[tok->op.idx].name, tok->gen.datatype); + print_stack_vec(stk + sp + vlen, tok->gen.datatype, dims[dp + 1]); } #endif - switch (tok->datatype) { + /* first copy stk[sp] elements if necessary */ + maxlen = dims[dp]; + for (i = 1; i < op_tbl[tok->op.idx].arity; i++) + maxlen = _max(maxlen, dims[dp + i]); + diff = maxlen - dims[dp]; + while (diff > 0) { + int mindiff = dims[dp] > diff ? diff : dims[dp]; + memcpy(&stk[sp + dims[dp]], &stk[sp], mindiff * sizeof(mpr_expr_val_t)); + dims[dp] += mindiff; + diff -= mindiff; + } + rdim = dims[dp + 1]; + switch (tok->gen.datatype) { case MPR_INT32: { - switch (tok->op) { - OP_CASES_META(i); - BINARY_OP_CASE(OP_MODULO, %, i); - BINARY_OP_CASE(OP_LEFT_BIT_SHIFT, <<, i); - BINARY_OP_CASE(OP_RIGHT_BIT_SHIFT, >>, i); - BINARY_OP_CASE(OP_BITWISE_AND, &, i); - BINARY_OP_CASE(OP_BITWISE_OR, |, i); - BINARY_OP_CASE(OP_BITWISE_XOR, ^, i); + switch (tok->op.idx) { + OP_CASES_META(i); + case OP_DIVIDE: + /* need to check for divide-by-zero */ + for (i = 0, j = 0; i < tok->gen.vec_len; i++, j = (j + 1) % rdim) { + if (stk[sp + vlen + j].i) + stk[sp + i].i /= stk[sp + vlen + j].i; + else { + /* skip to after this assignment */ + while (tok < end && !((++tok)->toktype & TOK_ASSIGN)) {} + while (tok < end && (++tok)->toktype & TOK_ASSIGN) {} + if (tok >= end) + return 0; + else + goto repeat; + } + } + break; + BINARY_OP_CASE(OP_MODULO, %, i); + BINARY_OP_CASE(OP_LEFT_BIT_SHIFT, <<, i); + BINARY_OP_CASE(OP_RIGHT_BIT_SHIFT, >>, i); + BINARY_OP_CASE(OP_BITWISE_AND, &, i); + BINARY_OP_CASE(OP_BITWISE_OR, |, i); + BINARY_OP_CASE(OP_BITWISE_XOR, ^, i); default: goto error; } break; } case MPR_FLT: { - switch (tok->op) { + switch (tok->op.idx) { OP_CASES_META(f); + BINARY_OP_CASE(OP_DIVIDE, /, f); case OP_MODULO: - for (i = 0; i < tok->vec_len; i++) - stk[top][i].f = fmodf(stk[top][i].f, stk[top+1][i].f); + for (i = 0; i < tok->gen.vec_len; i++) + stk[sp + i].f = fmodf(stk[sp + i].f, + stk[sp + vlen + i % rdim].f); break; default: goto error; } break; } case MPR_DBL: { - switch (tok->op) { + switch (tok->op.idx) { OP_CASES_META(d); + BINARY_OP_CASE(OP_DIVIDE, /, d); case OP_MODULO: - for (i = 0; i < tok->vec_len; i++) - stk[top][i].d = fmod(stk[top][i].d, stk[top+1][i].d); + for (i = 0; i < tok->gen.vec_len; i++) + stk[sp + i].d = fmod(stk[sp + i].d, + stk[sp + vlen + i % rdim].d); break; default: goto error; } @@ -2388,55 +3163,74 @@ int mpr_expr_eval(mpr_expr expr, mpr_value *v_in, mpr_value *v_vars, default: goto error; } -#if TRACING + +#if TRACE_EVAL printf(" = "); - print_stack_vec(stk[top], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); printf(" \n"); #endif break; - case TOK_FN: - top -= fn_tbl[tok->fn].arity-1; - dims[top] = tok->vec_len; -#if TRACING - printf("%s%c(", fn_tbl[tok->fn].name, tok->datatype); - for (i = 0; i < fn_tbl[tok->fn].arity; i++) { - print_stack_vec(stk[top+i], tok->datatype, tok->vec_len); + } + case TOK_FN: { + int maxlen, diff; + unsigned int ldim, rdim; + dp -= (fn_tbl[tok->fn.idx].arity - 1); + sp = dp * vlen; +#if TRACE_EVAL + printf("%s%c(", fn_tbl[tok->fn.idx].name, tok->gen.datatype); + for (i = 0; i < fn_tbl[tok->fn.idx].arity; i++) { + print_stack_vec(stk + sp + vlen, tok->gen.datatype, dims[dp + i]); printf(", "); } - printf("%s)", fn_tbl[tok->fn].arity ? "\b\b" : ""); + printf("%s)", fn_tbl[tok->fn.idx].arity ? "\b\b" : ""); #endif - switch (tok->datatype) { -#define TYPED_CASE(MTYPE, FN, EL) \ - case MTYPE: \ - switch (fn_tbl[tok->fn].arity) { \ - case 0: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = ((FN##_arity0*)fn_tbl[tok->fn].FN)(); \ - break; \ - case 1: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = (((FN##_arity1*)fn_tbl[tok->fn].FN) \ - (stk[top][i].EL)); \ - break; \ - case 2: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = (((FN##_arity2*)fn_tbl[tok->fn].FN) \ - (stk[top][i].EL, stk[top+1][i].EL)); \ - break; \ - case 3: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = (((FN##_arity3*)fn_tbl[tok->fn].FN) \ - (stk[top][i].EL, stk[top+1][i].EL, \ - stk[top+2][i].EL)); \ - break; \ - case 4: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL = (((FN##_arity4*)fn_tbl[tok->fn].FN) \ - (stk[top][i].EL, stk[top+1][i].EL, \ - stk[top+2][i].EL, stk[top+3][i].EL));\ - break; \ - default: goto error; \ - } \ + /* TODO: use preprocessor macro or inline func here */ + /* first copy stk[sp] elements if necessary */ + maxlen = dims[dp]; + for (i = 1; i < fn_tbl[tok->fn.idx].arity; i++) + maxlen = _max(maxlen, dims[dp + i]); + diff = maxlen - dims[dp]; + while (diff > 0) { + int mindiff = dims[dp] > diff ? diff : dims[dp]; + memcpy(&stk[sp + dims[dp]], &stk[sp], mindiff * sizeof(mpr_expr_val_t)); + dims[dp] += mindiff; + diff -= mindiff; + } + ldim = dims[dp]; + rdim = dims[dp + 1]; + switch (tok->gen.datatype) { +#define TYPED_CASE(MTYPE, FN, T) \ + case MTYPE: \ + switch (fn_tbl[tok->fn.idx].arity) { \ + case 0: \ + for (i = 0; i < ldim; i++) \ + stk[sp + i].T = ((FN##_arity0*)fn_tbl[tok->fn.idx].FN)(); \ + break; \ + case 1: \ + for (i = 0; i < ldim; i++) \ + stk[sp + i].T = (((FN##_arity1*)fn_tbl[tok->fn.idx].FN) \ + (stk[sp + i].T)); \ + break; \ + case 2: \ + for (i = 0; i < ldim; i++) \ + stk[sp + i].T = (((FN##_arity2*)fn_tbl[tok->fn.idx].FN) \ + (stk[sp + i].T, stk[sp + vlen + i % rdim].T)); \ + break; \ + case 3: \ + for (i = 0; i < ldim; i++) \ + stk[sp + i].T = (((FN##_arity3*)fn_tbl[tok->fn.idx].FN) \ + (stk[sp + i].T, stk[sp + vlen + i % rdim].T, \ + stk[sp + 2 * vlen + i % dims[dp + 2]].T)); \ + break; \ + case 4: \ + for (i = 0; i < ldim; i++) \ + stk[sp + i].T = (((FN##_arity4*)fn_tbl[tok->fn.idx].FN) \ + (stk[sp + i].T, stk[sp + vlen + i % rdim].T, \ + stk[sp + 2 * vlen + i % dims[dp + 2]].T, \ + stk[sp + 3 * vlen + i % dims[dp + 3]].T)); \ + break; \ + default: goto error; \ + } \ break; TYPED_CASE(MPR_INT32, fn_int, i) TYPED_CASE(MPR_FLT, fn_flt, f) @@ -2445,108 +3239,194 @@ int mpr_expr_eval(mpr_expr expr, mpr_value *v_in, mpr_value *v_vars, default: goto error; } -#if TRACING +#if TRACE_EVAL printf(" = "); - print_stack_vec(stk[top], tok->datatype, tok->vec_len); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); printf(" \n"); #endif break; + } case TOK_VFN: - top -= vfn_tbl[tok->fn].arity-1; -#if TRACING - printf("%s%c(", vfn_tbl[tok->fn].name, tok->datatype); - for (i = 0; i < vfn_tbl[tok->fn].arity; i++) { - print_stack_vec(stk[top], tok->datatype, dims[top]); + dp -= (vfn_tbl[tok->fn.idx].arity - 1); + sp = dp * vlen; +#if TRACE_EVAL + printf("%s%c(", vfn_tbl[tok->fn.idx].name, tok->gen.datatype); + for (i = 0; i < vfn_tbl[tok->fn.idx].arity; i++) { + print_stack_vec(stk + sp + i * vlen, tok->gen.datatype, dims[dp + i]); printf(", "); } printf("\b\b)"); #endif - switch (tok->datatype) { -#define TYPED_CASE(MTYPE, FN, EL) \ - case MTYPE: \ - switch (vfn_tbl[tok->fn].arity) { \ - case 1: \ - stk[top][0].EL \ - = (((v##FN##_arity1*)vfn_tbl[tok->fn].FN) \ - (stk[top], dims[top])); \ - for (i = 1; i < tok->vec_len; i++) \ - stk[top][i].EL = stk[top][0].EL; \ - break; \ - default: goto error; \ - } \ - break; - TYPED_CASE(MPR_INT32, fn_int, i) - TYPED_CASE(MPR_FLT, fn_flt, f) - TYPED_CASE(MPR_DBL, fn_dbl, d) + if (vfn_tbl[tok->fn.idx].arity > 1 || VFN_DOT == tok->fn.idx) { + /* we need to ensure the vector lengths are equal */ + while (dims[dp] > dims[dp + 1]) { + int diff = dims[dp] - dims[dp + 1]; + diff = diff < dims[dp + 1] ? diff : dims[dp + 1]; + memcpy(&stk[sp + vlen + dims[dp + 1]], &stk[sp + vlen], + diff * sizeof(mpr_expr_val_t)); + dims[dp + 1] += diff; + } + while (dims[dp] < dims[dp + 1]) { + int diff = dims[dp + 1] - dims[dp]; + diff = diff < dims[dp] ? diff : dims[dp]; + memcpy(&stk[sp + dims[dp]], &stk[sp], diff * sizeof(mpr_expr_val_t)); + dims[dp] += diff; + } + } + switch (tok->gen.datatype) { +#define TYPED_CASE(MTYPE, FN) \ + case MTYPE: \ + (((vfn_template*)vfn_tbl[tok->fn.idx].FN)(stk, dims, dp, vlen));\ + break; + TYPED_CASE(MPR_INT32, fn_int) + TYPED_CASE(MPR_FLT, fn_flt) + TYPED_CASE(MPR_DBL, fn_dbl) #undef TYPED_CASE - default: - break; + default: + break; } - dims[top] = tok->vec_len; -#if TRACING + + if (vfn_tbl[tok->fn.idx].reduce) { + for (i = 1; i < tok->gen.vec_len; i++) + stk[sp + i].d = stk[sp].d; + } + dims[dp] = tok->gen.vec_len; +#if TRACE_EVAL printf(" = "); - print_stack_vec(stk[top], tok->datatype, tok->vec_len); - printf(" \n"); + if (VFN_MAXMIN == tok->fn.idx || VFN_SUMNUM == tok->fn.idx) { + printf("["); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); + printf(", "); + print_stack_vec(stk + sp + vlen, tok->gen.datatype, dims[dp + 1]); + printf("]\n"); + } + else { + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); + printf(" \n"); + } #endif break; - case TOK_VECTORIZE: - // don't need to copy vector elements from first token - top -= tok->arity-1; - k = dims[top]; - switch (tok->datatype) { -#define TYPED_CASE(MTYPE, EL) \ - case MTYPE: \ - for (i = 1; i < tok->arity; i++) { \ - for (j = 0; j < dims[top+1]; j++) \ - stk[top][k++].EL = stk[top+i][j].EL; \ - } \ - break; - TYPED_CASE(MPR_INT32, i) - TYPED_CASE(MPR_FLT, f) - TYPED_CASE(MPR_DBL, d) -#undef TYPED_CASE - default: + case TOK_CACHE_INIT_INST: +#if TRACE_EVAL + printf("Caching instance idx %d on the eval stack.\n", inst_idx); +#endif + /* cache previous instance idx */ + ++dp; + sp += vlen; + stk[sp].i = inst_idx; + ++cache; + + if (x) { + /* find first active instance idx */ + for (i = 0; i < x->num_inst; i++) { + if (x->inst[i].pos >= 0) + break; + } + if (i >= x->num_inst) goto error; + inst_idx = i; + } +#if TRACE_EVAL + printf("Starting instance loop with idx %d.\n", inst_idx); +#endif + break; + case TOK_SP_ADD: +#if TRACE_EVAL + printf("Adding %d to eval stack pointer.\n", tok->lit.val.i); +#endif + dp += tok->lit.val.i; + sp = dp * vlen; + break; + case TOK_BRANCH_NEXT_INST: + /* increment instance idx */ + if (x) { + for (i = inst_idx + 1; i < x->num_inst; i++) { + if (x->inst[i].pos >= 0) + break; + } + } + if (x && i < x->num_inst) { +#if TRACE_EVAL + printf("Incrementing instance idx to %d and jumping %d\n", i, tok->lit.val.i); +#endif + inst_idx = i; + tok += tok->lit.val.i; + } + else { + inst_idx = stk[sp - tok->fn.inst_cache_pos * vlen].i; + if (x && inst_idx >= x->num_inst) + goto error; + memcpy(stk + sp - tok->fn.inst_cache_pos * vlen, + stk + sp - (tok->fn.inst_cache_pos - 1) * vlen, + sizeof(mpr_expr_val_t) * vlen * tok->fn.inst_cache_pos); + memcpy(dims + dp - tok->fn.inst_cache_pos, dims + dp - tok->fn.inst_cache_pos + 1, + sizeof(int) * tok->fn.inst_cache_pos); + sp -= vlen; + --dp; + --cache; +#if TRACE_EVAL + printf("Instance loop done; retrieved cached instance idx %d.\n", inst_idx); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); +#endif + } + break; + case TOK_VECTORIZE: + /* don't need to copy vector elements from first token */ + dp -= tok->fn.arity - 1; + sp = dp * vlen; + j = dims[dp]; + for (i = 1; i < tok->fn.arity; i++) { + memcpy(&stk[sp + j], &stk[sp + i * vlen], dims[dp + i] * sizeof(mpr_expr_val_t)); + j += dims[dp + i]; } - dims[top] = tok->vec_len; -#if TRACING - printf("built %u-element vector: ", tok->vec_len); - print_stack_vec(stk[top], tok->datatype, tok->vec_len); + dims[dp] = j; +#if TRACE_EVAL + printf("built %u-element vector: ", dims[dp]); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); printf(" \n"); #endif break; case TOK_ASSIGN: case TOK_ASSIGN_USE: can_advance = 0; - case TOK_ASSIGN_CONST: -#if TRACING - if (VAR_Y == tok->var) - printf("assigning values to y{%d}[%u] (%s x %u)\n", - tok->hist ? stk[top-1][0].i : 0, tok->vec_idx, type_name(tok->datatype), - tok->vec_len); + case TOK_ASSIGN_CONST: { + int hidx = tok->gen.flags & VAR_DELAY; + if (hidx) { + /* TODO: disallow assignment interpolation & verify parser does this check also */ + hidx = stk[sp - vlen].i; + /* var{-1} is the current sample, so we allow hidx range of 0 -> -mlen inclusive */ + if (hidx > 0 || hidx < -v_out->mlen) + goto error; + } +#if TRACE_EVAL + if (VAR_Y == tok->var.idx) + printf("assigning values to y{%d}[%u] (%s x %u)\n", hidx, tok->var.vec_idx, + type_name(tok->gen.datatype), tok->gen.vec_len); else - printf("assigning values to %s{%d}[%u] (%s x %u)\n", expr->vars[tok->var].name, - tok->hist ? stk[top-1][0].i : 0, tok->vec_idx, type_name(tok->datatype), - tok->vec_len); + printf("assigning values to %s{%d}[%u] (%s x %u)\n", expr->vars[tok->var.idx].name, + hidx, tok->var.vec_idx, type_name(tok->gen.datatype), tok->gen.vec_len); #endif - if (tok->var == VAR_Y) { + if (tok->var.idx == VAR_Y) { + int idx; + void *v; if (!alive) - break; - status |= muted ? EXPR_MUTED_UPDATE : EXPR_UPDATE; + goto assign_done; + + status |= muted ? EXPR_MUTED_UPDATE : EXPR_UPDATE; can_advance = 0; if (!v_out) return status; - int idx = (b_out->pos + v_out->mlen + (tok->hist ? stk[top-1][0].i : 0)) % v_out->mlen; - if (idx < 0) - idx = v_out->mlen + idx; - void *v = (b_out->samps + idx * v_out->vlen * mpr_type_get_size(v_out->type)); + + idx = (b_out->pos + v_out->mlen + hidx) % v_out->mlen; + v = (char*)b_out->samps + idx * v_out->vlen * mpr_type_get_size(v_out->type); switch (v_out->type) { -#define TYPED_CASE(MTYPE, TYPE, EL) \ - case MTYPE: \ - for (i = 0; i < tok->vec_len; i++) \ - ((TYPE*)v)[i + tok->vec_idx] \ - = stk[top][i + tok->offset].EL; \ +#define TYPED_CASE(MTYPE, TYPE, T) \ + case MTYPE: \ + for (i = 0, j = tok->var.offset; i < tok->gen.vec_len; i++, j++) { \ + if (j >= dims[dp]) j = 0; \ + ((TYPE*)v)[i + tok->var.vec_idx] = stk[sp + j].T; \ + } \ break; TYPED_CASE(MPR_INT32, int, i) TYPED_CASE(MPR_FLT, float, f) @@ -2557,133 +3437,182 @@ int mpr_expr_eval(mpr_expr expr, mpr_value *v_in, mpr_value *v_vars, } if (types) { - for (i = tok->vec_idx; i < tok->vec_idx + tok->vec_len; i++) - types[i] = tok->datatype; + for (i = tok->var.vec_idx; i < tok->var.vec_idx + tok->gen.vec_len; i++) + types[i] = tok->gen.datatype; } - - // Also copy time from input - if (t) { + /* Also copy time from input */ + if (time) { mpr_time *tvar = &b_out->times[idx]; - memcpy(tvar, t, sizeof(mpr_time)); + memcpy(tvar, time, sizeof(mpr_time)); } +#if TRACE_EVAL + mpr_value_print_hist(v_out, inst_idx); +#endif } - else if (tok->var >= 0 && tok->var < N_USER_VARS) { + else if (tok->var.idx >= 0 && tok->var.idx < N_USER_VARS) { + mpr_value v; + mpr_value_buffer b; if (!v_vars) goto error; - // passed the address of an array of mpr_value structs - mpr_value v = *v_vars + tok->var; - mpr_value_buffer b = &v->inst[inst_idx]; + /* var{-1} is the current sample, so we allow hidx of 0 or -1 */ + if (hidx < -1) + goto error; + /* passed the address of an array of mpr_value structs */ + v = *v_vars + tok->var.idx; + b = &v->inst[inst_idx]; - double *d = b->samps; - for (i = 0; i < tok->vec_len; i++) - d[i + tok->vec_idx] = stk[top][i + tok->offset].d; + switch (v->type) { +#define TYPED_CASE(MTYPE, TYPE, T) \ + case MTYPE: { \ + TYPE *vi = b->samps; \ + for (i = 0, j = tok->var.offset; i < tok->gen.vec_len; i++, j++) { \ + vi[i + tok->var.vec_idx] = stk[sp + j].T; \ + if (j >= dims[dp]) j = 0; \ + } \ + break; \ + } + TYPED_CASE(MPR_INT32, int, i) + TYPED_CASE(MPR_FLT, float, f) + TYPED_CASE(MPR_DBL, double, d) +#undef TYPED_CASE + } + + /* Also copy time from input */ + if (time) + memcpy(b->times, time, sizeof(mpr_time)); - // Also copy time from input - if (t) - memcpy(b->times, t, sizeof(mpr_time)); +#if TRACE_EVAL + mpr_value_print_hist(v, inst_idx); +#endif - expr->vars[tok->var].assigned = 1; + expr->vars[tok->var.idx].assigned = 1; - if (tok->var == expr->inst_ctl) { - if (alive && stk[top][0].d == 0) { + if (tok->var.idx == expr->inst_ctl) { + if (alive && stk[sp].i == 0) { if (status & EXPR_UPDATE) status |= EXPR_RELEASE_AFTER_UPDATE; else status |= EXPR_RELEASE_BEFORE_UPDATE; } - alive = stk[top][0].d != 0; + alive = stk[sp].i != 0; break; } - else if (tok->var == expr->mute_ctl) { - muted = stk[top][0].d != 0; + else if (tok->var.idx == expr->mute_ctl) { + muted = stk[sp].i != 0; break; } } else goto error; + assign_done: /* If assignment was constant or history initialization, move expr * start token pointer so we don't evaluate this section again. */ - if (tok->hist || can_advance) { -#if TRACING + if (can_advance || tok->gen.flags & VAR_DELAY) { +#if TRACE_EVAL printf("moving expr offset to %ld\n", tok - expr->start + 1); #endif expr->offset = tok - expr->start + 1; } + else + can_advance = 0; + + if (tok->gen.flags & CLEAR_STACK) + dp = -1; + else if (tok->gen.flags & VAR_DELAY) + --dp; + sp = dp * vlen; break; - case TOK_ASSIGN_TT: - if (tok->var != VAR_Y || tok->hist == 0) + } + case TOK_ASSIGN_TT: { + int idx, hist; + if (tok->var.idx != VAR_Y || !(tok->gen.flags & VAR_DELAY)) goto error; -#if TRACING - printf("assigning timetag to t_y{%d}\n", tok->hist ? stk[top-1][0].i : 0); +#if TRACE_EVAL + printf("assigning timetag to t_y{%d}\n", + tok->gen.flags & VAR_DELAY ? stk[sp - vlen].i : 0); #endif if (!v_out) return status; - int idx = (b_out->pos + v_out->mlen + (tok->hist ? stk[top-1][0].i : 0)) % v_out->mlen; + hist = tok->gen.flags & VAR_DELAY; + idx = (b_out->pos + v_out->mlen + (hist ? stk[sp - vlen].i : 0)) % v_out->mlen; if (idx < 0) idx = v_out->mlen + idx; - mpr_time_set_dbl(&b_out->times[idx], stk[top][0].d); + mpr_time_set_dbl(&b_out->times[idx], stk[sp].d); /* If assignment was constant or history initialization, move expr * start token pointer so we don't evaluate this section again. */ - if (tok->hist || can_advance) { -#if TRACING + if (hist || can_advance) { +#if TRACE_EVAL printf("moving expr offset to %ld\n", tok - expr->start + 1); #endif expr->offset = tok - expr->start + 1; } else can_advance = 0; + if (tok->gen.flags & CLEAR_STACK) + dp = -1; + else if (hist) + --dp; + sp = dp * vlen; break; + } default: goto error; } - if (tok->casttype && tok->toktype < TOK_ASSIGN) { -#if TRACING - printf("casting from %s to %s (%c)\n", type_name(tok->datatype), - type_name(tok->casttype), tok->casttype); + if (tok->gen.casttype && tok->toktype != TOK_LITERAL && tok->toktype < TOK_ASSIGN) { +#if TRACE_EVAL + printf("casting sp=%d from %s (%c) to %s (%c)\n", dp, type_name(tok->gen.datatype), + tok->gen.datatype, type_name(tok->gen.casttype), tok->gen.casttype); + print_stack_vec(stk + sp, tok->gen.datatype, dims[dp]); #endif - // need to cast to a different type - switch (tok->datatype) { -#define TYPED_CASE(MTYPE, EL, MTYPE1, TYPE1, EL1, MTYPE2, TYPE2, EL2) \ - case MTYPE: \ - switch (tok->casttype) { \ - case MTYPE1: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL1 = (TYPE1)stk[top][i].EL; \ - break; \ - case MTYPE2: \ - for (i = 0; i < tok->vec_len; i++) \ - stk[top][i].EL2 = (TYPE2)stk[top][i].EL; \ - break; \ - default: \ - goto error; \ - } \ + /* need to cast to a different type */ + switch (tok->gen.datatype) { +#define TYPED_CASE(MTYPE0, T0, MTYPE1, TYPE1, T1, MTYPE2, TYPE2, T2)\ + case MTYPE0: \ + switch (tok->gen.casttype) { \ + case MTYPE1: \ + for (i = sp; i < sp + dims[dp]; i++) \ + stk[i].T1 = (TYPE1)stk[i].T0; \ + break; \ + case MTYPE2: \ + for (i = sp; i < sp + dims[dp]; i++) \ + stk[i].T2 = (TYPE2)stk[i].T0; \ + break; \ + default: \ + goto error; \ + } \ break; TYPED_CASE(MPR_INT32, i, MPR_FLT, float, f, MPR_DBL, double, d) TYPED_CASE(MPR_FLT, f, MPR_INT32, int, i, MPR_DBL, double, d) TYPED_CASE(MPR_DBL, d, MPR_INT32, int, i, MPR_FLT, float, f) #undef TYPED_CASE - default: - goto error; } +#if TRACE_EVAL + printf(" -> "); + print_stack_vec(stk + sp, tok->gen.casttype, dims[dp]); + printf("\n"); +#endif + last_type = tok->gen.casttype; } + else + last_type = tok->gen.datatype; ++tok; - ++count; } - RETURN_UNLESS(v_out, status); + RETURN_ARG_UNLESS(v_out, status); if (!types) { + void *v; /* Internal evaluation during parsing doesn't contain assignment token, * so we need to copy to output here. */ /* Increment index position of output data structure. */ b_out->pos = (b_out->pos + 1) % v_out->mlen; - void *v = mpr_value_get_samp(v_out, inst_idx); + v = mpr_value_get_samp(v_out, inst_idx); switch (v_out->type) { -#define TYPED_CASE(MTYPE, TYPE, EL) \ - case MTYPE: \ - for (i = 0; i < v_out->vlen; i++) \ - ((TYPE*)v)[i] = stk[top][i].EL; \ +#define TYPED_CASE(MTYPE, TYPE, T) \ + case MTYPE: \ + for (i = 0, j = sp; i < v_out->vlen; i++, j++) \ + ((TYPE*)v)[i] = stk[j].T; \ break; TYPED_CASE(MPR_INT32, int, i) TYPED_CASE(MPR_FLT, float, f) diff --git a/src/mapper/graph.c b/src/mapper/graph.c index 951bdb8..8c43c11 100644 --- a/src/mapper/graph.c +++ b/src/mapper/graph.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -43,24 +43,24 @@ void print_subscription_flags(int flags) static void _on_dev_autosub(mpr_graph g, mpr_obj o, mpr_graph_evt e, const void *v) { - // New subscriptions are handled in network.c as response to "sync" msg + /* New subscriptions are handled in network.c as response to "sync" msg */ if (MPR_OBJ_REM == e) mpr_graph_subscribe(g, (mpr_dev)o, 0, 0); } static void set_net_dst(mpr_graph g, mpr_dev d) { - // TODO: look up device info, maybe send directly + /* TODO: look up device info, maybe send directly */ mpr_net_use_bus(&g->net); } static void send_subscribe_msg(mpr_graph g, mpr_dev d, int flags, int timeout) { char cmd[1024]; + NEW_LO_MSG(msg, return); snprintf(cmd, 1024, "/%s/subscribe", d->name); set_net_dst(g, d); - NEW_LO_MSG(msg, return); if (MPR_OBJ == flags) lo_message_add_string(msg, "all"); else { @@ -96,28 +96,28 @@ static void send_subscribe_msg(mpr_graph g, mpr_dev d, int flags, int timeout) static void _autosubscribe(mpr_graph g, int flags) { if (!g->autosub && flags) { - mpr_graph_add_cb(g, _on_dev_autosub, MPR_DEV, g); - // update flags for existing subscriptions + /* update flags for existing subscriptions */ + mpr_subscription s = g->subscriptions; mpr_time t; + NEW_LO_MSG(msg, ;); mpr_time_set(&t, MPR_NOW); - mpr_subscription s = g->subscriptions; while (s) { - trace_graph("adjusting flags for existing autorenewing subscription " - "to %s.\n", mpr_dev_get_name(s->dev)); + trace_graph("adjusting flags for existing autorenewing subscription to %s.\n", + mpr_dev_get_name(s->dev)); if (flags & ~s->flags) { send_subscribe_msg(g, s->dev, flags, AUTOSUB_INTERVAL); - // leave 10-second buffer for subscription renewal + /* leave 10-second buffer for subscription renewal */ s->lease_expiration_sec = (t.sec + AUTOSUB_INTERVAL - 10); } s->flags = flags; s = s->next; } - NEW_LO_MSG(msg, ;); if (msg) { trace_graph("pinging all devices.\n"); mpr_net_use_bus(&g->net); mpr_net_add_msg(&g->net, 0, MSG_WHO, msg); } + mpr_graph_add_cb(g, _on_dev_autosub, MPR_DEV, g); } else if (g->autosub && !flags) { mpr_graph_remove_cb(g, _on_dev_autosub, g); @@ -133,17 +133,19 @@ static void _autosubscribe(mpr_graph g, int flags) void mpr_graph_cleanup(mpr_graph g) { + int staged = 0; + mpr_list maps; if (!g->staged_maps) return; - // check for maps that were staged but never completed - int staged = 0; - mpr_list maps = mpr_list_from_data(g->maps); + /* check for maps that were staged but never completed */ + maps = mpr_list_from_data(g->maps); while (maps) { mpr_map map = (mpr_map)*maps; maps = mpr_list_get_next(maps); if (map->status <= MPR_STATUS_STAGED) { if (map->status <= MPR_STATUS_EXPIRED) { - mpr_rtr_remove_map(g->net.rtr, map); + if (map->is_local) + mpr_rtr_remove_map(g->net.rtr, (mpr_local_map)map); mpr_graph_remove_map(g, map, MPR_OBJ_REM); } else { @@ -157,65 +159,78 @@ void mpr_graph_cleanup(mpr_graph g) mpr_graph mpr_graph_new(int subscribe_flags) { + mpr_tbl tbl; mpr_graph g = (mpr_graph) calloc(1, sizeof(mpr_graph_t)); - RETURN_UNLESS(g, NULL); + RETURN_ARG_UNLESS(g, NULL); - g->net.graph = g; + g->obj.type = MPR_GRAPH; + g->net.graph = g->obj.graph = g; + g->obj.id = 0; g->own = 1; mpr_net_init(&g->net, 0, 0, 0); if (subscribe_flags) _autosubscribe(g, subscribe_flags); + + /* TODO: consider whether graph objects should sync properties over the network. */ + tbl = g->obj.props.synced = mpr_tbl_new(); + mpr_tbl_link(tbl, PROP(DATA), 1, MPR_PTR, &g->obj.data, + LOCAL_MODIFY | INDIRECT | LOCAL_ACCESS_ONLY); + mpr_tbl_set(tbl, PROP(LIBVER), NULL, 1, MPR_STR, PACKAGE_VERSION, NON_MODIFIABLE); + /* TODO: add object queries as properties. */ + return g; } void mpr_graph_free(mpr_graph g) { + mpr_list list; + fptr_list cb; RETURN_UNLESS(g); - // remove callbacks now so they won't be called when removing devices - fptr_list cb; + /* remove callbacks now so they won't be called when removing devices */ while ((cb = g->callbacks)) { g->callbacks = g->callbacks->next; free(cb); } - // unsubscribe from and remove any autorenewing subscriptions + /* unsubscribe from and remove any autorenewing subscriptions */ while (g->subscriptions) mpr_graph_subscribe(g, g->subscriptions->dev, 0, 0); /* Remove all non-local maps */ - mpr_list maps = mpr_list_from_data(g->maps); - while (maps) { - mpr_map map = (mpr_map)*maps; - maps = mpr_list_get_next(maps); - if (!map->loc) + list = mpr_list_from_data(g->maps); + while (list) { + mpr_map map = (mpr_map)*list; + list = mpr_list_get_next(list); + if (!map->is_local) mpr_graph_remove_map(g, map, MPR_OBJ_REM); } /* Remove all non-local devices and signals from the graph except for * those referenced by local maps. */ - mpr_list devs = mpr_list_from_data(g->devs); - while (devs) { - mpr_dev dev = (mpr_dev)*devs; - devs = mpr_list_get_next(devs); - if (dev->loc) + list = mpr_list_from_data(g->devs); + while (list) { + mpr_dev dev = (mpr_dev)*list; + int no_local_dev_maps = 1; + mpr_list sigs; + list = mpr_list_get_next(list); + if (dev->is_local) continue; - int no_local_dev_maps = 1; - mpr_list sigs = mpr_dev_get_sigs(dev, MPR_DIR_ANY); + sigs = mpr_dev_get_sigs(dev, MPR_DIR_ANY); while (sigs) { - mpr_sig sig = (mpr_sig)*sigs; - sigs = mpr_list_get_next(sigs); int no_local_sig_maps = 1; + mpr_sig sig = (mpr_sig)*sigs; mpr_list maps = mpr_sig_get_maps(sig, MPR_DIR_ANY); while (maps) { - if (((mpr_map)*maps)->loc) { + if (((mpr_map)*maps)->is_local) { no_local_dev_maps = no_local_sig_maps = 0; mpr_list_free(maps); break; } maps = mpr_list_get_next(maps); } + sigs = mpr_list_get_next(sigs); if (no_local_sig_maps) mpr_graph_remove_sig(g, sig, MPR_OBJ_REM); } @@ -224,6 +239,7 @@ void mpr_graph_free(mpr_graph g) } mpr_net_free(&g->net); + FUNC_IF(mpr_tbl_free, g->obj.props.synced); free(g); } @@ -251,7 +267,7 @@ mpr_obj mpr_graph_get_obj(mpr_graph g, mpr_type type, mpr_id id) return 0; } -// TODO: support queries over multiple object types. +/* TODO: support queries over multiple object types. */ mpr_list mpr_graph_get_objs(mpr_graph g, int types) { if (types & MPR_DEV) @@ -263,12 +279,11 @@ mpr_list mpr_graph_get_objs(mpr_graph g, int types) return 0; } -int mpr_graph_add_cb(mpr_graph g, mpr_graph_handler *h, int types, - const void *user) +int mpr_graph_add_cb(mpr_graph g, mpr_graph_handler *h, int types, const void *user) { fptr_list cb = g->callbacks; while (cb) { - if (cb->f == h && cb->ctx == user) { + if (cb->f == (void*)h && cb->ctx == user) { cb->types |= types; return 0; } @@ -284,23 +299,36 @@ int mpr_graph_add_cb(mpr_graph g, mpr_graph_handler *h, int types, return 1; } -int mpr_graph_remove_cb(mpr_graph g, mpr_graph_handler *h, const void *user) +void mpr_graph_call_cbs(mpr_graph g, mpr_obj o, mpr_type t, mpr_graph_evt e) +{ + fptr_list cb = g->callbacks, temp; + while (cb) { + temp = cb->next; + if (cb->types & t) + ((mpr_graph_handler*)cb->f)(g, o, e, cb->ctx); + cb = temp; + } +} + +void *mpr_graph_remove_cb(mpr_graph g, mpr_graph_handler *h, const void *user) { fptr_list cb = g->callbacks; fptr_list prevcb = 0; + void *ctx; while (cb) { - if (cb->f == h && cb->ctx == user) + if (cb->f == (void*)h && cb->ctx == user) break; prevcb = cb; cb = cb->next; } - RETURN_UNLESS(cb, 0); + RETURN_ARG_UNLESS(cb, 0); if (prevcb) prevcb->next = cb->next; else g->callbacks = cb->next; + ctx = cb->ctx; free(cb); - return 1; + return ctx; } static void _remove_by_qry(mpr_graph g, mpr_list l, mpr_graph_evt e) @@ -334,6 +362,7 @@ mpr_dev mpr_graph_add_dev(mpr_graph g, const char *name, mpr_msg msg) dev->obj.id <<= 32; dev->obj.type = MPR_DEV; dev->obj.graph = g; + dev->is_local = 0; init_dev_prop_tbl(dev); rc = 1; } @@ -344,29 +373,21 @@ mpr_dev mpr_graph_add_dev(mpr_graph g, const char *name, mpr_msg msg) trace_graph("updated %d props for device '%s'.\n", updated, name); mpr_time_set(&dev->synced, MPR_NOW); - if (rc || updated) { - fptr_list cb = g->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_DEV) - ((mpr_graph_handler*)cb->f)(g, (mpr_obj)dev, - rc ? MPR_OBJ_NEW : MPR_OBJ_MOD, - cb->ctx); - cb = temp; - } - } + if (rc || updated) + mpr_graph_call_cbs(g, (mpr_obj)dev, MPR_DEV, rc ? MPR_OBJ_NEW : MPR_OBJ_MOD); } return dev; } -// Internal function called by /logout protocol handler +/* Internal function called by /logout protocol handler */ void mpr_graph_remove_dev(mpr_graph g, mpr_dev d, mpr_graph_evt e, int quiet) { + mpr_list maps; RETURN_UNLESS(d); _remove_by_qry(g, mpr_dev_get_maps(d, MPR_DIR_ANY), e); - // remove matching maps scopes - mpr_list maps = mpr_graph_get_objs(g, MPR_MAP); + /* remove matching maps scopes */ + maps = mpr_graph_get_objs(g, MPR_MAP); while (maps) { mpr_map_remove_scope((mpr_map)*maps, d); maps = mpr_list_get_next(maps); @@ -377,15 +398,8 @@ void mpr_graph_remove_dev(mpr_graph g, mpr_dev d, mpr_graph_evt e, int quiet) mpr_list_remove_item((void**)&g->devs, d); - if (!quiet) { - fptr_list cb = g->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_DEV) - ((mpr_graph_handler*)cb->f)(g, (mpr_obj)d, e, cb->ctx); - cb = temp; - } - } + if (!quiet) + mpr_graph_call_cbs(g, (mpr_obj)d, MPR_DEV, e); FUNC_IF(mpr_tbl_free, d->obj.props.synced); FUNC_IF(mpr_tbl_free, d->obj.props.staged); @@ -408,15 +422,15 @@ mpr_dev mpr_graph_get_dev_by_name(mpr_graph g, const char *name) static void _check_dev_status(mpr_graph g, uint32_t time_sec) { - time_sec -= TIMEOUT_SEC; mpr_list devs = mpr_list_from_data(g->devs); + time_sec -= TIMEOUT_SEC; while (devs) { mpr_dev dev = (mpr_dev)*devs; devs = mpr_list_get_next(devs); - // check if device has "checked in" recently - // this could be /sync ping or any sent metadata + /* check if device has "checked in" recently + * this could be /sync ping or any sent metadata */ if (dev->synced.sec && (dev->synced.sec < time_sec)) { - // remove subscription + /* remove subscription */ mpr_graph_subscribe(g, dev, 0, 0); mpr_graph_remove_dev(g, dev, MPR_OBJ_EXP, 0); } @@ -425,16 +439,15 @@ static void _check_dev_status(mpr_graph g, uint32_t time_sec) /**** Signals ****/ -mpr_sig mpr_graph_add_sig(mpr_graph g, const char *name, const char *dev_name, - mpr_msg msg) +mpr_sig mpr_graph_add_sig(mpr_graph g, const char *name, const char *dev_name, mpr_msg msg) { mpr_sig sig = 0; - int sig_rc = 0, updated = 0; + int rc = 0, updated = 0; mpr_dev dev = mpr_graph_get_dev_by_name(g, dev_name); if (dev) { sig = mpr_dev_get_sig_by_name(dev, name); - if (sig && sig->loc) + if (sig && sig->is_local) return sig; } else @@ -444,31 +457,22 @@ mpr_sig mpr_graph_add_sig(mpr_graph g, const char *name, const char *dev_name, trace_graph("adding signal '%s:%s'.\n", dev_name, name); sig = (mpr_sig)mpr_list_add_item((void**)&g->sigs, sizeof(mpr_sig_t)); - // also add device record if necessary + /* also add device record if necessary */ sig->dev = dev; sig->obj.graph = g; + sig->is_local = 0; mpr_sig_init(sig, MPR_DIR_UNDEFINED, name, 0, 0, 0, 0, 0, 0); - sig_rc = 1; + rc = 1; } if (sig) { updated = mpr_sig_set_from_msg(sig, msg); - if (!sig_rc) - trace_graph("updated %d props for signal '%s:%s'.\n", updated, - dev_name, name); - - if (sig_rc || updated) { - fptr_list cb = g->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_SIG) - ((mpr_graph_handler*)cb->f)(g, (mpr_obj)sig, - sig_rc ? MPR_OBJ_NEW : MPR_OBJ_MOD, - cb->ctx); - cb = temp; - } - } + if (!rc) + trace_graph("updated %d props for signal '%s:%s'.\n", updated, dev_name, name); + + if (rc || updated) + mpr_graph_call_cbs(g, (mpr_obj)sig, MPR_SIG, rc ? MPR_OBJ_NEW : MPR_OBJ_MOD); } return sig; } @@ -477,18 +481,11 @@ void mpr_graph_remove_sig(mpr_graph g, mpr_sig s, mpr_graph_evt e) { RETURN_UNLESS(s); - // remove any stored maps using this signal + /* remove any stored maps using this signal */ _remove_by_qry(g, mpr_sig_get_maps(s, MPR_DIR_ANY), e); mpr_list_remove_item((void**)&g->sigs, s); - - fptr_list cb = g->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_SIG) - ((mpr_graph_handler*)cb->f)(g, (mpr_obj)s, e, cb->ctx); - cb = temp; - } + mpr_graph_call_cbs(g, (mpr_obj)s, MPR_SIG, e); if (s->dir & MPR_DIR_IN) --s->dev->num_inputs; @@ -503,19 +500,20 @@ void mpr_graph_remove_sig(mpr_graph g, mpr_sig s, mpr_graph_evt e) mpr_link mpr_graph_add_link(mpr_graph g, mpr_dev dev1, mpr_dev dev2) { - RETURN_UNLESS(dev1 && dev2, 0); - mpr_link link = mpr_dev_get_link_by_remote(dev1, dev2); + mpr_link link; + RETURN_ARG_UNLESS(dev1 && dev2, 0); + link = mpr_dev_get_link_by_remote((mpr_local_dev)dev1, dev2); if (link) return link; link = (mpr_link)mpr_list_add_item((void**)&g->links, sizeof(mpr_link_t)); - if (dev2->loc) { - link->local_dev = dev2; - link->remote_dev = dev1; + if (dev2->is_local) { + link->devs[LOCAL_DEV] = dev2; + link->devs[REMOTE_DEV] = dev1; } else { - link->local_dev = dev1; - link->remote_dev = dev2; + link->devs[LOCAL_DEV] = dev1; + link->devs[REMOTE_DEV] = dev2; } link->obj.type = MPR_LINK; link->obj.graph = g; @@ -536,8 +534,7 @@ void mpr_graph_remove_link(mpr_graph g, mpr_link l, mpr_graph_evt e) static int _compare_slot_names(const void *l, const void *r) { - int result = strcmp((*(mpr_slot*)l)->sig->dev->name, - (*(mpr_slot*)r)->sig->dev->name); + int result = strcmp((*(mpr_slot*)l)->sig->dev->name, (*(mpr_slot*)r)->sig->dev->name); if (0 == result) return strcmp((*(mpr_slot*)l)->sig->name, (*(mpr_slot*)r)->sig->name); return result; @@ -556,19 +553,18 @@ static mpr_sig add_sig_from_whole_name(mpr_graph g, const char* name) return mpr_graph_add_sig(g, signame, devname, 0); } -mpr_map mpr_graph_get_map_by_names(mpr_graph g, int num_src, const char **srcs, - const char *dst) +mpr_map mpr_graph_get_map_by_names(mpr_graph g, int num_src, const char **srcs, const char *dst) { mpr_map map = 0; mpr_list maps = mpr_list_from_data(g->maps); while (maps) { map = (mpr_map)*maps; - int i; if (map->num_src != num_src) map = 0; else if (mpr_slot_match_full_name(map->dst, dst)) map = 0; else { + int i; for (i = 0; i < num_src; i++) { if (mpr_slot_match_full_name(map->src[i], srcs[i])) { map = 0; @@ -583,79 +579,68 @@ mpr_map mpr_graph_get_map_by_names(mpr_graph g, int num_src, const char **srcs, return map; } -mpr_map mpr_graph_add_map(mpr_graph g, int num_src, const char **src_names, - const char *dst_name, mpr_msg msg) +mpr_map mpr_graph_add_map(mpr_graph g, mpr_id id, int num_src, const char **src_names, + const char *dst_name) { + mpr_map map = 0; + unsigned char rc = 0, updated = 0, i, j, is_local = 0; if (num_src > MAX_NUM_MAP_SRC) { trace_graph("error: maximum mapping sources exceeded.\n"); return 0; } - mpr_map map = 0; - int rc = 0, updated = 0, i, j; - /* We could be part of larger "convergent" mapping, so we will retrieve * record by mapping id instead of names. */ - uint64_t id = 0; - if (msg) { - mpr_msg_atom atom = mpr_msg_get_prop(msg, MPR_PROP_ID); - if (!atom || atom->types[0] != MPR_INT64) { - trace_graph("no 'id' prop found in map metadata, aborting.\n"); - return 0; - } - id = atom->vals[0]->i64; + if (id) { map = (mpr_map)_obj_by_id(g, (mpr_obj)g->maps, id); if (!map && _obj_by_id(g, (mpr_obj)g->maps, 0)) { - // may have staged map stored locally + /* may have staged map stored locally */ map = mpr_graph_get_map_by_names(g, num_src, src_names, dst_name); } } if (!map) { + mpr_sig *src_sigs, dst_sig; #ifdef DEBUG trace_graph("adding map ["); for (i = 0; i < num_src; i++) printf("%s, ", src_names[i]); printf("\b\b] -> [%s].\n", dst_name); #endif - // add signals first in case signal handlers trigger map queries - mpr_sig dst_sig = add_sig_from_whole_name(g, dst_name); - RETURN_UNLESS(dst_sig, 0); - mpr_sig src_sigs[num_src]; + /* add signals first in case signal handlers trigger map queries */ + dst_sig = add_sig_from_whole_name(g, dst_name); + RETURN_ARG_UNLESS(dst_sig, 0); + src_sigs = alloca(num_src * sizeof(mpr_sig)); for (i = 0; i < num_src; i++) { src_sigs[i] = add_sig_from_whole_name(g, src_names[i]); - RETURN_UNLESS(src_sigs[i], 0); + RETURN_ARG_UNLESS(src_sigs[i], 0); mpr_graph_add_link(g, dst_sig->dev, src_sigs[i]->dev); + is_local += src_sigs[i]->is_local; } + is_local += dst_sig->is_local; - map = (mpr_map)mpr_list_add_item((void**)&g->maps, sizeof(mpr_map_t)); + map = (mpr_map)mpr_list_add_item((void**)&g->maps, + is_local ? sizeof(mpr_local_map_t) : sizeof(mpr_map_t)); map->obj.type = MPR_MAP; map->obj.graph = g; map->obj.id = id; map->num_src = num_src; + map->is_local = 0; map->src = (mpr_slot*)malloc(sizeof(mpr_slot) * num_src); - for (i = 0; i < num_src; i++) { - map->src[i] = (mpr_slot)calloc(1, sizeof(struct _mpr_slot)); - map->src[i]->sig = src_sigs[i]; - map->src[i]->obj.id = i; - map->src[i]->obj.graph = g; - map->src[i]->causes_update = 1; - map->src[i]->map = map; - } - map->dst = (mpr_slot)calloc(1, sizeof(struct _mpr_slot)); - map->dst->sig = dst_sig; - map->dst->obj.graph = g; - map->dst->causes_update = 1; - map->dst->map = map; + for (i = 0; i < num_src; i++) + map->src[i] = mpr_slot_new(map, src_sigs[i], is_local, 1); + map->dst = mpr_slot_new(map, dst_sig, is_local, 0); mpr_map_init(map); rc = 1; } else { int changed = 0; - // may need to add sources to existing map + /* may need to add sources to existing map */ for (i = 0; i < num_src; i++) { mpr_sig src_sig = add_sig_from_whole_name(g, src_names[i]); - RETURN_UNLESS(src_sig, 0); + is_local += src_sig->is_local; + /* TODO: check if we might need to 'upgrade' existing map to local */ + RETURN_ARG_UNLESS(src_sig, 0); for (j = 0; j < map->num_src; j++) { if (map->src[j]->sig == src_sig) break; @@ -664,41 +649,21 @@ mpr_map mpr_graph_add_map(mpr_graph g, int num_src, const char **src_names, ++changed; ++map->num_src; map->src = realloc(map->src, sizeof(mpr_slot) * map->num_src); - map->src[j] = (mpr_slot) calloc(1, sizeof(struct _mpr_slot)); - map->src[j]->dir = MPR_DIR_OUT; - map->src[j]->sig = src_sig; - map->src[j]->obj.graph = g; - map->src[j]->causes_update = 1; - map->src[j]->map = map; - mpr_slot_init(map->src[j]); + map->src[j] = mpr_slot_new(map, src_sig, is_local, 1); ++updated; } } if (changed) { - // slots should be in alphabetical order + mpr_list maps; + /* slots should be in alphabetical order */ qsort(map->src, map->num_src, sizeof(mpr_slot), _compare_slot_names); - // fix slot ids - mpr_tbl tab; - mpr_tbl_record rec; - for (i = 0; i < num_src; i++) { - map->src[i]->obj.id = i; - // also need to correct slot table indices - tab = map->src[i]->obj.props.synced; - for (j = 0; j < tab->count; j++) { - rec = &tab->rec[j]; - rec->prop = MASK_PROP_BITFLAGS(rec->prop) | SRC_SLOT_PROP(i); - } - tab = map->src[i]->obj.props.staged; - for (j = 0; j < tab->count; j++) { - rec = &tab->rec[j]; - rec->prop = MASK_PROP_BITFLAGS(rec->prop) | SRC_SLOT_PROP(i); - } - } - // check again if this mirrors a staged map - mpr_list maps = mpr_list_from_data(g->maps); - mpr_map map2; + /* fix slot ids */ + for (i = 0; i < num_src; i++) + map->src[i]->id = i; + /* check again if this mirrors a staged map */ + maps = mpr_list_from_data(g->maps); while (maps) { - map2 = (mpr_map)*maps; + mpr_map map2 = (mpr_map)*maps; maps = mpr_list_get_next(maps); if (map2->obj.id != 0 || map->num_src != map2->num_src || map->dst->sig != map2->dst->sig) @@ -718,31 +683,18 @@ mpr_map mpr_graph_add_map(mpr_graph g, int num_src, const char **src_names, } if (map) { - updated += mpr_map_set_from_msg(map, msg, 0); #ifdef DEBUG if (!rc) { trace_graph("updated %d props for map [", updated); for (i = 0; i < map->num_src; i++) { - printf("%s:%s, ", map->src[i]->sig->dev->name, - map->src[i]->sig->name); + printf("%s:%s, ", map->src[i]->sig->dev->name, map->src[i]->sig->name); } - printf("\b\b] -> [%s:%s]\n", map->dst->sig->dev->name, - map->dst->sig->name); + printf("\b\b] -> [%s:%s]\n", map->dst->sig->dev->name, map->dst->sig->name); } #endif - - RETURN_UNLESS(map->status >= MPR_STATUS_ACTIVE, map); - if (rc || updated) { - fptr_list cb = g->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_MAP) - ((mpr_graph_handler*)cb->f)(g, (mpr_obj)map, - rc ? MPR_OBJ_NEW : MPR_OBJ_MOD, - cb->ctx); - cb = temp; - } - } + RETURN_ARG_UNLESS(map->status >= MPR_STATUS_ACTIVE, map); + if (rc || updated) + mpr_graph_call_cbs(g, (mpr_obj)map, MPR_MAP, rc ? MPR_OBJ_NEW : MPR_OBJ_MOD); } return map; } @@ -751,24 +703,17 @@ void mpr_graph_remove_map(mpr_graph g, mpr_map m, mpr_graph_evt e) { RETURN_UNLESS(m); mpr_list_remove_item((void**)&g->maps, m); - - fptr_list cb = g->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_MAP) - ((mpr_graph_handler*)cb->f)(g, (mpr_obj)m, e, cb->ctx); - cb = temp; - } - + mpr_graph_call_cbs(g, (mpr_obj)m, MPR_MAP, e); mpr_map_free(m); mpr_list_free_item(m); } void mpr_graph_print(mpr_graph g) { - printf("-------------------------------\n"); mpr_list devs = mpr_list_from_data(g->devs); mpr_list sigs = mpr_list_from_data(g->sigs); + mpr_list maps; + printf("-------------------------------\n"); printf("Registered devices (%d) and signals (%d):\n", mpr_list_get_size(devs), mpr_list_get_size(sigs)); mpr_list_free(sigs); @@ -786,12 +731,12 @@ void mpr_graph_print(mpr_graph g) } printf("-------------------------------\n"); - mpr_list maps = mpr_list_from_data(g->maps); + maps = mpr_list_from_data(g->maps); printf("Registered maps (%d):\n", mpr_list_get_size(maps)); while (maps) { - printf(" └─ "); - mpr_obj_print(*maps, 0); mpr_map map = (mpr_map)*maps; + printf(" └─ "); + mpr_obj_print((mpr_obj)map, 0); sigs = mpr_map_get_sigs(map, MPR_LOC_SRC); while (sigs) { mpr_sig sig = (mpr_sig)*sigs; @@ -814,14 +759,14 @@ void mpr_graph_print(mpr_graph g) static void renew_subscriptions(mpr_graph g, uint32_t time_sec) { - // check if any subscriptions need to be renewed + /* check if any subscriptions need to be renewed */ mpr_subscription s = g->subscriptions; while (s) { if (s->lease_expiration_sec <= time_sec) { - trace_graph("Automatically renewing subscription to %s for %d " - "secs.\n", mpr_dev_get_name(s->dev), AUTOSUB_INTERVAL); + trace_graph("Automatically renewing subscription to %s for %d secs.\n", + mpr_dev_get_name(s->dev), AUTOSUB_INTERVAL); send_subscribe_msg(g, s->dev, s->flags, AUTOSUB_INTERVAL); - // leave 10-second buffer for subscription renewal + /* leave 10-second buffer for subscription renewal */ s->lease_expiration_sec = (time_sec + AUTOSUB_INTERVAL - 10); } s = s->next; @@ -831,8 +776,9 @@ static void renew_subscriptions(mpr_graph g, uint32_t time_sec) int mpr_graph_poll(mpr_graph g, int block_ms) { mpr_net n = &g->net; - int count = 0, status[2]; + int count = 0, status[2], left_ms, elapsed, checked_admin = 0; mpr_time t; + double then; mpr_net_poll(n); mpr_time_set(&t, MPR_NOW); @@ -840,20 +786,20 @@ int mpr_graph_poll(mpr_graph g, int block_ms) _check_dev_status(g, t.sec); if (!block_ms) { - if (lo_servers_recv_noblock(n->server.admin, status, 2, 0)) { + if (lo_servers_recv_noblock(&n->servers[SERVER_ADMIN], status, 2, 0)) { count = (status[0] > 0) + (status[1] > 0); n->msgs_recvd |= count; } return count; } - double then = mpr_get_current_time(); - int left_ms = block_ms, elapsed, checked_admin = 0; + then = mpr_get_current_time(); + left_ms = block_ms; while (left_ms > 0) { if (left_ms > 100) left_ms = 100; - if (lo_servers_recv_noblock(n->server.admin, status, 2, left_ms)) + if (lo_servers_recv_noblock(&n->servers[SERVER_ADMIN], status, 2, left_ms)) count += (status[0] > 0) + (status[1] > 0); elapsed = (mpr_get_current_time() - then) * 1000; @@ -889,18 +835,18 @@ void mpr_graph_subscribe(mpr_graph g, mpr_dev d, int flags, int timeout) _autosubscribe(g, flags); return; } - else if (d->loc) { - // don't bother subscribing to local device + else if (d->is_local) { + /* don't bother subscribing to local device */ trace_graph("aborting subscription, device is local.\n"); return; } if (0 == flags || 0 == timeout) { - mpr_subscription *s = &g->subscriptions; + mpr_subscription *s = &g->subscriptions, temp; while (*s) { if ((*s)->dev == d) { - // remove from subscriber list + /* remove from subscriber list */ (*s)->dev->subscribed = 0; - mpr_subscription temp = *s; + temp = *s; *s = temp->next; free(temp); send_subscribe_msg(g, d, 0, 0); @@ -910,17 +856,18 @@ void mpr_graph_subscribe(mpr_graph g, mpr_dev d, int flags, int timeout) } } else if (-1 == timeout) { + mpr_time t; #ifdef DEBUG - trace_graph("adding %d-second autorenewing subscription to device '%s' " - "with flags ", AUTOSUB_INTERVAL, mpr_dev_get_name(d)); + trace_graph("adding %d-second autorenewing subscription to device '%s' with flags ", + AUTOSUB_INTERVAL, mpr_dev_get_name(d)); print_subscription_flags(flags); #endif - // special case: autorenew subscription lease - // first check if subscription already exists + /* special case: autorenew subscription lease */ + /* first check if subscription already exists */ mpr_subscription s = _get_subscription(g, d); if (!s) { - // store subscription record + /* store subscription record */ s = malloc(sizeof(struct _mpr_subscription)); s->flags = 0; s->dev = d; @@ -935,17 +882,16 @@ void mpr_graph_subscribe(mpr_graph g, mpr_dev d, int flags, int timeout) s->dev->obj.version = -1; s->flags = flags; - mpr_time t; mpr_time_set(&t, MPR_NOW); - // leave 10-second buffer for subscription lease + /* leave 10-second buffer for subscription lease */ s->lease_expiration_sec = (t.sec + AUTOSUB_INTERVAL - 10); timeout = AUTOSUB_INTERVAL; } #ifdef DEBUG else { - trace_graph("adding temporary %d-second subscription to device '%s' " - "with flags ", timeout, mpr_dev_get_name(d)); + trace_graph("adding temporary %d-second subscription to device '%s' with flags ", + timeout, mpr_dev_get_name(d)); print_subscription_flags(flags); } #endif @@ -972,7 +918,7 @@ int mpr_graph_subscribed_by_dev(mpr_graph g, const char *name) int mpr_graph_subscribed_by_sig(mpr_graph g, const char *name) { - // name needs to be split + mpr_dev dev; char *devnamep, *signame, devname[256]; int devnamelen = mpr_parse_names(name, &devnamep, &signame); if (!devnamelen || devnamelen >= 256) { @@ -981,7 +927,7 @@ int mpr_graph_subscribed_by_sig(mpr_graph g, const char *name) } strncpy(devname, devnamep, devnamelen); devname[devnamelen] = 0; - mpr_dev dev = mpr_graph_get_dev_by_name(g, devname); + dev = mpr_graph_get_dev_by_name(g, devname); if (dev) { mpr_subscription s = _get_subscription(g, dev); return s ? s->flags : 0; diff --git a/src/mapper/link.c b/src/mapper/link.c index bb0f5d8..397d5a5 100644 --- a/src/mapper/link.c +++ b/src/mapper/link.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -10,45 +10,49 @@ #include "types_internal.h" #include -mpr_link mpr_link_new(mpr_dev local_dev, mpr_dev remote_dev) +mpr_link mpr_link_new(mpr_local_dev local_dev, mpr_dev remote_dev) { - return mpr_graph_add_link(local_dev->obj.graph, local_dev, remote_dev); + return mpr_graph_add_link(local_dev->obj.graph, (mpr_dev)local_dev, remote_dev); } void mpr_link_init(mpr_link link) { mpr_net net = &link->obj.graph->net; + mpr_time t; + lo_message msg; + char cmd[256]; if (!link->num_maps) link->num_maps = (int*)calloc(1, sizeof(int) * 2); - link->obj.props.mask = 0; if (!link->obj.props.synced) { mpr_tbl t = link->obj.props.synced = mpr_tbl_new(); - mpr_tbl_link(t, MPR_PROP_DEV, 2, MPR_DEV, &link->devs, - NON_MODIFIABLE | LOCAL_ACCESS_ONLY); + mpr_tbl_link(t, MPR_PROP_DEV, 2, MPR_DEV, &link->devs, NON_MODIFIABLE | LOCAL_ACCESS_ONLY); mpr_tbl_link(t, MPR_PROP_ID, 1, MPR_INT64, &link->obj.id, NON_MODIFIABLE); - mpr_tbl_link(t, MPR_PROP_NUM_MAPS, 2, MPR_INT32, &link->num_maps, - NON_MODIFIABLE | INDIRECT); + mpr_tbl_link(t, MPR_PROP_NUM_MAPS, 2, MPR_INT32, &link->num_maps, NON_MODIFIABLE | INDIRECT); } if (!link->obj.props.staged) link->obj.props.staged = mpr_tbl_new(); - if (!link->obj.id && link->local_dev->loc) - link->obj.id = mpr_dev_generate_unique_id(link->local_dev); + if (!link->obj.id && link->devs[LOCAL_DEV]->is_local) + link->obj.id = mpr_dev_generate_unique_id(link->devs[LOCAL_DEV]); link->clock.new = 1; link->clock.sent.msg_id = 0; link->clock.rcvd.msg_id = -1; - mpr_time t; mpr_time_set(&t, MPR_NOW); link->clock.rcvd.time.sec = t.sec + 10; - // request missing metadata - char cmd[256]; - snprintf(cmd, 256, "/%s/subscribe", link->remote_dev->name); - NEW_LO_MSG(m, return); - lo_message_add_string(m, "device"); + /* request missing metadata */ + snprintf(cmd, 256, "/%s/subscribe", link->devs[REMOTE_DEV]->name); + + msg = lo_message_new(); + if (!msg) { + trace_net("couldn't allocate lo_message\n"); + return; + } + + lo_message_add_string(msg, "device"); mpr_net_use_bus(net); - mpr_net_add_msg(net, cmd, 0, m); + mpr_net_add_msg(net, cmd, 0, msg); mpr_net_send(net); } @@ -56,71 +60,73 @@ void mpr_link_connect(mpr_link link, const char *host, int admin_port, int data_port) { char str[16]; - mpr_tbl_set(link->remote_dev->obj.props.synced, MPR_PROP_HOST, NULL, 1, + mpr_tbl_set(link->devs[REMOTE_DEV]->obj.props.synced, MPR_PROP_HOST, NULL, 1, MPR_STR, host, REMOTE_MODIFY); - mpr_tbl_set(link->remote_dev->obj.props.synced, MPR_PROP_PORT, NULL, 1, + mpr_tbl_set(link->devs[REMOTE_DEV]->obj.props.synced, MPR_PROP_PORT, NULL, 1, MPR_INT32, &data_port, REMOTE_MODIFY); sprintf(str, "%d", data_port); link->addr.udp = lo_address_new(host, str); link->addr.tcp = lo_address_new_with_proto(LO_TCP, host, str); sprintf(str, "%d", admin_port); link->addr.admin = lo_address_new(host, str); - trace_dev(link->local_dev, "activated router to device '%s' at %s:%d\n", - link->remote_dev->name, host, data_port); + trace_dev(link->devs[LOCAL_DEV], "activated router to device '%s' at %s:%d\n", + link->devs[REMOTE_DEV]->name, host, data_port); memset(link->bundles, 0, sizeof(mpr_bundle_t) * NUM_BUNDLES); - mpr_dev_add_link(link->local_dev, link->remote_dev); + mpr_dev_add_link(link->devs[LOCAL_DEV], link->devs[REMOTE_DEV]); } void mpr_link_free(mpr_link link) { + int i; FUNC_IF(mpr_tbl_free, link->obj.props.synced); FUNC_IF(mpr_tbl_free, link->obj.props.staged); FUNC_IF(free, link->num_maps); - if (!link->local_dev->loc) + if (!link->devs[LOCAL_DEV]->is_local) return; FUNC_IF(lo_address_free, link->addr.admin); FUNC_IF(lo_address_free, link->addr.udp); FUNC_IF(lo_address_free, link->addr.tcp); - FUNC_IF(lo_bundle_free_recursive, link->bundles[0].udp); - FUNC_IF(lo_bundle_free_recursive, link->bundles[0].tcp); - FUNC_IF(lo_bundle_free_recursive, link->bundles[1].udp); - FUNC_IF(lo_bundle_free_recursive, link->bundles[1].tcp); - mpr_dev_remove_link(link->local_dev, link->remote_dev); + for (i = 0; i < NUM_BUNDLES; i++) { + FUNC_IF(lo_bundle_free_recursive, link->bundles[i].udp); + FUNC_IF(lo_bundle_free_recursive, link->bundles[i].tcp); + } + mpr_dev_remove_link(link->devs[LOCAL_DEV], link->devs[REMOTE_DEV]); } -// note on memory handling of mpr_link_add_msg(): -// message: will be owned, will be freed when done +/* note on memory handling of mpr_link_add_msg(): + * message: will be owned, will be freed when done */ void mpr_link_add_msg(mpr_link link, mpr_sig dst, lo_message msg, mpr_time t, mpr_proto proto, int idx) { + lo_bundle *b; RETURN_UNLESS(msg); - if (link->local_dev == link->remote_dev) + if (link->devs[0] == link->devs[1]) proto = MPR_PROTO_UDP; - // add message to existing bundles - lo_bundle *b = (proto == MPR_PROTO_UDP) ? &link->bundles[idx].udp : &link->bundles[idx].tcp; + /* add message to existing bundles */ + b = (proto == MPR_PROTO_UDP) ? &link->bundles[idx].udp : &link->bundles[idx].tcp; if (!(*b)) *b = lo_bundle_new(t); lo_bundle_add_message(*b, dst->path, msg); } -// TODO: pass in bundle index as argument -// TODO: interrupt driven signal updates may not be followed by mpr_dev_process_outputs(); in the case -// where the interrupt has interrupted mpr_dev_poll() these messages will not be dispatched. +/* TODO: pass in bundle index as argument */ +/* TODO: interrupt driven signal updates may not be followed by mpr_dev_process_outputs(); in the + * case where the interrupt has interrupted mpr_dev_poll() these messages will not be dispatched. */ int mpr_link_process_bundles(mpr_link link, mpr_time t, int idx) { - RETURN_UNLESS(link, 0); int i = 0, num = 0, tmp; - - mpr_bundle b = &link->bundles[idx]; + mpr_bundle b; lo_bundle lb; + RETURN_ARG_UNLESS(link, 0); + + b = &link->bundles[idx]; - if (link->local_dev != link->remote_dev) { + if (link->devs[0] != link->devs[1]) { mpr_net n = &link->obj.graph->net; if ((lb = b->udp)) { b->udp = 0; - if ((tmp = lo_bundle_count(lb))) { - num = tmp; - lo_send_bundle_from(link->addr.udp, n->server.udp, lb); + if ((num = lo_bundle_count(lb))) { + lo_send_bundle_from(link->addr.udp, n->servers[SERVER_UDP], lb); } lo_bundle_free_recursive(lb); } @@ -128,26 +134,25 @@ int mpr_link_process_bundles(mpr_link link, mpr_time t, int idx) b->tcp = 0; if ((tmp = lo_bundle_count(lb))) { num += tmp; - lo_send_bundle_from(link->addr.tcp, n->server.tcp, lb); + lo_send_bundle_from(link->addr.tcp, n->servers[SERVER_TCP], lb); } lo_bundle_free_recursive(lb); } } else if ((lb = b->udp)) { + const char *path; b->udp = 0; - // set out-of-band timestamp + /* set out-of-band timestamp */ mpr_dev_bundle_start(lo_bundle_get_timestamp(lb), NULL); - // call handler directly instead of sending over the network + /* call handler directly instead of sending over the network */ num = lo_bundle_count(lb); - const char *path; while (i < num) { lo_message m = lo_bundle_get_message(lb, i, &path); - // need to look up signal by path + /* need to look up signal by path */ mpr_rtr_sig rs = link->obj.graph->net.rtr->sigs; while (rs) { if (0 == strcmp(path, rs->sig->path)) { - mpr_dev_handler(NULL, lo_message_get_types(m), - lo_message_get_argv(m), + mpr_dev_handler(NULL, lo_message_get_types(m), lo_message_get_argv(m), lo_message_get_argc(m), m, (void*)rs->sig); break; } @@ -175,22 +180,23 @@ static int cmp_qry_link_maps(const void *context_data, mpr_map map) mpr_list mpr_link_get_maps(mpr_link link) { - RETURN_UNLESS(link && link->devs[0]->obj.graph->maps, 0); - mpr_list q = mpr_list_new_query((const void**)&link->devs[0]->obj.graph->maps, - cmp_qry_link_maps, "h", link->obj.id); + mpr_list q; + RETURN_ARG_UNLESS(link && link->devs[0]->obj.graph->maps, 0); + q = mpr_list_new_query((const void**)&link->devs[0]->obj.graph->maps, + (void*)cmp_qry_link_maps, "h", link->obj.id); return mpr_list_start(q); } -void mpr_link_remove_map(mpr_link link, mpr_map rem) +void mpr_link_remove_map(mpr_link link, mpr_local_map rem) { - int in = 0, out = 0, rev = link->devs[0]->loc ? 0 : 1; + int in = 0, out = 0, rev = link->devs[0]->is_local ? 0 : 1; mpr_list list = mpr_link_get_maps(link); while (list) { - mpr_map map = *(mpr_map*)list; + mpr_local_map map = *(mpr_local_map*)list; list = mpr_list_get_next(list); if (map == rem) continue; - if (map->dst->loc && map->dst->loc->rsig) + if (map->dst->is_local && map->dst->rsig) ++in; else ++out; @@ -210,5 +216,5 @@ void mpr_link_send(mpr_link link, net_msg_t cmd) int mpr_link_get_is_local(mpr_link link) { - return link->local_dev->loc || link->remote_dev->loc; + return link->devs[0]->is_local || link->devs[1]->is_local; } diff --git a/src/mapper/list.c b/src/mapper/list.c index bfa9fd2..ace54b7 100644 --- a/src/mapper/list.c +++ b/src/mapper/list.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -31,7 +31,7 @@ typedef enum { typedef enum { QUERY_STATIC = 1, - QUERY_DYNAMIC = 2, + QUERY_DYNAMIC = 2 } query_type_t; typedef struct { @@ -40,7 +40,7 @@ typedef struct { void **start; struct _query_info *query_ctx; query_type_t query_type; - int data[1]; // stub + int data[1]; /* stub */ } mpr_list_header_t; /*! Function for query comparison */ @@ -57,7 +57,7 @@ typedef struct _query_info { unsigned int size; query_compare_func_t *query_compare; query_free_func_t *query_free; - int data[0]; // stub + int *data; /* stub */ } query_info_t; #define LIST_HEADER_SIZE (sizeof(mpr_list_header_t)-sizeof(int[1])) @@ -68,8 +68,8 @@ static mpr_list_header_t* mpr_list_new_item(size_t size) { mpr_list_header_t *lh=0; - // make sure the compiler is doing what we think it's doing with - // the size of mpr_list_header_t and location of data + /* make sure the compiler is doing what we think it's doing with + * the size of mpr_list_header_t and location of data */ die_unless(LIST_HEADER_SIZE == sizeof(void*)*4 + sizeof(query_type_t), "unexpected size for mpr_list_header_t"); die_unless(LIST_HEADER_SIZE == ((char*)&lh->data - (char*)lh), @@ -77,7 +77,7 @@ static mpr_list_header_t* mpr_list_new_item(size_t size) size += LIST_HEADER_SIZE; lh = calloc(1, size); - RETURN_UNLESS(lh, 0); + RETURN_ARG_UNLESS(lh, 0); lh->self = &lh->data; lh->start = &lh->self; lh->query_type = QUERY_STATIC; @@ -88,20 +88,21 @@ static mpr_list_header_t* mpr_list_new_item(size_t size) /*! Get the list header for memory returned from mpr_list_new_item(). */ static mpr_list_header_t* mpr_list_header_by_data(const void *data) { - return (mpr_list_header_t*)(data - LIST_HEADER_SIZE); + return (mpr_list_header_t*)((char*)data - LIST_HEADER_SIZE); } /*! Get the list header for memory returned from mpr_list_new_item(). */ static mpr_list_header_t* mpr_list_header_by_self(void *self) { - mpr_list_header_t *lh=0; - return (mpr_list_header_t*)(self - ((void*)&lh->self - (void*)lh)); + mpr_list_header_t *lh = 0; + return (mpr_list_header_t*)((char*)self - ((char*)&lh->self - (char*)lh)); } void *mpr_list_from_data(const void *data) { - RETURN_UNLESS(data, 0); - mpr_list_header_t* lh = mpr_list_header_by_data(data); + mpr_list_header_t *lh; + RETURN_ARG_UNLESS(data, 0); + lh = mpr_list_header_by_data(data); die_unless(lh->self == &lh->data, "bad self pointer in list structure"); return &lh->self; } @@ -177,7 +178,7 @@ void **mpr_list_query_continuation(mpr_list_header_t *lh) return &lh->self; } - // Clean up + /* Clean up */ if (lh->query_ctx->query_free) lh->query_ctx->query_free(lh); return 0; @@ -186,10 +187,10 @@ void **mpr_list_query_continuation(mpr_list_header_t *lh) static void free_query_single_ctx(mpr_list_header_t *lh) { if (cmp_parallel_query == lh->query_ctx->query_compare) { - // this is a parallel query – we need to free components also + /* this is a parallel query – we need to free components also */ void *data = &lh->query_ctx->data; mpr_list_header_t *lh1 = *(mpr_list_header_t**)data; - mpr_list_header_t *lh2 = *(mpr_list_header_t**)(data+sizeof(void*)); + mpr_list_header_t *lh2 = *(mpr_list_header_t**)((char*)data + sizeof(void*)); free_query_single_ctx(lh1); free_query_single_ctx(lh2); } @@ -211,12 +212,12 @@ size += num_args * sizeof(TYPE); static int get_query_size(const char *types, va_list aq) { - RETURN_UNLESS(types, 0); int i = 0, j, size = 0, num_args; + RETURN_ARG_UNLESS(types, 0); while (types[i]) { switch (types[i]) { case MPR_INT32: - case MPR_TYPE: // store as int to avoid alignment problems + case MPR_TYPE: /* store as int to avoid alignment problems */ GET_TYPE_SIZE(int); break; case MPR_INT64: @@ -225,10 +226,10 @@ static int get_query_size(const char *types, va_list aq) case MPR_PTR: GET_TYPE_SIZE(void*); break; - case MPR_STR: // special case + case MPR_STR: /* special case */ if (types[i+1] && isdigit(types[i+1])) { - num_args = atoi(types+i+1); const char **val = va_arg(aq, const char**); + num_args = atoi(types+i+1); for (j = 0; j < num_args; j++) size += strlen(val[j]) + 1; ++i; @@ -246,18 +247,18 @@ static int get_query_size(const char *types, va_list aq) return size; } -#define COPY_TYPE(TYPE) \ -if (types[i+1] && isdigit(types[i+1])) { \ - num_args = atoi(types+i+1); \ - TYPE *val = (TYPE*)va_arg(aq, TYPE*); \ - memcpy(d+offset, val, sizeof(TYPE) * num_args); \ - ++i; \ -} \ -else { \ - num_args = 1; \ - TYPE val = (TYPE)va_arg(aq, TYPE); \ - memcpy(d+offset, &val, sizeof(TYPE)); \ -} \ +#define COPY_TYPE(TYPE) \ +if (types[i+1] && isdigit(types[i + 1])) { \ + TYPE *val = (TYPE*)va_arg(aq, TYPE*); \ + num_args = atoi(types + i + 1); \ + memcpy(data + offset, val, sizeof(TYPE) * num_args);\ + ++i; \ +} \ +else { \ + TYPE val = (TYPE)va_arg(aq, TYPE); \ + num_args = 1; \ + memcpy(data + offset, &val, sizeof(TYPE)); \ +} \ offset += sizeof(TYPE) * num_args; /* We need to be careful of memory alignment here - for now we will just ensure @@ -265,49 +266,51 @@ offset += sizeof(TYPE) * num_args; static void **new_query_internal(const void **list, int size, const void *func, const char *types, va_list aq) { - RETURN_UNLESS(list && size && func && types, 0); - mpr_list_header_t *lh = (mpr_list_header_t*)malloc(LIST_HEADER_SIZE); - lh->next = mpr_list_query_continuation; + mpr_list_header_t *lh; + int offset = 0, i = 0, j, num_args; + char *data; + RETURN_ARG_UNLESS(list && size && func && types, 0); + lh = (mpr_list_header_t*)malloc(LIST_HEADER_SIZE); + lh->next = (void*)mpr_list_query_continuation; lh->query_type = QUERY_DYNAMIC; lh->query_ctx = (query_info_t*)malloc(sizeof(query_info_t)+size); - char *d = (char*)&lh->query_ctx->data; - int offset = 0, i = 0, j, num_args;; + data = (char*)&lh->query_ctx->data; while (types[i]) { switch (types[i]) { case MPR_INT32: - case MPR_TYPE: // store char as int to avoid alignment problems + case MPR_TYPE: /* store char as int to avoid alignment problems */ COPY_TYPE(int); break; case MPR_INT64: COPY_TYPE(int64_t); break; case MPR_PTR: { - if (types[i+1] && isdigit(types[i+1])) { - // is array - num_args = atoi(types+i+1); + void *val = va_arg(aq, void**); + if (types[i+1] && isdigit(types[i + 1])) { + /* is array */ + num_args = atoi(types + i + 1); ++i; } else num_args = 1; - void *val = va_arg(aq, void**); - memcpy(d+offset, val, sizeof(void*) * num_args); + memcpy(data + offset, val, sizeof(void*) * num_args); offset += sizeof(void**) * num_args; break; } - case MPR_STR: // special case - if (types[i+1] && isdigit(types[i+1])) { - // is array - num_args = atoi(types+i+1); + case MPR_STR: /* special case */ + if (types[i+1] && isdigit(types[i + 1])) { + /* is array */ const char **val = (const char**)va_arg(aq, const char**); + num_args = atoi(types + i + 1); for (j = 0; j < num_args; j++) - snprintf(d+offset, size-offset, "%s", val[j]); + snprintf(data + offset, size - offset, "%s", val[j]); offset += strlen(val[j]) + 1; ++i; } else { const char *val = (const char*)va_arg(aq, const char*); - snprintf(d+offset, size-offset, "%s", val); + snprintf(data + offset, size - offset, "%s", val); offset += (val ? strlen(val) : 0) + 1; } break; @@ -319,7 +322,7 @@ static void **new_query_internal(const void **list, int size, const void *func, ++i; } - lh->query_ctx->size = sizeof(query_info_t)+size; + lh->query_ctx->size = sizeof(query_info_t) + size; lh->query_ctx->query_compare = (query_compare_func_t*)func; lh->query_ctx->query_free = (query_free_func_t*)free_query_single_ctx; lh->start = (void**)list; @@ -330,21 +333,24 @@ static void **new_query_internal(const void **list, int size, const void *func, mpr_list mpr_list_new_query(const void **list, const void *func, const char *types, ...) { + int size; va_list aq; + mpr_list qry; va_start(aq, types); - int size = get_query_size(types, aq); + size = get_query_size(types, aq); va_end(aq); va_start(aq, types); - mpr_list qry = (mpr_list)new_query_internal(list, size, func, types, aq); + qry = (mpr_list)new_query_internal(list, size, func, types, aq); va_end(aq); return qry; } mpr_list mpr_list_start(mpr_list list) { - RETURN_UNLESS(list, 0); - mpr_list_header_t *lh = mpr_list_header_by_self(list); + mpr_list_header_t *lh; + RETURN_ARG_UNLESS(list, 0); + lh = mpr_list_header_by_self(list); lh->self = *lh->start; if (QUERY_DYNAMIC == lh->query_type) { if (!*list) @@ -359,6 +365,7 @@ mpr_list mpr_list_start(mpr_list list) mpr_list mpr_list_get_next(mpr_list list) { + mpr_list_header_t *lh; if (!list) { trace("bad pointer in mpr_list_get_next()\n"); return 0; @@ -368,8 +375,8 @@ mpr_list mpr_list_get_next(mpr_list list) return 0; } - mpr_list_header_t *lh = mpr_list_header_by_self(list); - RETURN_UNLESS(lh->next, 0); + lh = mpr_list_header_by_self(list); + RETURN_ARG_UNLESS(lh->next, 0); if (QUERY_STATIC == lh->query_type) return (mpr_list)mpr_list_from_data(lh->next); @@ -378,7 +385,7 @@ mpr_list mpr_list_get_next(mpr_list list) * return items from the graph computed lazily. The context is * simply the string(s) to match. In the future, it might point to the * results of a SQL query for example. */ - void **(*f) (mpr_list_header_t*) = lh->next; + void **(*f) (mpr_list_header_t*) = (void **(*) (mpr_list_header_t*))lh->next; return (mpr_list)f(lh); } return 0; @@ -386,27 +393,28 @@ mpr_list mpr_list_get_next(mpr_list list) void mpr_list_free(mpr_list list) { + mpr_list_header_t *lh; RETURN_UNLESS(list); - mpr_list_header_t *lh = mpr_list_header_by_self(list); + lh = mpr_list_header_by_self(list); if (QUERY_DYNAMIC == lh->query_type && lh->query_ctx->query_free) lh->query_ctx->query_free(lh); } mpr_obj mpr_list_get_idx(mpr_list list, unsigned int idx) { - RETURN_UNLESS(list, 0); - mpr_list_header_t *lh = mpr_list_header_by_self(list); + int i = 0; + mpr_list_header_t *lh; + RETURN_ARG_UNLESS(list, 0); + lh = mpr_list_header_by_self(list); - if (0 == idx && *lh->start) - return *lh->start; - - // Reset to beginning of list + /* Reset to beginning of list */ lh->self = *lh->start; + mpr_list_start(list); - int i = 1; - while ((list = mpr_list_get_next(list))) { + while (list) { if (i == idx) return *list; + list = mpr_list_get_next(list); ++i; } return 0; @@ -416,8 +424,8 @@ mpr_obj mpr_list_get_idx(mpr_list list, unsigned int idx) static int cmp_parallel_query(const void *ctx_data, const void *list) { mpr_list_header_t *lh1 = *(mpr_list_header_t**)ctx_data; - mpr_list_header_t *lh2 = *(mpr_list_header_t**)(ctx_data+sizeof(void*)); - mpr_op op = *(mpr_op*)(ctx_data + sizeof(void*) * 2); + mpr_list_header_t *lh2 = *(mpr_list_header_t**)((char*)ctx_data + sizeof(void*)); + mpr_op op = *(mpr_op*)((char*)ctx_data + sizeof(void*) * 2); query_info_t *c1 = lh1->query_ctx, *c2 = lh2->query_ctx; int res1 = c1->query_compare(&c1->data, list); @@ -434,105 +442,84 @@ static mpr_list_header_t *mpr_list_header_cpy(mpr_list_header_t *lh) { mpr_list_header_t *cpy = (mpr_list_header_t*)malloc(LIST_HEADER_SIZE); memcpy(cpy, lh, LIST_HEADER_SIZE); - RETURN_UNLESS(lh->query_ctx, cpy); + RETURN_ARG_UNLESS(lh->query_ctx, cpy); cpy->query_ctx = (query_info_t*)malloc(lh->query_ctx->size); memcpy(cpy->query_ctx, lh->query_ctx, lh->query_ctx->size); if (cmp_parallel_query == cpy->query_ctx->query_compare) { - // this is a parallel query – we need to copy components + /* this is a parallel query – we need to copy components */ void *data = &cpy->query_ctx->data; mpr_list_header_t *lh1 = *(mpr_list_header_t**)data; - mpr_list_header_t *lh2 = *(mpr_list_header_t**)(data+sizeof(void*)); + mpr_list_header_t *lh2 = *(mpr_list_header_t**)((char*)data + sizeof(void*)); lh1 = mpr_list_header_cpy(lh1); lh2 = mpr_list_header_cpy(lh2); memcpy(data, &lh1, sizeof(void*)); - memcpy(data+sizeof(void*), &lh2, sizeof(void*)); + memcpy((char*)data + sizeof(void*), &lh2, sizeof(void*)); lh1 = *(mpr_list_header_t**)data; - lh2 = *(mpr_list_header_t**)(data+sizeof(void*)); + lh2 = *(mpr_list_header_t**)((char*)data + sizeof(void*)); } return cpy; } mpr_list mpr_list_get_cpy(mpr_list list) { - RETURN_UNLESS(list, 0); - mpr_list_header_t *lh = mpr_list_header_by_self(list); - mpr_list_header_t *cpy = mpr_list_header_cpy(lh); + mpr_list_header_t *lh, *cpy; + RETURN_ARG_UNLESS(list, 0); + lh = mpr_list_header_by_self(list); + cpy = mpr_list_header_cpy(lh); return (mpr_list)&cpy->self; } mpr_list mpr_list_get_union(mpr_list list1, mpr_list list2) { - RETURN_UNLESS(list1, list2); - RETURN_UNLESS(list2, list1); - mpr_list_header_t *lh1 = mpr_list_header_by_self(list1); - mpr_list_header_t *lh2 = mpr_list_header_by_self(list2); - mpr_list q = mpr_list_new_query((const void **)lh1->start, cmp_parallel_query, - "vvi", &lh1, &lh2, OP_UNION); - return mpr_list_start(q); + mpr_list_header_t *lh1, *lh2; + RETURN_ARG_UNLESS(list1, list2); + RETURN_ARG_UNLESS(list2, list1); + lh1 = mpr_list_header_by_self(list1); + lh2 = mpr_list_header_by_self(list2); + return mpr_list_start(mpr_list_new_query((const void **)lh1->start, (void*)cmp_parallel_query, + "vvi", &lh1, &lh2, OP_UNION)); } mpr_list mpr_list_get_isect(mpr_list list1, mpr_list list2) { - RETURN_UNLESS(list1 && list2, 0); - mpr_list_header_t *lh1 = mpr_list_header_by_self(list1); - mpr_list_header_t *lh2 = mpr_list_header_by_self(list2); - mpr_list q = mpr_list_new_query((const void **)lh1->start, cmp_parallel_query, - "vvi", &lh1, &lh2, OP_INTERSECTION); - return mpr_list_start(q); + mpr_list_header_t *lh1, *lh2; + RETURN_ARG_UNLESS(list1 && list2, 0); + lh1 = mpr_list_header_by_self(list1); + lh2 = mpr_list_header_by_self(list2); + return mpr_list_start(mpr_list_new_query((const void **)lh1->start, (void*)cmp_parallel_query, + "vvi", &lh1, &lh2, OP_INTERSECTION)); } -static mpr_list mpr_list_filter_internal(mpr_list list, const void *func, - const char *types, ...) +static mpr_list mpr_list_filter_internal(mpr_list list, const void *func, const char *types, ...) { - RETURN_UNLESS(list, 0); + int size; va_list aq; + mpr_list_header_t *lh1, *lh2; + void **filter; + + RETURN_ARG_UNLESS(list, 0); + va_start(aq, types); - int size = get_query_size(types, aq); + size = get_query_size(types, aq); va_end(aq); - mpr_list_header_t *lh1 = mpr_list_header_by_self(list); + lh1 = mpr_list_header_by_self(list); va_start(aq, types); - void **filter = new_query_internal((const void **)lh1->start, size, func, - types, aq); + filter = new_query_internal((const void **)lh1->start, size, func, types, aq); va_end(aq); if (QUERY_STATIC == lh1->query_type) return (mpr_list)filter; - // return intersection - mpr_list_header_t *lh2 = mpr_list_header_by_self(filter); - return mpr_list_new_query((const void **)lh1->start, cmp_parallel_query, + /* return intersection */ + lh2 = mpr_list_header_by_self(filter); + return mpr_list_new_query((const void **)lh1->start, (void*)cmp_parallel_query, "vvi", &lh1, &lh2, OP_INTERSECTION); } -static int match_pattern(const char* s, const char* p) -{ - RETURN_UNLESS(s && p, 1); - RETURN_UNLESS(strchr(p, '*'), strcmp(s, p)); - - // 1) tokenize pattern using strtok() with delimiter character '*' - // 2) use strstr() to check if token exists in offset string - char *str = (char*)s, *tok; - char dup[strlen(p)+1], *pat = dup; - strcpy(pat, p); - int ends_wild = ('*' == p[strlen(p)-1]); - while (str && *str) { - tok = strtok(pat, "*"); - RETURN_UNLESS(tok, !ends_wild); - str = strstr(str, tok); - if (str && *str) - str += strlen(tok); - else - return 1; - // subsequent calls to strtok() need first argument to be NULL - pat = NULL; - } - return 0; -} - #define COMPARE_TYPE(TYPE) \ for (i = 0; i < len; i++) { \ comp += ((TYPE*)v1)[i] > ((TYPE*)v2)[i]; \ @@ -550,8 +537,7 @@ static int compare_val(mpr_op op, int len, mpr_type type, comp = match_pattern((const char*)v1, (const char*)v2); else { for (i = 0; i < len; i++) { - comp += match_pattern(((const char**)v1)[i], - ((const char**)v2)[i]); + comp += match_pattern(((const char**)v1)[i], ((const char**)v2)[i]); diff += abs(comp); } } @@ -599,12 +585,12 @@ static int compare_val(mpr_op op, int len, mpr_type type, static int filter_by_prop(const void *ctx, mpr_obj o) { - mpr_prop p = *(int*) (ctx); - mpr_op op = *(int*) (ctx + sizeof(int)); - int len = *(int*) (ctx + sizeof(int)*2); - mpr_type type = *(mpr_type*) (ctx + sizeof(int)*3); - void *val = *(void**) (ctx + sizeof(int)*4); - const char *key = (const char*)(ctx + sizeof(int)*4 + sizeof(void*)); + mpr_prop p = *(int*) ((char*)ctx); + mpr_op op = *(int*) ((char*)ctx + sizeof(int)); + int len = *(int*) ((char*)ctx + sizeof(int)*2); + mpr_type type = *(mpr_type*) ((char*)ctx + sizeof(int)*3); + void *val = *(void**) ((char*)ctx + sizeof(int)*4); + const char *key = (const char*)((char*)ctx + sizeof(int)*4 + sizeof(void*)); int _len; mpr_type _type; const void *_val; @@ -617,10 +603,11 @@ static int filter_by_prop(const void *ctx, mpr_obj o) if (MPR_OP_EX == op) return 1; if (MPR_LIST == _type) { + mpr_list l; if (op < MPR_OP_ANY) return 0; - // use a copy of the list - mpr_list l = mpr_list_get_cpy((mpr_list)_val); + /* use a copy of the list */ + l = mpr_list_get_cpy((mpr_list)_val); while (l) { if (mpr_obj_get_type((mpr_obj)*l) != type) { mpr_list_free(l); @@ -645,41 +632,41 @@ mpr_list mpr_list_filter(mpr_list list, mpr_prop p, const char *key, int len, int mask = MPR_OP_ALL | MPR_OP_ANY; if (!list || op <= MPR_OP_UNDEFINED || (op | mask) > (MPR_OP_NEQ | mask)) return list; - mpr_list q = mpr_list_filter_internal(list, filter_by_prop, "iiicvs", p, op, - len, type, &val, key); - return mpr_list_start(q); + return mpr_list_start(mpr_list_filter_internal(list, (void*)filter_by_prop, "iiicvs", p, op, + len, type, &val, key)); } mpr_list mpr_list_get_diff(mpr_list list1, mpr_list list2) { - RETURN_UNLESS(list1, 0); - RETURN_UNLESS(list2, list1); - mpr_list_header_t *lh1 = mpr_list_header_by_self(list1); - mpr_list_header_t *lh2 = mpr_list_header_by_self(list2); - mpr_list q = mpr_list_new_query((const void **)lh1->start, cmp_parallel_query, - "vvi", &lh1, &lh2, OP_DIFFERENCE); - return mpr_list_start(q); + mpr_list_header_t *lh1, *lh2; + RETURN_ARG_UNLESS(list1, 0); + RETURN_ARG_UNLESS(list2, list1); + lh1 = mpr_list_header_by_self(list1); + lh2 = mpr_list_header_by_self(list2); + return mpr_list_start(mpr_list_new_query((const void **)lh1->start, (void*)cmp_parallel_query, + "vvi", &lh1, &lh2, OP_DIFFERENCE)); } int mpr_list_get_size(mpr_list list) { - RETURN_UNLESS(list, 0); - mpr_list_header_t *lh = mpr_list_header_by_self(list); - RETURN_UNLESS(lh->start && *lh->start, 0); int count = 1; + mpr_list_header_t *lh; + RETURN_ARG_UNLESS(list, 0); + lh = mpr_list_header_by_self(list); + RETURN_ARG_UNLESS(lh->start && *lh->start, 0); if (QUERY_DYNAMIC == lh->query_type) { - // use a copy + /* use a copy */ list = mpr_list_get_cpy(list); while ((list = mpr_list_get_next(list))) ++count; } else { - // cache list position + /* cache list position */ void *idx = lh->self; lh->self = *lh->start; while ((list = mpr_list_get_next(list))) ++count; - // restore list position + /* restore list position */ lh->self = idx; } return count; diff --git a/src/mapper/map.c b/src/mapper/map.c index 9333402..71872e2 100644 --- a/src/mapper/map.c +++ b/src/mapper/map.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -16,19 +16,19 @@ #define MPR_STATUS_LINK_KNOWN 0x10 #define METADATA_OK 0x1C -static inline int _max(int a, int b) +MPR_INLINE static int _max(int a, int b) { return a > b ? a : b; } -static inline int _min(int a, int b) +MPR_INLINE static int _min(int a, int b) { return a < b ? a : b; } -static int _sort_sigs(int num, mpr_sig *s, int *o) +static int _sort_sigs(int num, mpr_sig *s, unsigned char *o) { - int i, j, res1 = 1, res2 = 1; + int i, j, res1 = 1, res2 = 1, temp; for (i = 0; i < num; i++) o[i] = i; for (i = 1; i < num; i++) { @@ -40,14 +40,14 @@ static int _sort_sigs(int num, mpr_sig *s, int *o) else if (0 == res1) { res2 = strcmp(s[o[j]]->name, s[o[j+1]]->name); if (0 == res2) { - // abort: identical signal names + /* abort: identical signal names */ return 1; } else if (res2 < 0) break; } - // swap - int temp = o[j]; + /* swap */ + temp = o[j]; o[j] = o[j+1]; o[j+1] = temp; j--; @@ -58,8 +58,9 @@ static int _sort_sigs(int num, mpr_sig *s, int *o) static int _cmp_qry_scopes(const void *ctx, mpr_dev d) { + int i; mpr_map m = *(mpr_map*)ctx; - for (int i = 0; i < m->num_scopes; i++) { + for (i = 0; i < m->num_scopes; i++) { if (!m->scopes[i] || m->scopes[i]->obj.id == d->obj.id) return 1; } @@ -68,12 +69,13 @@ static int _cmp_qry_scopes(const void *ctx, mpr_dev d) void mpr_map_init(mpr_map m) { - m->obj.props.mask = 0; - m->obj.props.synced = mpr_tbl_new(); + int i, is_local = 0; + mpr_tbl t = m->obj.props.synced = mpr_tbl_new(); + mpr_list q = mpr_list_new_query((const void**)&m->obj.graph->devs, + (void*)_cmp_qry_scopes, "v", &m); m->obj.props.staged = mpr_tbl_new(); - mpr_tbl t = m->obj.props.synced; - // these properties need to be added in alphabetical order + /* these properties need to be added in alphabetical order */ mpr_tbl_link(t, PROP(DATA), 1, MPR_PTR, &m->obj.data, MODIFIABLE | INDIRECT | LOCAL_ACCESS_ONLY); mpr_tbl_link(t, PROP(EXPR), 1, MPR_STR, &m->expr_str, MODIFIABLE | INDIRECT); @@ -82,19 +84,16 @@ void mpr_map_init(mpr_map m) mpr_tbl_link(t, PROP(NUM_SIGS_IN), 1, MPR_INT32, &m->num_src, NON_MODIFIABLE); mpr_tbl_link(t, PROP(PROCESS_LOC), 1, MPR_INT32, &m->process_loc, MODIFIABLE); mpr_tbl_link(t, PROP(PROTOCOL), 1, MPR_INT32, &m->protocol, REMOTE_MODIFY); - mpr_list q = mpr_list_new_query((const void**)&m->obj.graph->devs, - _cmp_qry_scopes, "v", &m); mpr_tbl_link(t, PROP(SCOPE), 1, MPR_LIST, q, NON_MODIFIABLE | PROP_OWNED); mpr_tbl_link(t, PROP(STATUS), 1, MPR_INT32, &m->status, NON_MODIFIABLE); mpr_tbl_link(t, PROP(USE_INST), 1, MPR_BOOL, &m->use_inst, REMOTE_MODIFY); mpr_tbl_link(t, PROP(VERSION), 1, MPR_INT32, &m->obj.version, REMOTE_MODIFY); - int i, is_local = 0; - if (m->dst->sig->loc) + if (m->dst->sig->is_local) is_local = 1; else { for (i = 0; i < m->num_src; i++) { - if (m->src[i]->sig->loc) { + if (m->src[i]->sig->is_local) { is_local = 1; break; } @@ -102,16 +101,18 @@ void mpr_map_init(mpr_map m) } mpr_tbl_set(t, PROP(IS_LOCAL), NULL, 1, MPR_BOOL, &is_local, LOCAL_ACCESS_ONLY | NON_MODIFIABLE); - for (i = 0; i < m->num_src; i++) - mpr_slot_init(m->src[i]); - mpr_slot_init(m->dst); } mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst) { - RETURN_UNLESS(src && *src && dst && *dst, 0); - RETURN_UNLESS(num_src > 0 && num_src <= MAX_NUM_MAP_SRC, 0); - int i, j; + mpr_graph g; + mpr_map m; + mpr_obj o; + mpr_list maps; + unsigned char i, j, is_local = 0, order[MAX_NUM_MAP_SRC]; + + RETURN_ARG_UNLESS(src && *src && dst && *dst, 0); + RETURN_ARG_UNLESS(num_src > 0 && num_src <= MAX_NUM_MAP_SRC, 0); for (i = 0; i < num_src; i++) { for (j = 0; j < num_dst; j++) { if ( strcmp(src[i]->name, dst[j]->name)==0 @@ -121,20 +122,19 @@ mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst) return 0; } } + is_local += src[i]->is_local; } - // Only 1 destination supported for now - RETURN_UNLESS(1 == num_dst, 0); - mpr_graph g = (*dst)->obj.graph; + /* Only 1 destination supported for now */ + RETURN_ARG_UNLESS(1 == num_dst, 0); + g = (*dst)->obj.graph; - // check if record of map already exists - mpr_map m; - mpr_obj o; - mpr_list temp, maps = mpr_sig_get_maps(*dst, MPR_DIR_IN); + /* check if record of map already exists */ + maps = mpr_sig_get_maps(*dst, MPR_DIR_IN); if (maps) { for (i = 0; i < num_src; i++) { o = mpr_graph_get_obj(g, MPR_SIG, src[i]->obj.id); if (o) { - temp = mpr_sig_get_maps((mpr_sig)o, MPR_DIR_OUT); + mpr_list temp = mpr_sig_get_maps((mpr_sig)o, MPR_DIR_OUT); maps = mpr_list_get_isect(maps, temp); } else { @@ -153,22 +153,25 @@ mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst) } } - int order[num_src]; if (_sort_sigs(num_src, src, order)) { trace("error in mpr_map_new(): multiple use of source signal.\n"); return 0; } + if ((*dst)->is_local) + is_local = 1; - m = (mpr_map)mpr_list_add_item((void**)&g->maps, sizeof(mpr_map_t)); + m = (mpr_map)mpr_list_add_item((void**)&g->maps, + is_local ? sizeof(mpr_local_map_t) : sizeof(mpr_map_t)); m->obj.type = MPR_MAP; m->obj.graph = g; m->num_src = num_src; + m->is_local = 0; m->src = (mpr_slot*)malloc(sizeof(mpr_slot) * num_src); for (i = 0; i < num_src; i++) { - m->src[i] = mpr_slot_new(m, NULL, 1); if (src[order[i]]->dev->obj.graph == g) o = (mpr_obj)src[order[i]]; else if (!(o = mpr_graph_get_obj(g, MPR_SIG, src[order[i]]->obj.id))) { + mpr_dev dev; o = (mpr_obj)mpr_graph_add_sig(g, src[order[i]]->name, src[order[i]]->dev->name, 0); if (!o->id) { o->id = src[order[i]]->obj.id; @@ -176,18 +179,18 @@ mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst) ((mpr_sig)o)->len = src[order[i]]->len; ((mpr_sig)o)->type = src[order[i]]->type; } - mpr_dev d = ((mpr_sig)o)->dev; - if (!d->obj.id) - d->obj.id = src[order[i]]->dev->obj.id; + dev = ((mpr_sig)o)->dev; + if (!dev->obj.id) + dev->obj.id = src[order[i]]->dev->obj.id; } - m->src[i]->sig = (mpr_sig)o; - m->src[i]->obj.id = i; + m->src[i] = mpr_slot_new(m, (mpr_sig)o, is_local, 1); + m->src[i]->id = i; } - m->dst = mpr_slot_new(m, *dst, 0); + m->dst = mpr_slot_new(m, *dst, is_local, 0); m->dst->dir = MPR_DIR_IN; - // we need to give the map a temporary id – this may be overwritten later - if ((*dst)->dev->loc) + /* we need to give the map a temporary id – this may be overwritten later */ + if ((*dst)->dev->is_local) m->obj.id = mpr_dev_generate_unique_id((*dst)->dev); mpr_map_init(m); @@ -207,23 +210,19 @@ void mpr_map_refresh(mpr_map m) { RETURN_UNLESS(m); mpr_net_use_bus(&m->obj.graph->net); - mpr_map_send_state(m, -1, m->loc ? MSG_MAP_TO : MSG_MAP); + mpr_map_send_state(m, -1, m->is_local ? MSG_MAP_TO : MSG_MAP); } void mpr_map_free(mpr_map m) { int i; if (m->src) { - for (i = 0; i < m->num_src; i++) { + for (i = 0; i < m->num_src; i++) mpr_slot_free(m->src[i]); - free(m->src[i]); - } free(m->src); } - if (m->dst) { + if (m->dst) mpr_slot_free(m->dst); - free(m->dst); - } if (m->num_scopes && m->scopes) free(m->scopes); FUNC_IF(mpr_tbl_free, m->obj.props.synced); @@ -234,7 +233,7 @@ void mpr_map_free(mpr_map m) static int _cmp_qry_sigs(const void *ctx, mpr_sig s) { mpr_map m = *(mpr_map*)ctx; - mpr_loc l = *(mpr_loc*)(ctx + sizeof(mpr_map*)); + mpr_loc l = *(mpr_loc*)((char*)ctx + sizeof(mpr_map*)); int i; if (l & MPR_LOC_SRC) { for (i = 0; i < m->num_src; i++) { @@ -247,14 +246,15 @@ static int _cmp_qry_sigs(const void *ctx, mpr_sig s) mpr_list mpr_map_get_sigs(mpr_map m, mpr_loc l) { - RETURN_UNLESS(m && m->obj.graph->sigs, 0); - mpr_list qry = mpr_list_new_query((const void**)&m->obj.graph->sigs, _cmp_qry_sigs, "vi", &m, l); + mpr_list qry; + RETURN_ARG_UNLESS(m && m->obj.graph->sigs, 0); + qry = mpr_list_new_query((const void**)&m->obj.graph->sigs, (void*)_cmp_qry_sigs, "vi", &m, l); return mpr_list_start(qry); } mpr_sig mpr_map_get_sig(mpr_map map, int idx, mpr_loc loc) { - RETURN_UNLESS(map && map->obj.graph->sigs, 0); + RETURN_ARG_UNLESS(map && map->obj.graph->sigs, 0); if (loc & MPR_LOC_SRC) { int i; for (i = 0; i < map->num_src; i++, idx--) { @@ -286,14 +286,18 @@ int mpr_map_get_is_ready(mpr_map m) * change with device name arguments and send to the distrubuted graph. */ void mpr_map_add_scope(mpr_map m, mpr_dev d) { - RETURN_UNLESS(m); + int i; mpr_prop p = PROP(SCOPE) | PROP_ADD; - mpr_tbl_record r = mpr_tbl_get(m->obj.props.staged, p, NULL); + mpr_tbl_record r; + const char **names; + + RETURN_UNLESS(m); + r = mpr_tbl_get(m->obj.props.staged, p, NULL); if (r && MPR_STR == r->type) { - const char *names[r->len+1]; + names = alloca((r->len + 1) * sizeof(char*)); if (1 == r->len) names[0] = (const char*)r->val; - for (int i = 0; i < r->len; i++) + for (i = 0; i < r->len; i++) names[i] = ((const char**)r->val)[i]; names[r->len] = d ? d->name : "all"; mpr_tbl_set(m->obj.props.staged, p, NULL, r->len + 1, MPR_STR, names, REMOTE_MODIFY); @@ -306,12 +310,16 @@ void mpr_map_add_scope(mpr_map m, mpr_dev d) * change with device name arguments and send to the distrubuted graph. */ void mpr_map_remove_scope(mpr_map m, mpr_dev d) { - RETURN_UNLESS(m && d); mpr_prop p = PROP(SCOPE) | PROP_REMOVE; - mpr_tbl t = m->obj.props.staged; - mpr_tbl_record r = mpr_tbl_get(t, p, NULL); + mpr_tbl t; + mpr_tbl_record r; + const char **names; + + RETURN_UNLESS(m && d); + t = m->obj.props.staged; + r = mpr_tbl_get(t, p, NULL); if (r && MPR_STR == r->type) { - const char *names[r->len]; + names = alloca(r->len * sizeof(char*)); if (1 == r->len) { if (0 == strcmp((const char*)r->val, d->name)) mpr_tbl_remove(t, p, NULL, REMOTE_MODIFY); @@ -332,9 +340,9 @@ void mpr_map_remove_scope(mpr_map m, mpr_dev d) static int _add_scope(mpr_map m, const char *name) { - RETURN_UNLESS(m && name, 0); int i; mpr_dev d = 0; + RETURN_ARG_UNLESS(m && name, 0); if (strcmp(name, "all")==0) { for (i = 0; i < m->num_scopes; i++) { @@ -350,7 +358,7 @@ static int _add_scope(mpr_map m, const char *name) } } - // not found - add a new scope + /* not found - add a new scope */ i = ++m->num_scopes; m->scopes = realloc(m->scopes, i * sizeof(mpr_dev)); m->scopes[i-1] = d; @@ -359,8 +367,8 @@ static int _add_scope(mpr_map m, const char *name) static int _remove_scope(mpr_map m, const char *name) { - RETURN_UNLESS(m && name, 0); int i; + RETURN_ARG_UNLESS(m && name, 0); if (strcmp(name, "all")==0) name = 0; for (i = 0; i < m->num_scopes; i++) { @@ -373,7 +381,7 @@ static int _remove_scope(mpr_map m, const char *name) } if (i == m->num_scopes) return 0; - // found - remove scope at index i + /* found - remove scope at index i */ for (++i; i < m->num_scopes - 1; i++) m->scopes[i] = m->scopes[i + 1]; --m->num_scopes; @@ -386,11 +394,11 @@ static int _update_scope(mpr_map m, mpr_msg_atom a) int i = 0, j, updated = 0, num = a->len; lo_arg **scope_list = a->vals; if (scope_list && *scope_list) { + const char *name; if (1 == num && strcmp(&scope_list[0]->s, "none")==0) num = 0; - const char *name; - // First remove old scopes that are missing + /* First remove old scopes that are missing */ while (i < m->num_scopes) { int found = 0; for (j = 0; j < num; j++) { @@ -412,42 +420,261 @@ static int _update_scope(mpr_map m, mpr_msg_atom a) else ++i; } - // ...then add any new scopes + /* ...then add any new scopes */ for (i = 0; i < num; i++) updated += _add_scope(m, &scope_list[i]->s); } return updated; } -// only called for outgoing maps -int mpr_map_perform(mpr_map m, mpr_type *types, mpr_time *time, int inst_idx) +/* 1) update all signals for this timestep, mark signal instances as "updated" + * 1b) call rtr_process_sig (immediately?) to update slots. + * 1c) need to allow for users modifying sigs, maps, etc after updating sig and before processing + * 2) iterate through all the maps and process, mark map instances as "updated" + * 2b) if instance of a map has already been updated don't bother doing it again + * 3) can bundle map output during iteration + * + * Plan of change: + * 1) move idmaps to maps + * 2) on release of local instance, can reuse instance resource and mark idmap as "to release" + * 3) map should iterate through active idmaps instead of instances + * 4) when it comes to "to release" idmap, send release and decref LID + */ + +/* only called for outgoing maps */ +void mpr_map_send(mpr_local_map m, mpr_time time) { - int i; + int i, j, status, map_manages_inst = 0; + lo_message msg; + mpr_local_dev dev; + uint8_t bundle_idx; + mpr_local_slot src_slot, dst_slot; + mpr_local_sig src_sig; + struct _mpr_sig_idmap *idmaps; + mpr_id_map idmap = 0; + mpr_value *src_vals; + char *types; + + RETURN_UNLESS(m->updated && m->expr && MPR_DIR_OUT == m->src[0]->dir && !m->muted); + + dev = m->rtr->dev; + bundle_idx = dev->bundle_idx % NUM_BUNDLES; + + /* temporary solution: use most multitudinous source signal for idmap + * permanent solution: move idmaps to map? */ + src_slot = m->src[0]; + for (i = 1; i < m->num_src; i++) { + if (m->src[i]->sig->num_inst > src_slot->sig->num_inst) + src_slot = m->src[i]; + } + src_sig = (mpr_local_sig)src_slot->sig; + idmaps = src_sig->idmaps; - RETURN_UNLESS(MPR_STATUS_ACTIVE == m->status && !m->muted, 0); + src_vals = alloca(m->num_src * sizeof(mpr_value)); + for (i = 0; i < m->num_src; i++) + src_vals[i] = &m->src[i]->val; + dst_slot = m->dst; - if (!m->loc->expr) { - trace("error: missing expression.\n"); - return 0; + if (m->use_inst && !src_sig->use_inst) { + map_manages_inst = 1; + idmap = m->idmap; } - mpr_value src[m->num_src]; + types = alloca(dst_slot->sig->len * sizeof(char)); + + for (i = 0; i < m->num_inst; i++) { + if (!get_bitflag(m->updated_inst, i)) + continue; + status = mpr_expr_eval(m->expr, src_vals, &m->vars, &dst_slot->val, &time, types, i); + if (!status) + continue; + + if (src_sig->use_inst && !map_manages_inst) { + /* finding idmaps here will be a bit inefficient for now */ + /* TODO: optimize storage and lookup */ + for (j = 0; j < src_sig->idmap_len; j++) { + if (idmaps[j].inst && idmaps[j].inst->idx == i) { + idmap = idmaps[j].map; + break; + } + } + if (j == src_sig->idmap_len) { + trace("error: couldn't find idmap for signal instance idx %d\n", i); + continue; + } + } + + /* send instance release if dst is instanced and either src or map is also instanced. */ + if (idmap && status & EXPR_RELEASE_BEFORE_UPDATE && m->use_inst) { + msg = mpr_map_build_msg(m, 0, 0, 0, idmap); + mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, time, m->protocol, bundle_idx); + if (map_manages_inst) { + mpr_dev_LID_decref(dev, 0, idmap); + idmap = m->idmap = 0; + } + } + if (status & EXPR_UPDATE) { + /* send instance update */ + void *result = mpr_value_get_samp(&dst_slot->val, i); + if (map_manages_inst && !idmap) { + /* create an id_map and store it in the map */ + idmap = m->idmap = mpr_dev_add_idmap(dev, 0, 0, 0); + } + msg = mpr_map_build_msg(m, src_slot, result, types, idmap); + mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, + *(mpr_time*)mpr_value_get_time(&dst_slot->val, i), + m->protocol, bundle_idx); + } + /* send instance release if dst is instanced and either src or map is also instanced. */ + if (idmap && status & EXPR_RELEASE_AFTER_UPDATE && m->use_inst) { + msg = mpr_map_build_msg(m, 0, 0, 0, idmap); + mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, time, m->protocol, bundle_idx); + if (map_manages_inst) { + mpr_dev_LID_decref(dev, 0, idmap); + idmap = m->idmap = 0; + } + } + if ((status & EXPR_EVAL_DONE) && !m->use_inst) + break; + } + clear_bitflags(m->updated_inst, m->num_inst); + m->updated = 0; +} + +/* only called for incoming maps */ +/* TODO: merge with mpr_map_send()? */ +void mpr_map_receive(mpr_local_map m, mpr_time time) +{ + int i, j, status, type_size, map_manages_inst = 0; + mpr_local_slot src_slot, dst_slot; + mpr_sig src_sig; + mpr_local_sig dst_sig; + mpr_value src_vals[MAX_NUM_MAP_SRC]; + struct _mpr_sig_idmap *idmaps; + mpr_id_map idmap = 0; + char *types; + + /* temporary solution: use most multitudinous source signal for idmap + * permanent solution: move idmaps to map */ + src_slot = m->src[0]; + for (i = 1; i < m->num_src; i++) { + if (m->src[i]->sig->num_inst > src_slot->sig->num_inst) + src_slot = m->src[i]; + } + src_sig = src_slot->sig; + for (i = 0; i < m->num_src; i++) - src[i] = &m->src[i]->loc->val; - return (mpr_expr_eval(m->loc->expr, src, &m->loc->vars, &m->dst->loc->val, - time, types, inst_idx)); + src_vals[i] = &m->src[i]->val; + dst_slot = m->dst; + dst_sig = (mpr_local_sig)dst_slot->sig; + idmaps = dst_sig->idmaps; + type_size = mpr_type_get_size(dst_sig->type); + + if (!src_sig->use_inst) { + if (mpr_expr_get_manages_inst(m->expr)) { + map_manages_inst = 1; + idmap = m->idmap; + } + else + idmap = 0; + } + types = alloca(dst_sig->len * sizeof(char)); + + for (i = 0; i < m->num_inst; i++) { + mpr_sig_inst si; + float diff; + + if (!get_bitflag(m->updated_inst, i)) + continue; + status = mpr_expr_eval(m->expr, src_vals, &m->vars, &dst_slot->val, &time, types, i); + if (!status) + continue; + + j = 0; + if (dst_sig->use_inst && !map_manages_inst) { + /* finding idmaps here will be a bit inefficient for now */ + /* TODO: optimize storage and lookup */ + for (j = 0; j < dst_sig->idmap_len; j++) { + if (idmaps[j].inst && idmaps[j].inst->idx == i) { + idmap = idmaps[j].map; + break; + } + } + if (j == dst_sig->idmap_len) { + trace("error: couldn't find idmap for signal instance idx %d\n", i); + continue; + } + } + else { + + } + si = idmaps[j].inst; + diff = mpr_time_get_diff(time, si->time); + + if (status & EXPR_RELEASE_BEFORE_UPDATE) { + /* TODO: release map-tracked instance */ + /* Try to release instance, but do not call mpr_rtr_process_sig() here, since we don't + * know if the local signal instance will actually be released. */ + int evt = MPR_SIG_REL_UPSTRM & dst_sig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE; + mpr_sig_call_handler(dst_sig, evt, idmap ? idmap->LID : 0, 0, 0, &time, diff); + } + + if (status & EXPR_UPDATE) { + void *result = mpr_value_get_samp(&dst_slot->val, i); + /* TODO: create new map->idmap */ +/* + if (map_manages_inst) { + if (!idmap) { + // create an id_map and store it in the map + idmap = map->idmap = mpr_dev_add_idmap(sig->dev, sig->group, 0, 0); + } + } + */ + + /* copy to signal value */ + memcpy(si->val, result, type_size); + memcpy(&si->time, &time, sizeof(mpr_time)); + si->has_val = 1; + + mpr_sig_call_handler(dst_sig, MPR_SIG_UPDATE, idmap ? idmap->LID : 0, + dst_sig->len, si->val, &time, diff); + /* Pass this update downstream if signal is an input and was not updated in handler. */ + if ( !(dst_sig->dir & MPR_DIR_OUT) + && !get_bitflag(dst_sig->updated_inst, si->idx)) { + /* mark instance as updated */ + set_bitflag(dst_sig->updated_inst, si->idx); + ((mpr_local_dev)dst_sig->dev)->sending = dst_sig->updated = 1; + mpr_rtr_process_sig(m->rtr, dst_sig, i, si->val, time); + } + } + + if (status & EXPR_RELEASE_AFTER_UPDATE) { + /* TODO: release map-tracked instance */ + /* Try to release instance, but do not call mpr_rtr_process_sig() here, since we don't + * know if the local signal instance will actually be released. */ + int evt = MPR_SIG_REL_UPSTRM & dst_sig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE; + mpr_sig_call_handler(dst_sig, evt, idmap ? idmap->LID : 0, 0, 0, &time, diff); + } + + /* TODO: break if map performs instance reduce */ + } + clear_bitflags(m->updated_inst, m->num_inst); + m->updated = 0; } /*! Build a value update message for a given map. */ -lo_message mpr_map_build_msg(mpr_map m, mpr_slot slot, const void *val, +lo_message mpr_map_build_msg(mpr_local_map m, mpr_local_slot slot, const void *val, mpr_type *types, mpr_id_map idmap) { - int i; - int len = ((MPR_LOC_SRC == m->process_loc) ? m->dst->sig->len : slot->sig->len); + int i, len = 0; NEW_LO_MSG(msg, return 0); + if (MPR_LOC_SRC == m->process_loc) + len = m->dst->sig->len; + else if (slot) + len = slot->sig->len; if (val && types) { - // value of vector elements can be or NULL + /* value of vector elements can be or NULL */ for (i = 0; i < len; i++) { switch (types[i]) { case MPR_INT32: lo_message_add_int32(msg, ((int*)val)[i]); break; @@ -466,31 +693,33 @@ lo_message mpr_map_build_msg(mpr_map m, mpr_slot slot, const void *val, lo_message_add_string(msg, "@in"); lo_message_add_int64(msg, idmap->GID); } - if (MPR_LOC_DST == m->process_loc && MPR_DIR_OUT == m->dst->dir) { - // add slot + if (slot) { + /* add slot */ lo_message_add_string(msg, "@sl"); - lo_message_add_int32(msg, slot->obj.id); + lo_message_add_int32(msg, slot->id); } return msg; } -void mpr_map_alloc_values(mpr_map m) +void mpr_map_alloc_values(mpr_local_map m) { - // If there is no expression or the processing is remote, then no memory needs to be (re)allocated. - RETURN_UNLESS(m->loc->expr - && (m->loc->is_local_only + /* TODO: check if this filters non-local processing. + * if so we can eliminate process_loc tests below + * if not we are allocating variable memory when we don't need to */ + int i, j, hist_size, num_inst = 0, num_vars; + mpr_expr e = m->expr; + mpr_value_t *vars; + const char **var_names; + + /* If there is no expression or the processing is remote, + * then no memory needs to be (re)allocated. */ + RETURN_UNLESS(m->expr + && (m->is_local_only || !((MPR_DIR_OUT == m->dst->dir) ^ (MPR_LOC_SRC == m->process_loc)))); - // TODO: check if this filters non-local processing. - // if so we can eliminate process_loc tests below - // if not we are allocating variable memory when we don't need to + /* HANDLE edge case: if the map is local, then src->dir is OUT and dst->dir is IN */ - int i, j, hist_size, num_inst = 0; - mpr_expr e = m->loc->expr; - - // HANDLE edge case: if the map is local, then src->dir is OUT and dst->dir is IN - - // check if slot values need to be reallocated + /* check if slot values need to be reallocated */ if (MPR_DIR_OUT == m->dst->dir) { int max_num_inst = 0; for (i = 0; i < m->num_src; i++) { @@ -499,12 +728,12 @@ void mpr_map_alloc_values(mpr_map m) mpr_slot_alloc_values(m->src[i], m->src[i]->sig->num_inst, hist_size); } hist_size = mpr_expr_get_out_hist_size(e); - // allocate enough dst slot and variable instances for the most multitudinous source signal + /* allocate enough dst slot and variable instances for the most multitudinous source signal */ mpr_slot_alloc_values(m->dst, max_num_inst, hist_size); num_inst = max_num_inst; } else if (MPR_DIR_IN == m->dst->dir) { - // allocate enough instances for destination signal + /* allocate enough instances for destination signal */ for (i = 0; i < m->num_src; i++) { hist_size = mpr_expr_get_in_hist_size(e, i); mpr_slot_alloc_values(m->src[i], m->dst->sig->num_inst, hist_size); @@ -514,81 +743,87 @@ void mpr_map_alloc_values(mpr_map m) num_inst = m->dst->sig->num_inst; } - mpr_local_map lm = m->loc; - int num_vars = mpr_expr_get_num_vars(e); + num_vars = mpr_expr_get_num_vars(e); - // TODO: only need to allocate this memory for processing location - mpr_value_t *vars = calloc(1, sizeof(mpr_value_t) * num_vars); - const char **var_names = malloc(sizeof(char*) * num_vars); + /* TODO: only need to allocate this memory for processing location */ + vars = calloc(1, sizeof(mpr_value_t) * num_vars); + var_names = malloc(sizeof(char*) * num_vars); for (i = 0; i < num_vars; i++) { - var_names[i] = strdup(mpr_expr_get_var_name(e, i)); int vlen = mpr_expr_get_var_vec_len(e, i); - // check if var already exists - for (j = 0; j < lm->num_vars; j++) { - if (!lm->var_names[j] || strcmp(lm->var_names[j], var_names[i])) + var_names[i] = strdup(mpr_expr_get_var_name(e, i)); + /* check if var already exists */ + for (j = 0; j < m->num_vars; j++) { + if (!m->var_names[j] || strcmp(m->var_names[j], var_names[i])) continue; - if (lm->vars[i].vlen != vlen) + if (m->vars[i].vlen != vlen) continue; - // match found + /* match found */ break; } - if (j < lm->num_vars) { - // copy old variable memory - memcpy(&vars[i], &lm->vars[j], sizeof(mpr_value_t)); - lm->vars[j].inst = 0; + if (j < m->num_vars) { + /* copy old variable memory */ + memcpy(&vars[i], &m->vars[j], sizeof(mpr_value_t)); + m->vars[j].inst = 0; } - mpr_value_realloc(&vars[i], vlen, MPR_DBL, 1, num_inst, 0); - // set position to 0 since we are not currently allowing history on user variables + mpr_value_realloc(&vars[i], vlen, mpr_expr_get_var_type(e, i), 1, num_inst, 0); + /* set position to 0 since we are not currently allowing history on user variables */ for (j = 0; j < num_inst; j++) vars[i].inst[j].pos = 0; } - // free old variables and replace with new - for (i = 0; i < lm->num_vars; i++) { - mpr_value_free(&lm->vars[i]); - FUNC_IF(free, (void*)lm->var_names[i]); + /* free old variables and replace with new */ + for (i = 0; i < m->num_vars; i++) { + mpr_value_free(&m->vars[i]); + FUNC_IF(free, (void*)m->var_names[i]); } - FUNC_IF(free, lm->vars); - FUNC_IF(free, lm->var_names); + FUNC_IF(free, m->vars); + FUNC_IF(free, m->var_names); + + m->vars = vars; + m->var_names = var_names; + m->num_vars = num_vars; + m->num_inst = num_inst; - lm->vars = vars; - lm->var_names = var_names; - lm->num_vars = num_vars; - lm->num_inst = num_inst; + /* allocate update bitflags */ + if (m->updated_inst) + m->updated_inst = realloc(m->updated_inst, num_inst / 8 + 1); + else + m->updated_inst = calloc(1, num_inst / 8 + 1); } /* Helper to replace a map's expression only if the given string * parses successfully. Returns 0 on success, non-zero on error. */ -static int _replace_expr_str(mpr_map m, const char *expr_str) +static int _replace_expr_str(mpr_local_map m, const char *expr_str) { - if (m->loc->expr && m->expr_str && strcmp(m->expr_str, expr_str)==0) + int i, out_mem, src_lens[MAX_NUM_MAP_SRC]; + char src_types[MAX_NUM_MAP_SRC]; + mpr_expr expr; + if (m->expr && m->expr_str && strcmp(m->expr_str, expr_str)==0) return 1; - int i, src_lens[m->num_src]; - char src_types[m->num_src]; for (i = 0; i < m->num_src; i++) { src_types[i] = m->src[i]->sig->type; src_lens[i] = m->src[i]->sig->len; } - mpr_expr expr = mpr_expr_new_from_str(expr_str, m->num_src, src_types, src_lens, - m->dst->sig->type, m->dst->sig->len); - RETURN_UNLESS(expr, 1); - - // expression update may force processing location to change - // e.g. if expression combines signals from different devices - // e.g. if expression refers to current/past value of destination - int out_mem = mpr_expr_get_out_hist_size(expr); - if (!m->loc->is_local_only && out_mem > 1 && MPR_LOC_SRC == m->process_loc) { + expr = mpr_expr_new_from_str(expr_str, m->num_src, src_types, src_lens, + m->dst->sig->type, m->dst->sig->len); + RETURN_ARG_UNLESS(expr, 1); + + /* expression update may force processing location to change + * e.g. if expression combines signals from different devices + * e.g. if expression refers to current/past value of destination */ + out_mem = mpr_expr_get_out_hist_size(expr); + if (!m->is_local_only && (out_mem > 1 && MPR_LOC_SRC == m->process_loc)) { m->process_loc = MPR_LOC_DST; - if (!m->dst->sig->loc) { - // copy expression string but do not execute it + if (!m->dst->sig->is_local) { + /* copy expression string but do not execute it */ mpr_tbl_set(m->obj.props.synced, PROP(EXPR), NULL, 1, MPR_STR, expr_str, REMOTE_MODIFY); mpr_expr_free(expr); return 1; } } - FUNC_IF(mpr_expr_free, m->loc->expr); - m->loc->expr = expr; + FUNC_IF(mpr_expr_free, m->expr); + m->expr = expr; if (m->expr_str == expr_str) return 0; @@ -597,7 +832,7 @@ static int _replace_expr_str(mpr_map m, const char *expr_str) return 0; } -static inline int _trim_zeros(char *str, int len) +MPR_INLINE static int _trim_zeros(char *str, int len) { if (!strchr(str, '.')) return len; @@ -612,10 +847,11 @@ static inline int _trim_zeros(char *str, int len) static int _snprint_var(const char *varname, char *str, int max_len, int vec_len, mpr_type type, const void *val) { - if (!str || strlen <= 0) - return -1; + int i, str_len, var_len; + RETURN_ARG_UNLESS(str, -1); snprintf(str, max_len, "%s=", varname); - int i, str_len = strlen(str), var_len; + str_len = strlen(str); + if (vec_len > 1) str_len += snprintf(str+str_len, max_len-str_len, "["); switch (type) { @@ -628,14 +864,14 @@ static int _snprint_var(const char *varname, char *str, int max_len, int vec_len break; case MPR_FLT: for (i = 0; i < vec_len; i++) { - var_len = snprintf(str+str_len, max_len-str_len, "%f", ((float*)val)[i]); + var_len = snprintf(str+str_len, max_len-str_len, "%g", ((float*)val)[i]); str_len += _trim_zeros(str+str_len, var_len); str_len += snprintf(str+str_len, max_len-str_len, ","); } break; case MPR_DBL: for (i = 0; i < vec_len; i++) { - var_len = snprintf(str+str_len, max_len-str_len, "%f", ((double*)val)[i]); + var_len = snprintf(str+str_len, max_len-str_len, "%g", ((double*)val)[i]); str_len += _trim_zeros(str+str_len, var_len); str_len += snprintf(str+str_len, max_len-str_len, ","); } @@ -652,95 +888,84 @@ static int _snprint_var(const char *varname, char *str, int max_len, int vec_len } #define INSERT_VAL(VARNAME) \ -mpr_value_t *ev = m->loc->vars; \ -for (j = 0; j < m->loc->num_vars; j++) { \ - if (!mpr_expr_get_var_is_public(m->loc->expr, j)) \ +mpr_value_t *ev = m->vars; \ +for (j = 0; j < m->num_vars; j++) { \ + if (!mpr_expr_get_var_is_public(m->expr, j)) \ continue; \ /* TODO: handle multiple instances */ \ k = 0; \ - if (strcmp(VARNAME, mpr_expr_get_var_name(m->loc->expr, j))) \ + if (strcmp(VARNAME, mpr_expr_get_var_name(m->expr, j))) \ continue; \ if (ev[j].inst[k].pos < 0) { \ trace("expr var '%s' is not yet initialised.\n", VARNAME); \ goto abort; \ } \ - len += snprintf(expr+len, MAX_LEN-len, "%s=", VARNAME); \ - double *v = mpr_value_get_samp(&ev[j], k); \ - if (ev[j].vlen > 1) \ - len += snprintf(expr+len, MAX_LEN-len, "["); \ - for (l = 0; l < ev[j].vlen; l++) { \ - val_len = snprintf(expr+len, MAX_LEN-len, "%f", v[l]); \ - len += _trim_zeros(expr+len, val_len); \ - len += snprintf(expr+len, MAX_LEN-len, ","); \ - } \ - --len; \ - if (ev[j].vlen > 1) \ - len += snprintf(expr+len, MAX_LEN-len, "]"); \ - len += snprintf(expr+len, MAX_LEN-len, ";"); \ + len += _snprint_var(VARNAME, expr+len, MAX_LEN-len, ev[j].vlen, \ + ev[j].type, mpr_value_get_samp(&ev[j], k)); \ break; \ } \ -if (j == m->loc->num_vars) { \ +if (j == m->num_vars) { \ trace("expr var '%s' is not found.\n", VARNAME); \ goto abort; \ } -static const char *_set_linear(mpr_map m, const char *e) +static const char *_set_linear(mpr_local_map m, const char *e) { - // if e is NULL, try to fill in ranges from map signals - int j, k, l, len = 0, val_len; + /* if e is NULL, try to fill in ranges from map signals */ + int i, j, k, len = 0, val_len; char expr[MAX_LEN] = ""; char *var = "x"; int min_len = _min(m->src[0]->sig->len, m->dst->sig->len); if (e) { - // how many instances of 'linear' appear in the expression string? + /* how many instances of 'linear' appear in the expression string? */ int num_inst = 0; char *offset = (char*)e; while ((offset = strstr(offset, "linear"))) { ++num_inst; offset += 6; } - // for now we will only allow one instance of 'linear' function macro + /* for now we will only allow one instance of 'linear' function macro */ if (num_inst != 1) { trace("found %d instances of the string 'linear'\n", num_inst); return NULL; } - // use a copy in case we fail after tokenisation + /* use a copy in case we fail after tokenisation */ e = strdup(e); offset = (char*)e; - // for (i = 0; i < num_inst; i++) { - // TODO: copy sections of expression before 'linear(' + for (i = 0; i < num_inst; i++) { + char* arg_str, *args[5]; + /* TODO: copy sections of expression before 'linear(' */ offset = strstr(offset, "linear") + 6; - // remove any spaces + /* remove any spaces */ while (*offset && *offset == ' ') ++offset; - // next character must be '(' + /* next character must be '(' */ if (*offset != '(') { goto abort; } ++offset; - char* arg_str = strtok(offset, ")"); + arg_str = strtok(offset, ")"); if (!arg_str) { trace("error: no arguments found for 'linear' function\n"); goto abort; } - char *args[5]; for (j = 0; j < 5; j++) { args[j] = strtok(arg_str, ","); arg_str = NULL; if (!args[j]) goto abort; } - // we won't check if ranges are numeric since they could be variables - // but src extrema are allowed to be "?" to indicate calibration - // or '-' to indicate they should not be changed + /* we won't check if ranges are numeric since they could be variables but src extrema + * are allowed to be "?" to indicate calibration or '-' to indicate they should not + * be changed */ if (0 == strcmp(args[1], "?")) len = snprintf(expr, MAX_LEN, "sMin{-1}=x;sMin=min(%s,sMin);", var); else if (0 == strcmp(args[1], "-")) { - // try to load sMin variable from existing expression - if (!m->loc || !m->loc->expr) { - trace("can't retrieve previous expr var since map is not local\n"); + /* try to load sMin variable from existing expression */ + if (!m->expr) { + trace("can't retrieve previous expr variable\n"); len += snprintf(expr+len, MAX_LEN-len, "sMin=0;"); } else { @@ -756,11 +981,11 @@ static const char *_set_linear(mpr_map m, const char *e) if (0 == strcmp(args[2], "?")) len += snprintf(expr+len, MAX_LEN-len, "sMax{-1}=x;sMax=max(%s,sMax);", var); else if (0 == strcmp(args[2], "-")) { - // try to load sMax variable from existing expression - if (!m->loc || !m->loc->expr) { - // TODO: try using signal instead + /* try to load sMax variable from existing expression */ + if (!m->expr) { + /* TODO: try using signal instead */ trace("can't retrieve previous expr var, using default\n"); - // TODO: test with vector signals + /* TODO: test with vector signals */ len += snprintf(expr+len, MAX_LEN-len, "sMax=1;"); } else { @@ -774,9 +999,9 @@ static const char *_set_linear(mpr_map m, const char *e) } if (0 == strcmp(args[3], "-")) { - // try to load dMin variable from existing expression - if (!m->loc || !m->loc->expr) { - trace("can't retrieve previous expr var since map is not local\n"); + /* try to load dMin variable from existing expression */ + if (!m->expr) { + trace("can't retrieve previous expr variable\n"); len += snprintf(expr+len, MAX_LEN-len, "dMin=0;"); } else { @@ -790,9 +1015,9 @@ static const char *_set_linear(mpr_map m, const char *e) } if (0 == strcmp(args[4], "-")) { - // try to load dMin variable from existing expression - if (!m->loc || !m->loc->expr) { - trace("can't retrieve previous expr var since map is not local\n"); + /* try to load dMin variable from existing expression */ + if (!m->expr) { + trace("can't retrieve previous expr variable\n"); len += snprintf(expr+len, MAX_LEN-len, "dMax=1;"); } else { @@ -806,8 +1031,8 @@ static const char *_set_linear(mpr_map m, const char *e) } var = args[0]; - // TODO: copy sections of expression after closing paren ')' - // } + /* TODO: copy sections of expression after closing paren ')' */ + } } else if (m->src[0]->sig->min && m->src[0]->sig->max && m->dst->sig->min && m->dst->sig->max) { len = _snprint_var("sMin", expr, MAX_LEN, min_len, m->src[0]->sig->type, @@ -820,34 +1045,33 @@ static const char *_set_linear(mpr_map m, const char *e) m->dst->sig->type, m->dst->sig->max); } else { - // try linear combination of inputs + /* try linear combination of inputs */ if (1 == m->num_src) { if (m->src[0]->sig->len == m->dst->sig->len) snprintf(expr, MAX_LEN, "y=x"); else if (m->src[0]->sig->len > m->dst->sig->len) { - // truncate source + /* truncate source */ if (1 == m->dst->sig->len) snprintf(expr, MAX_LEN, "y=x[0]"); else snprintf(expr, MAX_LEN, "y=x[0:%i]", m->dst->sig->len-1); } else if (1 == m->src[0]->sig->len) { - // truncate dst + /* truncate dst */ snprintf(expr, MAX_LEN, "y[0]=x"); } else snprintf(expr, MAX_LEN, "y[0:%i]=x", m->src[0]->sig->len-1); } else { - // check vector lengths - int i, j, max_vec_len = 0, min_vec_len = INT_MAX; + /* check vector lengths */ + int i, j, max_vec_len = 0, min_vec_len = INT_MAX, dst_vec_len; for (i = 0; i < m->num_src; i++) { if (m->src[i]->sig->len > max_vec_len) max_vec_len = m->src[i]->sig->len; if (m->src[i]->sig->len < min_vec_len) min_vec_len = m->src[i]->sig->len; } - int dst_vec_len; if (max_vec_len < m->dst->sig->len) { if (1 == max_vec_len) len = snprintf(expr, MAX_LEN, "y[0]=("); @@ -864,8 +1088,7 @@ static const char *_set_linear(mpr_map m, const char *e) if (1 == dst_vec_len) len += snprintf(expr+len, MAX_LEN-len, "x%d[0]+", i); else - len += snprintf(expr+len, MAX_LEN-len, "x%d[0:%d]+", - i, dst_vec_len-1); + len += snprintf(expr+len, MAX_LEN-len, "x%d[0:%d]+", i, dst_vec_len-1); } else if (m->src[i]->sig->len < dst_vec_len) { len += snprintf(expr+len, MAX_LEN-len, "[x%d,0", i); @@ -912,25 +1135,25 @@ static const char *_set_linear(mpr_map m, const char *e) return NULL; } -static int _set_expr(mpr_map m, const char *expr) +static int _set_expr(mpr_local_map m, const char *expr) { - RETURN_UNLESS(m->loc && m->num_src > 0, 0); + int i, should_compile = 0; + const char *new_expr = 0; + RETURN_ARG_UNLESS(m->num_src > 0, 0); if (m->idmap) - mpr_dev_LID_decref(m->loc->rtr->dev, 0, m->idmap); + mpr_dev_LID_decref(m->rtr->dev, 0, m->idmap); - int i, should_compile = 0; - const char *new_expr = 0; - if (m->loc->is_local_only) + if (m->is_local_only) should_compile = 1; else if (MPR_LOC_DST == m->process_loc) { - // check if destination is local - if (m->dst->loc->rsig) + /* check if destination is local */ + if (m->dst->rsig) should_compile = 1; } else { for (i = 0; i < m->num_src; i++) { - if (m->src[i]->loc->rsig) + if (m->src[i]->rsig) should_compile = 1; } } @@ -942,20 +1165,21 @@ static int _set_expr(mpr_map m, const char *expr) } if (!expr || strstr(expr, "linear")) expr = new_expr = _set_linear(m, expr); - RETURN_UNLESS(expr, 1); + RETURN_ARG_UNLESS(expr, 1); if (!_replace_expr_str(m, expr)) { - mpr_map_alloc_values(m); - // evaluate expression to intialise literals mpr_time now; + char *types = alloca(m->dst->sig->len * sizeof(char)); + mpr_map_alloc_values(m); + /* evaluate expression to intialise literals */ mpr_time_set(&now, MPR_NOW); - for (i = 0; i < m->loc->num_inst; i++) - mpr_expr_eval(m->loc->expr, 0, &m->loc->vars, &m->dst->loc->val, &now, 0, i); + for (i = 0; i < m->num_inst; i++) + mpr_expr_eval(m->expr, 0, &m->vars, &m->dst->val, &now, types, i); } else { - if (!m->loc->expr && ( (MPR_LOC_DST == m->process_loc && m->dst->sig->loc) - || (MPR_LOC_SRC == m->process_loc && m->src[0]->sig->loc))) { - // no previous expression, abort map + if (!m->expr && ( (MPR_LOC_DST == m->process_loc && m->dst->sig->is_local) + || (MPR_LOC_SRC == m->process_loc && m->src[0]->sig->is_local))) { + /* no previous expression, abort map */ m->status = MPR_STATUS_EXPIRED; } goto done; @@ -964,64 +1188,63 @@ static int _set_expr(mpr_map m, const char *expr) /* Special case: if we are the receiver and the new expression evaluates to * a constant we can update immediately. */ /* TODO: should call handler for all instances updated through this map. */ - if (mpr_expr_get_num_input_slots(m->loc->expr) <= 0 && !m->use_inst && m->dst->sig->loc) { + if (mpr_expr_get_num_input_slots(m->expr) <= 0 && !m->use_inst && m->dst->sig->is_local) { + /* call handler if it exists */ + mpr_sig sig = m->dst->sig; + mpr_sig_handler *h = (mpr_sig_handler *)((mpr_local_sig)sig)->handler; mpr_time now; mpr_time_set(&now, MPR_NOW); - - // call handler if it exists - mpr_sig sig = m->dst->sig; - mpr_sig_handler *h = sig->loc->handler; if (h) - h(sig, MPR_SIG_UPDATE, 0, sig->len, sig->type, &m->dst->loc->val.inst[0].samps, now); + h(sig, MPR_SIG_UPDATE, 0, sig->len, sig->type, &m->dst->val.inst[0].samps, now); } - // check whether each source slot causes computation + /* check whether each source slot causes computation */ for (i = 0; i < m->num_src; i++) - m->src[i]->causes_update = !mpr_expr_get_src_is_muted(m->loc->expr, i); + m->src[i]->causes_update = !mpr_expr_get_src_is_muted(m->expr, i); done: if (new_expr) free((char*)new_expr); return 0; } -static void _check_status(mpr_map m) +static void _check_status(mpr_local_map m) { + int i, mask = ~METADATA_OK; RETURN_UNLESS(!bitmatch(m->status, MPR_STATUS_READY)); m->status |= METADATA_OK; - int i, mask = ~METADATA_OK; if (m->dst->sig->len) - m->dst->loc->status |= MPR_STATUS_LENGTH_KNOWN; + m->dst->status |= MPR_STATUS_LENGTH_KNOWN; if (m->dst->sig->type) - m->dst->loc->status |= MPR_STATUS_TYPE_KNOWN; - if (m->dst->loc->rsig || (m->dst->link && m->dst->link->addr.udp)) - m->dst->loc->status |= MPR_STATUS_LINK_KNOWN; - m->status &= (m->dst->loc->status | mask); + m->dst->status |= MPR_STATUS_TYPE_KNOWN; + if (m->dst->rsig || (m->dst->link && m->dst->link->addr.udp)) + m->dst->status |= MPR_STATUS_LINK_KNOWN; + m->status &= (m->dst->status | mask); for (i = 0; i < m->num_src; i++) { if (m->src[i]->sig->len) - m->src[i]->loc->status |= MPR_STATUS_LENGTH_KNOWN; + m->src[i]->status |= MPR_STATUS_LENGTH_KNOWN; if (m->src[i]->sig->type) - m->src[i]->loc->status |= MPR_STATUS_TYPE_KNOWN; - if (m->src[i]->loc->rsig || (m->src[i]->link && m->src[i]->link->addr.udp)) - m->src[i]->loc->status |= MPR_STATUS_LINK_KNOWN; - m->status &= (m->src[i]->loc->status | mask); + m->src[i]->status |= MPR_STATUS_TYPE_KNOWN; + if (m->src[i]->rsig || (m->src[i]->link && m->src[i]->link->addr.udp)) + m->src[i]->status |= MPR_STATUS_LINK_KNOWN; + m->status &= (m->src[i]->status | mask); } if ((m->status & METADATA_OK) == METADATA_OK) { trace("map metadata OK\n"); mpr_map_alloc_values(m); m->status = MPR_STATUS_READY; - // update in/out counts for link - if (m->loc->is_local_only) { + /* update in/out counts for link */ + if (m->is_local_only) { if (m->dst->link) ++m->dst->link->num_maps[0]; } else { + mpr_link last = 0, link; if (m->dst->link) { ++m->dst->link->num_maps[0]; m->dst->link->obj.props.synced->dirty = 1; } - mpr_link last = 0, link; for (i = 0; i < m->num_src; i++) { link = m->src[i]->link; if (link && link != last) { @@ -1036,7 +1259,7 @@ static void _check_status(mpr_map m) return; } -// if 'override' flag is not set, only remote properties can be set +/* if 'override' flag is not set, only remote properties can be set */ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) { int i, j, updated = 0, should_compile = 0; @@ -1046,32 +1269,20 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) goto done; if (MPR_DIR_OUT == m->dst->dir) { - // check if MPR_PROP_SLOT property is defined + /* check if MPR_PROP_SLOT property is defined */ a = mpr_msg_get_prop(msg, PROP(SLOT)); if (a && a->len == m->num_src) { - mpr_tbl_record rec; for (i = 0; i < m->num_src; i++) { int id = (a->vals[i])->i32; - m->src[i]->obj.id = id; - // also need to correct slot table indices - tbl = m->src[i]->obj.props.synced; - for (j = 0; j < tbl->count; j++) { - rec = &tbl->rec[j]; - rec->prop = MASK_PROP_BITFLAGS(rec->prop) | SRC_SLOT_PROP(id); - } - tbl = m->src[i]->obj.props.staged; - for (j = 0; j < tbl->count; j++) { - rec = &tbl->rec[j]; - rec->prop = MASK_PROP_BITFLAGS(rec->prop) | SRC_SLOT_PROP(id); - } + m->src[i]->id = id; } } } - // set destination slot properties + /* set destination slot properties */ updated += mpr_slot_set_from_msg(m->dst, msg); - // set source slot properties + /* set source slot properties */ for (i = 0; i < m->num_src; i++) updated += mpr_slot_set_from_msg(m->src[i], msg); @@ -1081,53 +1292,55 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) switch (MASK_PROP_BITFLAGS(a->prop)) { case PROP(NUM_SIGS_IN): case PROP(NUM_SIGS_OUT): - // these properties will be set by signal args + /* these properties will be set by signal args */ break; case PROP(STATUS): - if (m->loc) + if (m->is_local) break; updated += mpr_tbl_set_from_atom(tbl, a, REMOTE_MODIFY); break; case PROP(PROCESS_LOC): { - if (m->loc && m->loc->is_local_only) + mpr_loc loc; + if (m->is_local && ((mpr_local_map)m)->is_local_only) break; - mpr_loc loc = mpr_loc_from_str(&(a->vals[0])->s); + loc = mpr_loc_from_str(&(a->vals[0])->s); if (loc == m->process_loc) break; if (MPR_LOC_UNDEFINED == loc) { trace("map process location is undefined!\n"); break; } - if (m->loc) { + if (m->is_local) { + mpr_local_map lm = (mpr_local_map)m; if (MPR_LOC_ANY == loc) { - // no effect + /* no effect */ break; } - if (!m->loc->one_src) { + if (!lm->one_src) { /* Processing must take place at destination if map * includes source signals from different devices. */ loc = MPR_LOC_DST; } if (MPR_LOC_DST == loc) { - // check if destination is local - if (m->dst->loc->rsig) + /* check if destination is local */ + if (lm->dst->rsig) should_compile = 1; } else { for (j = 0; j < m->num_src; j++) { - if (m->src[j]->loc->rsig) + if (lm->src[j]->rsig) should_compile = 1; } } if (should_compile) { - if (_set_expr(m, m->expr_str)) { - // do not change process location + if (_set_expr(lm, m->expr_str)) { + /* do not change process location */ break; } ++updated; } updated += mpr_tbl_set(tbl, PROP(PROCESS_LOC), NULL, 1, - MPR_INT32, &loc, REMOTE_MODIFY); + MPR_INT32, &loc, REMOTE_MODIFY); } else updated += mpr_tbl_set(tbl, PROP(PROCESS_LOC), NULL, 1, @@ -1137,26 +1350,27 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) case PROP(EXPR): { const char *expr_str = &a->vals[0]->s; mpr_loc orig_loc = m->process_loc; - if (m->loc && bitmatch(m->status, MPR_STATUS_READY)) { - if (strstr(expr_str, "y{-")) - m->process_loc = MPR_LOC_DST; - if (m->loc->is_local_only) + if (m->is_local && bitmatch(m->status, MPR_STATUS_READY)) { + mpr_local_map lm = (mpr_local_map)m; + if (!lm->is_local_only && strstr(expr_str, "y{-")) + lm->process_loc = MPR_LOC_DST; + if (lm->is_local_only) should_compile = 1; - else if (MPR_LOC_DST == m->process_loc) { - // check if destination is local - if (m->dst->loc->rsig) + else if (MPR_LOC_DST == lm->process_loc) { + /* check if destination is local */ + if (lm->dst->rsig) should_compile = 1; } else { for (j = 0; j < m->num_src; j++) { - if (m->src[j]->loc->rsig) + if (lm->src[j]->rsig) should_compile = 1; } } if (should_compile) { - if (_set_expr(m, expr_str)) { - // restore original process location - m->process_loc = orig_loc; + if (_set_expr(lm, expr_str)) { + /* restore original process location */ + lm->process_loc = orig_loc; break; } ++updated; @@ -1176,8 +1390,8 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) updated += mpr_tbl_set(tbl, PROP(PROCESS_LOC), NULL, 1, MPR_INT32, &loc, REMOTE_MODIFY); } - if (!m->loc) { - // remove any cached expression variables from table + if (!m->is_local) { + /* remove any cached expression variables from table */ mpr_tbl_remove(tbl, MPR_PROP_EXTRA, "var@*", REMOTE_MODIFY); } break; @@ -1202,8 +1416,8 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) } case PROP(USE_INST): { int use_inst = a->types[0] == 'T'; - if (m->loc && m->use_inst && !use_inst) { - // TODO: release map instances + if (m->is_local && m->use_inst && !use_inst) { + /* TODO: release map instances */ } updated += mpr_tbl_set(tbl, PROP(USE_INST), NULL, 1, MPR_BOOL, &use_inst, REMOTE_MODIFY); @@ -1212,58 +1426,62 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) case PROP(EXTRA): if (strcmp(a->key, "expression")==0) { if (mpr_type_get_is_str(a->types[0])) { - // set property type to expr and repeat + /* set property type to expr and repeat */ a->prop = PROP(EXPR); --i; } } else if (strncmp(a->key, "var@", 4)==0) { - if (m->loc && m->loc->expr) { - for (j = 0; j < m->loc->num_vars; j++) { - if (!mpr_expr_get_var_is_public(m->loc->expr, j)) + if (m->is_local && ((mpr_local_map)m)->expr) { + mpr_local_map lm = (mpr_local_map)m; + const char *name; + int k = 0, l, var_len; + for (j = 0; j < lm->num_vars; j++) { + if (!mpr_expr_get_var_is_public(lm->expr, j)) continue; - // check if matches existing varname - const char *name = mpr_expr_get_var_name(m->loc->expr, j); + /* check if matches existing varname */ + name = mpr_expr_get_var_name(lm->expr, j); if (strcmp(name, a->key+4)!=0) continue; - // found variable + /* found variable */ ++updated; - // TODO: handle multiple instances - int k = 0, l, var_len = m->loc->vars[j].vlen; - double *v = mpr_value_get_samp(&m->loc->vars[j], k); - // cast to double if necessary - switch (a->types[0]) { - case MPR_DBL: - for (k = 0, l = 0; k < var_len; k++, l++) { - if (l >= a->len) - l = 0; - v[k] = a->vals[l]->d; - } - break; - case MPR_INT32: - for (k = 0, l = 0; k < var_len; k++, l++) { - if (l >= a->len) - l = 0; - v[k] = (double)a->vals[l]->i32; - } - break; - case MPR_FLT: - for (k = 0, l = 0; k < var_len; k++, l++) { - if (l >= a->len) - l = 0; - v[k] = (float)a->vals[l]->f; - } - break; + /* TODO: handle multiple instances */ + var_len = lm->vars[j].vlen; + /* cast to double if necessary */ + switch (lm->vars[j].type) { +#define TYPED_CASE(MTYPE, TYPE, MTYPE1, EL1, MTYPE2, EL2) \ + case MTYPE: { \ + TYPE *v = mpr_value_get_samp(&lm->vars[j], k); \ + for (k = 0, l = 0; k < var_len; k++, l++) { \ + if (l >= a->len) \ + l = 0; \ + switch (a->types[l]) { \ + case MTYPE1: \ + v[k] = (TYPE)a->vals[l]->EL1; \ + break; \ + case MTYPE2: \ + v[k] = (TYPE)a->vals[l]->EL2; \ + break; \ + default: \ + --updated; \ + k = var_len; \ + } \ + } \ + break; \ + } + TYPED_CASE(MPR_INT32, int, MPR_FLT, f, MPR_DBL, d) + TYPED_CASE(MPR_FLT, float, MPR_INT32, i, MPR_DBL, d) + TYPED_CASE(MPR_DBL, double, MPR_INT32, i, MPR_FLT, f) +#undef TYPED_CASE default: --updated; - break; } break; } } - if (m->loc) + if (m->is_local) break; - // otherwise continue to mpr_tbl_set_from_atom() below + /* otherwise continue to mpr_tbl_set_from_atom() below */ } case PROP(ID): case PROP(MUTED): @@ -1275,9 +1493,9 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) } } done: - if (m->loc && m->status < MPR_STATUS_READY) { - // check if mapping is now "ready" - _check_status(m); + if (m->is_local && m->status < MPR_STATUS_READY) { + /* check if mapping is now "ready" */ + _check_status((mpr_local_map)m); } return updated; } @@ -1286,21 +1504,28 @@ int mpr_map_set_from_msg(mpr_map m, mpr_msg msg, int override) * to a peer device rather than an administrator. */ int mpr_map_send_state(mpr_map m, int slot, net_msg_t cmd) { + lo_message msg; + char dst_name[256], src_names[1024]; + int i, len = 0, result, staged; + mpr_link link; + if (MSG_MAPPED == cmd && m->status < MPR_STATUS_READY) return slot; - NEW_LO_MSG(msg, return slot); - char dst_name[256], src_names[1024]; + msg = lo_message_new(); + if (!msg) { + trace_net("couldn't allocate lo_message\n"); + return slot; + } snprintf(dst_name, 256, "%s%s", m->dst->sig->dev->name, m->dst->sig->path); if (MPR_DIR_IN == m->dst->dir) { - // add mapping destination + /* add mapping destination */ lo_message_add_string(msg, dst_name); lo_message_add_string(msg, "<-"); } - // add mapping sources - int i = (slot >= 0) ? slot : 0; - int len = 0, result; - mpr_link link = m->src[i]->loc ? m->src[i]->link : 0; + /* add mapping sources */ + i = (slot >= 0) ? slot : 0; + link = m->src[i]->is_local ? m->src[i]->link : 0; for (; i < m->num_src; i++) { if ((slot >= 0) && link && (link != m->src[i]->link)) break; @@ -1316,12 +1541,12 @@ int mpr_map_send_state(mpr_map m, int slot, net_msg_t cmd) } if (MPR_DIR_OUT == m->dst->dir || !m->dst->dir) { - // add mapping destination + /* add mapping destination */ lo_message_add_string(msg, "->"); lo_message_add_string(msg, dst_name); } - // Add unique id + /* Add unique id */ if (m->obj.id) { lo_message_add_string(msg, mpr_prop_as_str(PROP(ID), 0)); lo_message_add_int64(msg, *((int64_t*)&m->obj.id)); @@ -1332,25 +1557,25 @@ int mpr_map_send_state(mpr_map m, int slot, net_msg_t cmd) return i-1; } - // add other properties - int staged = (MSG_MAP == cmd) || (MSG_MAP_MOD == cmd); + /* add other properties */ + staged = (MSG_MAP == cmd) || (MSG_MAP_MOD == cmd); mpr_tbl_add_to_msg(0, staged ? m->obj.props.staged : m->obj.props.synced, msg); - // add slot id + /* add slot id */ if (MPR_DIR_IN == m->dst->dir && m->status <= MPR_STATUS_READY && !staged) { lo_message_add_string(msg, mpr_prop_as_str(PROP(SLOT), 0)); i = (slot >= 0) ? slot : 0; - link = m->src[i]->loc ? m->src[i]->link : 0; + link = m->src[i]->is_local ? m->src[i]->link : 0; for (; i < m->num_src; i++) { if ((slot >= 0) && link && (link != m->src[i]->link)) break; - lo_message_add_int32(msg, m->src[i]->obj.id); + lo_message_add_int32(msg, m->src[i]->id); } } /* source properties */ i = (slot >= 0) ? slot : 0; - link = m->src[i]->loc ? m->src[i]->link : 0; + link = m->src[i]->is_local ? m->src[i]->link : 0; for (; i < m->num_src; i++) { if ((slot >= 0) && link && (link != m->src[i]->link)) break; @@ -1362,25 +1587,45 @@ int mpr_map_send_state(mpr_map m, int slot, net_msg_t cmd) if (MSG_MAPPED == cmd || (MPR_DIR_IN == m->dst->dir)) mpr_slot_add_props_to_msg(msg, m->dst, 1, staged); - // add public expression variables - int j, k, l; - char varname[32]; - if (m->loc && m->loc->expr) { - for (j = 0; j < m->loc->num_vars; j++) { - if (!mpr_expr_get_var_is_public(m->loc->expr, j)) + /* add public expression variables */ + if (m->is_local && ((mpr_local_map)m)->expr) { + mpr_local_map lm = (mpr_local_map)m; + int j, k, l; + char varname[32]; + for (j = 0; j < lm->num_vars; j++) { + if (!mpr_expr_get_var_is_public(lm->expr, j)) continue; - // TODO: handle multiple instances + /* TODO: handle multiple instances */ k = 0; - if (m->loc->vars[j].inst[k].pos >= 0) { - snprintf(varname, 32, "@var@%s", mpr_expr_get_var_name(m->loc->expr, j)); + if (lm->vars[j].inst[k].pos >= 0) { + snprintf(varname, 32, "@var@%s", mpr_expr_get_var_name(lm->expr, j)); lo_message_add_string(msg, varname); - double *v = mpr_value_get_samp(&m->loc->vars[j], k); - for (l = 0; l < m->loc->vars[j].vlen; l++) - lo_message_add_double(msg, v[l]); + switch (lm->vars[j].type) { + case MPR_INT32: { + int *v = mpr_value_get_samp(&lm->vars[j], k); + for (l = 0; l < lm->vars[j].vlen; l++) + lo_message_add_int32(msg, v[l]); + break; + } + case MPR_FLT: { + float *v = mpr_value_get_samp(&lm->vars[j], k); + for (l = 0; l < lm->vars[j].vlen; l++) + lo_message_add_float(msg, v[l]); + break; + } + case MPR_DBL: { + double *v = mpr_value_get_samp(&lm->vars[j], k); + for (l = 0; l < lm->vars[j].vlen; l++) + lo_message_add_double(msg, v[l]); + break; + } + default: + break; + } } else { trace("public expression variable '%s' is not yet initialised.\n", - mpr_expr_get_var_name(m->loc->expr, j)); + mpr_expr_get_var_name(lm->expr, j)); } } } @@ -1390,13 +1635,13 @@ int mpr_map_send_state(mpr_map m, int slot, net_msg_t cmd) mpr_map mpr_map_new_from_str(const char *expr, ...) { - RETURN_UNLESS(expr, 0); mpr_sig sig, srcs[MAX_NUM_MAP_SRC]; mpr_sig dst = NULL; mpr_map map = NULL; int i = 0, j, num_src = 0; - + char *dup; va_list aq; + RETURN_ARG_UNLESS(expr, 0); va_start(aq, expr); while (expr[i]) { while (expr[i] && expr[i] != '%') @@ -1446,12 +1691,12 @@ mpr_map mpr_map_new_from_str(const char *expr, ...) TRACE_RETURN_UNLESS(dst, NULL, "Map format string '%s' has no output signal!\n", expr); TRACE_RETURN_UNLESS(num_src, NULL, "Map format string '%s' has no input signals!\n", expr); - // create the map + /* create the map */ map = mpr_map_new(num_src, srcs, 1, &dst); - // edit the expression string in-place + /* edit the expression string in-place */ i = 0; - char *dup = strdup(expr); + dup = strdup(expr); va_start(aq, expr); while (expr[i]) { while (expr[i] && expr[i] != '%') @@ -1460,13 +1705,13 @@ mpr_map mpr_map_new_from_str(const char *expr, ...) break; sig = va_arg(aq, void*); if (expr[i+1] == 'y') { - // replace the preceding '%' with a space + /* replace the preceding '%' with a space */ dup[i] = ' '; } - else { // 'x' - // retrieve signal index + else { /* 'x' */ + /* retrieve signal index */ j = mpr_map_get_sig_idx(map, sig); - // replace "%x" with "xi" where i is the signal index + /* replace "%x" with "xi" where i is the signal index */ dup[i] = 'x'; dup[i+1] = "0123456789"[j%10]; } diff --git a/src/mapper/mapper.h b/src/mapper/mapper.h index f48b230..06c4896 100644 --- a/src/mapper/mapper.h +++ b/src/mapper/mapper.h @@ -10,9 +10,9 @@ extern "C" { /*! \mainpage libmapper -This is the API documentation for libmapper, a distributed signal mapping -framework. Please see the Modules section for detailed information, and be -sure to consult the tutorial to get started with libmapper concepts. +This is the API documentation for libmapper, a distributed signal mapping framework. +Please see the Modules section for detailed information, and be sure to consult the tutorials +to get started with libmapper concepts. */ @@ -23,42 +23,40 @@ sure to consult the tutorial to get started with libmapper concepts. @{ Objects provide a generic representation of Devices, Signals, and Maps. */ /*! Return the internal mpr_graph structure used by an object. - * \param obj The object to query. + * \param object The object to query. * \return The mpr_graph used by this object. */ -mpr_graph mpr_obj_get_graph(mpr_obj obj); +mpr_graph mpr_obj_get_graph(mpr_obj object); /*! Return the specific type of an object. - * \param obj The object to query. + * \param object The object to query. * \return The object type. */ -mpr_type mpr_obj_get_type(mpr_obj obj); +mpr_type mpr_obj_get_type(mpr_obj object); /*! Get an object's number of properties. - * \param obj The object to check. + * \param object The object to check. * \param staged 1 to include staged properties in the count, 0 otherwise. * \return The number of properties stored in the table. */ -int mpr_obj_get_num_props(mpr_obj obj, int staged); +int mpr_obj_get_num_props(mpr_obj object, int staged); -/*! Look up a property by index or one of the symbolic identifiers listed in - * mpr_constants.h. - * \param obj The object to check. - * \param prop Index or symbolic identifier of the property to retrieve. +/*! Look up a property by index or one of the symbolic identifiers listed in mpr_constants.h. + * \param object The object to check. + * \param property Index or symbolic identifier of the property to retrieve. * \param key A pointer to a location to receive the name of the * property value (Optional, pass 0 to ignore). - * \param len A pointer to a location to receive the vector length of + * \param length A pointer to a location to receive the vector length of * the property value. (Required.) * \param type A pointer to a location to receive the type of the * property value. (Required.) - * \param val A pointer to a location to receive the address of the + * \param value A pointer to a location to receive the address of the * property's value. (Required.) - * \param pub 1 if property is public, 0 otherwise. + * \param publish 1 to publish to the distributed graph, 0 for local-only. * \return Symbolic identifier of the retrieved property, or * MPR_PROP_UNKNOWN if not found. */ -mpr_prop mpr_obj_get_prop_by_idx(mpr_obj obj, mpr_prop prop, const char **key, - int *len, mpr_type *type, const void **val, - int *pub); +mpr_prop mpr_obj_get_prop_by_idx(mpr_obj object, mpr_prop property, const char **key, int *length, + mpr_type *type, const void **value, int *publish); /*! Look up a property by name. - * \param obj The object to check. + * \param object The object to check. * \param key The name of the property to retrieve. * \param length A pointer to a location to receive the vector length of * the property value. (Required.) @@ -66,304 +64,274 @@ mpr_prop mpr_obj_get_prop_by_idx(mpr_obj obj, mpr_prop prop, const char **key, * property value. (Required.) * \param value A pointer to a location to receive the address of the * property's value. (Required.) - * \param pub 1 if property is public, 0 otherwise. + * \param publish 1 to publish to the distributed graph, 0 for local-only. * \return Symbolic identifier of the retrieved property, or * MPR_PROP_UNKNOWN if not found. */ -mpr_prop mpr_obj_get_prop_by_key(mpr_obj obj, const char *key, int *length, - mpr_type *type, const void **value, int *pub); - -/*! Look up a property by symbolic identifier or name and return as an integer - * if possible. Since the returned value cannot represent a missing property it - * is recommended that this function only be used to recover properties that - * are guaranteed to exist and have a compatible type. - * \param obj The object to check. - * \param prop The symbolic identifier of the property to recover. Can - * be set to MPR_UNKNOWN or MPR_EXTRA to specify the - * property by name instead. - * \param key A string identifier (name) for the property. Only used - * if the 'prop' argument is set to MPR_UNKNOWN or - * MPR_EXTRA. - * \return Value of the property cast to integer type, or zero - * if the property does not exist or can't be cast. */ -int mpr_obj_get_prop_as_int32(mpr_obj obj, mpr_prop prop, const char *key); - -/*! Look up a property by symbolic identifier or name and return as a float - * if possible. Since the returned value cannot represent a missing property it - * is recommended that this function only be used to recover properties that - * are guaranteed to exist and have a compatible type. - * \param obj The object to check. - * \param prop The symbolic identifier of the property to recover. Can - * be set to MPR_UNKNOWN or MPR_EXTRA to specify the - * property by name instead. - * \param key A string identifier (name) for the property. Only used - * if the 'prop' argument is set to MPR_UNKNOWN or - * MPR_EXTRA. - * \return Value of the property cast to float type, or zero - * if the property does not exist or can't be cast. */ -float mpr_obj_get_prop_as_flt(mpr_obj obj, mpr_prop prop, const char *key); - -/*! Look up a property by symbolic identifier or name and return as a c string - * if possible. The returned value belongs to the object and should not be - * freed. - * \param obj The object to check. - * \param prop The symbolic identifier of the property to recover. Can - * be set to MPR_UNKNOWN or MPR_EXTRA to specify the - * property by name instead. - * \param key A string identifier (name) for the property. Only used - * if the 'prop' argument is set to MPR_UNKNOWN or - * MPR_EXTRA. - * \return Value of the property, or null if the property does not - * exist or has an incompatible type. */ -const char *mpr_obj_get_prop_as_str(mpr_obj obj, mpr_prop prop, const char *key); - -/*! Look up a property by symbolic identifier or name and return as a c pointer - * if possible. The returned value belongs to the object and should not be - * freed. - * \param obj The object to check. - * \param prop The symbolic identifier of the property to recover. Can - * be set to MPR_UNKNOWN or MPR_EXTRA to specify the - * property by name instead. - * \param key A string identifier (name) for the property. Only used - * if the 'prop' argument is set to MPR_UNKNOWN or - * MPR_EXTRA. +mpr_prop mpr_obj_get_prop_by_key(mpr_obj object, const char *key, int *length, + mpr_type *type, const void **value, int *publish); + +/*! Look up a property by symbolic identifier or name and return as an integer if possible. Since + * the returned value cannot represent a missing property it is recommended that this function + * only be used to recover properties that are guaranteed to exist and have a compatible type. + * \param object The object to check. + * \param property The symbolic identifier of the property to recover. Can be set to + * MPR_UNKNOWN or MPR_EXTRA to specify the property by name instead. + * \param key A string identifier (name) for the property. Only used if the 'property' + * argument is set to MPR_UNKNOWN or MPR_EXTRA. + * \return Value of the property cast to integer type, or zero if the property does + * not exist or can't be cast to int. */ +int mpr_obj_get_prop_as_int32(mpr_obj object, mpr_prop property, const char *key); + +/*! Look up a property by symbolic identifier or name and return as a float if possible. Since the + * returned value cannot represent a missing property it is recommended that this function only be + * used to recover properties that are guaranteed to exist and have a compatible type. + * \param object The object to check. + * \param property The symbolic identifier of the property to recover. Can be set to + * MPR_UNKNOWN or MPR_EXTRA to specify the property by name instead. + * \param key A string identifier (name) for the property. Only used if the 'property' + * argument is set to MPR_UNKNOWN or MPR_EXTRA. + * \return Value of the property cast to float type, or zero if the property does not + * exist or can't be cast to float. */ +float mpr_obj_get_prop_as_flt(mpr_obj object, mpr_prop property, const char *key); + +/*! Look up a property by symbolic identifier or name and return as a c string if possible. + * The returned value belongs to the object and should not be freed. + * \param object The object to check. + * \param property The symbolic identifier of the property to recover. Can be set to + * MPR_UNKNOWN or MPR_EXTRA to specify the property by name instead. + * \param key A string identifier (name) for the property. Only used if the 'property' + * argument is set to MPR_UNKNOWN or MPR_EXTRA. * \return Value of the property, or null if the property does not * exist or has an incompatible type. */ -const void *mpr_obj_get_prop_as_ptr(mpr_obj obj, mpr_prop prop, const char *key); - -/*! Look up a property by symbolic identifier or name and return as a mpr_obj - * if possible. The returned value belongs to the object and should not be - * freed. - * \param obj The object to check. - * \param prop The symbolic identifier of the property to recover. Can - * be set to MPR_UNKNOWN or MPR_EXTRA to specify the - * property by name instead. - * \param key A string identifier (name) for the property. Only used - * if the 'prop' argument is set to MPR_UNKNOWN or - * MPR_EXTRA. - * \return Value of the property, or null if the property does not - * exist or has an incompatible type. */ -mpr_obj mpr_obj_get_prop_as_obj(mpr_obj obj, mpr_prop prop, const char *key); - -/*! Look up a property by symbolic identifier or name and return as a mpr_list - * if possible. The returned value is a copy and can be safely modified (e.g. - * iterated) or freed. - * \param obj The object to check. - * \param prop The symbolic identifier of the property to recover. Can - * be set to MPR_UNKNOWN or MPR_EXTRA to specify the - * property by name instead. - * \param key A string identifier (name) for the property. Only used - * if the 'prop' argument is set to MPR_UNKNOWN or - * MPR_EXTRA. - * \return Value of the property, or null if the property does not - * exist or has an incompatible type. */ -mpr_list mpr_obj_get_prop_as_list(mpr_obj obj, mpr_prop prop, const char *key); - -/*! Set a property. Can be used to provide arbitrary metadata. Value pointed - * to will be copied. Properties can be specified by setting the 'prop' - * argument to one of the symbolic identifiers listed in mpr_constants.h; - * if 'prop' is set to MPR_PROP_UNKNOWN or MPR_PROP_EXTRA the 'name' argument - * will be used instead. - * \param obj The object to operate on. - * \param prop Symbolic identifier of the property to add. +const char *mpr_obj_get_prop_as_str(mpr_obj object, mpr_prop property, const char *key); + +/*! Look up a property by symbolic identifier or name and return as a c pointer if possible. + * The returned value belongs to the object and should not be freed. + * \param object The object to check. + * \param property The symbolic identifier of the property to recover. Can be set to + * MPR_UNKNOWN or MPR_EXTRA to specify the property by name instead. + * \param key A string identifier (name) for the property. Only used if the 'property' + * argument is set to MPR_UNKNOWN or MPR_EXTRA. + * \return Value of the property, or null if the property does not exist or has an + * incompatible type. */ +const void *mpr_obj_get_prop_as_ptr(mpr_obj object, mpr_prop property, const char *key); + +/*! Look up a property by symbolic identifier or name and return as a mpr_obj if possible. + * The returned value belongs to the object and should not be freed. + * \param object The object to check. + * \param property The symbolic identifier of the property to recover. Can be set to + * MPR_UNKNOWN or MPR_EXTRA to specify the property by name instead. + * \param key A string identifier (name) for the property. Only used if the 'property' + * argument is set to MPR_UNKNOWN or MPR_EXTRA. + * \return Value of the property, or null if the property does not exist or has an + * incompatible type. */ +mpr_obj mpr_obj_get_prop_as_obj(mpr_obj object, mpr_prop property, const char *key); + +/*! Look up a property by symbolic identifier or name and return as a mpr_list if possible. + * The returned value is a copy and can be safely modified (e.g. iterated) or freed. + * \param object The object to check. + * \param property The symbolic identifier of the property to recover. Can be set to + * MPR_UNKNOWN or MPR_EXTRA to specify the property by name instead. + * \param key A string identifier (name) for the property. Only used if the 'proerty' + * argument is set to MPR_UNKNOWN or MPR_EXTRA. + * \return Value of the property, or null if the property does not exist or has an + * incompatible type. */ +mpr_list mpr_obj_get_prop_as_list(mpr_obj object, mpr_prop property, const char *key); + +/*! Set a property. Can be used to provide arbitrary metadata. Value pointed to will be copied. + * Properties can be specified by setting the 'property' argument to one of the symbolic + * identifiers listed in mpr_constants.h; if 'property' is set to MPR_PROP_UNKNOWN or + * MPR_PROP_EXTRA the 'name' argument will be used instead. + * \param object The object to operate on. + * \param property Symbolic identifier of the property to add. * \param key The name of the property to add. - * \param len The length of value array. + * \param length The length of value array. * \param type The property datatype. * \param value An array of property values. * \param publish 1 to publish to the distributed graph, 0 for local-only. * \return Symbolic identifier of the set property, or * MPR_PROP_UNKNOWN if not found. */ -mpr_prop mpr_obj_set_prop(mpr_obj obj, mpr_prop prop, const char *key, int len, +mpr_prop mpr_obj_set_prop(mpr_obj object, mpr_prop property, const char *key, int length, mpr_type type, const void *value, int publish); /*! Remove a property from an object. - * \param obj The object to operate on. - * \param prop Symbolic identifier of the property to remove. + * \param object The object to operate on. + * \param property Symbolic identifier of the property to remove. * \param key The name of the property to remove. * \return 1 if property has been removed, 0 otherwise. */ -int mpr_obj_remove_prop(mpr_obj obj, mpr_prop prop, const char *key); +int mpr_obj_remove_prop(mpr_obj object, mpr_prop property, const char *key); /*! Push any property changes out to the distributed graph. - * \param obj The object to operate on. */ -void mpr_obj_push(mpr_obj obj); + * \param object The object to operate on. */ +void mpr_obj_push(mpr_obj object); /*! Helper to print the properties of an object. - * \param obj The object to print. + * \param object The object to print. * \param staged 1 to print staged properties, 0 otherwise. */ -void mpr_obj_print(mpr_obj obj, int staged); +void mpr_obj_print(mpr_obj object, int staged); /*** Devices ***/ /*! @defgroup devices Devices - @{ A device is an entity on the distributed graph which has input and/or - output signals. The mpr_dev is the primary interface through which - a program uses libmapper. A device must have a name, to which a unique - ordinal is subsequently appended. It can also be given other - user-specified metadata. Device signals can be connected, which is - accomplished by requests from an external GUI or session manager. */ + @{ A device is an entity on the distributed graph which has input and/or output signals. + The mpr_dev is the primary interface through which a program uses libmapper. + A device must have a name, to which a unique ordinal is subsequently appended. + It can also be given other user-specified metadata. + Device signals can be connected, which is accomplished by requests from an external GUI + or session manager. */ /*! Allocate and initialize a device. - * \param name A short descriptive string to identify the device. - * Must not contain spaces or the slash character '/'. - * \param g A previously allocated graph structure to use. - * If 0, one will be allocated for use with this device. - * \return A newly allocated device. Should be freed - * using mpr_dev_free(). */ -mpr_dev mpr_dev_new(const char *name, mpr_graph g); + * \param name A short descriptive string to identify the device. Must not contain spaces + * or the slash character '/'. + * \param graph A previously allocated graph structure to use. If 0, one will be allocated + * for use with this device. + * \return A newly allocated device. Should be freed using mpr_dev_free(). */ +mpr_dev mpr_dev_new(const char *name, mpr_graph graph); /*! Free resources used by a device. - * \param dev The device to free. */ -void mpr_dev_free(mpr_dev dev); + * \param device The device to free. */ +void mpr_dev_free(mpr_dev device); /*! Return a unique identifier associated with a given device. - * \param dev The device to use. + * \param device The device to use. * \return A new unique id. */ -mpr_id mpr_dev_generate_unique_id(mpr_dev dev); +mpr_id mpr_dev_generate_unique_id(mpr_dev device); /*! Return the list of signals for a given device. - * \param dev The device to query. - * \param dir The direction of the signals to return, should be - * MPR_DIR_IN, MPR_DIR_OUT, or MPR_DIR_ANY. + * \param device The device to query. + * \param direction The direction of the signals to return, should be MPR_DIR_IN, MPR_DIR_OUT, + * or MPR_DIR_ANY. * \return A list of results. Use mpr_list_get_next() to iterate. */ -mpr_list mpr_dev_get_sigs(mpr_dev dev, mpr_dir dir); +mpr_list mpr_dev_get_sigs(mpr_dev device, mpr_dir direction); /*! Return the list of maps for a given device. - * \param dev The device to query. - * \param dir The direction of the maps to return, should be - * MPR_DIR_IN, MPR_DIR_OUT, or MPR_DIR_ANY. + * \param device The device to query. + * \param direction The direction of the maps to return, should be MPR_DIR_IN, MPR_DIR_OUT, or + * MPR_DIR_ANY. * \return A list of results. Use mpr_list_get_next() to iterate. */ -mpr_list mpr_dev_get_maps(mpr_dev dev, mpr_dir dir); - -/*! Poll this device for new messages. Note, if you have multiple devices, the - * right thing to do is call this function for each of them with block_ms=0, - * and add your own sleep if necessary. - * \param dev The device to check messages for. - * \param block_ms Number of milliseconds to block waiting for messages, or - * 0 for non-blocking behaviour. - * \return The number of handled messages. May be zero if there was - * nothing to do. */ -int mpr_dev_poll(mpr_dev dev, int block_ms); +mpr_list mpr_dev_get_maps(mpr_dev device, mpr_dir direction); + +/*! Poll this device for new messages. Note, if you have multiple devices, the right thing to do + * is call this function for each of them with block_ms=0, and add your own sleep if necessary. + * \param device The device to check messages for. + * \param block_ms Number of milliseconds to block waiting for messages, or 0 for non-blocking + * behaviour. + * \return The number of handled messages. May be zero if there was nothing to do. */ +int mpr_dev_poll(mpr_dev device, int block_ms); /*! Detect whether a device is completely initialized. - * \param dev The device to query. - * \return Non-zero if device is completely initialized, i.e., has - * an allocated receiving port and unique identifier. - * Zero otherwise. */ -int mpr_dev_get_is_ready(mpr_dev dev); + * \param device The device to query. + * \return Non-zero if device is completely initialized, i.e., has an allocated + * receiving port and unique identifier. Zero otherwise. */ +int mpr_dev_get_is_ready(mpr_dev device); /*! Get the current time for a device. - * \param dev The device to use. + * \param device The device to use. * \return The current time. */ -mpr_time mpr_dev_get_time(mpr_dev dev); +mpr_time mpr_dev_get_time(mpr_dev device); /*! Set the time for a device. Use only if user code has access to a more accurate * timestamp than the operating system. - * \param dev The device to use. - * \param time The time to set. This time will be used for tagging signal - * updates until the next occurrence mpr_dev_set_time() or - * mpr_dev_poll(). */ -void mpr_dev_set_time(mpr_dev dev, mpr_time time); + * \param device The device to use. + * \param time The time to set. This time will be used for tagging signal updates until + * the next occurrence mpr_dev_set_time() or mpr_dev_poll(). */ +void mpr_dev_set_time(mpr_dev device, mpr_time time); -/*! Indicates that all signal values have been updated for a given timestep. - * This function can be omitted if mpr_dev_poll() is called each sampling - * timestep instead, however calling mpr_dev_poll() at a lower rate may be - * more performant. - * \param dev The device to use. */ -void mpr_dev_process_outputs(mpr_dev dev); +/*! Indicates that all signal values have been updated for a given timestep. This function can be + * omitted if mpr_dev_poll() is called each sampling timestep instead, however calling + * mpr_dev_poll() at a lower rate may be more performant. + * \param device The device to use. */ +void mpr_dev_update_maps(mpr_dev device); -/** @} */ // end of group Devices +/** @} */ /* end of group Devices */ /*** Signals ***/ /*! @defgroup signals Signals - @{ Signals define inputs or outputs for devices. A signal consists of a - scalar or vector value of some integer or floating-point type. A signal - is created by adding an input or output to a device. It can optionally - be provided with some metadata such as a signal's range, unit, or other - properties. Signals can be mapped by creating maps through a GUI. */ + @{ Signals define inputs or outputs for devices. A signal consists of a scalar or vector value + of some integer or floating-point type. A signal is created by adding an input or output to + a device. It can optionally be provided with some metadata such as a signal's range, unit, + or other properties. Signals can be mapped by creating maps through a GUI. */ /*! A signal handler function can be called whenever a signal value changes. - * \param sig The signal that has been updated. - * \param evt The type of event that has occured, e.g. MPR_SIG_UPDATE - * when the value has changed. - * \param inst The identifier of the instance that has been changed, if - * applicable. + * \param signal The signal that has been updated. + * \param event The type of event that has occured, e.g. MPR_SIG_UPDATE when the value has + * changed. Event types are listed in the enum mpr_sig_evt found in + * mapper_constants.h + * \param instance The identifier of the instance that has been changed, if applicable. * \param length The array length of the update value. * \param type The data type of the update value. * \param value A pointer to the value update. * \param time The timetag associated with this event. */ -typedef void mpr_sig_handler(mpr_sig sig, mpr_sig_evt evt, mpr_id inst, int length, +typedef void mpr_sig_handler(mpr_sig signal, mpr_sig_evt event, mpr_id instance, int length, mpr_type type, const void *value, mpr_time time); -/*! Allocate and initialize a signal. Values and strings pointed to by this - * call will be copied. For min and max values, actual type must correspond - * to 'type' (if type=MPR_INT32, then int*, etc). - * \param parent The object to add a signal to. - * \param dir The signal direction. - * \param name The name of the signal. - * \param len The length of the signal vector, or 1 for a scalar. - * \param type The type fo the signal value. - * \param unit The unit of the signal, or 0 for none. - * \param min Pointer to a minimum value, or 0 for none. - * \param max Pointer to a maximum value, or 0 for none. - * \param num_inst Pointer to the number of signal instances or 0 to - * indicate that instances will not be used. - * \param handler Function to be called when the value of the signal is - * updated. - * \param events Bitflags for types of events we are interested in. - * \return The new signal. */ -mpr_sig mpr_sig_new(mpr_dev parent, mpr_dir dir, const char *name, int len, - mpr_type type, const char *unit, const void *min, - const void *max, int *num_inst, mpr_sig_handler *handler, - int events); +/*! Allocate and initialize a signal. Values and strings pointed to by this call will be copied. + * For minimum and maximum values, type must match 'type' (if type=MPR_INT32, then int*, etc). + * \param parent The object to add a signal to. + * \param direction The signal direction. + * \param name The name of the signal. + * \param length The length of the signal vector, or 1 for a scalar. + * \param type The type fo the signal value. + * \param unit The unit of the signal, or 0 for none. + * \param minimum Pointer to a minimum value, or 0 for none. + * \param maximum Pointer to a maximum value, or 0 for none. + * \param num_instances Pointer to the number of signal instances or 0 to indicate that + * instances will not be used. + * \param handler Function to be called when the value of the signal is updated. + * \param events Bitflags for types of events we are interested in. Event types are + * listed in the enum mpr_sig_evt found in mapper_constants.h + * \return The new signal. */ +mpr_sig mpr_sig_new(mpr_dev parent, mpr_dir direction, const char *name, int length, mpr_type type, + const char *unit, const void *minimum, const void *maximum, int *num_instances, + mpr_sig_handler *handler, int events); /* Free resources used by a signal. - * \param sig The signal to free. */ -void mpr_sig_free(mpr_sig sig); + * \param signal The signal to free. */ +void mpr_sig_free(mpr_sig signal); /*! Update the value of a signal instance. The signal will be routed according * to external requests. - * \param sig The signal to operate on. - * \param inst A pointer to the identifier of the instance to update, + * \param signal The signal to operate on. + * \param instance A pointer to the identifier of the instance to update, * or 0 for the default instance. - * \param length Length of the value argument. Expected to be a multiple - * of the signal length. A block of values can be accepted, - * with the current value as the last value(s) in an array. + * \param length Length of the value argument. Expected to be equal to the signal length. * \param type Data type of the value argument. - * \param value A pointer to a new value for this signal. If the signal - * type is MPR_INT32, this should be int*; if the signal - * type is MPR_FLOAT, this should be float* (etc). It - * should be an array at least as long as the signal's - * length property. */ -void mpr_sig_set_value(mpr_sig sig, mpr_id inst, int length, mpr_type type, const void *value); + * \param value A pointer to a new value for this signal. If the type argument is + * MPR_INT32, this should be int*; if the type argument is MPR_FLOAT, this + * should be float* (etc). It should be an array at least as long as the + * length argument. */ +void mpr_sig_set_value(mpr_sig signal, mpr_id instance, int length, mpr_type type, + const void *value); /*! Get the value of a signal instance. - * \param sig The signal to operate on. - * \param inst A pointer to the identifier of the instance to query, + * \param signal The signal to operate on. + * \param instance A pointer to the identifier of the instance to query, * or 0 for the default instance. * \param time A location to receive the value's time tag. May be 0. * \return A pointer to an array containing the value of the signal * instance, or 0 if the signal instance has no value. */ -const void *mpr_sig_get_value(mpr_sig sig, mpr_id inst, mpr_time *time); +const void *mpr_sig_get_value(mpr_sig signal, mpr_id instance, mpr_time *time); /*! Return the list of maps associated with a given signal. - * \param sig Signal record to query for maps. - * \param dir The direction of the map relative to the given signal. + * \param signal Signal record to query for maps. + * \param direction The direction of the map relative to the given signal. * \return A list of results. Use mpr_list_get_next() to iterate. */ -mpr_list mpr_sig_get_maps(mpr_sig sig, mpr_dir dir); +mpr_list mpr_sig_get_maps(mpr_sig signal, mpr_dir direction); /*! Get the parent mpr_dev for a specific signal. - * \param sig The signal to check. + * \param signal The signal to check. * \return The signal's parent device. */ -mpr_dev mpr_sig_get_dev(mpr_sig sig); +mpr_dev mpr_sig_get_dev(mpr_sig signal); /*! Set or unset the message handler for a signal. - * \param sig The signal to operate on. - * \param handler A pointer to a mpr_sig_handler function - * for processing incoming messages. - * \param events Bitflags for types of events we are interested in. */ -void mpr_sig_set_cb(mpr_sig sig, mpr_sig_handler *handler, int events); + * \param signal The signal to operate on. + * \param handler A pointer to a mpr_sig_handler function for processing incoming messages. + * \param events Bitflags for types of events we are interested in. Event types are listed + * in the enum mpr_sig_evt found in mapper_constants.h */ +void mpr_sig_set_cb(mpr_sig signal, mpr_sig_handler *handler, int events); /**** Signal Instances ****/ @@ -376,108 +344,103 @@ void mpr_sig_set_cb(mpr_sig sig, mpr_sig_handler *handler, int events); /*! Add new instances to the reserve list. Note that if instance ids are * specified, libmapper will not add multiple instances with the same id. - * \param sig The signal to which the instances will be added. - * \param num The number of instances to add. + * \param signal The signal to which the instances will be added. + * \param number The number of instances to add. * \param ids Array of integer ids, one for each new instance, * or 0 for automatically-generated instance ids. * \param data Array of user context pointers, one for each new instance, * or 0 if not needed. * \return Number of instances added. */ -int mpr_sig_reserve_inst(mpr_sig sig, int num, mpr_id *ids, void **data); +int mpr_sig_reserve_inst(mpr_sig signal, int number, mpr_id *ids, void **data); /*! Release a specific instance of a signal by removing it from the list of * active instances and adding it to the reserve list. - * \param sig The signal to operate on. - * \param inst The identifier of the instance to suspend. */ -void mpr_sig_release_inst(mpr_sig sig, mpr_id inst); + * \param signal The signal to operate on. + * \param instance The identifier of the instance to suspend. */ +void mpr_sig_release_inst(mpr_sig signal, mpr_id instance); /*! Remove a specific instance of a signal and free its memory. - * \param sig The signal to operate on. - * \param inst The identifier of the instance to suspend. */ -void mpr_sig_remove_inst(mpr_sig sig, mpr_id inst); + * \param signal The signal to operate on. + * \param instance The identifier of the instance to suspend. */ +void mpr_sig_remove_inst(mpr_sig signal, mpr_id instance); /*! Return whether a given signal instance is currently active. - * \param sig The signal to operate on. - * \param inst The identifier of the instance to check. + * \param signal The signal to operate on. + * \param instance The identifier of the instance to check. * \return Non-zero if the instance is active, zero otherwise. */ -int mpr_sig_get_inst_is_active(mpr_sig sig, mpr_id inst); +int mpr_sig_get_inst_is_active(mpr_sig signal, mpr_id instance); /*! Activate a specific signal instance without setting it's value. In general it is not necessary * to use this function, since signal instances will be automatically activated as necessary when * signals are updated by mpr_sig_set_value() or through a map. - * \param sig The signal to operate on. - * \param inst The identifier of the instance to activate. + * \param signal The signal to operate on. + * \param instance The identifier of the instance to activate. * \return Non-zero if the instance is active, zero otherwise. */ -int mpr_sig_activate_inst(mpr_sig sig, mpr_id inst); +int mpr_sig_activate_inst(mpr_sig signal, mpr_id instance); /*! Get the local identifier of the oldest active instance. - * \param sig The signal to operate on. + * \param signal The signal to operate on. * \return The instance identifier, or zero if unsuccessful. */ -mpr_id mpr_sig_get_oldest_inst_id(mpr_sig sig); +mpr_id mpr_sig_get_oldest_inst_id(mpr_sig signal); /*! Get the local identifier of the newest active instance. - * \param sig The signal to operate on. + * \param signal The signal to operate on. * \return The instance identifier, or zero if unsuccessful. */ -mpr_id mpr_sig_get_newest_inst_id(mpr_sig sig); +mpr_id mpr_sig_get_newest_inst_id(mpr_sig signal); /*! Get a signal instance's identifier by its index. Intended to be used for * iterating over the active instances. - * \param sig The signal to operate on. - * \param idx The numerical index of the instance to retrieve. Should be - * between zero and the number of instances. - * \param status The status of the instances to searchl should be set to - * MPR_STATUS_ACTIVE, MPR_STATUS_RESERVED, or both - * (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED). + * \param signal The signal to operate on. + * \param index The numerical index of the instance to retrieve. Should be between zero + * and the number of instances. + * \param status The status of the instances to searchl should be set to MPR_STATUS_ACTIVE, + * MPR_STATUS_RESERVED, or both (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED). * \return The instance identifier associated with the given index, or zero * if unsuccessful. */ -mpr_id mpr_sig_get_inst_id(mpr_sig sig, int idx, mpr_status status); +mpr_id mpr_sig_get_inst_id(mpr_sig signal, int index, mpr_status status); /*! Associate a signal instance with an arbitrary pointer. - * \param sig The signal to operate on. - * \param inst The identifier of the instance to operate on. - * \param data A pointer to user data to be associated with this - * instance. */ -void mpr_sig_set_inst_data(mpr_sig sig, mpr_id inst, const void *data); + * \param signal The signal to operate on. + * \param instance The identifier of the instance to operate on. + * \param data A pointer to user data to be associated with this instance. */ +void mpr_sig_set_inst_data(mpr_sig signal, mpr_id instance, const void *data); /*! Retrieve the arbitrary pointer associated with a signal instance. - * \param sig The signal to operate on. - * \param inst The identifier of the instance to operate on. + * \param signal The signal to operate on. + * \param instance The identifier of the instance to operate on. * \return A pointer associated with this instance. */ -void *mpr_sig_get_inst_data(mpr_sig sig, mpr_id inst); +void *mpr_sig_get_inst_data(mpr_sig signal, mpr_id instance); /*! Get the number of instances for a specific signal. - * \param sig The signal to check. - * \param status The status of the instances to searchl should be set to - * MPR_STATUS_ACTIVE, MPR_STATUS_RESERVED, or both - * (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED). + * \param signal The signal to check. + * \param status The status of the instances to searchl should be set to MPR_STATUS_ACTIVE, + * MPR_STATUS_RESERVED, or both (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED). * \return The number of allocated signal instances. */ -int mpr_sig_get_num_inst(mpr_sig sig, mpr_status status); +int mpr_sig_get_num_inst(mpr_sig signal, mpr_status status); -/** @} */ // end of group Instances +/** @} */ /* end of group Instances */ -/** @} */ // end of group Signals +/** @} */ /* end of group Signals */ /***** Maps *****/ /*! @defgroup maps Maps - @{ Maps define dataflow connections between sets of signals. A map consists - of one or more sources, one destination, and properties which determine - how the source data is processed. */ + @{ Maps define dataflow connections between sets of signals. A map consists of one or more + sources, one destination, and properties which determine how the source data is processed. */ /*! Create a map between a set of signals. The map will not take effect until it * has been added to the distributed graph using mpr_obj_push(). - * \param num_srcs The number of source signals in this map. - * \param srcs Array of source signal data structures. - * \param num_dsts The number of destination signals in this map. - * Currently restricted to 1. - * \param dsts Array of destination signal data structures. - * \return A map data structure – either loaded from the graph - * (if the map already existed) or newly created. In the - * latter case the map will not take effect until it has - * been added to the distributed graph using - * mpr_obj_push(). */ -mpr_map mpr_map_new(int num_srcs, mpr_sig *srcs, int num_dsts, mpr_sig *dsts); + * \param num_sources The number of source signals in this map. + * \param sources Array of source signal data structures. + * \param num_destinations The number of destination signals in this map. + * Currently restricted to 1. + * \param destinations Array of destination signal data structures. + * \return A map data structure – either loaded from the graph (if the map already + * existed) or newly created. In the latter case the map will not take + * effect until it has been added to the distributed graph using + * mpr_obj_push(). */ +mpr_map mpr_map_new(int num_sources, mpr_sig *sources, int num_destinations, mpr_sig *destinations); /*! Create a map between a set of signals using an expression string containing embedded format * specifiers that are replaced by mpr_sig values specified in subsequent additional arguments. @@ -499,56 +462,53 @@ void mpr_map_release(mpr_map map); /*! Retrieve a connected signal for a specific map by index. * \param map The map to check. - * \param idx The index of the signal to return. - * \param loc The map endpoint, must be MPR_LOC_SRC, MPR_LOC_DST, or MPR_LOC_ANY. + * \param index The index of the signal to return. + * \param endpoint The map endpoint, must be MPR_LOC_SRC, MPR_LOC_DST, or MPR_LOC_ANY. * \return A signal, or NULL if not found. */ -mpr_sig mpr_map_get_sig(mpr_map map, int idx, mpr_loc loc); +mpr_sig mpr_map_get_sig(mpr_map map, int index, mpr_loc endpoint); /*! Retrieve a list of connected signals for a specific map. * \param map The map to check. - * \param loc The map endpoint, must be MPR_LOC_SRC, MPR_LOC_DST, or MPR_LOC_ANY. + * \param endpoint The map endpoint, must be MPR_LOC_SRC, MPR_LOC_DST, or MPR_LOC_ANY. * \return A list of results. Use mpr_list_get_next() to iterate. */ -mpr_list mpr_map_get_sigs(mpr_map map, mpr_loc loc); +mpr_list mpr_map_get_sigs(mpr_map map, mpr_loc endpoint); /*! Retrieve the index for a specific map signal. * \param map The map to check. - * \param sig The signal to find. + * \param signal The signal to find. * \return The signal index, or -1 if not found. */ -int mpr_map_get_sig_idx(mpr_map map, mpr_sig sig); +int mpr_map_get_sig_idx(mpr_map map, mpr_sig signal); /*! Detect whether a map is completely initialized. * \param map The device to query. - * \return Non-zero if map is completely initialized, zero - * otherwise. */ + * \return Non-zero if map is completely initialized, zero otherwise. */ int mpr_map_get_is_ready(mpr_map map); /*! Re-create stale map if necessary. * \param map The map to operate on. */ void mpr_map_refresh(mpr_map map); -/*! Add a scope to this map. Map scopes configure the propagation of signal - * instance updates across the map. Changes to remote maps will not take effect - * until synchronized with the distributed graph using mpr_obj_push(). +/*! Add a scope to this map. Map scopes configure the propagation of signal instance updates across + * the map. Changes to remote maps will not take effect until synchronized with the distributed + * graph using mpr_obj_push(). * \param map The map to modify. - * \param dev Device to add as a scope for this map. After taking - * effect, this setting will cause instance updates - * originating at this device to be propagated across the - * map. */ -void mpr_map_add_scope(mpr_map map, mpr_dev dev); - -/*! Remove a scope from this map. Map scopes configure the propagation of signal - * instance updates across the map. Changes to remote maps will not take effect - * until synchronized with the distributed graph using mpr_obj_push(). + * \param device Device to add as a scope for this map. After taking effect, this setting + * will cause instance updates originating at this device to be propagated + * across the map. */ +void mpr_map_add_scope(mpr_map map, mpr_dev device); + +/*! Remove a scope from this map. Map scopes configure the propagation of signal instance updates + * across the map. Changes to remote maps will not take effect until synchronized with the + * distributed graph using mpr_obj_push(). * \param map The map to modify. - * \param dev Device to remove as a scope for this map. After taking - * effect, this setting will cause instance updates - * originating at this device to be blocked from + * \param device Device to remove as a scope for this map. After taking effect, this setting + * will cause instance updates originating at this device to be blocked from * propagating across the map. */ -void mpr_map_remove_scope(mpr_map map, mpr_dev dev); +void mpr_map_remove_scope(mpr_map map, mpr_dev device); -/** @} */ // end of group Maps +/** @} */ /* end of group Maps */ -/** @} */ // end of group Objects +/** @} */ /* end of group Objects */ /*** Lists ***/ @@ -559,14 +519,14 @@ void mpr_map_remove_scope(mpr_map map, mpr_dev dev); /*! Filter a list of objects using the given property. * \param list The list of objects to filter. - * \param prop Symbolic identifier of the property to look for. + * \param property Symbolic identifier of the property to look for. * \param key The name of the property to search for. - * \param len The value length. + * \param length The value length. * \param type The value type. * \param value The value. * \param op The comparison operator. * \return A list of results. Use mpr_list_get_next() to iterate. */ -mpr_list mpr_list_filter(mpr_list list, mpr_prop prop, const char *key, int len, +mpr_list mpr_list_filter(mpr_list list, mpr_prop property, const char *key, int length, mpr_type type, const void *value, mpr_op op); /*! Get the union of two object lists (objects matching list1 OR list2). @@ -589,10 +549,9 @@ mpr_list mpr_list_get_diff(mpr_list list1, mpr_list list2); /*! Get an indexed item in a list of objects. * \param list The previous object record pointer. - * \param idx The index of the list element to retrieve. - * \return A pointer to the object record, or zero if it doesn't - * exist. */ -mpr_obj mpr_list_get_idx(mpr_list list, unsigned int idx); + * \param index The index of the list element to retrieve. + * \return A pointer to the object record, or zero if it doesn't exist. */ +mpr_obj mpr_list_get_idx(mpr_list list, unsigned int index); /*! Given a object record pointer returned from a previous object query, get the * next item in the list. @@ -615,118 +574,112 @@ void mpr_list_free(mpr_list list); * \return The number of objects in the list. */ int mpr_list_get_size(mpr_list list); -/** @} */ // end of group Lists +/** @} */ /* end of group Lists */ /***** Graph *****/ /*! @defgroup graphs Graphs - @{ Graphs are the primary interface through which a program may observe - the distributed graph and store information about devices and signals - that are present. Each Graph stores records of devices, signals, and - maps, which can be queried. */ + @{ Graphs are the primary interface through which a program may observe the distributed graph + and store information about devices and signals that are present. Each Graph stores records + of devices, signals, and maps, which can be queried. */ /*! Create a peer in the distributed graph. - * \param autosub_flags A combination of mpr_type values controlling whether the graph should - * automatically subscribe to information about devices, signals and/or - * maps when it encounters a previously-unseen device. - * \return The new graph. */ -mpr_graph mpr_graph_new(int autosub_flags); + * \param autosubscribe_types A combination of mpr_type values controlling whether the graph + * should automatically subscribe to information about devices, + * signals and/or maps when it encounters a previously-unseen device. + * \return The new graph. */ +mpr_graph mpr_graph_new(int autosubscribe_types); /*! Specify network interface to use. - * \param g The graph structure to use. + * \param graph The graph structure to use. * \param iface The name of the network interface to use. */ -void mpr_graph_set_interface(mpr_graph g, const char *iface); +void mpr_graph_set_interface(mpr_graph graph, const char *iface); /*! Return a string indicating the name of the network interface in use. - * \param g The graph structure to query. + * \param graph The graph structure to query. * \return A string containing the name of the network interface. */ -const char *mpr_graph_get_interface(mpr_graph g); +const char *mpr_graph_get_interface(mpr_graph graph); /*! Set the multicast group and port to use. - * \param g The graph structure to query. - * \param group A string specifying the multicast group for bus - * communication with the distributed graph. + * \param graph The graph structure to query. + * \param group A string specifying the multicast group for bus communication with the + * distributed graph. * \param port The port to use for multicast communication. */ -void mpr_graph_set_address(mpr_graph g, const char *group, int port); +void mpr_graph_set_address(mpr_graph graph, const char *group, int port); /*! Retrieve the multicast group currently in use. - * \param g The graph structure to query. - * \return A string specifying the multicast url for bus - * communication with the distributed graph. */ -const char *mpr_graph_get_address(mpr_graph g); + * \param graph The graph structure to query. + * \return A string specifying the multicast URL for bus communication with the + * distributed graph. */ +const char *mpr_graph_get_address(mpr_graph graph); /*! Synchonize a local graph copy with the distributed graph. - * \param g The graph to update. - * \param block_ms The number of milliseconds to block, or 0 for - * non-blocking behaviour. + * \param graph The graph to update. + * \param block_ms The number of milliseconds to block, or 0 for non-blocking behaviour. * \return The number of handled messages. */ -int mpr_graph_poll(mpr_graph g, int block_ms); +int mpr_graph_poll(mpr_graph graph, int block_ms); /*! Free a graph. - * \param g The graph to free. */ -void mpr_graph_free(mpr_graph g); + * \param graph The graph to free. */ +void mpr_graph_free(mpr_graph graph); /*! Print the contents of a graph. - * \param g The graph to print. */ -void mpr_graph_print(mpr_graph g); + * \param graph The graph to print. */ +void mpr_graph_print(mpr_graph graph); /*! Subscribe to information about a specific device. - * \param g The graph to use. - * \param dev The device of interest. If NULL the graph will - * automatically subscribe to all discovered devices. + * \param graph The graph to use. + * \param device The device of interest. If NULL the graph will automatically subscribe to + * all discovered devices. * \param types Bitflags setting the type of information of interest. * Can be a combination of mpr_type values. - * \param timeout The length in seconds for this subscription. If set to - * -1, the graph will automatically renew the - * subscription until it is freed or this function is + * \param timeout The length in seconds for this subscription. If set to -1, the graph will + * automatically renew the subscription until it is freed or this function is * called again. */ -void mpr_graph_subscribe(mpr_graph g, mpr_dev dev, int types, int timeout); +void mpr_graph_subscribe(mpr_graph graph, mpr_dev device, int types, int timeout); /*! Unsubscribe from information about a specific device. - * \param g The graph to use. - * \param dev The device of interest. If NULL the graph will + * \param graph The graph to use. + * \param device The device of interest. If NULL the graph will * unsubscribe from all devices. */ -void mpr_graph_unsubscribe(mpr_graph g, mpr_dev dev); +void mpr_graph_unsubscribe(mpr_graph graph, mpr_dev device); /*! A callback function prototype for when an object record is added or updated. * Such a function is passed in to mpr_graph_add_cb(). - * \param g The graph that registered this callback. - * \param obj The object record. - * \param evt A value of mpr_graph_evt indicating what is happening - * to the object record. + * \param graph The graph that registered this callback. + * \param object The object record. + * \param event A value of mpr_graph_evt indicating what is happening to the object record. * \param data The user context pointer registered with this callback. */ -typedef void mpr_graph_handler(mpr_graph g, mpr_obj obj, const mpr_graph_evt evt, +typedef void mpr_graph_handler(mpr_graph graph, mpr_obj object, const mpr_graph_evt event, const void *data); /*! Register a callback for when an object record is added or updated in the * graph. - * \param g The graph to query. - * \param h Callback function. + * \param graph The graph to query. + * \param handler Callback function. * \param types Bitflags setting the type of information of interest. * Can be a combination of mpr_type values. - * \param data A user-defined pointer to be passed to the callback - * for context. + * \param data A user-defined pointer to be passed to the callback for context. * \return One if a callback was added, otherwise zero. */ -int mpr_graph_add_cb(mpr_graph g, mpr_graph_handler *h, int types, - const void *data); +int mpr_graph_add_cb(mpr_graph graph, mpr_graph_handler *handler, int types, const void *data); /*! Remove a device record callback from the graph service. - * \param g The graph to query. - * \param h Callback function. + * \param graph The graph to query. + * \param handler Callback function. * \param data The user context pointer that was originally specified * when adding the callback. - * \return One if a callback was removed, otherwise zero. */ -int mpr_graph_remove_cb(mpr_graph g, mpr_graph_handler *h, const void *data); + * \return User data pointer associated with this callback (if any). */ +void *mpr_graph_remove_cb(mpr_graph graph, mpr_graph_handler *handler, const void *data); /*! Return a list of objects. - * \param g The graph to query. + * \param graph The graph to query. * \param types Bitflags setting the type of information of interest. * Can be a combination of mpr_type values. * \return A list of results. Use mpr_list_get_next() to iterate. */ -mpr_list mpr_graph_get_objs(mpr_graph g, int types); +mpr_list mpr_graph_get_objs(mpr_graph graph, int types); -/** @} */ // end of group Graphs +/** @} */ /* end of group Graphs */ /***** Time *****/ @@ -769,14 +722,14 @@ void mpr_time_set_dbl(mpr_time *time, double value); * \param timer The source time. */ void mpr_time_set(mpr_time *timel, mpr_time timer); -/*! Compare two timetags, returning zero if they all match or a value - * different from zero representing which is greater if they do not. +/*! Compare two timetags, returning zero if they all match or a value different from zero + * representing which is greater if they do not. * \param time1 A previously allocated time to augment. * \param time2 A time to add. * \return <0 if time1 < time2; 0 if time1 == time2; >0 if time1 > time2. */ int mpr_time_cmp(mpr_time time1, mpr_time time2); -/** @} */ // end of group Times +/** @} */ /* end of group Times */ /*! Get the version of libmapper. * \return A string specifying the version of libmapper. */ @@ -786,4 +739,4 @@ const char *mpr_get_version(void); } #endif -#endif // __MPR_H__ +#endif /* __MPR_H__ */ diff --git a/src/mapper/mapper_constants.h b/src/mapper/mapper_constants.h index d1aa430..2e17776 100644 --- a/src/mapper/mapper_constants.h +++ b/src/mapper/mapper_constants.h @@ -9,28 +9,31 @@ extern "C" { #include -#define MPR_NOW ((mpr_time){0L,1L}) +/*! A 64-bit data structure containing an NTP-compatible time tag, as used by OSC. */ +typedef lo_timetag mpr_time; +#define MPR_NOW LO_TT_IMMEDIATE enum { - MPR_DEV = 0x01, //!< Devices only. - MPR_SIG_IN = 0x02, //!< Input signals. - MPR_SIG_OUT = 0x04, //!< Output signals. - MPR_SIG = 0x06, //!< All signals. - MPR_MAP_IN = 0x08, //!< Incoming maps. - MPR_MAP_OUT = 0x10, //!< Outgoing maps. - MPR_MAP = 0x18, //!< All maps. - MPR_OBJ = 0x1F, //!< All objects: devs, sigs, maps. - MPR_LIST = 0x40, //!< object query. - MPR_BOOL = 'b', /* 0x62 */ //!< Boolean value. - MPR_TYPE = 'c', /* 0x63 */ //!< libmapper data type. - MPR_DBL = 'd', /* 0x64 */ //!< 64-bit floating point. - MPR_FLT = 'f', /* 0x66 */ //!< 32-bit floating point. - MPR_INT64 = 'h', /* 0x68 */ //!< 64-bit integer. - MPR_INT32 = 'i', /* 0x69 */ //!< 32-bit integer. - MPR_STR = 's', /* 0x73 */ //!< String. - MPR_TIME = 't', /* 0x74 */ //!< 64-bit NTP timestamp. - MPR_PTR = 'v', /* 0x76 */ //!< pointer. - MPR_NULL = 'N' /* 0x4E */ //!< NULL value. + MPR_DEV = 0x01, /*!< Devices only. */ + MPR_SIG_IN = 0x02, /*!< Input signals. */ + MPR_SIG_OUT = 0x04, /*!< Output signals. */ + MPR_SIG = 0x06, /*!< All signals. */ + MPR_MAP_IN = 0x08, /*!< Incoming maps. */ + MPR_MAP_OUT = 0x10, /*!< Outgoing maps. */ + MPR_MAP = 0x18, /*!< All maps. */ + MPR_OBJ = 0x1F, /*!< All objects: devs, sigs, maps. */ + MPR_LIST = 0x40, /*!< Object query. */ + MPR_GRAPH = 0x41, /*!< Graph. */ + MPR_BOOL = 'b', /* 0x62 */ /*!< Boolean value. */ + MPR_TYPE = 'c', /* 0x63 */ /*!< libmapper data type. */ + MPR_DBL = 'd', /* 0x64 */ /*!< 64-bit floating point. */ + MPR_FLT = 'f', /* 0x66 */ /*!< 32-bit floating point. */ + MPR_INT64 = 'h', /* 0x68 */ /*!< 64-bit integer. */ + MPR_INT32 = 'i', /* 0x69 */ /*!< 32-bit integer. */ + MPR_STR = 's', /* 0x73 */ /*!< String. */ + MPR_TIME = 't', /* 0x74 */ /*!< 64-bit NTP timestamp. */ + MPR_PTR = 'v', /* 0x76 */ /*!< pointer. */ + MPR_NULL = 'N' /* 0x4E */ /*!< NULL value. */ }; typedef char mpr_type; @@ -77,59 +80,54 @@ typedef enum { MPR_PROP_UNIT = 0x2500, MPR_PROP_USE_INST = 0x2600, MPR_PROP_VERSION = 0x2700, - MPR_PROP_EXTRA = 0x2800, + MPR_PROP_EXTRA = 0x2800 } mpr_prop; -/*! A 64-bit data structure containing an NTP-compatible time tag, as - * used by OSC. */ -typedef lo_timetag mpr_time; - -/*! This data structure must be large enough to hold a system pointer or a - * uin64_t */ +/*! This data structure must be large enough to hold a system pointer or a uin64_t */ typedef uint64_t mpr_id; /*! Possible operations for composing queries. */ typedef enum { MPR_OP_UNDEFINED = 0x00, - MPR_OP_NEX = 0x01, //!< Property does not exist for this entity. - MPR_OP_EQ = 0x02, //!< Property value == query value. - MPR_OP_EX = 0x03, //!< Property exists for this entity. - MPR_OP_GT = 0x04, //!< Property value > query value. - MPR_OP_GTE = 0x05, //!< Property value >= query value - MPR_OP_LT = 0x06, //!< Property value < query value - MPR_OP_LTE = 0x07, //!< Property value <= query value - MPR_OP_NEQ = 0x08, //!< Property value != query value - MPR_OP_ALL = 0x10, //!< Applies to all elements of value - MPR_OP_ANY = 0x20, //!< Applies to any element of value + MPR_OP_NEX = 0x01, /*!< Property does not exist for this entity. */ + MPR_OP_EQ = 0x02, /*!< Property value == query value. */ + MPR_OP_EX = 0x03, /*!< Property exists for this entity. */ + MPR_OP_GT = 0x04, /*!< Property value > query value. */ + MPR_OP_GTE = 0x05, /*!< Property value >= query value */ + MPR_OP_LT = 0x06, /*!< Property value < query value */ + MPR_OP_LTE = 0x07, /*!< Property value <= query value */ + MPR_OP_NEQ = 0x08, /*!< Property value != query value */ + MPR_OP_ALL = 0x10, /*!< Applies to all elements of value */ + MPR_OP_ANY = 0x20, /*!< Applies to any element of value */ MPR_OP_NONE = 0x40 } mpr_op; /*! Describes the possible endpoints of a map. * @ingroup map */ typedef enum { - MPR_LOC_UNDEFINED = 0x00, //!< Not yet defined - MPR_LOC_SRC = 0x01, //!< Source signal(s) for this map. - MPR_LOC_DST = 0x02, //!< Destination signal(s) for this map. - MPR_LOC_ANY = 0x03 //!< Either source or destination signals. + MPR_LOC_UNDEFINED = 0x00, /*!< Not yet defined */ + MPR_LOC_SRC = 0x01, /*!< Source signal(s) for this map. */ + MPR_LOC_DST = 0x02, /*!< Destination signal(s) for this map. */ + MPR_LOC_ANY = 0x03 /*!< Either source or destination signals. */ } mpr_loc; /*! Describes the possible network protocol for map communication * @ingroup map */ typedef enum { - MPR_PROTO_UNDEFINED, //!< Not yet defined - MPR_PROTO_UDP, //!< Map updates are sent using UDP. - MPR_PROTO_TCP, //!< Map updates are sent using TCP. + MPR_PROTO_UNDEFINED, /*!< Not yet defined */ + MPR_PROTO_UDP, /*!< Map updates are sent using UDP. */ + MPR_PROTO_TCP, /*!< Map updates are sent using TCP. */ MPR_NUM_PROTO } mpr_proto; /*! The set of possible directions for a signal. - * @ingroup map */ + * @ingroup signal */ typedef enum { - MPR_DIR_UNDEFINED = 0x00, //!< Not yet defined. - MPR_DIR_IN = 0x01, //!< Signal is an input - MPR_DIR_OUT = 0x02, //!< Signal is an output - MPR_DIR_ANY = 0x03, //!< Either incoming or outgoing - MPR_DIR_BOTH = 0x04, /*!< Both directions apply. Currently signals + MPR_DIR_UNDEFINED = 0x00, /*!< Not yet defined. */ + MPR_DIR_IN = 0x01, /*!< Signal is an input */ + MPR_DIR_OUT = 0x02, /*!< Signal is an output */ + MPR_DIR_ANY = 0x03, /*!< Either incoming or outgoing */ + MPR_DIR_BOTH = 0x04 /*!< Both directions apply. Currently signals * cannot be both inputs and outputs, so this * value is only used for querying device maps * that touch only local signals. */ @@ -138,29 +136,29 @@ typedef enum { /*! The set of possible signal events, used to register and inform callbacks. * @ingroup signal */ typedef enum { - MPR_SIG_INST_NEW = 0x01, //!< New instance has been created. - MPR_SIG_REL_UPSTRM = 0x02, //!< Instance was released upstream. - MPR_SIG_REL_DNSTRM = 0x04, //!< Instance was released downstream. - MPR_SIG_INST_OFLW = 0x08, //!< No local instances left. - MPR_SIG_UPDATE = 0x10, //!< Instance value has been updated. - MPR_SIG_ALL = 0x1F, + MPR_SIG_INST_NEW = 0x01, /*!< New instance has been created. */ + MPR_SIG_REL_UPSTRM = 0x02, /*!< Instance was released upstream. */ + MPR_SIG_REL_DNSTRM = 0x04, /*!< Instance was released downstream. */ + MPR_SIG_INST_OFLW = 0x08, /*!< No local instances left. */ + MPR_SIG_UPDATE = 0x10, /*!< Instance value has been updated. */ + MPR_SIG_ALL = 0x1F } mpr_sig_evt; /*! Describes the voice-stealing mode for instances. * @ingroup map */ typedef enum { - MPR_STEAL_NONE, //!< No stealing will take place. - MPR_STEAL_OLDEST, //!< Steal the oldest instance. - MPR_STEAL_NEWEST, //!< Steal the newest instance. + MPR_STEAL_NONE, /*!< No stealing will take place. */ + MPR_STEAL_OLDEST, /*!< Steal the oldest instance. */ + MPR_STEAL_NEWEST /*!< Steal the newest instance. */ } mpr_steal_type; /*! The set of possible graph events, used to inform callbacks. * @ingroup graph */ typedef enum { - MPR_OBJ_NEW, //!< New record has been added to the graph. - MPR_OBJ_MOD, //!< The existing record has been modified. - MPR_OBJ_REM, //!< The existing record has been removed. - MPR_OBJ_EXP, //!< The graph has lost contact with the remote entity. + MPR_OBJ_NEW, /*!< New record has been added to the graph. */ + MPR_OBJ_MOD, /*!< The existing record has been modified. */ + MPR_OBJ_REM, /*!< The existing record has been removed. */ + MPR_OBJ_EXP /*!< The graph has lost contact with the remote entity. */ } mpr_graph_evt; typedef enum { @@ -168,13 +166,13 @@ typedef enum { MPR_STATUS_EXPIRED = 0x01, MPR_STATUS_STAGED = 0x02, MPR_STATUS_READY = 0x3E, - MPR_STATUS_ACTIVE = 0x7E, // must exclude MPR_STATUS_RESERVED + MPR_STATUS_ACTIVE = 0x7E, /* must exclude MPR_STATUS_RESERVED */ MPR_STATUS_RESERVED = 0x80, - MPR_STATUS_ALL = 0xFF, + MPR_STATUS_ALL = 0xFF } mpr_status; #ifdef __cplusplus } #endif -#endif // __MPR_CONSTANTS_H__ +#endif /* __MPR_CONSTANTS_H__ */ diff --git a/src/mapper/mapper_cpp.h b/src/mapper/mapper_cpp.h index c431cd4..54ce741 100644 --- a/src/mapper/mapper_cpp.h +++ b/src/mapper/mapper_cpp.h @@ -1,4 +1,3 @@ - #ifndef _MPR_CPP_H_ #define _MPR_CPP_H_ @@ -17,41 +16,26 @@ #include #include -//signal_update_handler(Signal sig, instance_id, val, len, Time) -//- optional: instance_id, time, len -// -//possible forms: -//(Signal sig, void *val) -//(Signal sig, void *val, Time time) -//(Signal sig, int instance_id, void *val) -//(Signal sig, int instance_id, void *val, Time time) -//(Signal sig, void *val, int len) -//(Signal sig, void *val, int len, Time time) -//(Signal sig, int instance_id, void *val, int len) -//(Signal sig, int instance_id, void *val, int len, Time time) - #ifdef interface #undef interface #endif -#define RETURN_SELF(FUNC) \ -{ FUNC; return (*this); } +#define RETURN_SELF \ +{ return (*this); } #define MPR_TYPE(NAME) mpr_ ## NAME #define MPR_FUNC(OBJ, FUNC) mpr_ ## OBJ ## _ ## FUNC #define OBJ_METHODS(CLASS_NAME) \ public: \ - void set_property(const Property& p) \ - { Object::set_property(p); } \ template \ CLASS_NAME& set_property(const Values... vals) \ - { RETURN_SELF(Object::set_property(vals...)); } \ + { Object::set_property(vals...); RETURN_SELF } \ template \ CLASS_NAME& remove_property(const T prop) \ - { RETURN_SELF(Object::remove_property(prop)); } \ + { Object::remove_property(prop); RETURN_SELF } \ const CLASS_NAME& push() const \ - { RETURN_SELF(Object::push()); } \ + { Object::push(); RETURN_SELF } \ namespace mapper { @@ -59,9 +43,101 @@ namespace mapper { class Device; class Signal; class Map; - class Property; + class PropVal; class Graph; + /*! The set of possible datatypes. */ + enum class Type : char + { + DEVICE = MPR_DEV, /*!< Devices only. */ + SIGNAL_IN = MPR_SIG_IN, /*!< Input signals. */ + SIGNAL_OUT = MPR_SIG_OUT, /*!< Output signals. */ + SIGNAL = MPR_SIG, /*!< All signals. */ + MAP_IN = MPR_MAP_IN, /*!< Incoming maps. */ + MAP_OUT = MPR_MAP_OUT, /*!< Outgoing maps. */ + MAP = MPR_MAP, /*!< All maps. */ + OBJECT = MPR_OBJ, /*!< All objects: devs, sigs, maps. */ + LIST = MPR_LIST, /*!< object query. */ + BOOLEAN = MPR_BOOL, /*!< Boolean value. */ + TYPE = MPR_TYPE, /*!< libmapper data type. */ + DOUBLE = MPR_DBL, /*!< 64-bit floating point. */ + FLOAT = MPR_FLT, /*!< 32-bit floating point. */ + INT64 = MPR_INT64, /*!< 64-bit integer. */ + INT32 = MPR_INT32, /*!< 32-bit integer. */ + STRING = MPR_STR, /*!< String. */ + TIME = MPR_TIME, /*!< 64-bit NTP timestamp. */ + POINTER = MPR_PTR /*!< pointer. */ + }; + + /*! The set of possible directions for a signal. */ + enum class Direction : int + { + INCOMING = MPR_DIR_IN, /*!< Incoming */ + OUTGOING = MPR_DIR_OUT, /*!< Outgoing */ + ANY = MPR_DIR_ANY, /*!< Either incoming or outgoing */ + BOTH = MPR_DIR_BOTH /*!< Both directions apply. Currently signals cannot be both + * inputs and outputs, so this value is only used for querying + * device maps that touch only local signals. */ + }; + + /*! Possible operations for composing queries. */ + enum class Operator + { + DOES_NOT_EXIST = MPR_OP_NEX, /*!< Property does not exist for this entity. */ + EQUAL = MPR_OP_EQ, /*!< Property value == query value. */ + EXISTS = MPR_OP_EX, /*!< Property exists for this entity. */ + GREATER_THAN = MPR_OP_GT, /*!< Property value > query value. */ + GREATER_THAN_OR_EQUAL = MPR_OP_GTE, /*!< Property value >= query value */ + LESS_THAN = MPR_OP_LT, /*!< Property value < query value */ + LESS_THAN_OR_EQUAL = MPR_OP_LTE, /*!< Property value <= query value */ + NOT_EQUAL = MPR_OP_NEQ, /*!< Property value != query value */ + ALL = MPR_OP_ALL, /*!< Applies to all elements of value */ + ANY = MPR_OP_ANY, /*!< Applies to any element of value */ + NONE = MPR_OP_NONE + }; + + enum class Property + { + CALIBRATING = MPR_PROP_CALIB, + DEVICE = MPR_PROP_DEV, + DIRECTION = MPR_PROP_DIR, + EXPRESSION = MPR_PROP_EXPR, + HOST = MPR_PROP_HOST, + ID = MPR_PROP_ID, + IS_LOCAL = MPR_PROP_IS_LOCAL, + JITTER = MPR_PROP_JITTER, + LENGTH = MPR_PROP_LEN, + LIBVERSION = MPR_PROP_LIBVER, + LINKED = MPR_PROP_LINKED, + MAX = MPR_PROP_MAX, + MIN = MPR_PROP_MIN, + MUTED = MPR_PROP_MUTED, + NAME = MPR_PROP_NAME, + NUM_INSTANCES = MPR_PROP_NUM_INST, + NUM_MAPS = MPR_PROP_NUM_MAPS, + NUM_MAPS_IN = MPR_PROP_NUM_MAPS_IN, + NUM_MAPS_OUT = MPR_PROP_NUM_MAPS_OUT, + NUM_SIGNALS_IN = MPR_PROP_NUM_SIGS_IN, + NUM_SIGNALS_OUT = MPR_PROP_NUM_SIGS_OUT, + ORDINAL = MPR_PROP_ORDINAL, + PERIOD = MPR_PROP_PERIOD, + PORT = MPR_PROP_PORT, + PROCESS_LOCATION = MPR_PROP_PROCESS_LOC, + PROTOCOL = MPR_PROP_PROTOCOL, + RATE = MPR_PROP_RATE, + SCOPE = MPR_PROP_SCOPE, + SIGNALS = MPR_PROP_SIG, + STATUS = MPR_PROP_STATUS, + STEAL_MODE = MPR_PROP_STEAL_MODE, + SYNCED = MPR_PROP_SYNCED, + TYPE = MPR_PROP_TYPE, + UNIT = MPR_PROP_UNIT, + USE_INSTANCES = MPR_PROP_USE_INST, + VERSION = MPR_PROP_VERSION, + }; + + typedef mpr_id Id; + // Helper class to allow polymorphism on "const char *" and "std::string". class str_type { public: @@ -86,21 +162,21 @@ namespace mapper { uint32_t sec() { return _time.sec; } Time& set_sec(uint32_t sec) - { RETURN_SELF(_time.sec = sec); } + { _time.sec = sec; RETURN_SELF } uint32_t frac() { return _time.frac; } Time& set_frac (uint32_t frac) - { RETURN_SELF(_time.frac = frac); } + { _time.frac = frac; RETURN_SELF } Time& now() - { RETURN_SELF(mpr_time_set(&_time, MPR_NOW)); } + { mpr_time_set(&_time, MPR_NOW); RETURN_SELF } operator mpr_time*() { return &_time; } operator double() const { return mpr_time_as_dbl(_time); } Time& operator=(Time& time) - { RETURN_SELF(mpr_time_set(&_time, time._time)); } + { mpr_time_set(&_time, time._time); RETURN_SELF } Time& operator=(double d) - { RETURN_SELF(mpr_time_set_dbl(&_time, d)); } + { mpr_time_set_dbl(&_time, d); RETURN_SELF } Time operator+(Time& addend) { mpr_time temp; @@ -116,15 +192,15 @@ namespace mapper { return temp; } Time& operator+=(Time& addend) - { RETURN_SELF(mpr_time_add(&_time, *(mpr_time*)addend)); } + { mpr_time_add(&_time, *(mpr_time*)addend); RETURN_SELF } Time& operator+=(double addend) - { RETURN_SELF(mpr_time_add_dbl(&_time, addend)); } + { mpr_time_add_dbl(&_time, addend); RETURN_SELF } Time& operator-=(Time& subtrahend) - { RETURN_SELF(mpr_time_sub(&_time, *(mpr_time*)subtrahend)); } + { mpr_time_sub(&_time, *(mpr_time*)subtrahend); RETURN_SELF } Time& operator-=(double subtrahend) - { RETURN_SELF(mpr_time_add_dbl(&_time, -subtrahend)); } + { mpr_time_add_dbl(&_time, -subtrahend); RETURN_SELF } Time& operator*=(double multiplicand) - { RETURN_SELF(mpr_time_mul(&_time, multiplicand)); } + { mpr_time_mul(&_time, multiplicand); RETURN_SELF } bool operator<(Time& rhs) { return mpr_time_cmp(_time, rhs._time) < 0; } bool operator<=(Time& rhs) @@ -161,7 +237,6 @@ namespace mapper { ~List() { mpr_list_free(_list); } - virtual operator std::vector() const; operator mpr_list() { return _list; } bool operator==(const List& rhs) @@ -169,7 +244,7 @@ namespace mapper { bool operator!=(const List& rhs) { return (_list != rhs._list); } List& operator++() - { RETURN_SELF(if (_list) _list = mpr_list_get_next(_list)); } + { if (_list) _list = mpr_list_get_next(_list); RETURN_SELF } List operator++(int) { List tmp(*this); operator++(); return tmp; } List begin() @@ -200,10 +275,12 @@ namespace mapper { } /*! Filter items from this List based on property matching - * \param p Property to match. + * \param prop The name or id of the property to match. + * \param value The property value. * \param op The comparison operator. * \return Self. */ - List& filter(const Property& p, mpr_op op); + template + List& filter(P&& prop, V&& value, Operator op); /*! Remove items found in List rhs from this List * \param rhs A second list. @@ -272,7 +349,7 @@ namespace mapper { List& set_property(const Values... vals); T operator*() - { return T(*_list); } + { return _list ? T(*_list) : T(NULL); } /*! Retrieve an indexed item in the List. * \param idx The index of the element to retrieve. @@ -313,8 +390,7 @@ namespace mapper { friend class List; friend class List; friend class List; - friend class Property; - void set_property(const Property& p); + friend class PropVal; mpr_obj _obj; public: @@ -322,11 +398,13 @@ namespace mapper { virtual ~Object() {} operator mpr_obj() const { return _obj; } + bool operator == (Object o) const + { return _obj == o._obj; } /*! Get the specific type of an Object. * \return Object type. */ - mpr_type type() const - { return mpr_obj_get_type(_obj); } + Type type() const + { return Type(mpr_obj_get_type(_obj)); } /*! Get the underlying Graph. * \return Graph. */ @@ -341,8 +419,8 @@ namespace mapper { /*! Remove a Property from an Object by symbolic identifier. * \param prop The Property to remove. * \return Self. */ - virtual Object& remove_property(mpr_prop prop) - { RETURN_SELF(mpr_obj_remove_prop(_obj, prop, NULL)); } + virtual Object& remove_property(Property prop) + { mpr_obj_remove_prop(_obj, static_cast(prop), NULL); RETURN_SELF } /*! Remove a named Property from an Object. * \param key Name of the Property to remove. @@ -357,7 +435,10 @@ namespace mapper { /*! Push "staged" property changes out to the distributed graph. * \return Self. */ virtual const Object& push() const - { RETURN_SELF(mpr_obj_push(_obj)); } + { mpr_obj_push(_obj); RETURN_SELF } + + const Object& print(int staged=0) const + { mpr_obj_print(_obj, staged); RETURN_SELF } /*! Retrieve the number of Properties owned by an Object. * \param staged Set to true to count properties that have been @@ -368,16 +449,18 @@ namespace mapper { /*! Retrieve a Property by name. * \param key The name of the Property to retrieve. - * \return The retrieved Property. */ - Property property(const str_type &key=NULL) const; + * \return The retrieved PropVal. */ + PropVal property(const str_type &key=NULL) const; /*! Retrieve a Property by index. * \param prop The index of or symbolic identifier of the Property to retrieve. * \return The retrieved Property. */ - Property property(mpr_prop prop) const; + PropVal property(Property prop) const; template - Property operator [] (T prop) const; + PropVal operator [] (T prop) const; + + friend std::ostream& operator<<(std::ostream& os, const mapper::Object& o); }; class signal_type { @@ -390,12 +473,34 @@ namespace mapper { mpr_sig _sig; }; - /*! Maps define dataflow connections between sets of Signals. A Map consists - * of one or more source Signals, one or more destination Signal (currently), - * restricted to one) and properties which determine how the source data is - * processed.*/ + /*! Maps define dataflow connections between sets of Signals. A Map consists of one or more + * source Signals, one or more destination Signal (currently), restricted to one) and + * properties which determine how the source data is processed. */ class Map : public Object { + public: + /*! Describes the possible endpoints of a map. */ + enum class Location + { + SRC = MPR_LOC_SRC, /*!< Source signal(s) for this map. */ + DST = MPR_LOC_DST, /*!< Destination signal(s) for this map. */ + ANY = MPR_LOC_ANY /*!< Either source or destination signals. */ + }; + + /*! Describes the possible network protocols for map communication. */ + enum class Protocol + { + UDP = MPR_PROTO_UDP, /*!< Map updates are sent using UDP. */ + TCP = MPR_PROTO_TCP /*!< Map updates are sent using TCP. */ + }; + + /*! the set of possible voice-stealing modes for instances. */ + enum class Stealing + { + NONE = MPR_STEAL_NONE, /*!< No stealing will take place. */ + OLDEST = MPR_STEAL_OLDEST, /*!< Steal the oldest instance. */ + NEWEST = MPR_STEAL_NEWEST /*!< Steal the newest instance. */ + }; private: /* This constructor accepts a between 2 and 10 signal object arguments inclusive. It is * delagated to by the variadic template constructor and in turn it calls the vararg @@ -423,10 +528,9 @@ namespace mapper { /*! Create a map between a pair of Signals. * \param src Source Signal. * \param dst Destination Signal object. - * \return A new Map object – either loaded from the Graph (if the - * Map already exists) or newly created. In the latter case - * the Map will not take effect until it has been added to - * the distributed graph using push(). */ + * \return A new Map object – either loaded from the Graph (if the Map already exists) + * or newly created. In the latter case the Map will not take effect until it + * has been added to the distributed graph using push(). */ Map(signal_type src, signal_type dst) : Object(NULL) { mpr_sig cast_src = src, cast_dst = dst; @@ -440,7 +544,7 @@ namespace mapper { * destination signals. The format specifier "%x" is used to specify * source signals and the "%y" is used to specify the destination * signal. - * \param ... A sequence of additional Signal arguments, one for each format + * \param args A sequence of additional Signal arguments, one for each format * specifier in the format string * \return A map data structure – either loaded from the graph and modified * with the new expression (if the map already existed) or newly @@ -452,13 +556,11 @@ namespace mapper { /*! Create a map between a set of Signals. * \param num_srcs The number of source signals in this map. * \param srcs Array of source Signal objects. - * \param num_dsts The number of destination signals in this map. - * Currently restricted to 1. + * \param num_dsts The number of destination signals in this map, currently restricted to 1. * \param dsts Array of destination Signal objects. - * \return A new Map object – either loaded from the Graph (if - * the Map already exists) or newly created. In the - * latter case the Map will not take effect until it - * has been added to the graph using push(). */ + * \return A new Map object – either loaded from the Graph (if the Map already + * exists) or newly created. In the latter case the Map will not take + * effect until it has been added to the graph using push(). */ Map(int num_srcs, signal_type srcs[], int num_dsts, signal_type dsts[]) : Object(NULL) { mpr_sig cast_src[num_srcs], cast_dst = dsts[0]; @@ -470,10 +572,9 @@ namespace mapper { /*! Create a map between a set of Signals. * \param srcs std::array of source Signal objects. * \param dsts std::array of destination Signal objects. - * \return A new Map object – either loaded from the Graph (if the - * Map already exists) or newly created. In the latter case - * the Map will not take effect until it has been added to - * the distributed graph using push(). */ + * \return A new Map object – either loaded from the Graph (if the Map already exists) + * or newly created. In the latter case the Map will not take effect until it + * has been added to the distributed graph using push(). */ template Map(std::array& srcs, std::array& dsts) : Object(NULL) @@ -491,10 +592,9 @@ namespace mapper { /*! Create a map between a set of Signals. * \param srcs std::vector of source Signal objects. * \param dsts std::vector of destination Signal objects. - * \return A new Map object – either loaded from the Graph (if the - * Map already exists) or newly created. In the latter case - * the Map will not take effect until it has been added to - * the distributed graph using push(). */ + * \return A new Map object – either loaded from the Graph (if the Map already exists) + * or newly created. In the latter case the Map will not take effect until it + * has been added to the distributed graph using push(). */ Map(std::vector& srcs, std::vector& dsts) : Object(NULL) { if (!srcs.size() || (dsts.size() != 1)) { @@ -521,7 +621,7 @@ namespace mapper { /*! Re-create stale map if necessary. * \return Self. */ const Map& refresh() const - { RETURN_SELF(mpr_map_refresh(_obj)); } + { mpr_map_refresh(_obj); RETURN_SELF } /*! Release the Map between a set of Signals. */ // this function can be const since it only sends the unmap msg @@ -539,23 +639,21 @@ namespace mapper { // List scopes() const // { return List((void**)mpr_map_scopes(_obj)); } - /*! Add a scope to this Map. Map scopes configure the propagation of - * Signal updates across the Map. Changes will not take effect until - * synchronized with the distributed graph using push(). - * \param dev Device to add as a scope for this Map. After taking - * effect, this setting will cause instance updates - * originating from the specified Device to be - * propagated across the Map. + /*! Add a scope to this Map. Map scopes configure the propagation of Signal updates across + * the Map. Changes will not take effect until synchronized with the distributed graph + * using push(). + * \param dev Device to add as a scope for this Map. After taking effect, this + * setting will cause instance updates originating from the specified + * Device to be propagated across the Map. * \return Self. */ inline Map& add_scope(const Device& dev); - /*! Remove a scope from this Map. Map scopes configure the propagation - * of Signal updates across the Map. Changes will not take effect until - * synchronized with the distributed graph using push(). - * \param dev Device to remove as a scope for this Map. After - * taking effect, this setting will cause instance - * updates originating from the specified Device to be - * blocked from propagating across the Map. + /*! Remove a scope from this Map. Map scopes configure the propagation of Signal updates + * across the Map. Changes will not take effect until synchronized with the distributed + * graph using push(). + * \param dev Device to remove as a scope for this Map. After taking effect, this + * setting will cause instance updates originating from the specified + * Device to be blocked from propagating across the Map. * \return Self. */ inline Map& remove_scope(const Device& dev); @@ -569,24 +667,45 @@ namespace mapper { * \param loc MPR_LOC_SRC for source signals for this Map, * MPR_LOC_DST for destinations, or MPR_LOC_ANY for both. * \return A List of Signals. */ - List signals(mpr_loc loc=MPR_LOC_ANY) const - { return List(mpr_map_get_sigs(_obj, loc)); } + List signals(Location loc = Location::ANY) const + { return List(mpr_map_get_sigs(_obj, static_cast(loc))); } OBJ_METHODS(Map); + friend std::ostream& operator<<(std::ostream& os, const mapper::Map& map); + protected: friend class Graph; }; - /*! Signals define inputs or outputs for Devices. A Signal consists of a - * scalar or vector value of some integer or floating-point type. A Signal - * is created by adding an input or output to a Device. It can optionally - * be provided with some metadata such as a range, unit, or other - * properties. Signals can be mapped by creating Maps using remote - * requests on the network, usually generated by a standalone GUI. */ + /*! Signals define inputs or outputs for Devices. A Signal consists of a scalar or vector + * value of some integer or floating-point type. A Signal is created by adding an input or + * output to a Device. It can optionally be provided with some metadata such as a range, + * unit, or other properties. Signals can be mapped by creating Maps using remote requests + * on the network, usually generated by a standalone GUI. */ class Signal : public Object { + protected: + friend class Device; + Signal(mpr_dev dev, mpr_dir dir, const str_type &name, int len, mpr_type type, + const str_type &unit=0, void *min=0, void *max=0, int *num_inst=0) + { + _obj = mpr_sig_new(dev, dir, name, len, type, unit, min, max, num_inst, NULL, 0); + } + public: + /*! The set of possible signal events, used to register and inform callbacks. */ + enum class Event + { + NONE = 0, + INST_NEW = MPR_SIG_INST_NEW, /*!< New instance has been created. */ + REL_UPSTRM = MPR_SIG_REL_UPSTRM, /*!< Instance was released upstream. */ + REL_DNSTRM = MPR_SIG_REL_DNSTRM, /*!< Instance was released downstream. */ + INST_OFLW = MPR_SIG_INST_OFLW, /*!< No local instances left. */ + UPDATE = MPR_SIG_UPDATE, /*!< Instance value has been updated. */ + ALL = MPR_SIG_ALL + }; + Signal() : Object() {} Signal(mpr_sig sig) : Object(sig) {} operator mpr_sig() const @@ -594,16 +713,16 @@ namespace mapper { operator bool() const { return _obj ? true : false; } inline Device device() const; - List maps(mpr_dir dir=MPR_DIR_ANY) const - { return List(mpr_sig_get_maps(_obj, dir)); } + List maps(Direction dir = Direction::ANY) const + { return List(mpr_sig_get_maps(_obj, static_cast(dir))); } /* Value update functions*/ Signal& set_value(const int *val, int len) - { RETURN_SELF(mpr_sig_set_value(_obj, 0, len, MPR_INT32, val)); } + { mpr_sig_set_value(_obj, 0, len, MPR_INT32, val); RETURN_SELF } Signal& set_value(const float *val, int len) - { RETURN_SELF(mpr_sig_set_value(_obj, 0, len, MPR_FLT, val)); } + { mpr_sig_set_value(_obj, 0, len, MPR_FLT, val); RETURN_SELF } Signal& set_value(const double *val, int len) - { RETURN_SELF(mpr_sig_set_value(_obj, 0, len, MPR_DBL, val)); } + { mpr_sig_set_value(_obj, 0, len, MPR_DBL, val); RETURN_SELF } template Signal& set_value(T val) { return set_value(&val, 1); } @@ -623,20 +742,18 @@ namespace mapper { { return mpr_sig_get_value(_obj, 0, 0); } const void *value(Time time) const { return mpr_sig_get_value(_obj, 0, (mpr_time*)time); } - Signal& set_callback(mpr_sig_handler *h, int events=MPR_SIG_UPDATE) - { RETURN_SELF(mpr_sig_set_cb(_obj, h, events)); } - /*! Signal Instances can be used to describe the multiplicity and/or ephemerality - of phenomena associated with Signals. A signal describes the phenomena, e.g. - the position of a 'blob' in computer vision, and the signal's instances will - describe the positions of actual detected blobs. */ + /*! Signal Instances can be used to describe the multiplicity and/or ephemerality of + * phenomena associated with Signals. A signal describes the phenomena, e.g. the position + * of a 'blob' in computer vision, and the signal's instances will describe the positions + * of actual detected blobs. */ class Instance { public: - Instance(mpr_sig sig, mpr_id id) + Instance(mpr_sig sig, Id id) { _sig = sig; _id = id; } - bool operator == (Instance i) + bool operator == (Instance i) const { return (_id == i._id); } - operator mpr_id() const + operator Id() const { return _id; } int is_active() const { return mpr_sig_get_inst_is_active(_sig, _id); } @@ -675,11 +792,11 @@ namespace mapper { Instance& set_value(std::vector val) { return set_value(&val[0], val.size()); } - mpr_id id() const + Id id() const { return _id; } Instance& set_data(void *data) - { RETURN_SELF(mpr_sig_set_inst_data(_sig, _id, data)); } + { mpr_sig_set_inst_data(_sig, _id, data); RETURN_SELF } void *data() const { return mpr_sig_get_inst_data(_sig, _id); } @@ -690,27 +807,220 @@ namespace mapper { mpr_time *_time = time; return mpr_sig_get_value(_sig, _id, _time); } + Signal signal() const + { return Signal(_sig); } protected: friend class Signal; private: mpr_id _id; mpr_sig _sig; }; + friend std::ostream& operator<<(std::ostream& os, const mapper::Signal& sig); + private: + enum handler_type { + NONE = -1, + STANDARD, + SIMPLE, + INST, + SIG_INT, + SIG_FLT, + SIG_DBL, + INST_INT, + INST_FLT, + INST_DBL + }; + typedef struct _handler_data { + union { + void (*standard)(Signal&&, Signal::Event, Id, int, Type, const void*, Time&&); + void (*simple)(Signal&&, int, Type, const void*, Time&&); + void (*inst)(Signal::Instance&&, Signal::Event, int, Type, const void*, Time&&); + void (*sig_int)(Signal&&, int, Time&&); + void (*sig_flt)(Signal&&, float, Time&&); + void (*sig_dbl)(Signal&&, double, Time&&); + void (*inst_int)(Signal::Instance&&, Signal::Event, int, Time&&); + void (*inst_flt)(Signal::Instance&&, Signal::Event, float, Time&&); + void (*inst_dbl)(Signal::Instance&&, Signal::Event, double, Time&&); + } handler; + enum handler_type type; + } *handler_data; + static void _generic_handler(mpr_sig sig, mpr_sig_evt evt, mpr_id inst, int len, + mpr_type type, const void *val, mpr_time time) + { + // recover signal user_data + handler_data data = (handler_data)mpr_obj_get_prop_as_ptr(sig, MPR_PROP_DATA, NULL); + if (!data) + return; + switch (data->type) { + case STANDARD: { + data->handler.standard(Signal(sig), Signal::Event(evt), inst, len, Type(type), + val, Time(time)); + break; + } + case SIMPLE: { + data->handler.simple(Signal(sig), len, Type(type), val, Time(time)); + break; + } + case INST: + data->handler.inst(Signal::Instance(sig, inst), Signal::Event(evt), len, + Type(type), val, Time(time)); + break; + case SIG_INT: + if (val) + data->handler.sig_int(Signal(sig), *(int*)val, Time(time)); + break; + case SIG_FLT: + if (val) + data->handler.sig_flt(Signal(sig), *(float*)val, Time(time)); + break; + case SIG_DBL: + if (val) + data->handler.sig_dbl(Signal(sig), *(double*)val, Time(time)); + break; + case INST_INT: + data->handler.inst_int(Signal::Instance(sig, inst), Signal::Event(evt), + val ? *(int*)val : 0, Time(time)); + break; + case INST_FLT: + data->handler.inst_flt(Signal::Instance(sig, inst), Signal::Event(evt), + val ? *(float*)val : 0, Time(time)); + break; + case INST_DBL: + data->handler.inst_dbl(Signal::Instance(sig, inst), Signal::Event(evt), + val ? *(double*)val : 0, Time(time)); + break; + default: + return; + } + } + void _set_callback(handler_data data, + void (*h)(Signal&&, Signal::Event, Id, int, + Type, const void*, Time&&)) + { + data->type = STANDARD; + data->handler.standard = h; + } + void _set_callback(handler_data data, void (*h)(Signal&&, int, Type, const void*, Time&&)) + { + data->type = SIMPLE; + data->handler.simple = h; + } + void _set_callback(handler_data data, + void (*h)(Signal::Instance&&, Signal::Event, int, + Type, const void*, Time&&)) + { + data->type = INST; + data->handler.inst = h; + } + void _set_callback(handler_data data, void (*h)(Signal&&, int, Time&&)) + { + if (mpr_obj_get_prop_as_int32(_obj, MPR_PROP_TYPE, NULL) != MPR_INT32 + || mpr_obj_get_prop_as_int32(_obj, MPR_PROP_LEN, NULL) != 1) { + printf("wrong type 'i' in handler definition\n"); + data->type = NONE; + return; + } + data->type = SIG_INT; + data->handler.sig_int = h; + } + void _set_callback(handler_data data, void (*h)(Signal&&, float, Time&&)) + { + if (mpr_obj_get_prop_as_int32(_obj, MPR_PROP_TYPE, NULL) != MPR_FLT + || mpr_obj_get_prop_as_int32(_obj, MPR_PROP_LEN, NULL) != 1) { + printf("wrong type 'q' in handler definition\n"); + data->type = NONE; + return; + } + data->type = SIG_FLT; + data->handler.sig_flt = h; + } + void _set_callback(handler_data data, void (*h)(Signal&&, double, Time&&)) + { + if (mpr_obj_get_prop_as_int32(_obj, MPR_PROP_TYPE, NULL) != MPR_DBL + || mpr_obj_get_prop_as_int32(_obj, MPR_PROP_LEN, NULL) != 1) { + printf("wrong type 'd' in handler definition\n"); + data->type = NONE; + return; + } + data->type = SIG_DBL; + data->handler.sig_dbl = h; + } + void _set_callback(handler_data data, void (*h)(Signal::Instance&&, Signal::Event, int, Time&&)) + { + if (mpr_obj_get_prop_as_int32(_obj, MPR_PROP_TYPE, NULL) != MPR_INT32 + || mpr_obj_get_prop_as_int32(_obj, MPR_PROP_LEN, NULL) != 1) { + printf("wrong type 'i' in handler definition\n"); + data->type = NONE; + return; + } + data->type = INST_INT; + data->handler.inst_int = h; + } + void _set_callback(handler_data data, void (*h)(Signal::Instance&&, Signal::Event, float, Time&&)) + { + if (mpr_obj_get_prop_as_int32(_obj, MPR_PROP_TYPE, NULL) != MPR_FLT + || mpr_obj_get_prop_as_int32(_obj, MPR_PROP_LEN, NULL) != 1) { + printf("wrong type 'q' in handler definition\n"); + data->type = NONE; + return; + } + data->type = INST_FLT; + data->handler.inst_flt = h; + } + void _set_callback(handler_data data, void (*h)(Signal::Instance&&, Signal::Event, double, Time&&)) + { + if (mpr_obj_get_prop_as_int32(_obj, MPR_PROP_TYPE, NULL) != MPR_DBL + || mpr_obj_get_prop_as_int32(_obj, MPR_PROP_LEN, NULL) != 1) { + printf("wrong type 'd' in handler definition\n"); + data->type = NONE; + return; + } + data->type = INST_DBL; + data->handler.inst_dbl = h; + } + public: + template + Signal& set_callback(H& h, Signal::Event events = Signal::Event::UPDATE) + { + handler_data data = (handler_data)mpr_obj_get_prop_as_ptr(_obj, MPR_PROP_DATA, NULL); + if (data) + free(data); + if (events > Signal::Event::NONE) { + data = (handler_data)malloc(sizeof(struct _handler_data)); + _set_callback(data, h); + mpr_sig_set_cb(_obj, _generic_handler, static_cast(events)); + mpr_obj_set_prop(_obj, MPR_PROP_DATA, NULL, 1, MPR_PTR, data, 0); + } + else { + mpr_sig_set_cb(_obj, NULL, 0); + mpr_obj_remove_prop(_obj, MPR_PROP_DATA, NULL); + } + RETURN_SELF + } + Signal& set_callback() + { + handler_data data = (handler_data)mpr_obj_get_prop_as_ptr(_obj, MPR_PROP_DATA, NULL); + if (data) { + mpr_sig_set_cb(_obj, NULL, 0); + mpr_obj_remove_prop(_obj, MPR_PROP_DATA, NULL); + free(data); + } + RETURN_SELF + } Instance instance() { mpr_id id = mpr_dev_generate_unique_id(mpr_sig_get_dev(_obj)); return Instance(_obj, id); } - Instance instance(mpr_id id) + Instance instance(Id id) { return Instance(_obj, id); } Signal& reserve_instances(int num, mpr_id *ids = 0) - { RETURN_SELF(mpr_sig_reserve_inst(_obj, num, ids, 0)); } - Signal& reserve_instances(int num, mpr_id *ids, void **data) - { RETURN_SELF(mpr_sig_reserve_inst(_obj, num, ids, data)); } + { mpr_sig_reserve_inst(_obj, num, ids, 0); RETURN_SELF } + Signal& reserve_instances(int num, Id *ids, void **data) + { mpr_sig_reserve_inst(_obj, num, ids, data); RETURN_SELF } Instance instance(int idx, mpr_status status) const { return Instance(_obj, mpr_sig_get_inst_id(_obj, idx, status)); } Signal& remove_instance(Instance instance) - { RETURN_SELF(mpr_sig_remove_inst(_obj, instance._id)); } + { mpr_sig_remove_inst(_obj, instance._id); RETURN_SELF } Instance oldest_instance() { return Instance(_obj, mpr_sig_get_oldest_inst_id(_obj)); } Instance newest_instance() @@ -721,11 +1031,10 @@ namespace mapper { OBJ_METHODS(Signal); }; - /*! A Device is an entity on the network which has input and/or output - * Signals. The Device is the primary interface through which a program - * uses libmapper. A Device must have a name, to which a unique ordinal is - * subsequently appended. It can also be given other user-specified - * metadata. Signals can be mapped using local code or messages over the + /*! A Device is an entity on the network which has input and/or output Signals. The Device is + * the primary interface through which a program uses libmapper. A Device must have a name, + * to which a unique ordinal is subsequently appended. It can also be given other + * user-specified metadata. Signals can be mapped using local code or messages over the * network, usually sent from an external GUI. */ class Device : public Object { @@ -757,12 +1066,17 @@ namespace mapper { incr_refcount(); } Device(mpr_dev dev) : Object(dev) - { - _owned = false; - } + { _owned = false; } ~Device() { if (_owned && _obj && decr_refcount() <= 0) { + mpr_list sigs = mpr_dev_get_sigs(_obj, MPR_DIR_ANY); + while (sigs) { + const void *data = mpr_obj_get_prop_as_ptr((mpr_sig)*sigs, MPR_PROP_DATA, NULL); + if (data) + free((void*)data); + sigs = mpr_list_get_next(sigs); + } mpr_dev_free(_obj); free(_refcount_ptr); } @@ -770,22 +1084,24 @@ namespace mapper { operator mpr_dev() const { return _obj; } - Signal add_signal(mpr_dir dir, const str_type &name, int len, mpr_type type, - const str_type &unit=0, void *min=0, void *max=0, - int *num_inst=0, mpr_sig_handler h=0, - int events=MPR_SIG_UPDATE) + Signal add_signal(Direction dir, const str_type &name, int len, Type type, + const str_type &unit=0, void *min=0, void *max=0, int *num_inst=0) { - return Signal(mpr_sig_new(_obj, dir, name, len, type, - unit, min, max, num_inst, h, events)); + return Signal(_obj, static_cast(dir), name, len, static_cast(type), + unit, min, max, num_inst); } Device& remove_signal(Signal& sig) - { RETURN_SELF(mpr_sig_free(sig)); } + { + sig.set_callback(); + mpr_sig_free(sig); + RETURN_SELF + } - List signals(mpr_dir dir=MPR_DIR_ANY) const - { return List(mpr_dev_get_sigs(_obj, dir)); } + List signals(Direction dir = Direction::ANY) const + { return List(mpr_dev_get_sigs(_obj, static_cast(dir))); } - List maps(mpr_dir dir=MPR_DIR_ANY) const - { return List(mpr_dev_get_maps(_obj, dir)); } + List maps(Direction dir = Direction::ANY) const + { return List(mpr_dev_get_maps(_obj, static_cast(dir))); } int poll(int block_ms=0) const { return mpr_dev_poll(_obj, block_ms); } @@ -795,11 +1111,13 @@ namespace mapper { Time get_time() { return mpr_dev_get_time(_obj); } Device& set_time(Time time) - { RETURN_SELF(mpr_dev_set_time(_obj, *time)); } - Device& process_outputs() - { RETURN_SELF(mpr_dev_process_outputs(_obj)); } + { mpr_dev_set_time(_obj, *time); RETURN_SELF } + Device& update_maps() + { mpr_dev_update_maps(_obj); RETURN_SELF } OBJ_METHODS(Device); + + friend std::ostream& operator<<(std::ostream& os, const mapper::Device& dev); }; class device_type { @@ -810,28 +1128,107 @@ namespace mapper { mpr_dev _dev; }; - /*! Graphs are the primary interface through which a program may observe - * the network and store information about Devices and Signals that are - * present. Each Graph stores records of Devices, Signals, and Maps, - * which can be queried. */ - class Graph + /*! Graphs are the primary interface through which a program may observe the network and store + * information about Devices and Signals that are present. Each Graph stores records of + * Devices, Signals, and Maps, which can be queried. */ + class Graph : public Object { + public: + /*! The set of possible graph events, used to inform callbacks. */ + enum class Event + { + OBJ_NEW = MPR_OBJ_NEW, /*!< New record has been added to the graph. */ + OBJ_MOD = MPR_OBJ_MOD, /*!< The existing record has been modified. */ + OBJ_REM = MPR_OBJ_REM, /*!< The existing record has been removed. */ + OBJ_EXP = MPR_OBJ_EXP /*!< The graph has lost contact with the remote entity. */ + }; + private: + enum handler_type { + OBJECT, + DEVICE, + SIGNAL, + MAP + }; + typedef struct _handler_data { + union { + void (*object)(Graph&&, Object&&, Graph::Event); + void (*device)(Graph&&, Device&&, Graph::Event); + void (*signal)(Graph&&, Signal&&, Graph::Event); + void (*map)(Graph&&, Map&&, Graph::Event); + } handler; + enum handler_type type; + } *handler_data; + static void _generic_handler(mpr_graph g, mpr_obj o, mpr_graph_evt e, const void *user) + { + handler_data data = (handler_data)user; + switch (data->type) { + case OBJECT: + switch (mpr_obj_get_type(o)) { + case MPR_DEV: + data->handler.object(Graph(g), Device(o), Graph::Event(e)); + break; + case MPR_SIG: + data->handler.object(Graph(g), Signal(o), Graph::Event(e)); + break; + case MPR_MAP: + data->handler.object(Graph(g), Map(o), Graph::Event(e)); + break; + } + break; + case DEVICE: + data->handler.device(Graph(g), Device(o), Graph::Event(e)); + break; + case SIGNAL: + data->handler.signal(Graph(g), Signal(o), Graph::Event(e)); + break; + case MAP: + data->handler.map(Graph(g), Map(o), Graph::Event(e)); + break; + } + } + int _set_callback(handler_data data, mpr_type types, + void (*h)(Graph&&, Object&&, Graph::Event)) + { + data->type = OBJECT; + data->handler.object = h; + return types; + } + int _set_callback(handler_data data, mpr_type types, + void (*h)(Graph&&, Device&&, Graph::Event)) + { + data->type = DEVICE; + data->handler.device = h; + return MPR_DEV; + } + int _set_callback(handler_data data, mpr_type types, + void (*h)(Graph&&, Signal&&, Graph::Event)) + { + data->type = SIGNAL; + data->handler.signal = h; + return MPR_SIG; + } + int _set_callback(handler_data data, mpr_type types, + void (*h)(Graph&&, Map&&, Graph::Event)) + { + data->type = MAP; + data->handler.map = h; + return MPR_MAP; + } public: /*! Create a peer in the libmapper distributed graph. - * \param flags Sets whether the graph should automatically - * subscribe to information about Signals and Maps when - * it encounters a previously-unseen Device. + * \param types Sets whether the graph should automatically subscribe to information + * about Signals and Maps when it encounters a previously-unseen Device. * \return The new Graph. */ - Graph(int flags = MPR_OBJ) + Graph(Type types = Type::OBJECT) { - _graph = mpr_graph_new(flags); + _obj = mpr_graph_new(static_cast(types)); _owned = true; _refcount_ptr = (int*)malloc(sizeof(int)); *_refcount_ptr = 1; } Graph(const Graph& orig) { - _graph = orig._graph; + _obj = orig._obj; _owned = orig._owned; _refcount_ptr = orig._refcount_ptr; if (_owned) @@ -839,32 +1236,31 @@ namespace mapper { } Graph(mpr_graph graph) { - _graph = graph; + _obj = graph; _owned = false; _refcount_ptr = 0; } ~Graph() { - if (_owned && _graph && decr_refcount() <= 0) { - mpr_graph_free(_graph); + if (_owned && _obj && decr_refcount() <= 0) { + mpr_graph_free(_obj); free(_refcount_ptr); } } operator mpr_graph() const - { return _graph; } + { return _obj; } /*! Specify the network interface to use. - * \param iface A string specifying the name of the network - * interface to use. + * \param iface A string specifying the name of the network interface to use. * \return Self. */ Graph& set_iface(const str_type &iface) - { RETURN_SELF(mpr_graph_set_interface(_graph, iface)); } + { mpr_graph_set_interface(_obj, iface); RETURN_SELF } /*! Return a string indicating the name of the network interface in use. * \return A string containing the name of the network interface.*/ std::string iface() const { - const char *iface = mpr_graph_get_interface(_graph); + const char *iface = mpr_graph_get_interface(_obj); return iface ? std::string(iface) : 0; } @@ -873,135 +1269,116 @@ namespace mapper { * \param port The multicast port to use. * \return Self. */ Graph& set_address(const str_type &group, int port) - { RETURN_SELF(mpr_graph_set_address(_graph, group, port)); } + { mpr_graph_set_address(_obj, group, port); RETURN_SELF } /*! Retrieve the multicast url currently in use. * \return A string specifying the multicast url in use. */ std::string address() const - { return std::string(mpr_graph_get_address(_graph)); } + { return std::string(mpr_graph_get_address(_obj)); } /*! Update a Graph. - * \param block_ms The number of milliseconds to block, or 0 for - * non-blocking behaviour. + * \param block_ms The number of milliseconds to block, or 0 for non-blocking behavior. * \return The number of handled messages. */ int poll(int block_ms=0) const - { return mpr_graph_poll(_graph, block_ms); } + { return mpr_graph_poll(_obj, block_ms); } // subscriptions /*! Subscribe to information about a specific Device. * \param dev The Device of interest. - * \param flags Bitflags setting the type of information of interest. - * Can be a combination of MPR_DEV, MPR_SIG_IN, - * MPR_SIG_OUT, MPR_SIG, MPR_MAP_IN, MPR_MAP_OUT, - * MPR_MAP, or simply MPR_OBJ for all information. - * \param timeout The desired duration in seconds for this - * subscription. If set to -1, the graph will - * automatically renew the subscription until it is + * \param types Bitflags setting the type of information of interest. Can be a + * combination of MPR_DEV, MPR_SIG_IN, MPR_SIG_OUT, MPR_SIG, MPR_MAP_IN, + * MPR_MAP_OUT, MPR_MAP, or simply MPR_OBJ for all information. + * \param timeout The desired duration in seconds for this subscription. If set to -1, + * the graph will automatically renew the subscription until it is * freed or this function is called again. * \return Self. */ - const Graph& subscribe(const device_type& dev, int flags, int timeout) - { RETURN_SELF(mpr_graph_subscribe(_graph, dev, flags, timeout)); } + const Graph& subscribe(const device_type& dev, Type types, int timeout) + { mpr_graph_subscribe(_obj, dev, static_cast(types), timeout); RETURN_SELF } /*! Subscribe to information about all discovered Devices. - * \param flags Bitflags setting the type of information of interest. - * Can be a combination of MPR_DEV, MPR_SIG_IN, - * MPR_SIG_OUT, MPR_SIG, MPR_MAP_IN, MPR_MAP_OUT, - * MPR_MAP, or simply MPR_OBJ for all information. + * \param types Bitflags setting the type of information of interest. Can be a + * combination of MPR_DEV, MPR_SIG_IN, MPR_SIG_OUT, MPR_SIG, MPR_MAP_IN, + * MPR_MAP_OUT, MPR_MAP, or simply MPR_OBJ for all information. * \return Self. */ - const Graph& subscribe(int flags) - { RETURN_SELF(mpr_graph_subscribe(_graph, 0, flags, -1)); } + const Graph& subscribe(Type types) + { mpr_graph_subscribe(_obj, 0, static_cast(types), -1); RETURN_SELF } /*! Unsubscribe from information about a specific Device. * \param dev The Device of interest. * \return Self. */ const Graph& unsubscribe(const device_type& dev) - { RETURN_SELF(mpr_graph_unsubscribe(_graph, dev)); } + { mpr_graph_unsubscribe(_obj, dev); RETURN_SELF } /*! Cancel all subscriptions. * \return Self. */ const Graph& unsubscribe() - { RETURN_SELF(mpr_graph_unsubscribe(_graph, 0)); } + { mpr_graph_unsubscribe(_obj, 0); RETURN_SELF } - // graph signals - /*! Register a callback for when an Object record is added, updated, or - * removed. + /*! Register a callback for when an Object record is added, updated, or removed. * \param h Callback function. * \param types Bitflags setting the type of information of interest. - * Can be a combination of mpr_type values. - * \param data A user-defined pointer to be passed to the - * callback for context. + * Can be a combination of Type values. * \return Self. */ - const Graph& add_callback(mpr_graph_handler *h, int types, void *data) const - { RETURN_SELF(mpr_graph_add_cb(_graph, h, types, data)); } + template + const Graph& add_callback(void (*h)(Graph&&, T&&, Graph::Event), + Type types = Type::OBJECT) + { + handler_data data = (handler_data)malloc(sizeof(struct _handler_data)); + int mtypes = _set_callback(data, static_cast(types), h); + mpr_graph_add_cb(_obj, _generic_handler, mtypes, data); + RETURN_SELF + } /*! Remove an Object record callback from the Graph service. * \param h Callback function. - * \param data The user context pointer that was originally - * specified when adding the callback * \return Self. */ - const Graph& remove_callback(mpr_graph_handler *h, void *data) const - { RETURN_SELF(mpr_graph_remove_cb(_graph, h, data)); } + const Graph& remove_callback(void (*h)(Graph&&, Object&&, Graph::Event)) + { + // need to recover and free data + void *data = mpr_graph_remove_cb(_obj, _generic_handler, reinterpret_cast(h)); + if (data) + free(data); + RETURN_SELF + } const Graph& print() const - { RETURN_SELF(mpr_graph_print(_graph)); } + { mpr_graph_print(_obj); RETURN_SELF } // graph devices List devices() const - { return List(mpr_graph_get_objs(_graph, MPR_DEV)); } + { return List(mpr_graph_get_objs(_obj, MPR_DEV)); } // graph signals List signals() const - { return List(mpr_graph_get_objs(_graph, MPR_SIG)); } + { return List(mpr_graph_get_objs(_obj, MPR_SIG)); } // graph maps List maps() const - { return List(mpr_graph_get_objs(_graph, MPR_MAP)); } + { return List(mpr_graph_get_objs(_obj, MPR_MAP)); } - private: - mpr_graph _graph; - int* _refcount_ptr; - int incr_refcount() - { return _refcount_ptr ? ++(*_refcount_ptr) : 0; } - int decr_refcount() - { return _refcount_ptr ? --(*_refcount_ptr) : 0; } - bool _owned; + OBJ_METHODS(Graph); }; - class Property + class PropVal { - public: - template - Property(mpr_prop _prop, T _val) : Property(_prop) - { _set(_val); } - template - Property(const str_type &_key, T _val) : Property(_key) + protected: + template + PropVal(P&& _prop, T&& _val) : PropVal(_prop) { _set(_val); } - template - Property(mpr_prop _prop, int _len, T& _val) : Property(_prop) - { _set(_len, _val); } - template - Property(const str_type &_key, int _len, T& _val) : Property(_key) + template + PropVal(P&& _prop, int _len, T&& _val) : PropVal(_prop) { _set(_len, _val); } - template - Property(mpr_prop _prop, std::array _val) : Property(_prop) - { _set(_val); } - template - Property(const str_type &_key, std::array _val) : Property(_key) - { _set(_val); } - template - Property(mpr_prop _prop, std::vector _val) : Property(_prop) + template + PropVal(P&& _prop, std::array _val) : PropVal(_prop) { _set(_val); } - template - Property(const str_type &_key, std::vector _val) : Property(_key) + template + PropVal(P&& _prop, std::vector _val) : PropVal(_prop) { _set(_val); } - template - Property(mpr_prop _prop, int _len, mpr_type _type, T& _val) : Property(_prop) - { _set(_len, _type, _val); } - template - Property(const str_type &_key, int _len, mpr_type _type, T& _val) : Property(_key) + template + PropVal(P&& _prop, int _len, Type _type, T&& _val) : PropVal(_prop) { _set(_len, _type, _val); } - - ~Property() + public: + ~PropVal() { maybe_free(); } template @@ -1020,9 +1397,30 @@ namespace mapper { } template operator const T*() const - { return (const T*)val; } + { return (const T*)(len > 1 ? val : &val); } + operator const char*() const + { + if (!val || !len || type != MPR_STR) + return NULL; + return len > 1 ? ((const char**)val)[0] : (const char*)val; + } operator const char**() const - { return (const char**)val; } + { + if (!val || !len || type != MPR_STR) + return NULL; + return (const char**)(len > 1 ? val : &val); + } + operator std::string() const + { + if (!val || !len || type != MPR_STR) + return NULL; + return std::string(len > 1 ? *(const char**)val : (const char*)val); + } + operator void*() const + { + if (MPR_PTR != type) return 0; + return (void*)val; + } template operator const std::array() const { @@ -1061,7 +1459,7 @@ namespace mapper { operator const std::vector() const { std::vector temp_v; - for (int i = 0; i < len; i++) + for (unsigned int i = 0; i < len; i++) temp_v.push_back(((T*)val)[i]); return temp_v; } @@ -1097,22 +1495,27 @@ namespace mapper { { return (type == MPR_LIST) ? (mpr_list)val : NULL; } template - Property& operator = (Values... vals) - { RETURN_SELF(_set(vals...)); } + PropVal& operator = (Values... vals) + { _set(vals...); RETURN_SELF } + + friend std::ostream& operator<<(std::ostream& os, const PropVal& p); + protected: mpr_prop prop; const char *key; mpr_type type; unsigned int len; const void *val; bool pub; - protected: friend class Graph; friend class Object; + friend class List; + friend class List; + friend class List; mpr_obj parent = NULL; - Property(mpr_prop _prop, const str_type &_key, int _len, mpr_type _type, - const void *_val, int _pub) + PropVal(mpr_prop _prop, const str_type &_key, int _len, mpr_type _type, + const void *_val, int _pub) { prop = _prop; key = _key; @@ -1120,15 +1523,15 @@ namespace mapper { owned = false; pub = _pub; } - Property(mpr_prop _prop) + PropVal(Property _prop) { - prop = _prop; + prop = static_cast(_prop); key = NULL; val = 0; owned = false; pub = true; } - Property(const str_type &_key) + PropVal(const str_type&& _key) { prop = MPR_PROP_UNKNOWN; key = _key; @@ -1160,6 +1563,7 @@ namespace mapper { type = _type; val = _val; len = _len; + pub = (MPR_PTR == _type); maybe_update(); } void _set(int _len, bool _val[]) @@ -1177,6 +1581,8 @@ namespace mapper { owned = true; maybe_update(); } + void _set(int _len, void* _val[]) + { _set(_len, MPR_PTR, (1 == _len) ? (void*)_val[0] : _val); } void _set(int _len, int _val[]) { _set(_len, MPR_INT32, _val); } void _set(int _len, float _val[]) @@ -1190,6 +1596,9 @@ namespace mapper { template void _set(const T _val) { _set(1, (T*)&_val); } + template + void _set(const T* _val) + { _set(1, (const T**)&_val); } template void _set(const std::array& _val) { @@ -1291,77 +1700,74 @@ namespace mapper { } void _set(mpr_list _val) { _set(1, MPR_LIST, _val); } - }; - void Object::set_property(const Property& p) - { - mpr_obj_set_prop(_obj, p.prop, p.key, p.len, p.type, p.val, p.pub); - } + // handle some enum classes + void _set(Direction dir) + { _set(static_cast(dir)); } + void _set(Map::Location loc) + { _set(static_cast(loc)); } + void _set(Map::Protocol proto) + { _set(static_cast(proto)); } + void _set(Map::Stealing stl) + { _set(static_cast(stl)); } + }; template - Object& Object::set_property(const Values... vals) + inline Object& Object::set_property(const Values... vals) { - Property p(vals...); - set_property(p); + PropVal p(vals...); + if (p.prop != MPR_PROP_DATA && (!p.key || strcmp(p.key, "data"))) + mpr_obj_set_prop(_obj, p.prop, p.key, p.len, p.type, p.val, p.pub); return (*this); } - Property Object::property(const str_type &key) const + inline PropVal Object::property(const str_type &key) const { mpr_prop prop; mpr_type type; const void *val; int len, pub; prop = mpr_obj_get_prop_by_key(_obj, key, &len, &type, &val, &pub); - Property p(prop, key, len, type, val, pub); + PropVal p(prop, key, len, type, val, pub); p.parent = _obj; return p; } - /*! Retrieve a Property by index. - * \param prop The index or symbolic identifier of the Property to retrieve. - * \return The retrieved Property. */ - Property Object::property(mpr_prop prop) const + /*! Retrieve a PropVal by index. + * \param prop The index or symbolic identifier of the PropVal to retrieve. + * \return The retrieved PropVal. */ + inline PropVal Object::property(Property prop) const { const char *key; mpr_type type; const void *val; int len, pub; - prop = mpr_obj_get_prop_by_idx(_obj, prop, &key, &len, &type, &val, &pub); - Property p(prop, key, len, type, val, pub); + mpr_prop mprop = mpr_obj_get_prop_by_idx(_obj, static_cast(prop), + &key, &len, &type, &val, &pub); + PropVal p(mprop, key, len, type, val, pub); p.parent = _obj; return p; } template - Property Object::operator [] (const T prop) const + inline PropVal Object::operator [] (const T prop) const { return property(prop); } template - List::operator std::vector() const - { - std::vector vec; - mpr_list cpy = mpr_list_get_cpy(_list); - while (cpy) { - vec.push_back(Object(*cpy)); - cpy = mpr_list_get_next(cpy); - } - return vec; - } - - template - List& List::filter(const Property& p, mpr_op op) + template + inline List& List::filter(P&& property, V&& value, Operator op) { - _list = mpr_list_filter(_list, p.prop, p.key, p.len, p.type, p.val, op); + PropVal p(property, value); + _list = mpr_list_filter(_list, p.prop, p.key, p.len, p.type, p.val, static_cast(op)); return (*this); } template template - List& List::set_property(const Values... vals) + inline List& List::set_property(const Values... vals) { - Property p(vals...); - if (!p) + PropVal p(vals...); + if (!p || p.prop == MPR_PROP_DATA || (p.key && !strcmp(p.key, "data"))) return (*this); mpr_list cpy = mpr_list_get_cpy(_list); while (cpy) { @@ -1371,10 +1777,10 @@ namespace mapper { return (*this); } - Graph Object::graph() const + inline Graph Object::graph() const { return Graph(mpr_obj_get_graph(_obj)); } - Device::Device(const str_type &name, const Graph& graph) : Object(NULL) + inline Device::Device(const str_type &name, const Graph& graph) : Object(NULL) { _obj = mpr_dev_new(name, graph); _owned = true; @@ -1382,99 +1788,109 @@ namespace mapper { *_refcount_ptr = 1; } - signal_type::signal_type(const Signal& sig) + inline signal_type::signal_type(const Signal& sig) { _sig = (mpr_sig)sig; } - Map& Map::add_scope(const Device& dev) - { RETURN_SELF(mpr_map_add_scope(_obj, mpr_dev(dev))); } + inline Map& Map::add_scope(const Device& dev) + { mpr_map_add_scope(_obj, mpr_dev(dev)); RETURN_SELF } - Map& Map::remove_scope(const Device& dev) - { RETURN_SELF(mpr_map_remove_scope(_obj, mpr_dev(dev))); } + inline Map& Map::remove_scope(const Device& dev) + { mpr_map_remove_scope(_obj, mpr_dev(dev)); RETURN_SELF } - Device Signal::device() const + inline Device Signal::device() const { return Device(mpr_sig_get_dev(_obj)); } inline std::string version() { return std::string(mpr_get_version()); } -}; -#define OSTREAM_TYPE(TYPE) \ -if (p.len == 1) \ - os << *(TYPE*)p.val; \ -else if (p.len > 1) { \ - os << "["; \ - for (unsigned int i = 0; i < p.len; i++)\ - os << ((TYPE*)p.val)[i] << ", "; \ - os << "\b\b]"; \ -} - -std::ostream& operator<<(std::ostream& os, const mapper::Property& p) -{ - if (p.len <= 0 || p.type == MPR_NULL) - return os << "NULL"; - switch (p.type) { - case MPR_INT32: OSTREAM_TYPE(int); break; - case MPR_INT64: OSTREAM_TYPE(int64_t); break; - case MPR_FLT: OSTREAM_TYPE(float); break; - case MPR_DBL: OSTREAM_TYPE(double); break; - case MPR_BOOL: OSTREAM_TYPE(bool); break; - case MPR_STR: - if (p.len == 1) - os << (const char*)p.val; - else if (p.len > 1) { - os << "["; - for (unsigned int i = 0; i < p.len; i++) - os << ((const char**)p.val)[i] << ", "; - os << "\b\b]"; - } - break; - default: - os << "Property type not handled by ostream operator!"; + inline constexpr Type operator|(Type l, Type r) + { + return static_cast(static_cast(l) | static_cast(r)); + } + + inline constexpr Signal::Event operator|(Signal::Event l, Signal::Event r) + { + return static_cast(static_cast(l) | static_cast(r)); + } + + #define OSTREAM_TYPE(TYPE) \ + if (p.len == 1) \ + os << *(TYPE*)p.val; \ + else if (p.len > 1) { \ + os << "["; \ + for (unsigned int i = 0; i < p.len; i++)\ + os << ((TYPE*)p.val)[i] << ", "; \ + os << "\b\b]"; \ + } + + inline std::ostream& operator<<(std::ostream& os, const PropVal& p) + { + if (p.len <= 0 || p.type == MPR_NULL) + return os << "NULL"; + switch (p.type) { + case MPR_INT32: OSTREAM_TYPE(int); break; + case MPR_INT64: OSTREAM_TYPE(int64_t); break; + case MPR_FLT: OSTREAM_TYPE(float); break; + case MPR_DBL: OSTREAM_TYPE(double); break; + case MPR_BOOL: OSTREAM_TYPE(bool); break; + case MPR_STR: + if (p.len == 1) + os << (const char*)p.val; + else if (p.len > 1) { + os << "["; + for (unsigned int i = 0; i < p.len; i++) + os << ((const char**)p.val)[i] << ", "; + os << "\b\b]"; + } + break; + default: + os << "Property type not handled by ostream operator!"; + } + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const Device& dev) + { + return os << ""; + } + + inline std::ostream& operator<<(std::ostream& os, const Signal& sig) + { + os << ""; + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const Map& map) + { + os << " "; + + // add destinations + os << "["; + for (const Signal s : map.signals(Map::Location::DST)) + os << s << ", "; + os << "\b\b]"; + + os << ">"; + return os; } - return os; -} - -std::ostream& operator<<(std::ostream& os, const mapper::Device& dev) -{ - return os << ""; -} - -std::ostream& operator<<(std::ostream& os, const mapper::Signal& sig) -{ - os << ""; - return os; -} - -std::ostream& operator<<(std::ostream& os, const mapper::Map& map) -{ - os << " "; - - // add destinations - os << "["; - for (const mapper::Signal s : map.signals(MPR_LOC_DST)) - os << s << ", "; - os << "\b\b]"; - - os << ">"; - return os; -} - -std::ostream& operator<<(std::ostream& os, const mapper::Object& o) -{ - mpr_obj obj = (mpr_obj)o; - switch (mpr_obj_get_type(obj)) { - case MPR_DEV: os << mapper::Device(obj); break; - case MPR_SIG: os << mapper::Signal(obj); break; - case MPR_MAP: os << mapper::Map(obj); break; - default: break; + + inline std::ostream& operator<<(std::ostream& os, const Object& o) + { + mpr_obj obj = (mpr_obj)o; + switch (mpr_obj_get_type(obj)) { + case MPR_DEV: os << Device(obj); break; + case MPR_SIG: os << Signal(obj); break; + case MPR_MAP: os << Map(obj); break; + default: break; + } + return os; } - return os; -} +}; #endif // _MPR_CPP_H_ diff --git a/src/mapper/mapper_internal.h b/src/mapper/mapper_internal.h index b069c8f..abf3458 100644 --- a/src/mapper/mapper_internal.h +++ b/src/mapper/mapper_internal.h @@ -9,9 +9,10 @@ /* Structs that refer to things defined in mapper.h are declared here instead of in types_internal.h */ -#define RETURN_UNLESS(a, ...) { if (!(a)) { return __VA_ARGS__; }} -#define DONE_UNLESS(a) { if (!(a)) { goto done; }} -#define FUNC_IF(a, b) { if (b) { a(b); }} +#define RETURN_UNLESS(condition) { if (!(condition)) { return; }} +#define RETURN_ARG_UNLESS(condition, arg) { if (!(condition)) { return arg; }} +#define DONE_UNLESS(condition) { if (!(condition)) { goto done; }} +#define FUNC_IF(func, arg) { if (arg) { func(arg); }} #define PROP(NAME) MPR_PROP_##NAME #if DEBUG @@ -24,47 +25,47 @@ if (!(a)) { trace_dev(dev, __VA_ARGS__); return ret; } #define TRACE_DEV_RETURN_UNLESS(a, ret, ...) if (!(a)) { return ret; } #endif +#if defined(WIN32) || defined(_MSC_VER) +#define MPR_INLINE __inline +#else +#define MPR_INLINE __inline +#endif + /**** Debug macros ****/ /*! Debug tracer */ -#ifdef DEBUG #ifdef __GNUC__ +#ifdef DEBUG #include #include #define trace(...) { printf("-- " __VA_ARGS__); } #define trace_graph(...) { printf("\x1B[31m-- \x1B[0m " __VA_ARGS__);} -#define trace_dev(DEV, ...) \ -{ \ - if (!DEV) \ - printf("\x1B[32m-- \x1B[0m "); \ - else if (DEV->loc && DEV->loc->registered) \ - printf("\x1B[32m-- \x1B[0m ", mpr_dev_get_name(DEV)); \ - else \ - printf("\x1B[32m-- \x1B[0m ", DEV->prefix, DEV); \ - printf(__VA_ARGS__); \ +#define trace_dev(DEV, ...) \ +{ \ + if (!DEV) \ + printf("\x1B[32m-- \x1B[0m "); \ + else if (DEV->is_local && ((mpr_local_dev)DEV)->registered) \ + printf("\x1B[32m-- \x1B[0m ", mpr_dev_get_name((mpr_dev)DEV)); \ + else \ + printf("\x1B[32m-- \x1B[0m ", DEV->prefix, DEV); \ + printf(__VA_ARGS__); \ } #define trace_net(...) { printf("\x1B[33m-- \x1B[0m " __VA_ARGS__);} #define die_unless(a, ...) { if (!(a)) { printf("-- " __VA_ARGS__); assert(a); } } -#else -static void trace(...) -{ -}; -static void die_unless(...) {}; -#endif -#else -#ifdef __GNUC__ +#else /* !DEBUG */ #define trace(...) {} #define trace_graph(...) {} #define trace_dev(...) {} #define trace_net(...) {} #define die_unless(...) {} -#else -static void trace(...) -{ -}; +#endif /* DEBUG */ +#else /* !__GNUC__ */ +static void trace(...) {}; +static void trace_graph(...) {}; +static void trace_dev(...) {}; +static void trace_net(...) {}; static void die_unless(...) {}; -#endif -#endif +#endif /* __GNUC__ */ /**** Subscriptions ****/ #ifdef DEBUG @@ -78,9 +79,9 @@ void mpr_obj_increment_version(mpr_obj obj); /**** Networking ****/ -void mpr_net_add_dev(mpr_net n, mpr_dev d); +void mpr_net_add_dev(mpr_net n, mpr_local_dev d); -void mpr_net_remove_dev_methods(mpr_net n, mpr_dev d); +void mpr_net_remove_dev_methods(mpr_net n, mpr_local_dev d); void mpr_net_poll(mpr_net n); @@ -90,7 +91,7 @@ void mpr_net_use_bus(mpr_net n); void mpr_net_use_mesh(mpr_net n, lo_address addr); -void mpr_net_use_subscribers(mpr_net net, mpr_dev dev, int type); +void mpr_net_use_subscribers(mpr_net net, mpr_local_dev dev, int type); void mpr_net_add_msg(mpr_net n, const char *str, net_msg_t cmd, lo_message msg); @@ -111,7 +112,7 @@ if (!VARNAME) { \ int mpr_dev_set_from_msg(mpr_dev dev, mpr_msg msg); -void mpr_dev_manage_subscriber(mpr_dev dev, lo_address address, int flags, +void mpr_dev_manage_subscriber(mpr_local_dev dev, lo_address address, int flags, int timeout_seconds, int revision); /*! Return the list of inter-device links associated with a given device. @@ -122,7 +123,13 @@ mpr_list mpr_dev_get_links(mpr_dev dev, mpr_dir dir); mpr_list mpr_dev_get_maps(mpr_dev dev, mpr_dir dir); -mpr_id mpr_dev_get_unused_sig_id(mpr_dev dev); +/*! Find information for a registered signal. + * \param dev The device to query. + * \param sig_name Name of the signal to find in the graph. + * \return Information about the signal, or zero if not found. */ +mpr_sig mpr_dev_get_sig_by_name(mpr_dev dev, const char *sig_name); + +mpr_id mpr_dev_get_unused_sig_id(mpr_local_dev dev); int mpr_dev_add_link(mpr_dev dev, mpr_dev rem); void mpr_dev_remove_link(mpr_dev dev, mpr_dev rem); @@ -132,35 +139,33 @@ int mpr_dev_handler(const char *path, const char *types, lo_arg **argv, int argc int mpr_dev_bundle_start(lo_timetag t, void *data); -inline static void mpr_dev_LID_incref(mpr_dev dev, mpr_id_map map) +MPR_INLINE static void mpr_dev_LID_incref(mpr_local_dev dev, mpr_id_map map) { ++map->LID_refcount; } -inline static void mpr_dev_GID_incref(mpr_dev dev, mpr_id_map map) +MPR_INLINE static void mpr_dev_GID_incref(mpr_local_dev dev, mpr_id_map map) { ++map->GID_refcount; } -int mpr_dev_LID_decref(mpr_dev dev, int group, mpr_id_map map); +int mpr_dev_LID_decref(mpr_local_dev dev, int group, mpr_id_map map); -int mpr_dev_GID_decref(mpr_dev dev, int group, mpr_id_map map); +int mpr_dev_GID_decref(mpr_local_dev dev, int group, mpr_id_map map); void init_dev_prop_tbl(mpr_dev dev); -void mpr_dev_on_registered(mpr_dev dev); +void mpr_dev_on_registered(mpr_local_dev dev); -void mpr_dev_add_sig_methods(mpr_dev dev, mpr_sig sig); +void mpr_dev_add_sig_methods(mpr_local_dev dev, mpr_local_sig sig); -void mpr_dev_remove_sig_methods(mpr_dev dev, mpr_sig sig); +void mpr_dev_remove_sig_methods(mpr_local_dev dev, mpr_local_sig sig); -void mpr_dev_release_scope(mpr_dev dev, const char *scope); +mpr_id_map mpr_dev_add_idmap(mpr_local_dev dev, int group, mpr_id LID, mpr_id GID); -mpr_id_map mpr_dev_add_idmap(mpr_dev dev, int group, mpr_id LID, mpr_id GID); +mpr_id_map mpr_dev_get_idmap_by_LID(mpr_local_dev dev, int group, mpr_id LID); -mpr_id_map mpr_dev_get_idmap_by_LID(mpr_dev dev, int group, mpr_id LID); - -mpr_id_map mpr_dev_get_idmap_by_GID(mpr_dev dev, int group, mpr_id GID); +mpr_id_map mpr_dev_get_idmap_by_GID(mpr_local_dev dev, int group, mpr_id GID); const char *mpr_dev_get_name(mpr_dev dev); @@ -170,7 +175,7 @@ void mpr_dev_send_state(mpr_dev dev, net_msg_t cmd); * \param dev Device record to query. * \param remote Remote device. * \return Information about the link, or zero if not found. */ -mpr_link mpr_dev_get_link_by_remote(mpr_dev dev, mpr_dev remote); +mpr_link mpr_dev_get_link_by_remote(mpr_local_dev dev, mpr_dev remote); /*! Look up information for a registered object using its unique id. * \param g The graph to query. @@ -185,38 +190,38 @@ mpr_obj mpr_graph_get_obj(mpr_graph g, mpr_type type, mpr_id id); * \return Information about the device, or zero if not found. */ mpr_dev mpr_graph_get_dev_by_name(mpr_graph g, const char *name); -mpr_map mpr_graph_get_map_by_names(mpr_graph g, int num_src, const char **srcs, - const char *dst); +mpr_map mpr_graph_get_map_by_names(mpr_graph g, int num_src, const char **srcs, const char *dst); -void mpr_graph_cleanup(mpr_graph g); +/*! Call registered graph callbacks for a given object type. + * \param g The graph to query. + * \param o The object to pass to the callbacks. + * \param t The object type. + * \param e The graph event type. */ +void mpr_graph_call_cbs(mpr_graph g, mpr_obj o, mpr_type t, mpr_graph_evt e); -/*! Find information for a registered signal. - * \param dev The device to query. - * \param sig_name Name of the signal to find in the graph. - * \return Information about the signal, or zero if not found. */ -mpr_sig mpr_dev_get_sig_by_name(mpr_dev dev, const char *sig_name); +void mpr_graph_cleanup(mpr_graph g); /***** Router *****/ void mpr_rtr_remove_sig(mpr_rtr r, mpr_rtr_sig rs); -void mpr_rtr_num_inst_changed(mpr_rtr r, mpr_sig s, int size); +void mpr_rtr_num_inst_changed(mpr_rtr r, mpr_local_sig sig, int size); -void mpr_rtr_remove_inst(mpr_rtr rtr, mpr_sig sig, int idx); +void mpr_rtr_remove_inst(mpr_rtr rtr, mpr_local_sig sig, int idx); /*! For a given signal instance, calculate mapping outputs and forward to * destinations. */ -void mpr_rtr_process_sig(mpr_rtr r, mpr_sig s, int inst_idx, const void *val, mpr_time t); +void mpr_rtr_process_sig(mpr_rtr rtr, mpr_local_sig sig, int inst_idx, const void *val, mpr_time t); -void mpr_rtr_add_map(mpr_rtr r, mpr_map m); +void mpr_rtr_add_map(mpr_rtr rtr, mpr_local_map map); -void mpr_rtr_remove_link(mpr_rtr r, mpr_link l); +void mpr_rtr_remove_link(mpr_rtr rtr, mpr_link lnk); -int mpr_rtr_remove_map(mpr_rtr r, mpr_map m); +int mpr_rtr_remove_map(mpr_rtr rtr, mpr_local_map map); -mpr_slot mpr_rtr_get_slot(mpr_rtr r, mpr_sig s, int slot_num); +mpr_local_slot mpr_rtr_get_slot(mpr_rtr rtr, mpr_local_sig sig, int slot_num); -int mpr_rtr_loop_check(mpr_rtr r, mpr_sig s, int n_remote, const char **remote); +int mpr_rtr_loop_check(mpr_rtr rtr, mpr_local_sig sig, int n_remote, const char **remote); /**** Signals ****/ @@ -235,21 +240,21 @@ void mpr_sig_init(mpr_sig s, mpr_dir dir, const char *name, int len, * cases the name may not be available. */ int mpr_sig_get_full_name(mpr_sig sig, char *name, int len); -void mpr_sig_call_handler(mpr_sig sig, int evt, mpr_id inst, int len, +void mpr_sig_call_handler(mpr_local_sig sig, int evt, mpr_id inst, int len, const void *val, mpr_time *time, float diff); int mpr_sig_set_from_msg(mpr_sig sig, mpr_msg msg); -void mpr_sig_update_timing_stats(mpr_sig sig, float diff); +void mpr_sig_update_timing_stats(mpr_local_sig sig, float diff); /*! Free memory used by a mpr_sig. Call this only for signals that are not * registered with a device. Registered signals will be freed by mpr_sig_free(). * \param s The signal to free. */ -void mpr_sig_free_internal(mpr_sig s); +void mpr_sig_free_internal(mpr_sig sig); -void mpr_sig_send_state(mpr_sig s, net_msg_t cmd); +void mpr_sig_send_state(mpr_sig sig, net_msg_t cmd); -void mpr_sig_send_removed(mpr_sig s); +void mpr_sig_send_removed(mpr_local_sig sig); /**** Instances ****/ @@ -261,11 +266,11 @@ void mpr_sig_send_removed(mpr_sig s); * instances. * \param t Time associated with this action. * \param activate Set to 1 to activate a reserved instance if necessary. - * \return The index of the retrieved signal instance, or -1 if no free + * \return The index of the retrieved instance id map, or -1 if no free * instances were available and allocation of a new instance * was unsuccessful according to the selected allocation * strategy. */ -int mpr_sig_get_idmap_with_LID(mpr_sig s, mpr_id LID, int flags, mpr_time t, int activate); +int mpr_sig_get_idmap_with_LID(mpr_local_sig sig, mpr_id LID, int flags, mpr_time t, int activate); /*! Fetch a reserved (preallocated) signal instance using instance id map, * activating it if necessary. @@ -274,25 +279,25 @@ int mpr_sig_get_idmap_with_LID(mpr_sig s, mpr_id LID, int flags, mpr_time t, int * \param flags Bitflags indicating if search should include released instances. * \param t Time associated with this action. * \param activate Set to 1 to activate a reserved instance if necessary. - * \return The index of the retrieved signal instance, or NULL if no free + * \return The index of the retrieved instance id map, or -1 if no free * instances were available and allocation of a new instance * was unsuccessful according to the selected allocation * strategy. */ -int mpr_sig_get_idmap_with_GID(mpr_sig s, mpr_id GID, int flags, mpr_time t, int activate); +int mpr_sig_get_idmap_with_GID(mpr_local_sig sig, mpr_id GID, int flags, mpr_time t, int activate); /*! Release a specific signal instance. */ -void mpr_sig_release_inst_internal(mpr_sig s, int inst_idx); +void mpr_sig_release_inst_internal(mpr_local_sig sig, int inst_idx); /**** Links ****/ -mpr_link mpr_link_new(mpr_dev local_dev, mpr_dev remote_dev); +mpr_link mpr_link_new(mpr_local_dev local_dev, mpr_dev remote_dev); /*! Return the list of maps associated with a given link. * \param link The link to check. * \return The list of results. Use mpr_list_next() to iterate. */ mpr_list mpr_link_get_maps(mpr_link link); -void mpr_link_remove_map(mpr_link link, mpr_map rem); +void mpr_link_remove_map(mpr_link link, mpr_local_map rem); void mpr_link_init(mpr_link link); void mpr_link_connect(mpr_link link, const char *host, int admin_port, @@ -307,18 +312,17 @@ int mpr_link_get_is_local(mpr_link link); /**** Maps ****/ -void mpr_map_alloc_values(mpr_map map); +void mpr_map_alloc_values(mpr_local_map map); /*! Process the signal instance value according to mapping properties. * The result of this operation should be sent to the destination. * \param map The mapping process to perform. - * \param typestring Pointer to a string to receive types. - * \param time Timestamp for this update. - * \param inst Index of the signal instance to process. - * \return Zero if the operation was muted, one if performed. */ -int mpr_map_perform(mpr_map map, mpr_type *typestring, mpr_time *time, int inst); + * \param time Timestamp for this update. */ +void mpr_map_send(mpr_local_map map, mpr_time time); + +void mpr_map_receive(mpr_local_map map, mpr_time time); -lo_message mpr_map_build_msg(mpr_map map, mpr_slot slot, const void *val, +lo_message mpr_map_build_msg(mpr_local_map map, mpr_local_slot slot, const void *val, mpr_type *types, mpr_id_map idmap); /*! Set a mapping's properties based on message parameters. */ @@ -340,24 +344,21 @@ void mpr_map_free(mpr_map map); /**** Slot ****/ -mpr_slot mpr_slot_new(mpr_map map, mpr_sig sig, int is_src); +mpr_slot mpr_slot_new(mpr_map map, mpr_sig sig, unsigned char is_local, unsigned char is_src); -void mpr_slot_init(mpr_slot slot); - -void mpr_slot_alloc_values(mpr_slot slot, int num_inst, int hist_size); +void mpr_slot_alloc_values(mpr_local_slot slot, int num_inst, int hist_size); void mpr_slot_free(mpr_slot slot); -void mpr_slot_free_value(mpr_slot slot); +void mpr_slot_free_value(mpr_local_slot slot); int mpr_slot_set_from_msg(mpr_slot slot, mpr_msg msg); -void mpr_slot_add_props_to_msg(lo_message msg, mpr_slot slot, int is_dest, - int staged); +void mpr_slot_add_props_to_msg(lo_message msg, mpr_slot slot, int is_dest, int staged); int mpr_slot_match_full_name(mpr_slot slot, const char *full_name); -void mpr_slot_remove_inst(mpr_slot slot, int idx); +void mpr_slot_remove_inst(mpr_local_slot slot, int idx); /**** Graph ****/ @@ -382,10 +383,9 @@ mpr_sig mpr_graph_add_sig(mpr_graph g, const char *sig_name, * \param num_src The number of source slots for this map * \param src_names The full names of the source signals. * \param dst_name The full name of the destination signal. - * \param msg The parsed message parameters containing new metadata. * \return Pointer to the map. */ -mpr_map mpr_graph_add_map(mpr_graph g, int num_src, const char **src_names, - const char *dst_name, mpr_msg msg); +mpr_map mpr_graph_add_map(mpr_graph g, mpr_id id, int num_src, const char **src_names, + const char *dst_name); /*! Remove a device from the graph. */ void mpr_graph_remove_dev(mpr_graph g, mpr_dev dev, mpr_graph_evt evt, int quiet); @@ -448,6 +448,8 @@ int mpr_expr_get_num_vars(mpr_expr expr); int mpr_expr_get_var_vec_len(mpr_expr expr, int idx); +int mpr_expr_get_var_type(mpr_expr expr, int idx); + int mpr_expr_get_src_is_muted(mpr_expr expr, int idx); const char *mpr_expr_get_var_name(mpr_expr expr, int idx); @@ -483,6 +485,8 @@ int mpr_expr_get_num_input_slots(mpr_expr expr); void mpr_expr_free(mpr_expr expr); +void mpr_expr_free_buffers(); + /**** String tables ****/ /*! Create a new string table. */ @@ -503,11 +507,11 @@ int mpr_tbl_get_size(mpr_tbl tab); * and fills in value if found. */ mpr_tbl_record mpr_tbl_get(mpr_tbl tab, mpr_prop prop, const char *key); -int mpr_tbl_get_prop_by_key(mpr_tbl tab, const char *key, int *len, - mpr_type *type, const void **val, int *pub); +mpr_prop mpr_tbl_get_prop_by_key(mpr_tbl tab, const char *key, int *len, + mpr_type *type, const void **val, int *pub); -int mpr_tbl_get_prop_by_idx(mpr_tbl tab, mpr_prop prop, const char **key, - int *len, mpr_type *type, const void **val, int *pub); +mpr_prop mpr_tbl_get_prop_by_idx(mpr_tbl tab, mpr_prop prop, const char **key, + int *len, mpr_type *type, const void **val, int *pub); /*! Remove a key-value pair from a table (by index or name). */ int mpr_tbl_remove(mpr_tbl tab, mpr_prop prop, const char *key, int flags); @@ -552,6 +556,8 @@ void mpr_tbl_add_to_msg(mpr_tbl tab, mpr_tbl updates, lo_message msg); * removal to propagate to subscribed graph instances and peer devices. */ void mpr_tbl_clear_empty(mpr_tbl tab); +int match_pattern(const char* s, const char* p); + /**** Lists ****/ void *mpr_list_from_data(const void *data); @@ -593,7 +599,7 @@ const char *mpr_prop_as_str(mpr_prop prop, int skip_slash); /**** Types ****/ /*! Helper to find size of signal value types. */ -inline static int mpr_type_get_size(mpr_type type) +MPR_INLINE static int mpr_type_get_size(mpr_type type) { if (type <= MPR_LIST) return sizeof(void*); switch (type) { @@ -626,45 +632,64 @@ int mpr_value_remove_inst(mpr_value v, int idx); void mpr_value_set_sample(mpr_value v, int idx, void *s, mpr_time t); /*! Helper to find the pointer to the current value in a mpr_value_t. */ -inline static void* mpr_value_get_samp(mpr_value v, int idx) +MPR_INLINE static void* mpr_value_get_samp(mpr_value v, int idx) { mpr_value_buffer b = &v->inst[idx]; - return b->samps + b->pos * v->vlen * mpr_type_get_size(v->type); + return (char*)b->samps + b->pos * v->vlen * mpr_type_get_size(v->type); +} + +MPR_INLINE static void* mpr_value_get_samp_hist(mpr_value v, int inst_idx, int hist_idx) +{ + mpr_value_buffer b = &v->inst[inst_idx]; + int idx = (b->pos + v->mlen + hist_idx) % v->mlen; + if (idx < 0) + idx += v->mlen; + return (char*)b->samps + idx * v->vlen * mpr_type_get_size(v->type); } /*! Helper to find the pointer to the current time in a mpr_value_t. */ -inline static void* mpr_value_get_time(mpr_value v, int idx) +MPR_INLINE static mpr_time* mpr_value_get_time(mpr_value v, int idx) { mpr_value_buffer b = &v->inst[idx]; return &b->times[b->pos]; } +MPR_INLINE static mpr_time* mpr_value_get_time_hist(mpr_value v, int inst_idx, int hist_idx) +{ + mpr_value_buffer b = &v->inst[inst_idx]; + int idx = (b->pos + v->mlen + hist_idx) % v->mlen; + if (idx < 0) + idx += v->mlen; + return &b->times[idx]; +} + void mpr_value_free(mpr_value v); #ifdef DEBUG void mpr_value_print(mpr_value v, int inst_idx); +void mpr_value_print_hist(mpr_value v, int inst_idx); #endif /*! Helper to find the size in bytes of a signal's full vector. */ -inline static size_t mpr_sig_get_vector_bytes(mpr_sig sig) +MPR_INLINE static size_t mpr_sig_get_vector_bytes(mpr_sig sig) { return mpr_type_get_size(sig->type) * sig->len; } /*! Helper to check if a type character is valid. */ -inline static int check_sig_length(int length) +MPR_INLINE static int check_sig_length(int length) { return (length < 1 || length > MPR_MAX_VECTOR_LEN); } /*! Helper to check if bitfields match completely. */ -inline static int bitmatch(unsigned int a, unsigned int b) +MPR_INLINE static int bitmatch(unsigned int a, unsigned int b) { return (a & b) == b; } /*! Helper to check if type is a number. */ -inline static int mpr_type_get_is_num(mpr_type type) +MPR_INLINE static int mpr_type_get_is_num(mpr_type type) { switch (type) { case MPR_INT32: @@ -676,33 +701,53 @@ inline static int mpr_type_get_is_num(mpr_type type) } /*! Helper to check if type is a boolean. */ -inline static int mpr_type_get_is_bool(mpr_type type) +MPR_INLINE static int mpr_type_get_is_bool(mpr_type type) { return 'T' == type || 'F' == type; } /*! Helper to check if type is a string. */ -inline static int mpr_type_get_is_str(mpr_type type) +MPR_INLINE static int mpr_type_get_is_str(mpr_type type) { return MPR_STR == type; } /*! Helper to check if type is a string or void* */ -inline static int mpr_type_get_is_ptr(mpr_type type) +MPR_INLINE static int mpr_type_get_is_ptr(mpr_type type) { return MPR_PTR == type || MPR_STR == type; } /*! Helper to check if data type matches, but allowing 'T' and 'F' for bool. */ -inline static int type_match(const mpr_type l, const mpr_type r) +MPR_INLINE static int type_match(const mpr_type l, const mpr_type r) { return (l == r) || (strchr("bTF", l) && strchr("bTF", r)); } /*! Helper to remove a leading slash '/' from a string. */ -inline static const char *skip_slash(const char *string) +MPR_INLINE static const char *skip_slash(const char *string) { return string + (string && string[0]=='/'); } -#endif // __MAPPER_INTERNAL_H__ +MPR_INLINE static void set_bitflag(char *bytearray, int idx) +{ + bytearray[idx / 8] |= 1 << (idx % 8); +} + +MPR_INLINE static int get_bitflag(char *bytearray, int idx) +{ + return bytearray[idx / 8] & 1 << (idx % 8); +} + +MPR_INLINE static int compare_bitflags(char *l, char *r, int num_flags) +{ + return memcmp(l, r, num_flags / 8 + 1); +} + +MPR_INLINE static void clear_bitflags(char *bytearray, int num_flags) +{ + memset(bytearray, 0, num_flags / 8 + 1); +} + +#endif /* __MAPPER_INTERNAL_H__ */ diff --git a/src/mapper/mapper_types.h b/src/mapper/mapper_types.h index 6c8b529..1963cf5 100644 --- a/src/mapper/mapper_types.h +++ b/src/mapper/mapper_types.h @@ -13,24 +13,24 @@ typedef void *mpr_obj; /*! An internal structure defining a device. */ typedef void *mpr_dev; -//! An internal structure defining a signal. +/*! An internal structure defining a signal. */ typedef void *mpr_sig; -//! An internal structure defining a mapping between a set of signals. +/*! An internal structure defining a mapping between a set of signals. */ typedef void *mpr_map; /*! An internal structure defining a list of objects. */ typedef void **mpr_list; -//! An internal structure representing the distributed mapping graph. -//! This can be retrieved by calling mpr_obj_graph(). +/*! An internal structure representing the distributed mapping graph. */ +/*! This can be retrieved by calling mpr_obj_graph(). */ typedef void *mpr_graph; -//! An internal structure defining a grouping of signals. +/*! An internal structure defining a grouping of signals. */ typedef int mpr_sig_group; #ifdef __cplusplus } #endif -#endif // __MPR_TYPES_H__ +#endif /* __MPR_TYPES_H__ */ diff --git a/src/mapper/network.c b/src/mapper/network.c index f58068b..d81a110 100644 --- a/src/mapper/network.c +++ b/src/mapper/network.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include "config.h" #include @@ -31,30 +31,18 @@ extern const char* prop_msg_strings[MPR_PROP_EXTRA+1]; -// set to 1 to force mesh comms to use multicast bus instead for debugging -#define FORCE_COMMS_TO_BUS 0 #define BUNDLE_DST_SUBSCRIBERS (void*)-1 #define BUNDLE_DST_BUS 0 -#define MAX_BUNDLE_COUNT 10 - -#if FORCE_COMMS_TO_BUS - #define NET_SERVER_FUNC(NET, FUNC, ...) \ - { \ - lo_server_ ## FUNC((NET)->server.bus, __VA_ARGS__); \ - } -#else - #define NET_SERVER_FUNC(NET, FUNC, ...) \ - { \ - lo_server_ ## FUNC((NET)->server.bus, __VA_ARGS__); \ - lo_server_ ## FUNC((NET)->server.mesh, __VA_ARGS__); \ - } -#endif +#define MAX_BUNDLE_LEN 1460 +#define FIND 0 +#define UPDATE 1 +#define ADD 2 static int is_alphabetical(int num, lo_arg **names) { - RETURN_UNLESS(num > 1, 1); int i; + RETURN_ARG_UNLESS(num > 1, 1); for (i = 1; i < num; i++) TRACE_RETURN_UNLESS(strcmp(&names[i-1]->s, &names[i]->s)<0, 0, "error: signal names out of order."); @@ -63,13 +51,23 @@ static int is_alphabetical(int num, lo_arg **names) /* Extract the ordinal from a device name in the format: . */ static int extract_ordinal(char *name) { + int ordinal; char *s = name; - RETURN_UNLESS(s = strrchr(s, '.'), -1); - int ordinal = atoi(s+1); + RETURN_ARG_UNLESS(s = strrchr(s, '.'), -1); + ordinal = atoi(s+1); *s = 0; return ordinal; } +MPR_INLINE static void inform_device_subscribers(mpr_net net, mpr_local_dev dev) +{ + if (dev->subscribers) { + trace_dev(dev, "informing subscribers (DEVICE)\n") + mpr_net_use_subscribers(net, dev, MPR_DEV); + mpr_dev_send_state((mpr_dev)dev, MPR_DEV); + } +} + const char* net_msg_strings[] = { "/device", /* MSG_DEV */ @@ -120,7 +118,7 @@ struct handler_method_assoc { lo_method_handler h; }; -// handlers needed by devices +/* handlers needed by devices */ static struct handler_method_assoc device_handlers[] = { {MSG_DEV, NULL, handler_dev}, {MSG_DEV_MOD, NULL, handler_dev_mod}, @@ -140,7 +138,7 @@ static struct handler_method_assoc device_handlers[] = { const int NUM_DEV_HANDLERS = sizeof(device_handlers)/sizeof(device_handlers[0]); -// handlers needed by graph for archiving +/* handlers needed by graph for archiving */ static struct handler_method_assoc graph_handlers[] = { {MSG_DEV, NULL, handler_dev}, {MSG_LOGOUT, NULL, handler_logout}, @@ -166,17 +164,16 @@ static int check_collisions(mpr_net net, mpr_allocated resource); /*! Local function to get the IP address of a network interface. */ static int get_iface_addr(const char* pref, struct in_addr* addr, char **iface) { - struct in_addr zero; struct sockaddr_in *sa; - *(unsigned int *)&zero = inet_addr("0.0.0.0"); #ifdef HAVE_GETIFADDRS + struct in_addr zero; struct ifaddrs *ifaphead; struct ifaddrs *ifap; struct ifaddrs *iflo=0, *ifchosen=0; - RETURN_UNLESS(0 == getifaddrs(&ifaphead), 1); - + RETURN_ARG_UNLESS(0 == getifaddrs(&ifaphead), 1); + *(unsigned int *)&zero = inet_addr("0.0.0.0"); ifap = ifaphead; while (ifap) { sa = (struct sockaddr_in *) ifap->ifa_addr; @@ -199,7 +196,7 @@ static int get_iface_addr(const char* pref, struct in_addr* addr, char **iface) ifap = ifap->ifa_next; } - // Default to loopback address in case user is working locally. + /* Default to loopback address in case user is working locally. */ if (!ifchosen) ifchosen = iflo; @@ -214,10 +211,10 @@ static int get_iface_addr(const char* pref, struct in_addr* addr, char **iface) freeifaddrs(ifaphead); -#else // !HAVE_GETIFADDRS +#else /* !HAVE_GETIFADDRS */ #ifdef HAVE_LIBIPHLPAPI - // TODO consider "pref" as well + /* TODO consider "pref" as well */ /* Start with recommended 15k buffer for GetAdaptersAddresses. */ ULONG size = 15*1024/2; @@ -229,20 +226,20 @@ static int get_iface_addr(const char* pref, struct in_addr* addr, char **iface) paa = realloc(paa, size); rc = GetAdaptersAddresses(AF_INET, 0, 0, paa, &size); } - RETURN_UNLESS(ERROR_SUCCESS == rc, 2); + RETURN_ARG_UNLESS(ERROR_SUCCESS == rc, 2); PIP_ADAPTER_ADDRESSES loaa=0, aa = paa; PIP_ADAPTER_UNICAST_ADDRESS lopua=0; while (aa && ERROR_SUCCESS == rc) { PIP_ADAPTER_UNICAST_ADDRESS pua = aa->FirstUnicastAddress; - // Skip adapters that are not "Up". + /* Skip adapters that are not "Up". */ if (pua && IfOperStatusUp == aa->OperStatus) { if (IF_TYPE_SOFTWARE_LOOPBACK == aa->IfType) { loaa = aa; lopua = pua; } else { - // Skip addresses starting with 0.X.X.X or 169.X.X.X. + /* Skip addresses starting with 0.X.X.X or 169.X.X.X. */ sa = (struct sockaddr_in *) pua->Address.lpSockaddr; unsigned char prefix = sa->sin_addr.s_addr&0xFF; if (prefix!=0xA9 && prefix!=0) { @@ -270,8 +267,8 @@ static int get_iface_addr(const char* pref, struct in_addr* addr, char **iface) #else #error No known method on this system to get the network interface address. -#endif // HAVE_LIBIPHLPAPI -#endif // !HAVE_GETIFADDRS +#endif /* HAVE_LIBIPHLPAPI */ +#endif /* !HAVE_GETIFADDRS */ return 2; } @@ -280,6 +277,7 @@ static int get_iface_addr(const char* pref, struct in_addr* addr, char **iface) static void seed_srand() { unsigned int s; + double d; #ifndef WIN32 FILE *f = fopen("/dev/urandom", "rb"); @@ -293,28 +291,31 @@ static void seed_srand() } #endif - double d = mpr_get_current_time(); + d = mpr_get_current_time(); s = (unsigned int)((d-(unsigned long)d)*100000); srand(s); } -static void mpr_net_add_dev_methods(mpr_net net, mpr_dev dev) +static void mpr_net_add_dev_methods(mpr_net net, mpr_local_dev dev) { int i; char path[256]; - const char *dname = mpr_dev_get_name(dev); + const char *dname = mpr_dev_get_name((mpr_dev)dev); for (i = 0; i < NUM_DEV_HANDLERS; i++) { snprintf(path, 256, net_msg_strings[device_handlers[i].str_idx], dname); - NET_SERVER_FUNC(net, add_method, path, device_handlers[i].types, device_handlers[i].h, net); + lo_server_add_method((net)->servers[SERVER_BUS], path, device_handlers[i].types, + device_handlers[i].h, net); + lo_server_add_method((net)->servers[SERVER_MESH], path, device_handlers[i].types, + device_handlers[i].h, net); } } -void mpr_net_remove_dev_methods(mpr_net net, mpr_dev dev) +void mpr_net_remove_dev_methods(mpr_net net, mpr_local_dev dev) { int i, j; char path[256]; for (i = 0; i < NUM_DEV_HANDLERS; i++) { - // make sure method isn't also used by graph + /* make sure method isn't also used by graph */ int found = 0; for (j = 0; j < NUM_GRAPH_HANDLERS; j++) { if (device_handlers[i].str_idx == graph_handlers[j].str_idx) { @@ -324,29 +325,36 @@ void mpr_net_remove_dev_methods(mpr_net net, mpr_dev dev) } if (found) continue; - snprintf(path, 256, net_msg_strings[device_handlers[i].str_idx], mpr_dev_get_name(dev)); - NET_SERVER_FUNC(net, del_method, path, device_handlers[i].types); + snprintf(path, 256, net_msg_strings[device_handlers[i].str_idx], + mpr_dev_get_name((mpr_dev)dev)); + lo_server_del_method((net)->servers[SERVER_BUS], path, device_handlers[i].types); + lo_server_del_method((net)->servers[SERVER_MESH], path, device_handlers[i].types); } } void mpr_net_add_graph_methods(mpr_net net) { - // add graph methods + /* add graph methods */ int i; - for (i = 0; i < NUM_GRAPH_HANDLERS; i++) - NET_SERVER_FUNC(net, add_method, net_msg_strings[graph_handlers[i].str_idx], - graph_handlers[i].types, graph_handlers[i].h, net); + for (i = 0; i < NUM_GRAPH_HANDLERS; i++) { + lo_server_add_method((net)->servers[SERVER_BUS], net_msg_strings[graph_handlers[i].str_idx], + graph_handlers[i].types, graph_handlers[i].h, net); + lo_server_add_method((net)->servers[SERVER_MESH], net_msg_strings[graph_handlers[i].str_idx], + graph_handlers[i].types, graph_handlers[i].h, net); + } return; } void mpr_net_init(mpr_net net, const char *iface, const char *group, int port) { - // send out any cached messages - mpr_net_send(net); + int i; /* Default standard ip and port is group 224.0.1.3, port 7570 */ char port_str[10], *s_port = port_str; + /* send out any cached messages */ + mpr_net_send(net); + if (net->multicast.group) { if (group && strcmp(group, net->multicast.group)) { free(net->multicast.group); @@ -354,9 +362,9 @@ void mpr_net_init(mpr_net net, const char *iface, const char *group, int port) } } else - net->multicast.group = strdup(group ?: "224.0.1.3"); + net->multicast.group = strdup(group ? group : "224.0.1.3"); if (!net->multicast.port) - net->multicast.port = port ?: 7570; + net->multicast.port = port ? port : 7570; snprintf(port_str, 10, "%d", net->multicast.port); /* Initialize interface information. */ @@ -366,8 +374,8 @@ void mpr_net_init(mpr_net net, const char *iface, const char *group, int port) /* Remove existing structures if necessary */ FUNC_IF(lo_address_free, net->addr.bus); - FUNC_IF(lo_server_free, net->server.bus); - FUNC_IF(lo_server_free, net->server.mesh); + FUNC_IF(lo_server_free, net->servers[SERVER_BUS]); + FUNC_IF(lo_server_free, net->servers[SERVER_MESH]); /* Open address */ net->addr.bus = lo_address_new(net->multicast.group, s_port); @@ -383,10 +391,10 @@ void mpr_net_init(mpr_net net, const char *iface, const char *group, int port) lo_address_set_iface(net->addr.bus, net->iface.name, 0); /* Open server for multicast */ - net->server.bus = lo_server_new_multicast_iface(net->multicast.group, s_port, net->iface.name, - 0, handler_error); + net->servers[SERVER_BUS] = lo_server_new_multicast_iface(net->multicast.group, s_port, + net->iface.name, 0, handler_error); - if (!net->server.bus) { + if (!net->servers[SERVER_BUS]) { lo_address_free(net->addr.bus); trace_net("problem allocating bus server.\n"); return; @@ -394,16 +402,16 @@ void mpr_net_init(mpr_net net, const char *iface, const char *group, int port) else trace_net("bus connected to %s:%s\n", net->multicast.group, s_port); - // Also open address/server for mesh-style communications - // TODO: use TCP instead? - while (!(net->server.mesh = lo_server_new(0, handler_error))) {} + /* Also open address/server for mesh-style communications */ + /* TODO: use TCP instead? */ + while (!(net->servers[SERVER_MESH] = lo_server_new(0, handler_error))) {} - // Disable liblo message queueing. - NET_SERVER_FUNC(net, enable_queue, 0, 1); + /* Disable liblo message queueing. */ + lo_server_enable_queue((net)->servers[SERVER_BUS], 0, 1); + lo_server_enable_queue((net)->servers[SERVER_MESH], 0, 1); mpr_net_add_graph_methods(net); - int i; for (i = 0; i < net->num_devs; i++) mpr_net_add_dev(net, net->devs[i]); } @@ -417,17 +425,14 @@ void mpr_net_send(mpr_net net) { RETURN_UNLESS(net->bundle); -#if FORCE_COMMS_TO_BUS - lo_send_bundle_from(net->addr.bus, net->server.mesh, net->bundle); -#else if (BUNDLE_DST_SUBSCRIBERS == net->addr.dst) { - mpr_subscriber *sub = &net->addr.dev->loc->subscribers; + mpr_subscriber *sub = &net->addr.dev->subscribers; mpr_time t; if (*sub) mpr_time_set(&t, MPR_NOW); while (*sub) { if ((*sub)->lease_exp < t.sec || !(*sub)->flags) { - // subscription expired, remove from subscriber list + /* subscription expired, remove from subscriber list */ #ifdef DEBUG char *addr = lo_address_get_url((*sub)->addr); trace_dev(net->addr.dev, "removing expired subscription from " @@ -441,23 +446,23 @@ void mpr_net_send(mpr_net net) continue; } if ((*sub)->flags & net->msg_type) - lo_send_bundle_from((*sub)->addr, net->server.mesh, net->bundle); + lo_send_bundle_from((*sub)->addr, net->servers[SERVER_MESH], net->bundle); sub = &(*sub)->next; } } else if (BUNDLE_DST_BUS == net->addr.dst) - lo_send_bundle_from(net->addr.bus, net->server.mesh, net->bundle); + lo_send_bundle_from(net->addr.bus, net->servers[SERVER_MESH], net->bundle); else - lo_send_bundle_from(net->addr.dst, net->server.mesh, net->bundle); -#endif + lo_send_bundle_from(net->addr.dst, net->servers[SERVER_MESH], net->bundle); + lo_bundle_free_recursive(net->bundle); net->bundle = 0; } static int init_bundle(mpr_net net) { - mpr_net_send(net); mpr_time t; + mpr_net_send(net); mpr_time_set(&t, MPR_NOW); net->bundle = lo_bundle_new(t); return net->bundle ? 0 : 1; @@ -465,8 +470,7 @@ static int init_bundle(mpr_net net) void mpr_net_use_bus(mpr_net net) { - if (net->bundle && ( net->addr.dst != BUNDLE_DST_BUS - || lo_bundle_count(net->bundle) >= MAX_BUNDLE_COUNT)) + if (net->bundle && (net->addr.dst != BUNDLE_DST_BUS)) mpr_net_send(net); net->addr.dst = BUNDLE_DST_BUS; if (!net->bundle) @@ -475,20 +479,18 @@ void mpr_net_use_bus(mpr_net net) void mpr_net_use_mesh(mpr_net net, lo_address addr) { - if (net->bundle && ( net->addr.dst != addr - || lo_bundle_count(net->bundle) >= MAX_BUNDLE_COUNT)) + if (net->bundle && (net->addr.dst != addr)) mpr_net_send(net); net->addr.dst = addr; if (!net->bundle) init_bundle(net); } -void mpr_net_use_subscribers(mpr_net net, mpr_dev dev, int type) +void mpr_net_use_subscribers(mpr_net net, mpr_local_dev dev, int type) { if (net->bundle && ( net->addr.dst != BUNDLE_DST_SUBSCRIBERS || net->addr.dev != dev - || net->msg_type != type - || lo_bundle_count(net->bundle) >= MAX_BUNDLE_COUNT)) + || net->msg_type != type)) mpr_net_send(net); net->addr.dst = BUNDLE_DST_SUBSCRIBERS; net->addr.dev = dev; @@ -499,11 +501,14 @@ void mpr_net_use_subscribers(mpr_net net, mpr_dev dev, int type) void mpr_net_add_msg(mpr_net net, const char *s, net_msg_t c, lo_message m) { - if (lo_bundle_count(net->bundle) >= MAX_BUNDLE_COUNT) { + int len = lo_bundle_length(net->bundle); + if (!s) + s = net_msg_strings[c]; + if (len && len + lo_message_length(m, s) >= MAX_BUNDLE_LEN) { mpr_net_send(net); init_bundle(net); } - lo_bundle_add_message(net->bundle, s ?: net_msg_strings[c], m); + lo_bundle_add_message(net->bundle, s, m); } void mpr_net_free_msgs(mpr_net net) @@ -517,31 +522,31 @@ void mpr_net_free_msgs(mpr_net net) * \param net A network structure handle. */ void mpr_net_free(mpr_net net) { - // send out any cached messages + /* send out any cached messages */ mpr_net_send(net); FUNC_IF(free, net->iface.name); FUNC_IF(free, net->multicast.group); - FUNC_IF(lo_server_free, net->server.bus); - FUNC_IF(lo_server_free, net->server.mesh); + FUNC_IF(lo_server_free, net->servers[SERVER_BUS]); + FUNC_IF(lo_server_free, net->servers[SERVER_MESH]); FUNC_IF(lo_address_free, net->addr.bus); FUNC_IF(free, net->addr.url); } /*! Probe the network to see if a device's proposed name.ordinal is available. */ -static void mpr_net_probe_dev_name(mpr_net net, mpr_dev dev) +static void mpr_net_probe_dev_name(mpr_net net, mpr_local_dev dev) { int i; + char name[256]; - // reset collisions and hints - dev->loc->ordinal.collision_count = 0; - dev->loc->ordinal.count_time = mpr_get_current_time(); + /* reset collisions and hints */ + dev->ordinal_allocator.collision_count = 0; + dev->ordinal_allocator.count_time = mpr_get_current_time(); for (i = 0; i < 8; i++) - dev->loc->ordinal.hints[i] = 0; + dev->ordinal_allocator.hints[i] = 0; /* Note: mpr_dev_get_name() would refuse here since the ordinal is not * yet locked, so we have to build it manually at this point. */ - char name[256]; - snprintf(name, 256, "%s.%d", dev->prefix, dev->loc->ordinal.val); + snprintf(name, 256, "%s.%d", dev->prefix, dev->ordinal_allocator.val); trace_dev(dev, "probing name '%s'\n", name); /* Calculate an id from the name and store it in id.val */ @@ -552,20 +557,20 @@ static void mpr_net_probe_dev_name(mpr_net net, mpr_dev dev) } /*! Add an uninitialized device to this network. */ -void mpr_net_add_dev(mpr_net net, mpr_dev dev) +void mpr_net_add_dev(mpr_net net, mpr_local_dev dev) { + int i; RETURN_UNLESS(dev); /* Check if device was already added. */ - int i; for (i = 0; i < net->num_devs; i++) { if (net->devs[i] == dev) break; } if (i < net->num_devs) { - // reset registered flag - dev->loc->registered = 0; - dev->loc->ordinal.val = 0; + /* reset registered flag */ + dev->registered = 0; + dev->ordinal_allocator.val = 0; } else { /* Initialize data structures */ @@ -582,39 +587,40 @@ void mpr_net_add_dev(mpr_net net, mpr_dev dev) /* Add allocation methods for bus communications. Further methods are added * when the device is registered. */ - lo_server_add_method(net->server.bus, net_msg_strings[MSG_NAME_PROBE], "si", + lo_server_add_method(net->servers[SERVER_BUS], net_msg_strings[MSG_NAME_PROBE], "si", handler_name_probe, net); - lo_server_add_method(net->server.bus, net_msg_strings[MSG_NAME_REG], NULL, handler_name, net); + lo_server_add_method(net->servers[SERVER_BUS], net_msg_strings[MSG_NAME_REG], NULL, handler_name, net); /* Probe potential name. */ mpr_net_probe_dev_name(net, dev); } -static void _send_device_sync(mpr_net net, mpr_dev dev) +static void _send_device_sync(mpr_net net, mpr_local_dev dev) { NEW_LO_MSG(msg, return); - lo_message_add_string(msg, mpr_dev_get_name(dev)); + lo_message_add_string(msg, mpr_dev_get_name((mpr_dev)dev)); lo_message_add_int32(msg, dev->obj.version); mpr_net_add_msg(net, 0, MSG_SYNC, msg); } -// TODO: rename to mpr_dev...? +/* TODO: rename to mpr_dev...? */ static void mpr_net_maybe_send_ping(mpr_net net, int force) { int i; + mpr_graph gph = net->graph; + mpr_list list; mpr_time now; mpr_time_set(&now, MPR_NOW); - mpr_graph gph = net->graph; if (now.sec > net->next_sub_ping) { net->next_sub_ping = now.sec + 2; - // housekeeping #1: check for staged maps that have expired + /* housekeeping #1: check for staged maps that have expired */ mpr_graph_cleanup(gph); RETURN_UNLESS(net->num_devs); for (i = 0; i < net->num_devs; i++) { - mpr_dev dev = net->devs[i]; - if (dev->loc->subscribers) { + mpr_local_dev dev = net->devs[i]; + if (dev->subscribers) { mpr_net_use_subscribers(net, dev, MPR_DEV); _send_device_sync(net, dev); } @@ -630,59 +636,58 @@ static void mpr_net_maybe_send_ping(mpr_net net, int force) _send_device_sync(net, net->devs[i]); } - // housekeeping #2: periodically check if our links are still active - mpr_list list = mpr_list_from_data(gph->links); + /* housekeeping #2: periodically check if our links are still active */ + list = mpr_list_from_data(gph->links); while (list) { + int num_maps; + mpr_sync_clock clk; + double elapsed; mpr_link lnk = (mpr_link)*list; list = mpr_list_get_next(list); - if (lnk->remote_dev->loc) + if (lnk->devs[REMOTE_DEV]->is_local) continue; - int num_maps = lnk->num_maps[0] + lnk->num_maps[1]; - mpr_sync_clock clk = &lnk->clock; - double elapsed = (clk->rcvd.time.sec ? mpr_time_get_diff(now, clk->rcvd.time) : 0); + num_maps = lnk->num_maps[0] + lnk->num_maps[1]; + clk = &lnk->clock; + elapsed = (clk->rcvd.time.sec ? mpr_time_get_diff(now, clk->rcvd.time) : 0); if (elapsed > TIMEOUT_SEC) { if (clk->rcvd.msg_id > 0) { if (num_maps) - trace_dev(lnk->local_dev, "Lost contact with linked device '%s' (%g seconds " - "since sync).\n", lnk->remote_dev->name, elapsed); - // tentatively mark link as expired + trace_dev(lnk->devs[LOCAL_DEV], "Lost contact with linked device '%s' " + "(%g seconds since sync).\n", lnk->devs[REMOTE_DEV]->name, elapsed); + /* tentatively mark link as expired */ clk->rcvd.msg_id = -1; clk->rcvd.time.sec = now.sec; } else { if (num_maps) { - trace_dev(lnk->local_dev, "Removing link to unresponsive device '%s' (%g " - "seconds since warning).\n", lnk->remote_dev->name, elapsed); + trace_dev(lnk->devs[LOCAL_DEV], "Removing link to unresponsive device '%s' " + "(%g seconds since warning).\n", lnk->devs[REMOTE_DEV]->name, elapsed); /* TODO: release related maps, call local handlers * and inform subscribers. */ } else - trace_dev(lnk->local_dev, "Removing link to device '%s'.\n", - lnk->remote_dev->name); - // remove related data structures + trace_dev(lnk->devs[LOCAL_DEV], "Removing link to device '%s'.\n", + lnk->devs[REMOTE_DEV]->name); + /* remove related data structures */ mpr_rtr_remove_link(net->rtr, lnk); mpr_graph_remove_link(gph, lnk, num_maps ? MPR_OBJ_EXP : MPR_OBJ_REM); continue; } } - if (num_maps && mpr_obj_get_prop_as_str(&lnk->remote_dev->obj, MPR_PROP_HOST, 0)) { + if (num_maps && mpr_obj_get_prop_as_str(&lnk->devs[REMOTE_DEV]->obj, MPR_PROP_HOST, 0)) { /* Only send pings if this link has associated maps, ensuring empty * links are removed after the ping timeout. */ lo_bundle bun = lo_bundle_new(now); NEW_LO_MSG(msg, ;); - lo_message_add_int64(msg, lnk->local_dev->obj.id); + lo_message_add_int64(msg, lnk->devs[LOCAL_DEV]->obj.id); if (++clk->sent.msg_id < 0) clk->sent.msg_id = 0; lo_message_add_int32(msg, clk->sent.msg_id); lo_message_add_int32(msg, clk->rcvd.msg_id); lo_message_add_double(msg, elapsed); - // need to send immediately + /* need to send immediately */ lo_bundle_add_message(bun, net_msg_strings[MSG_PING], msg); -#if FORCE_COMMS_TO_BUS - lo_send_bundle_from(net->addr.bus, net->server.mesh, bun); -#else - lo_send_bundle_from(lnk->addr.admin, net->server.mesh, bun); -#endif + lo_send_bundle_from(lnk->addr.admin, net->servers[SERVER_MESH], bun); mpr_time_set(&clk->sent.time, lo_bundle_get_timestamp(bun)); lo_bundle_free_recursive(bun); } @@ -693,7 +698,9 @@ static void mpr_net_maybe_send_ping(mpr_net net, int force) * that the libmapper bus can be automatically managed. */ void mpr_net_poll(mpr_net net) { - // send out any cached messages + int i, registered = 0; + + /* send out any cached messages */ mpr_net_send(net); if (!net->num_devs) { @@ -703,20 +710,20 @@ void mpr_net_poll(mpr_net net) /* If the ordinal is not yet locked, process collision timing. * Once the ordinal is locked it won't change. */ - int i, registered = 0; for (i = 0; i < net->num_devs; i++) { - mpr_dev dev = net->devs[i]; - if (!dev->loc->registered) { + mpr_local_dev dev = net->devs[i]; + if (!dev->registered) { /* If the ordinal has changed, re-probe the new name. */ - if (1 == check_collisions(net, &dev->loc->ordinal)) + if (1 == check_collisions(net, &dev->ordinal_allocator)) mpr_net_probe_dev_name(net, dev); /* If we are ready to register the device, add the message handlers. */ - if (dev->loc->ordinal.locked) { + if (dev->ordinal_allocator.locked) { mpr_dev_on_registered(dev); /* Send registered msg. */ - lo_send(net->addr.bus, net_msg_strings[MSG_NAME_REG], "s", mpr_dev_get_name(dev)); + lo_send(net->addr.bus, net_msg_strings[MSG_NAME_REG], "s", + mpr_dev_get_name((mpr_dev)dev)); mpr_net_add_dev_methods(net, dev); mpr_net_maybe_send_ping(net, 1); @@ -727,7 +734,7 @@ void mpr_net_poll(mpr_net net) ++registered; } if (registered) { - // Send out clock sync messages occasionally + /* Send out clock sync messages occasionally */ mpr_net_maybe_send_ping(net, 0); } return; @@ -736,14 +743,15 @@ void mpr_net_poll(mpr_net net) /*! Algorithm for checking collisions and allocating resources. */ static int check_collisions(mpr_net net, mpr_allocated resource) { - RETURN_UNLESS(!resource->locked, 0); - double current_time = mpr_get_current_time(); - double timediff = current_time - resource->count_time; int i; + double current_time, timediff; + RETURN_ARG_UNLESS(!resource->locked, 0); + current_time = mpr_get_current_time(); + timediff = current_time - resource->count_time; if (!resource->online) { if (timediff >= 5.0) { - // reprobe with the same value + /* reprobe with the same value */ resource->count_time = current_time; return 1; } @@ -783,7 +791,7 @@ static int handler_who(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - RETURN_UNLESS(net->devs, 0); + RETURN_ARG_UNLESS(net->devs, 0); trace_dev(net->devs[0], "received /who\n"); mpr_net_maybe_send_ping(net, 1); return 0; @@ -793,35 +801,45 @@ static int handler_who(const char *path, const char *types, lo_arg **av, int ac, static int handler_dev(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { - RETURN_UNLESS(ac && MPR_STR == types[0], 0); - mpr_net net = (mpr_net)user; -#ifdef DEBUG - mpr_dev dev = net->devs ? net->devs[0] : 0; -#endif - mpr_graph graph = net->graph; - int i, j; + mpr_net net; + mpr_local_dev dev; + mpr_dev remote; + mpr_graph graph; + int i, j, data_port, found; mpr_msg props = 0; + mpr_msg_atom atom; mpr_list links = 0, cpy; - const char *name = &av[0]->s; + const char *name, *host, *admin_port; + lo_address a; + mpr_rtr_sig rs; + + RETURN_ARG_UNLESS(ac && MPR_STR == types[0], 0); + net = (mpr_net)user; + dev = net->devs ? net->devs[0] : 0; + graph = net->graph; + name = &av[0]->s; if (graph->autosub || mpr_graph_subscribed_by_dev(graph, name)) { props = mpr_msg_parse_props(ac-1, &types[1], &av[1]); - trace_net("received /device %s + %i arguments\n", name, ac-1); - mpr_dev remote = mpr_graph_add_dev(graph, name, props); +#ifdef DEBUG + trace_net("received /device "); + lo_message_pp(msg); +#endif + remote = mpr_graph_add_dev(graph, name, props); if (!remote->subscribed && graph->autosub) mpr_graph_subscribe(graph, remote, graph->autosub, -1); } - if (!net->num_devs) + if (!net->devs) goto done; for (i = 0; i < net->num_devs; i++) { - if (0 == strcmp(&av[0]->s, mpr_dev_get_name(net->devs[i]))) + if (0 == strcmp(&av[0]->s, mpr_dev_get_name((mpr_dev)net->devs[i]))) break; } TRACE_DEV_RETURN_UNLESS(i == net->num_devs, 0, "ignoring /device message from self\n"); trace_dev(dev, "received /device %s\n", &av[0]->s); - // Discover whether the device is linked. - mpr_dev remote = mpr_graph_get_dev_by_name(graph, name); + /* Discover whether the device is linked. */ + remote = mpr_graph_get_dev_by_name(graph, name); links = mpr_dev_get_links(remote, MPR_DIR_ANY); if (!links || !(*links)) { trace_net("ignoring /device '%s', no link.\n", name); @@ -842,46 +860,57 @@ static int handler_dev(const char *path, const char *types, lo_arg **av, int ac, mpr_list_free(cpy); } - lo_address a = lo_message_get_source(msg); + a = lo_message_get_source(msg); if (!a) { trace_net("can't perform /linkTo, address unknown\n"); goto done; } - // Find the sender's hostname - const char *host = lo_address_get_hostname(a); - const char *admin_port = lo_address_get_port(a); + /* Find the sender's hostname */ + host = lo_address_get_hostname(a); + admin_port = lo_address_get_port(a); if (!host) { trace_net("can't perform /linkTo, host unknown\n"); goto done; } - // Retrieve the port + /* Retrieve the port */ if (!props) props = mpr_msg_parse_props(ac-1, &types[1], &av[1]); - mpr_msg_atom atom = mpr_msg_get_prop(props, MPR_PROP_PORT); + atom = mpr_msg_get_prop(props, MPR_PROP_PORT); if (!atom || atom->len != 1 || atom->types[0] != MPR_INT32) { trace_net("can't perform /linkTo, port unknown\n"); goto done; } - int data_port = (atom->vals[0])->i; + data_port = (atom->vals[0])->i; cpy = mpr_list_get_cpy(links); + found = 0; while (cpy) { mpr_link link = (mpr_link)*cpy; cpy = mpr_list_get_next(cpy); - if (mpr_link_get_is_local(link)) + if (mpr_link_get_is_local(link)) { mpr_link_connect(link, host, atoi(admin_port), data_port); + found = 1; + break; + } } + if (!found) + goto done; - // check if we have maps waiting for this link - mpr_rtr_sig rs = net->rtr->sigs; + /* links property has been updated, inform subscribers */ + if (found) + inform_device_subscribers(net, dev); + + /* check if we have maps waiting for this link */ + rs = net->rtr->sigs; while (rs) { for (i = 0; i < rs->num_slots; i++) { + mpr_local_map map; if (!rs->slots[i]) continue; - mpr_map map = rs->slots[i]->map; + map = (mpr_local_map)rs->slots[i]->map; if (MPR_DIR_OUT == rs->slots[i]->dir) { - // only send /mapTo once even if we have multiple local sources - if (map->loc->one_src && (rs->slots[i] != map->src[0])) + /* only send /mapTo once even if we have multiple local sources */ + if (map->one_src && (rs->slots[i] != map->src[0])) continue; cpy = mpr_list_get_cpy(links); while (cpy) { @@ -889,9 +918,9 @@ static int handler_dev(const char *path, const char *types, lo_arg **av, int ac, cpy = mpr_list_get_next(cpy); if (mpr_link_get_is_local(link) && map->dst->link == link) { mpr_net_use_mesh(net, link->addr.admin); - mpr_map_send_state(map, -1, MSG_MAP_TO); + mpr_map_send_state((mpr_map)map, -1, MSG_MAP_TO); for (j = 0; j < map->num_src; j++) { - if (!map->src[j]->sig->loc) + if (!map->src[j]->sig->is_local) continue; mpr_sig_send_state(map->src[j]->sig, MSG_SIG); } @@ -909,7 +938,7 @@ static int handler_dev(const char *path, const char *types, lo_arg **av, int ac, if (map->src[j]->link != link) continue; mpr_net_use_mesh(net, link->addr.admin); - j = mpr_map_send_state(map, map->loc->one_src ? -1 : j, MSG_MAP_TO); + j = mpr_map_send_state((mpr_map)map, map->one_src ? -1 : j, MSG_MAP_TO); mpr_sig_send_state(map->dst->sig, MSG_SIG); } } @@ -928,16 +957,15 @@ static int handler_dev_mod(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev && mpr_dev_get_is_ready(dev) && ac >= 2 && MPR_STR == types[0], 0); - mpr_msg props = mpr_msg_parse_props(ac, types, av); + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + mpr_msg props; + + RETURN_ARG_UNLESS(dev && mpr_dev_get_is_ready((mpr_dev)dev) + && ac >= 2 && MPR_STR == types[0], 0); + props = mpr_msg_parse_props(ac, types, av); trace_dev(dev, "received /%s/modify + %d properties.\n", path, props->num_atoms); - if (mpr_dev_set_from_msg(dev, props)) { - if (dev->loc->subscribers) { - trace_dev(dev, "informing subscribers (DEVICE)\n") - mpr_net_use_subscribers(net, dev, MPR_DEV); - mpr_dev_send_state(dev, MSG_DEV); - } + if (mpr_dev_set_from_msg((mpr_dev)dev, props)) { + inform_device_subscribers(net, dev); mpr_tbl_clear_empty(dev->obj.props.synced); } mpr_msg_free(props); @@ -948,29 +976,36 @@ static int handler_dev_mod(const char *path, const char *types, lo_arg **av, static int handler_logout(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { - RETURN_UNLESS(ac && MPR_STR == types[0], 0); - mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0, remote; - mpr_graph gph = net->graph; + mpr_net net; + mpr_graph gph; + mpr_local_dev dev; + mpr_dev remote; mpr_link lnk; int diff, ordinal; - char *s, *name = &av[0]->s; + char *s, *name; + + RETURN_ARG_UNLESS(ac && MPR_STR == types[0], 0); + net = (mpr_net)user; + dev = net->devs ? net->devs[0] : 0; + gph = net->graph; + + name = &av[0]->s; remote = mpr_graph_get_dev_by_name(gph, name); if (!dev) {trace_net("received /logout '%s'\n", name);} - else if (dev->loc->ordinal.locked) { + else if (dev->ordinal_allocator.locked) { trace_dev(dev, "received /logout '%s'\n", name); - // Check if we have any links to this device, if so remove them + /* Check if we have any links to this device, if so remove them */ lnk = remote ? mpr_dev_get_link_by_remote(dev, remote) : 0; if (lnk) { - // TODO: release maps, call local handlers and inform subscribers + /* TODO: release maps, call local handlers and inform subscribers */ trace_dev(dev, "removing link to expired device '%s'.\n", name); mpr_rtr_remove_link(net->rtr, lnk); mpr_graph_remove_link(gph, lnk, MPR_OBJ_REM); } - // Parse the ordinal from name in the format: . + /* Parse the ordinal from name in the format: . */ s = name; while (*s != '.' && *s++) {} ordinal = atoi(++s); @@ -978,10 +1013,10 @@ static int handler_logout(const char *path, const char *types, lo_arg **av, strtok(name, "."); ++name; if (0 == strcmp(name, dev->prefix)) { - // If device name matches and ordinal is within my block, free it - diff = ordinal - dev->loc->ordinal.val - 1; + /* If device name matches and ordinal is within my block, free it */ + diff = ordinal - dev->ordinal_allocator.val - 1; if (diff >= 0 && diff < 8) - dev->loc->ordinal.hints[diff] = 0; + dev->ordinal_allocator.hints[diff] = 0; } } if (remote) { @@ -996,8 +1031,8 @@ static int handler_subscribe(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - int version = -1; + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + int i, version = -1, flags = 0, timeout_seconds = 0; #ifdef DEBUG trace_dev(dev, "received /subscribe "); @@ -1005,10 +1040,8 @@ static int handler_subscribe(const char *path, const char *types, lo_arg **av, #endif lo_address addr = lo_message_get_source(msg); - TRACE_DEV_RETURN_UNLESS(addr && ac, 0, "error retrieving subscription " - "source address.\n"); + TRACE_DEV_RETURN_UNLESS(addr && ac, 0, "error retrieving subscription source address.\n"); - int i, flags = 0, timeout_seconds = 0; for (i = 0; i < ac; i++) { if (types[i] != MPR_STR) break; @@ -1029,13 +1062,13 @@ static int handler_subscribe(const char *path, const char *types, lo_arg **av, else if (0 == strcmp(&av[i]->s, "maps_out")) flags |= MPR_MAP_OUT; else if (0 == strcmp(&av[i]->s, "@version")) { - // next argument is last device version recorded by subscriber + /* next argument is last device version recorded by subscriber */ ++i; if (i < ac && MPR_INT32 == types[i]) version = av[i]->i; } else if (0 == strcmp(&av[i]->s, "@lease")) { - // next argument is lease timeout in seconds + /* next argument is lease timeout in seconds */ ++i; if (MPR_INT32 == types[i]) timeout_seconds = av[i]->i; @@ -1048,7 +1081,7 @@ static int handler_subscribe(const char *path, const char *types, lo_arg **av, } } - // add or renew subscription + /* add or renew subscription */ mpr_dev_manage_subscriber(dev, addr, flags, timeout_seconds, version); return 0; } @@ -1057,14 +1090,17 @@ static int handler_subscribe(const char *path, const char *types, lo_arg **av, static int handler_sig(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { - RETURN_UNLESS(ac >= 2 && MPR_STR == types[0], 1); - mpr_net net = (mpr_net)user; - const char *full_sig_name = &av[0]->s; - char *signamep, *devnamep; - int devnamelen = mpr_parse_names(full_sig_name, &devnamep, &signamep); - RETURN_UNLESS(devnamep && signamep && devnamelen < 1024, 0); + mpr_net net; + char *full_sig_name, *signamep, *devnamep, devname[1024]; + int devnamelen; + mpr_msg props; + + RETURN_ARG_UNLESS(ac >= 2 && MPR_STR == types[0], 1); + net = (mpr_net)user; + full_sig_name = &av[0]->s; + devnamelen = mpr_parse_names(full_sig_name, &devnamep, &signamep); + RETURN_ARG_UNLESS(devnamep && signamep && devnamelen < 1024, 0); - char devname[1024]; strncpy(devname, devnamep, devnamelen); devname[devnamelen]=0; @@ -1077,7 +1113,7 @@ static int handler_sig(const char *path, const char *types, lo_arg **av, int ac, } #endif - mpr_msg props = mpr_msg_parse_props(ac-1, &types[1], &av[1]); + props = mpr_msg_parse_props(ac-1, &types[1], &av[1]); mpr_graph_add_sig(net->graph, signamep, devname, props); mpr_msg_free(props); return 0; @@ -1088,19 +1124,24 @@ static int handler_sig(const char *path, const char *types, lo_arg **av, int ac, * pointer to the remainder of str1 after the prefix. */ static int prefix_cmp(const char *str1, const char *str2, const char **rest) { - // skip first slash + const char *s1, *s2; + int n1, n2, result; + + /* skip first slash */ str1 += ('/' == str1[0]); str2 += ('/' == str2[0]); - const char *s1=str1, *s2 = str2; + s1 = str1; + s2 = str2; while (*s1 && (*s1)!='/') ++s1; while (*s2 && (*s2)!='/') ++s2; - int n1 = s1-str1, n2 = s2-str2; + n1 = s1 - str1; + n2 = s2 - str2; if (n1!=n2) return 1; - int result = strncmp(str1, str2, n1); + result = strncmp(str1, str2, n1); if (!result && rest) *rest = s1+1; @@ -1112,20 +1153,22 @@ static int handler_sig_mod(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev && mpr_dev_get_is_ready(dev) && ac > 1 && MPR_STR == types[0], 0); + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + mpr_sig sig; + mpr_msg props; + RETURN_ARG_UNLESS(dev && mpr_dev_get_is_ready((mpr_dev)dev) && ac > 1 && MPR_STR == types[0], 0); - // retrieve signal - mpr_sig sig = mpr_dev_get_sig_by_name(dev, &av[0]->s); + /* retrieve signal */ + sig = mpr_dev_get_sig_by_name((mpr_dev)dev, &av[0]->s); TRACE_DEV_RETURN_UNLESS(sig, 0, "no signal found with name '%s'.\n", &av[0]->s); - mpr_msg props = mpr_msg_parse_props(ac-1, &types[1], &av[1]); + props = mpr_msg_parse_props(ac-1, &types[1], &av[1]); trace_dev(dev, "received %s '%s' + %d properties.\n", path, sig->name, props->num_atoms); if (mpr_sig_set_from_msg(sig, props)) { - if (dev->loc->subscribers) { - trace_dev(dev, "informing subscribers (SIGNAL)\n"); + if (dev->subscribers) { int dir = (MPR_DIR_IN == sig->dir) ? MPR_SIG_IN : MPR_SIG_OUT; + trace_dev(dev, "informing subscribers (SIGNAL)\n"); mpr_net_use_subscribers(net, dev, dir); mpr_sig_send_state(sig, MSG_SIG); } @@ -1139,21 +1182,23 @@ static int handler_sig_mod(const char *path, const char *types, lo_arg **av, static int handler_sig_removed(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { - RETURN_UNLESS(ac && MPR_STR == types[0], 1); mpr_net net = (mpr_net)user; - const char *full_sig_name = &av[0]->s; - char *signamep, *devnamep; - int devnamelen = mpr_parse_names(full_sig_name, &devnamep, &signamep); - RETURN_UNLESS(devnamep && signamep && devnamelen < 1024, 0); + mpr_dev dev; + char *full_sig_name, *signamep, *devnamep, devname[1024]; + int devnamelen; + + RETURN_ARG_UNLESS(ac && MPR_STR == types[0], 1); + full_sig_name = &av[0]->s; + devnamelen = mpr_parse_names(full_sig_name, &devnamep, &signamep); + RETURN_ARG_UNLESS(devnamep && signamep && devnamelen < 1024, 0); - char devname[1024]; strncpy(devname, devnamep, devnamelen); devname[devnamelen]=0; trace_net("received /signal/removed %s:%s\n", devname, signamep); - mpr_dev dev = mpr_graph_get_dev_by_name(net->graph, devname); - if (dev && !dev->loc) + dev = mpr_graph_get_dev_by_name(net->graph, devname); + if (dev && !dev->is_local) mpr_graph_remove_sig(net->graph, mpr_dev_get_sig_by_name(dev, signamep), MPR_OBJ_REM); return 0; } @@ -1162,12 +1207,16 @@ static int handler_sig_removed(const char *path, const char *types, lo_arg **av, static int handler_name(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { - RETURN_UNLESS(ac && MPR_STR == types[0], 0); - mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev, 0); + mpr_net net; + mpr_local_dev dev; int ordinal, diff, temp_id = -1, hint = 0; - char *name = &av[0]->s; + char *name; + + RETURN_ARG_UNLESS(ac && MPR_STR == types[0], 0); + net = (mpr_net)user; + dev = net->devs ? net->devs[0] : 0; + RETURN_ARG_UNLESS(dev, 0); + name = &av[0]->s; if (ac > 1) { if (MPR_INT32 == types[1]) temp_id = av[1]->i; @@ -1182,21 +1231,21 @@ static int handler_name(const char *path, const char *types, lo_arg **av, {trace_dev(dev, "received name %s\n", name);} #endif - if (dev->loc->ordinal.locked) { + if (dev->ordinal_allocator.locked) { ordinal = extract_ordinal(name); - RETURN_UNLESS(ordinal >= 0, 0); + RETURN_ARG_UNLESS(ordinal >= 0, 0); - // If device name matches + /* If device name matches */ if (0 == strcmp(name, dev->prefix)) { - // if id is locked and registered id is within my block, store it - diff = ordinal - dev->loc->ordinal.val - 1; + /* if id is locked and registered id is within my block, store it */ + diff = ordinal - dev->ordinal_allocator.val - 1; if (diff >= 0 && diff < 8) - dev->loc->ordinal.hints[diff] = -1; + dev->ordinal_allocator.hints[diff] = -1; if (hint) { - // if suggested id is within my block, store timestamp - diff = hint - dev->loc->ordinal.val - 1; + /* if suggested id is within my block, store timestamp */ + diff = hint - dev->ordinal_allocator.val - 1; if (diff >= 0 && diff < 8) - dev->loc->ordinal.hints[diff] = mpr_get_current_time(); + dev->ordinal_allocator.hints[diff] = mpr_get_current_time(); } } } @@ -1205,11 +1254,11 @@ static int handler_name(const char *path, const char *types, lo_arg **av, if (id == dev->obj.id) { if (temp_id < net->random_id) { /* Count ordinal collisions. */ - ++dev->loc->ordinal.collision_count; - dev->loc->ordinal.count_time = mpr_get_current_time(); + ++dev->ordinal_allocator.collision_count; + dev->ordinal_allocator.count_time = mpr_get_current_time(); } - else if (temp_id == net->random_id && hint > 0 && hint != dev->loc->ordinal.val) { - dev->loc->ordinal.val = hint; + else if (temp_id == net->random_id && hint > 0 && hint != dev->ordinal_allocator.val) { + dev->ordinal_allocator.val = hint; mpr_net_probe_dev_name(net, dev); } } @@ -1222,34 +1271,38 @@ static int handler_name_probe(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev, 0); - char *name = &av[0]->s; - int i, temp_id = av[1]->i; + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + mpr_id id; + char *name; + int i, temp_id; + + RETURN_ARG_UNLESS(dev, 0); + name = &av[0]->s; + temp_id = av[1]->i; trace_dev(dev, "received name probe %s %i \n", name, temp_id); - mpr_id id = (mpr_id) crc32(0L, (const Bytef *)name, strlen(name)) << 32; + id = (mpr_id) crc32(0L, (const Bytef *)name, strlen(name)) << 32; if (id == dev->obj.id) { double current_time = mpr_get_current_time(); - if (dev->loc->ordinal.locked || temp_id > net->random_id) { + if (dev->ordinal_allocator.locked || temp_id > net->random_id) { for (i = 0; i < 8; i++) { - if (dev->loc->ordinal.hints[i] >= 0 - && (current_time - dev->loc->ordinal.hints[i]) > 2.0) { - // reserve suggested ordinal - dev->loc->ordinal.hints[i] = current_time; + if (dev->ordinal_allocator.hints[i] >= 0 + && (current_time - dev->ordinal_allocator.hints[i]) > 2.0) { + /* reserve suggested ordinal */ + dev->ordinal_allocator.hints[i] = current_time; break; } } - // Name may not yet be registered, so we can't use mpr_net_send(). + /* Name may not yet be registered, so we can't use mpr_net_send(). */ lo_send(net->addr.bus, net_msg_strings[MSG_NAME_REG], "sii", name, - temp_id, dev->loc->ordinal.val + i + 1); + temp_id, dev->ordinal_allocator.val + i + 1); } else if (temp_id == net->random_id) - dev->loc->ordinal.online = 1; + dev->ordinal_allocator.online = 1; else { - ++dev->loc->ordinal.collision_count; - dev->loc->ordinal.count_time = current_time; + ++dev->ordinal_allocator.collision_count; + dev->ordinal_allocator.count_time = current_time; } } return 0; @@ -1281,9 +1334,9 @@ static int handler_name_probe(const char *path, const char *types, lo_arg **av, static int parse_sig_names(const char *types, lo_arg **av, int ac, int *src_idx, int *dst_idx, int *prop_idx) { - // protocol: /map src1 ... srcN -> dst OR /map dst <- src1 ... srcN - RETURN_UNLESS(!strncmp(types, "sss", 3), 0); + /* protocol: /map src1 ... srcN -> dst OR /map dst <- src1 ... srcN */ int i, num_src = 0; + RETURN_ARG_UNLESS(!strncmp(types, "sss", 3), 0); if (0 == strcmp(&av[1]->s, "<-")) { *src_idx = 2; *dst_idx = 0; @@ -1338,74 +1391,94 @@ static int parse_sig_names(const char *types, lo_arg **av, int ac, int *src_idx, #define MPR_MAP_ERROR (mpr_map)-1 static mpr_map find_map(mpr_net net, const char *types, int ac, lo_arg **av, - mpr_loc loc, mpr_sig *sig_ptr, int add) + mpr_loc loc, mpr_sig *sig_ptr, int flags) { - int i; + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + int i, is_loc = 0, src_idx, dst_idx, prop_idx, num_src; + mpr_sig sig = 0; + mpr_map map; + mpr_id id = 0; + const char *sig_name, *src_names[MAX_NUM_MAP_SRC], *dst_name; - // first check for an 'id' property + RETURN_ARG_UNLESS(dev || !loc, MPR_MAP_ERROR); + num_src = parse_sig_names(types, av, ac, &src_idx, &dst_idx, &prop_idx); + RETURN_ARG_UNLESS(num_src, MPR_MAP_ERROR); + RETURN_ARG_UNLESS(is_alphabetical(num_src, &av[src_idx]), MPR_MAP_ERROR); + + /* first check for an 'id' property */ for (i = 3; i < ac; i++) { if (types[i] != MPR_STR) continue; if (0 == strcmp(&av[i]->s, "@id")) break; } + if (i < ac && MPR_INT64 == types[++i]) { - mpr_obj obj = mpr_graph_get_obj(net->graph, MPR_MAP, av[i]->i64); - trace_graph("%s map with id %"PR_MPR_ID"\n", obj ? "found" : "couldn't find", av[i]->i64); - if (obj) { - int is_loc = mpr_obj_get_prop_as_int32(obj, MPR_PROP_IS_LOCAL, NULL); - return loc && !is_loc ? MPR_MAP_ERROR : (mpr_map)obj; + id = av[i]->i64; + map = (mpr_map)mpr_graph_get_obj(net->graph, MPR_MAP, id); + trace_graph("%s map with id %"PR_MPR_ID"\n", map ? "found" : "couldn't find", id); + if (map) { +#ifdef DEBUG + trace_graph(" %s", map->num_src > 1 ? "[" : ""); + for (i = 0; i < map->num_src; i++) + printf("'%s', ", map->src[i]->sig->name); + printf("\b\b%s -> '%s'\n", map->num_src > 1 ? "]" : "", map->dst->sig->name); +#endif + is_loc = mpr_obj_get_prop_as_int32((mpr_obj)map, MPR_PROP_IS_LOCAL, NULL); + RETURN_ARG_UNLESS(!loc || is_loc, MPR_MAP_ERROR); + if (map->num_src < num_src && (flags & UPDATE)) { + trace_graph("adding additional sources to map.\n"); + /* add additional sources */ + for (i = 0; i < num_src; i++) + src_names[i] = &av[src_idx+i]->s; + map = mpr_graph_add_map(net->graph, id, num_src, src_names, &av[dst_idx]->s); + } + return map; } + else if (!flags) + return 0; } - // try signal names instead - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev || !loc, MPR_MAP_ERROR); - mpr_sig sig = 0; - int num_src, src_idx, dst_idx, prop_idx; - const char *sig_name; - num_src = parse_sig_names(types, av, ac, &src_idx, &dst_idx, &prop_idx); - RETURN_UNLESS(num_src, MPR_MAP_ERROR); - RETURN_UNLESS(is_alphabetical(num_src, &av[src_idx]), MPR_MAP_ERROR); - -#ifdef DEBUG - trace_graph("looking for map with signals: "); - if (src_idx) - printf(" %s <-", &av[dst_idx]->s); - for (i = 0; i < num_src; i++) - printf(" %s", &av[src_idx+i]->s); - if (!src_idx) - printf(" -> %s", &av[dst_idx]->s); - printf("\n"); -#endif + /* try signal names instead */ - const char *src_names[num_src]; + dst_name = &av[dst_idx]->s; for (i = 0; i < num_src; i++) src_names[i] = &av[src_idx+i]->s; - const char *dst_name = &av[dst_idx]->s; if (MPR_LOC_DST & loc) { - // check if we are the destination - if ( prefix_cmp(&av[dst_idx]->s, mpr_dev_get_name(dev), &sig_name) - || !(sig = mpr_dev_get_sig_by_name(dev, sig_name))) - RETURN_UNLESS(MPR_LOC_DST != loc, MPR_MAP_ERROR); + /* check if we are the destination */ + if ( !prefix_cmp(&av[dst_idx]->s, mpr_dev_get_name((mpr_dev)dev), &sig_name) + && (sig = mpr_dev_get_sig_by_name((mpr_dev)dev, sig_name))) + is_loc = 1; + else + RETURN_ARG_UNLESS(MPR_LOC_DST != loc, MPR_MAP_ERROR); } if (!sig && MPR_LOC_SRC & loc) { - // check if we are a source – all sources must match! + /* check if we are a source – all sources must match! */ for (i = 0; i < num_src; i++) { - if (prefix_cmp(src_names[i], mpr_dev_get_name(dev), &sig_name) - || !(sig = mpr_dev_get_sig_by_name(dev, sig_name))) - RETURN_UNLESS(MPR_LOC_SRC != loc, MPR_MAP_ERROR); + if ( !prefix_cmp(src_names[i], mpr_dev_get_name((mpr_dev)dev), &sig_name) + && (sig = mpr_dev_get_sig_by_name((mpr_dev)dev, sig_name))) + is_loc = 1; + else + RETURN_ARG_UNLESS(MPR_LOC_SRC != loc, MPR_MAP_ERROR); } } - mpr_map map = mpr_graph_get_map_by_names(net->graph, num_src, src_names, dst_name); - if (!map && add) { - // safety check: make sure we don't have an outgoing map to src (loop) - if (sig && mpr_rtr_loop_check(net->rtr, sig, num_src, src_names)) { + RETURN_ARG_UNLESS(!loc || is_loc, MPR_MAP_ERROR); + map = mpr_graph_get_map_by_names(net->graph, num_src, src_names, dst_name); +#ifdef DEBUG + trace_graph("%s map with src name%s", map ? "found" : "couldn't find", + num_src > 1 ? "s: [" : ": "); + for (i = 0; i < num_src; i++) + printf("'%s', ", &av[src_idx+i]->s); + printf("\b\b%s and dst name '%s'\n", num_src > 1 ? "]" : "", &av[dst_idx]->s); +#endif + if (!map && (flags & ADD)) { + /* safety check: make sure we don't have an outgoing map to src (loop) */ + if (sig && mpr_rtr_loop_check(net->rtr, (mpr_local_sig)sig, num_src, src_names)) { trace_dev(dev, "error in /map: potential loop detected.") return MPR_MAP_ERROR; } - map = mpr_graph_add_map(net->graph, num_src, src_names, &av[dst_idx]->s, 0); + map = mpr_graph_add_map(net->graph, id, num_src, src_names, &av[dst_idx]->s); } if (sig_ptr) *sig_ptr = sig; @@ -1420,17 +1493,20 @@ static int handler_map(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev, 0); + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + mpr_sig sig = 0; + mpr_local_map map; + mpr_msg props; + int i; + + RETURN_ARG_UNLESS(dev, 0); #ifdef DEBUG trace_dev(dev, "received /map "); lo_message_pp(msg); #endif - mpr_sig sig = 0; - int i; - mpr_map map = find_map(net, types, ac, av, MPR_LOC_DST, &sig, 1); - RETURN_UNLESS(map && map != MPR_MAP_ERROR, 0); + map = (mpr_local_map)find_map(net, types, ac, av, MPR_LOC_DST, &sig, ADD | UPDATE); + RETURN_ARG_UNLESS(map && MPR_MAP_ERROR != (mpr_map)map, 0); if (map->status >= MPR_STATUS_ACTIVE) { /* Forward to handler_map_mod() and stop. */ handler_map_mod(path, types, av, ac, msg, user); @@ -1438,19 +1514,17 @@ static int handler_map(const char *path, const char *types, lo_arg **av, int ac, } mpr_rtr_add_map(net->rtr, map); - mpr_msg props = mpr_msg_parse_props(ac, types, av); - mpr_map_set_from_msg(map, props, 1); + props = mpr_msg_parse_props(ac, types, av); + mpr_map_set_from_msg((mpr_map)map, props, 1); mpr_msg_free(props); - if (map->loc->is_local_only && map->loc->expr) { + if (map->is_local_only && map->expr) { trace_dev(dev, "map references only local signals... activating.\n"); map->status = MPR_STATUS_ACTIVE; - // Inform subscribers - if (dev->loc->subscribers) { - trace_dev(dev, "informing subscribers (DEVICE)\n") - mpr_net_use_subscribers(net, dev, MPR_DEV); - mpr_dev_send_state(dev, MSG_DEV); + /* Inform subscribers */ + if (dev->subscribers) { + inform_device_subscribers(net, dev); trace_dev(dev, "informing subscribers (SIGNAL)\n") mpr_net_use_subscribers(net, dev, MPR_SIG); @@ -1460,27 +1534,26 @@ static int handler_map(const char *path, const char *types, lo_arg **av, int ac, trace_dev(dev, "informing subscribers (MAPPED)\n") mpr_net_use_subscribers(net, dev, MPR_MAP); - mpr_map_send_state(map, -1, MSG_MAPPED); + mpr_map_send_state((mpr_map)map, -1, MSG_MAPPED); } return 0; } - if (map->loc->one_src && !map->src[0]->loc->rsig - && map->src[0]->link && map->src[0]->link->addr.admin) { + if (map->one_src && !map->src[0]->rsig && map->src[0]->link && map->src[0]->link->addr.admin) { mpr_net_use_mesh(net, map->src[0]->link->addr.admin); - mpr_map_send_state(map, -1, MSG_MAP_TO); + mpr_map_send_state((mpr_map)map, -1, MSG_MAP_TO); mpr_sig_send_state(sig, MSG_SIG); } else { for (i = 0; i < map->num_src; i++) { - // do not send if is local mapping - if (map->src[i]->loc->rsig) + /* do not send if is local mapping */ + if (map->src[i]->rsig) continue; - // do not send if device host/port not yet known + /* do not send if device host/port not yet known */ if (!map->src[i]->link || !map->src[i]->link->addr.admin) continue; mpr_net_use_mesh(net, map->src[i]->link->addr.admin); - i = mpr_map_send_state(map, i, MSG_MAP_TO); + i = mpr_map_send_state((mpr_map)map, i, MSG_MAP_TO); mpr_sig_send_state(sig, MSG_SIG); } } @@ -1499,14 +1572,14 @@ static int handler_map_to(const char *path, const char *types, lo_arg **av, lo_message_pp(msg); #endif - mpr_map map = find_map(net, types, ac, av, MPR_LOC_ANY, 0, 1); - RETURN_UNLESS(map && MPR_MAP_ERROR != map, 0); + mpr_local_map map = (mpr_local_map)find_map(net, types, ac, av, MPR_LOC_ANY, 0, ADD | UPDATE); + RETURN_ARG_UNLESS(map && MPR_MAP_ERROR != (mpr_map)map, 0); mpr_rtr_add_map(net->rtr, map); if (map->status < MPR_STATUS_ACTIVE) { /* Set map properties. */ mpr_msg props = mpr_msg_parse_props(ac, types, av); - mpr_map_set_from_msg(map, props, 1); + mpr_map_set_from_msg((mpr_map)map, props, 1); mpr_msg_free(props); } @@ -1514,9 +1587,9 @@ static int handler_map_to(const char *path, const char *types, lo_arg **av, int i; if (MPR_DIR_OUT == map->dst->dir) { mpr_net_use_mesh(net, map->dst->link->addr.admin); - mpr_map_send_state(map, -1, MSG_MAPPED); + mpr_map_send_state((mpr_map)map, -1, MSG_MAPPED); for (i = 0; i < map->num_src; i++) { - if (!map->src[i]->sig->loc) + if (!map->src[i]->sig->is_local) continue; mpr_sig_send_state(map->src[i]->sig, MSG_SIG); } @@ -1524,7 +1597,7 @@ static int handler_map_to(const char *path, const char *types, lo_arg **av, else { for (i = 0; i < map->num_src; i++) { mpr_net_use_mesh(net, map->src[i]->link->addr.admin); - i = mpr_map_send_state(map, map->loc->one_src ? -1 : i, MSG_MAPPED); + i = mpr_map_send_state((mpr_map)map, map->one_src ? -1 : i, MSG_MAPPED); mpr_sig_send_state(map->dst->sig, MSG_SIG); } } @@ -1533,15 +1606,17 @@ static int handler_map_to(const char *path, const char *types, lo_arg **av, return 0; } -/*! Respond to /mapped by storing mapping in graph. Also used by devices to +/*! Respond to /mapped by storing a map in the graph. Also used by devices to * confirm connection to remote peers, and to share property changes. */ static int handler_mapped(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; mpr_graph graph = net->graph; - mpr_dev dev = net->devs ? net->devs[0] : 0; - int i; + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + mpr_map map; + mpr_msg props; + int i, rc = 0, updated; #ifdef DEBUG if (dev) @@ -1551,8 +1626,8 @@ static int handler_mapped(const char *path, const char *types, lo_arg **av, lo_message_pp(msg); #endif - mpr_map map = find_map(net, types, ac, av, 0, 0, 0); - RETURN_UNLESS(MPR_MAP_ERROR != map, 0); + map = find_map(net, types, ac, av, 0, 0, UPDATE); + RETURN_ARG_UNLESS(MPR_MAP_ERROR != map, 0); if (!map) { int store = 0, i = 0; if (graph->autosub & MPR_MAP) @@ -1566,54 +1641,54 @@ static int handler_mapped(const char *path, const char *types, lo_arg **av, ++i; } } - if (store) - map = find_map(net, types, ac, av, 0, 0, 1); - RETURN_UNLESS(map && MPR_MAP_ERROR != map, 0); + if (store) { + map = find_map(net, types, ac, av, 0, 0, ADD); + rc = 1; + } + RETURN_ARG_UNLESS(map && MPR_MAP_ERROR != map, 0); } - else if (map->loc && map->loc->is_local_only) { - // no need to update since all properties are local + else if (map->is_local && ((mpr_local_map)map)->is_local_only) { + /* no need to update since all properties are local */ return 0; } - mpr_msg props = mpr_msg_parse_props(ac, types, av); + props = mpr_msg_parse_props(ac, types, av); - // TODO: if this endpoint is map admin, do not allow overwriting props - int rc = 0, updated = mpr_map_set_from_msg(map, props, 0); + /* TODO: if this endpoint is map admin, do not allow overwriting props */ + updated = mpr_map_set_from_msg(map, props, 0); mpr_msg_free(props); #ifdef DEBUG if (dev) - { trace_dev(dev, "updated %d map properties.\n", updated); } + { trace_dev(dev, "updated %d map properties. (1)\n", updated); } else - { trace_graph("updated %d map properties.\n", updated); } + { trace_graph("updated %d map properties. (2)\n", updated); } #endif if (dev) { - RETURN_UNLESS(map->status >= MPR_STATUS_READY, 0); + RETURN_ARG_UNLESS(map->status >= MPR_STATUS_READY, 0); if (MPR_STATUS_READY == map->status) { map->status = MPR_STATUS_ACTIVE; rc = 1; if (MPR_DIR_OUT == map->dst->dir) { - // Inform remote destination + /* Inform remote destination */ mpr_net_use_mesh(net, map->dst->link->addr.admin); mpr_map_send_state(map, -1, MSG_MAPPED); } else { - // Inform remote sources + /* Inform remote sources */ for (i = 0; i < map->num_src; i++) { mpr_net_use_mesh(net, map->src[i]->link->addr.admin); - i = mpr_map_send_state(map, map->loc->one_src ? -1 : i, MSG_MAPPED); + i = mpr_map_send_state(map, ((mpr_local_map)map)->one_src ? -1 : i, MSG_MAPPED); } } - if (dev->loc->subscribers) { - trace_dev(dev, "informing subscribers (DEVICE)\n"); - mpr_net_use_subscribers(net, dev, MPR_DEV); - mpr_dev_send_state(dev, MSG_DEV); + if (dev->subscribers) { + inform_device_subscribers(net, dev); trace_dev(dev, "informing subscribers (SIGNAL)\n"); mpr_net_use_subscribers(net, dev, MPR_SIG); if (MPR_DIR_OUT == map->dst->dir) { for (i = 0; i < map->num_src; i++) { - if (map->src[i]->sig->loc) + if (map->src[i]->sig->is_local) mpr_sig_send_state(map->src[i]->sig, MSG_SIG); } } @@ -1625,21 +1700,13 @@ static int handler_mapped(const char *path, const char *types, lo_arg **av, } if (rc || updated) { if (mpr_obj_get_prop_as_int32(&map->obj, MPR_PROP_IS_LOCAL, 0) - && dev && dev->loc && dev->loc->subscribers) { - trace_dev(dev, "informing subscribers (MAPPED)\n") + && dev && dev->subscribers) { int dir = (MPR_DIR_OUT == map->dst->dir) ? MPR_MAP_OUT : MPR_MAP_IN; + trace_dev(dev, "informing subscribers (MAPPED)\n") mpr_net_use_subscribers(net, dev, dir); mpr_map_send_state(map, -1, MSG_MAPPED); } - fptr_list cb = graph->callbacks, temp; - while (cb) { - temp = cb->next; - if (cb->types & MPR_MAP) { - mpr_graph_handler *h = cb->f; - h(graph, (mpr_obj)map, rc ? MPR_OBJ_NEW : MPR_OBJ_MOD, cb->ctx); - } - cb = temp; - } + mpr_graph_call_cbs(graph, (mpr_obj)map, MPR_MAP, rc ? MPR_OBJ_NEW : MPR_OBJ_MOD); } mpr_tbl_clear_empty(map->obj.props.synced); return 0; @@ -1649,25 +1716,32 @@ static int handler_mapped(const char *path, const char *types, lo_arg **av, static int handler_map_mod(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { - RETURN_UNLESS(ac >= 4, 0); - mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev, 0); - mpr_map map = find_map(net, types, ac, av, MPR_LOC_ANY, 0, 0); - RETURN_UNLESS(map && MPR_MAP_ERROR != map, 0); - RETURN_UNLESS(map->loc && map->status >= MPR_STATUS_ACTIVE, 0); + mpr_net net; + mpr_local_dev dev; + mpr_local_map map; + mpr_msg props; + mpr_msg_atom a; + mpr_loc loc = MPR_LOC_UNDEFINED; + int updated; - mpr_msg props = mpr_msg_parse_props(ac, types, av); - TRACE_DEV_RETURN_UNLESS(props, 0, "ignoring /map/modify, no properties.\n"); + RETURN_ARG_UNLESS(ac >= 4, 0); + net = (mpr_net)user; + dev = net->devs ? net->devs[0] : 0; + RETURN_ARG_UNLESS(dev, 0); #ifdef DEBUG trace_dev(dev, "received /map/modify "); lo_message_pp(msg); #endif - mpr_msg_atom a = mpr_msg_get_prop(props, MPR_PROP_PROCESS_LOC); - mpr_loc loc = MPR_LOC_UNDEFINED; + map = (mpr_local_map)find_map(net, types, ac, av, MPR_LOC_ANY, 0, FIND); + RETURN_ARG_UNLESS(map && MPR_MAP_ERROR != (mpr_map)map, 0); + RETURN_ARG_UNLESS(map->status >= MPR_STATUS_ACTIVE, 0); + + props = mpr_msg_parse_props(ac, types, av); + TRACE_DEV_RETURN_UNLESS(props, 0, "ignoring /map/modify, no properties.\n"); + a = mpr_msg_get_prop(props, MPR_PROP_PROCESS_LOC); if (a) { loc = mpr_loc_from_str(&(a->vals[0])->s); - if (!map->loc->one_src) { + if (!map->one_src) { /* if map has sources from different remote devices, processing must * occur at the destination. */ loc = MPR_LOC_DST; @@ -1680,43 +1754,44 @@ static int handler_map_mod(const char *path, const char *types, lo_arg **av, else if (map->expr_str && strstr(map->expr_str, "y{-")) loc = MPR_LOC_DST; - // do not continue if we are not in charge of processing + /* do not continue if we are not in charge of processing */ if (MPR_LOC_DST == loc) { - if (!map->dst->sig->loc) { + if (!map->dst->sig->is_local) { trace_dev(dev, "ignoring /map/modify, synced to remote source.\n"); goto done; } } - else if (!map->src[0]->sig->loc) { + else if (!map->src[0]->sig->is_local) { trace_dev(dev, "ignoring /map/modify, synced to remote destination.\n"); goto done; } - int updated = mpr_map_set_from_msg(map, props, 1); + updated = mpr_map_set_from_msg((mpr_map)map, props, 1); if (updated) { - if (!map->loc->is_local_only) { - // Inform remote peer(s) of relevant changes - if (!map->dst->loc->rsig) { + if (!map->is_local_only) { + /* Inform remote peer(s) of relevant changes */ + if (!map->dst->rsig) { mpr_net_use_mesh(net, map->dst->link->addr.admin); - mpr_map_send_state(map, -1, MSG_MAPPED); + mpr_map_send_state((mpr_map)map, -1, MSG_MAPPED); } else { - for (int i = 0; i < map->num_src; i++) { - if (map->src[i]->loc->rsig) + int i; + for (i = 0; i < map->num_src; i++) { + if (map->src[i]->rsig) continue; mpr_net_use_mesh(net, map->src[i]->link->addr.admin); - i = mpr_map_send_state(map, i, MSG_MAPPED); + i = mpr_map_send_state((mpr_map)map, i, MSG_MAPPED); } } } - if (dev->loc->subscribers) { + if (dev->subscribers) { + int dir = map->dst->rsig ? MPR_MAP_IN : MPR_MAP_OUT; trace_dev(dev, "informing subscribers (MAPPED)\n") - int dir = map->dst->loc->rsig ? MPR_MAP_IN : MPR_MAP_OUT; mpr_net_use_subscribers(net, dev, dir); - mpr_map_send_state(map, -1, MSG_MAPPED); + mpr_map_send_state((mpr_map)map, -1, MSG_MAPPED); } } - trace_dev(dev, "updated %d map properties.\n", updated); + trace_dev(dev, "updated %d map properties. (3)\n", updated); done: mpr_msg_free(props); @@ -1729,43 +1804,43 @@ static int handler_unmap(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs ? net->devs[0] : 0; - RETURN_UNLESS(dev, 0); - mpr_map map = find_map(net, types, ac, av, MPR_LOC_ANY, 0, 0); + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + mpr_local_map map; int i; + RETURN_ARG_UNLESS(dev, 0); #ifdef DEBUG - trace_dev(dev, "%s /unmap", map && MPR_MAP_ERROR != map ? "got" : "ignoring"); + trace_dev(dev, "received /unmap"); lo_message_pp(msg); #endif - RETURN_UNLESS(map, 0); + map = (mpr_local_map)find_map(net, types, ac, av, MPR_LOC_ANY, 0, FIND); + RETURN_ARG_UNLESS(map && MPR_MAP_ERROR != (mpr_map)map, 0); - // inform remote peer(s) - if (!map->dst->loc || !map->dst->loc->rsig) { - if (!map->dst->link) { + /* inform remote peer(s) */ + if (!map->dst->is_local || !map->dst->rsig) { + if (map->dst->link && map->dst->link->addr.admin) { mpr_net_use_mesh(net, map->dst->link->addr.admin); - mpr_map_send_state(map, -1, MSG_UNMAP); + mpr_map_send_state((mpr_map)map, -1, MSG_UNMAP); } } else { for (i = 0; i < map->num_src; i++) { - if (map->src[i]->loc->rsig) + mpr_local_slot src = map->src[i]; + if (src->rsig || !src->link || !src->link->addr.admin) continue; - mpr_net_use_mesh(net, map->src[i]->link->addr.admin); - i = mpr_map_send_state(map, i, MSG_UNMAP); + mpr_net_use_mesh(net, src->link->addr.admin); + i = mpr_map_send_state((mpr_map)map, i, MSG_UNMAP); } } - if (dev->loc->subscribers) { - trace_dev(dev, "informing subscribers (DEVICE)\n") - mpr_net_use_subscribers(net, dev, MPR_DEV); - mpr_dev_send_state(dev, MSG_DEV); + if (dev->subscribers) { + inform_device_subscribers(net, dev); trace_dev(dev, "informing subscribers (SIGNAL)\n") mpr_net_use_subscribers(net, dev, MPR_SIG); if (MPR_DIR_OUT == map->dst->dir) { for (i = 0; i < map->num_src; i++) { - if (map->src[i]->sig->loc) + if (map->src[i]->sig->is_local) mpr_sig_send_state(map->src[i]->sig, MSG_SIG); } } @@ -1773,15 +1848,15 @@ static int handler_unmap(const char *path, const char *types, lo_arg **av, mpr_sig_send_state(map->dst->sig, MSG_SIG); trace_dev(dev, "informing subscribers (UNMAPPED)\n") - int dir = map->dst->loc->rsig ? MPR_MAP_IN : MPR_MAP_OUT; - mpr_net_use_subscribers(net, dev, dir); - mpr_map_send_state(map, -1, MSG_UNMAPPED); + mpr_net_use_subscribers(net, dev, + map->dst->is_local && map->dst->rsig ? MPR_MAP_IN : MPR_MAP_OUT); + mpr_map_send_state((mpr_map)map, -1, MSG_UNMAPPED); } /* The mapping is removed. */ mpr_rtr_remove_map(net->rtr, map); - mpr_graph_remove_map(net->graph, map, MPR_OBJ_REM); - // TODO: remove empty rtr_sigs + mpr_graph_remove_map(net->graph, (mpr_map)map, MPR_OBJ_REM); + /* TODO: remove empty rtr_sigs */ return 0; } @@ -1790,13 +1865,17 @@ static int handler_unmapped(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_map map = find_map(net, types, ac, av, 0, 0, 0); #ifdef DEBUG - trace_net("%s /unmapped", map ? "got" : "ignoring"); + mpr_local_dev dev = net->devs ? net->devs[0] : 0; + if (dev) + { trace_dev(dev, "received /unmapped"); } + else + { trace_graph("received /unmapped"); } lo_message_pp(msg); #endif - if (map) - mpr_graph_remove_map(net->graph, map, MPR_OBJ_REM); + mpr_map map = find_map(net, types, ac, av, 0, 0, FIND); + RETURN_ARG_UNLESS(map && MPR_MAP_ERROR != map, 0); + mpr_graph_remove_map(net->graph, map, MPR_OBJ_REM); return 0; } @@ -1804,24 +1883,27 @@ static int handler_ping(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { mpr_net net = (mpr_net)user; - mpr_dev dev = net->devs[0], remote; - RETURN_UNLESS(dev, 0); + mpr_local_dev dev = net->devs[0]; + mpr_dev remote; mpr_link lnk; mpr_time now; + lo_timetag then; + + RETURN_ARG_UNLESS(dev, 0); mpr_time_set(&now, MPR_NOW); - lo_timetag then = lo_message_get_timestamp(msg); + then = lo_message_get_timestamp(msg); remote = (mpr_dev)mpr_graph_get_obj(net->graph, MPR_DEV, av[0]->h); lnk = remote ? mpr_dev_get_link_by_remote(dev, remote) : 0; if (lnk) { mpr_sync_clock clk = &lnk->clock; - trace_dev(dev, "ping received from linked device '%s'\n", lnk->remote_dev->name); + trace_dev(dev, "ping received from linked device '%s'\n", lnk->devs[REMOTE_DEV]->name); if (av[2]->i == clk->sent.msg_id) { - // total elapsed time since ping sent + /* total elapsed time since ping sent */ double elapsed = mpr_time_get_diff(now, clk->sent.time); - // assume symmetrical latency + /* assume symmetrical latency */ double latency = (elapsed - av[3]->d) * 0.5; - // difference between remote and local clocks (latency compensated) + /* difference between remote and local clocks (latency compensated) */ double offset = mpr_time_get_diff(now, then) - latency; if (latency < 0) { @@ -1838,7 +1920,7 @@ static int handler_ping(const char *path, const char *types, lo_arg **av, else { clk->jitter = (clk->jitter * 0.9 + fabs(clk->latency - latency) * 0.1); if (offset > clk->offset) { - // remote time is in the future + /* remote time is in the future */ clk->offset = offset; } else if ( latency < clk->latency + clk->jitter @@ -1849,7 +1931,7 @@ static int handler_ping(const char *path, const char *types, lo_arg **av, } } - // update sync status + /* update sync status */ mpr_time_set(&clk->rcvd.time, now); clk->rcvd.msg_id = av[1]->i; } @@ -1859,12 +1941,14 @@ static int handler_ping(const char *path, const char *types, lo_arg **av, static int handler_sync(const char *path, const char *types, lo_arg **av, int ac, lo_message msg, void *user) { + mpr_graph graph; + mpr_dev dev; mpr_net net = (mpr_net)user; - RETURN_UNLESS(net && ac && MPR_STR == types[0], 0); - mpr_graph graph = net->graph; - mpr_dev dev = mpr_graph_get_dev_by_name(graph, &av[0]->s); + RETURN_ARG_UNLESS(net && ac && MPR_STR == types[0], 0); + graph = net->graph; + dev = mpr_graph_get_dev_by_name(graph, &av[0]->s); if (dev) { - RETURN_UNLESS(!dev->loc, 0); + RETURN_ARG_UNLESS(!dev->is_local, 0); trace_graph("updating sync record for device '%s'\n", dev->name); mpr_time_set(&dev->synced, MPR_NOW); @@ -1874,12 +1958,12 @@ static int handler_sync(const char *path, const char *types, lo_arg **av, } } else if (graph->autosub) { - // only create device record after requesting more information - trace_net("requesting metadata for device '%s'.\n", &av[0]->s); + /* only create device record after requesting more information */ mpr_dev_t temp; temp.name = &av[0]->s; temp.obj.version = -1; - temp.loc = 0; + temp.is_local = 0; + trace_net("requesting metadata for device '%s'.\n", &av[0]->s); mpr_graph_subscribe(graph, &temp, MPR_DEV, 0); } else diff --git a/src/mapper/object.c b/src/mapper/object.c index 7f13021..344c75b 100644 --- a/src/mapper/object.c +++ b/src/mapper/object.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -39,23 +39,25 @@ int mpr_obj_get_num_props(mpr_obj o, int staged) mpr_prop mpr_obj_get_prop_by_key(mpr_obj o, const char *s, int *l, mpr_type *t, const void **v, int *p) { - RETURN_UNLESS(o && s, 0); + RETURN_ARG_UNLESS(o && s, 0); return mpr_tbl_get_prop_by_key(o->props.synced, s, l, t, v, p); } mpr_prop mpr_obj_get_prop_by_idx(mpr_obj o, mpr_prop p, const char **k, int *l, mpr_type *t, const void **v, int *pub) { - RETURN_UNLESS(o, 0); - return mpr_tbl_get_prop_by_idx(o->props.synced, p | o->props.mask, k, l, t, v, pub); + RETURN_ARG_UNLESS(o, 0); + return mpr_tbl_get_prop_by_idx(o->props.synced, p, k, l, t, v, pub); } int mpr_obj_get_prop_as_int32(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - mpr_tbl_record r = mpr_tbl_get(o->props.synced, p, s); - RETURN_UNLESS(r && r->val && 1 == r->len, 0); - void *v = (r->flags & INDIRECT) ? *r->val : r->val; + mpr_tbl_record r; + void *v; + RETURN_ARG_UNLESS(o, 0); + r = mpr_tbl_get(o->props.synced, p, s); + RETURN_ARG_UNLESS(r && r->val, 0); + v = (r->flags & INDIRECT) ? *r->val : r->val; switch(r->type) { case MPR_BOOL: case MPR_INT32: return *(int*)v; @@ -69,10 +71,12 @@ int mpr_obj_get_prop_as_int32(mpr_obj o, mpr_prop p, const char *s) float mpr_obj_get_prop_as_flt(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - mpr_tbl_record r = mpr_tbl_get(o->props.synced, p, s); - RETURN_UNLESS(r && r->val && 1 == r->len, 0); - void *v = (r->flags & INDIRECT) ? *r->val : r->val; + mpr_tbl_record r; + void *v; + RETURN_ARG_UNLESS(o, 0); + r = mpr_tbl_get(o->props.synced, p, s); + RETURN_ARG_UNLESS(r && r->val, 0); + v = (r->flags & INDIRECT) ? *r->val : r->val; switch(r->type) { case MPR_BOOL: case MPR_INT32: return (float)(*(int*)v); @@ -85,80 +89,93 @@ float mpr_obj_get_prop_as_flt(mpr_obj o, mpr_prop p, const char *s) const char *mpr_obj_get_prop_as_str(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - mpr_tbl_record r = mpr_tbl_get(o->props.synced, p, s); - RETURN_UNLESS(r && r->val && MPR_STR == r->type && 1 == r->len, 0); + mpr_tbl_record r; + RETURN_ARG_UNLESS(o, 0); + r = mpr_tbl_get(o->props.synced, p, s); + RETURN_ARG_UNLESS(r && r->val && MPR_STR == r->type && 1 == r->len, 0); return r->flags & INDIRECT ? *r->val : r->val; } const void *mpr_obj_get_prop_as_ptr(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - mpr_tbl_record r = mpr_tbl_get(o->props.synced, p, s); - RETURN_UNLESS(r && r->val && MPR_PTR == r->type && 1 == r->len, 0); + mpr_tbl_record r; + RETURN_ARG_UNLESS(o, 0); + r = mpr_tbl_get(o->props.synced, p, s); + RETURN_ARG_UNLESS(r && r->val && MPR_PTR == r->type && 1 == r->len, 0); return r->flags & INDIRECT ? *r->val : r->val; } mpr_obj mpr_obj_get_prop_as_obj(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - mpr_tbl_record r = mpr_tbl_get(o->props.synced, p, s); - RETURN_UNLESS(r && r->val && MPR_OBJ >= r->type && 1 == r->len, 0); + mpr_tbl_record r; + RETURN_ARG_UNLESS(o, 0); + r = mpr_tbl_get(o->props.synced, p, s); + RETURN_ARG_UNLESS(r && r->val && MPR_OBJ >= r->type && 1 == r->len, 0); return r->flags & INDIRECT ? *r->val : r->val; } mpr_list mpr_obj_get_prop_as_list(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - mpr_tbl_record r = mpr_tbl_get(o->props.synced, p, s); - RETURN_UNLESS(r && r->val && MPR_LIST == r->type && 1 == r->len, 0); - mpr_list l = r->flags & INDIRECT ? *r->val : r->val; + mpr_list l; + mpr_tbl_record r; + RETURN_ARG_UNLESS(o, 0); + r = mpr_tbl_get(o->props.synced, p, s); + RETURN_ARG_UNLESS(r && r->val && MPR_LIST == r->type && 1 == r->len, 0); + l = r->flags & INDIRECT ? *r->val : r->val; return l ? mpr_list_start(mpr_list_get_cpy(l)) : 0; } mpr_prop mpr_obj_set_prop(mpr_obj o, mpr_prop p, const char *s, int len, mpr_type type, const void *val, int publish) { - RETURN_UNLESS(o, 0); - // TODO: ensure ID property can't be changed by user code + int local, flags, updated; + RETURN_ARG_UNLESS(o, 0); + /* TODO: ensure ID property can't be changed by user code */ if (MPR_PROP_UNKNOWN == p || !MASK_PROP_BITFLAGS(p)) { if (!s || '@' == s[0]) return MPR_PROP_UNKNOWN; p = mpr_prop_from_str(s); } - // check if object represents local resource - int local = o->props.staged ? 0 : 1; - int flags = local ? LOCAL_MODIFY : REMOTE_MODIFY; + /* check if object represents local resource */ + local = o->props.staged ? 0 : 1; + flags = local ? LOCAL_MODIFY : REMOTE_MODIFY; if (!publish) flags |= LOCAL_ACCESS_ONLY; - return mpr_tbl_set(local ? o->props.synced : o->props.staged, - p | o->props.mask, s, len, type, val, flags); + updated = mpr_tbl_set(local ? o->props.synced : o->props.staged, p, s, len, type, val, flags); + if (updated) + mpr_obj_increment_version(o); + return updated; } int mpr_obj_remove_prop(mpr_obj o, mpr_prop p, const char *s) { - RETURN_UNLESS(o, 0); - // check if object represents local resource - int local = o->props.staged ? 0 : 1; + int updated = 0, local; + RETURN_ARG_UNLESS(o, 0); + + /* check if object represents local resource */ + local = o->props.staged ? 0 : 1; if (MPR_PROP_UNKNOWN == p) p = mpr_prop_from_str(s); if (MPR_PROP_DATA == p || local) - return mpr_tbl_remove(o->props.synced, p, s, LOCAL_MODIFY); + updated = mpr_tbl_remove(o->props.synced, p, s, LOCAL_MODIFY); else if (MPR_PROP_EXTRA == p) - return mpr_tbl_set(o->props.staged, p | PROP_REMOVE, s, 0, 0, 0, REMOTE_MODIFY); + updated = mpr_tbl_set(o->props.staged, p | PROP_REMOVE, s, 0, 0, 0, REMOTE_MODIFY); + if (updated) + mpr_obj_increment_version(o); return 0; } void mpr_obj_push(mpr_obj o) { + mpr_net n; RETURN_UNLESS(o); - mpr_net n = &o->graph->net; + n = &o->graph->net; if (MPR_DEV == o->type) { mpr_dev d = (mpr_dev)o; - if (d->loc) { - mpr_net_use_subscribers(n, d, o->type); + if (d->is_local) { + mpr_net_use_subscribers(n, (mpr_local_dev)d, o->type); mpr_dev_send_state(d, MSG_DEV); } else { @@ -168,9 +185,9 @@ void mpr_obj_push(mpr_obj o) } else if (o->type & MPR_SIG) { mpr_sig s = (mpr_sig)o; - if (s->loc) { + if (s->is_local) { mpr_type type = ((s->dir == MPR_DIR_OUT) ? MPR_SIG_OUT : MPR_SIG_IN); - mpr_net_use_subscribers(n, s->dev, type); + mpr_net_use_subscribers(n, (mpr_local_dev)s->dev, type); mpr_sig_send_state(s, MSG_SIG); } else { @@ -179,8 +196,8 @@ void mpr_obj_push(mpr_obj o) } } else if (o->type & MPR_MAP) { - mpr_net_use_bus(n); mpr_map m = (mpr_map)o; + mpr_net_use_bus(n); if (m->status >= MPR_STATUS_ACTIVE) mpr_map_send_state(m, -1, MSG_MAP_MOD); else @@ -191,19 +208,20 @@ void mpr_obj_push(mpr_obj o) return; } - // clear the staged properties + /* clear the staged properties */ FUNC_IF(mpr_tbl_clear, o->props.staged); } void mpr_obj_print(mpr_obj o, int staged) { - RETURN_UNLESS(o && o->props.synced); - int i = 0, len; + int i = 0, len, num_props; mpr_prop p; const char *key; mpr_type type; const void *val; + RETURN_UNLESS(o && o->props.synced); + switch (o->type) { case MPR_DEV: printf("DEVICE: "); @@ -214,11 +232,12 @@ void mpr_obj_print(mpr_obj o, int staged) mpr_prop_print(1, MPR_SIG, o); break; case MPR_MAP: { - printf("MAP: "); + mpr_list l; mpr_map m = (mpr_map)o; + printf("MAP: "); if (m->num_src > 1) printf("["); - mpr_list l = mpr_map_get_sigs(m, MPR_LOC_SRC); + l = mpr_map_get_sigs(m, MPR_LOC_SRC); while (l) { mpr_prop_print(1, MPR_SIG, *l); l = mpr_list_get_next(l); @@ -240,21 +259,21 @@ void mpr_obj_print(mpr_obj o, int staged) return; } - int num_props = mpr_obj_get_num_props(o, 0); + num_props = mpr_obj_get_num_props(o, 0); for (i = 0; i < num_props; i++) { p = mpr_obj_get_prop_by_idx(o, i, &key, &len, &type, &val, 0); die_unless(val != 0 || MPR_LIST == type, "returned zero value\n"); - // already printed this + /* already printed this */ if (MPR_PROP_NAME == p) continue; - // don't print device signals as metadata + /* don't print device signals as metadata */ if (MPR_DEV == o->type && MPR_PROP_SIG == p) continue; printf(", %s=", key); - // handle pretty-printing a few enum values + /* handle pretty-printing a few enum values */ if (1 == len && MPR_INT32 == type) { switch(p) { case MPR_PROP_DIR: @@ -276,7 +295,7 @@ void mpr_obj_print(mpr_obj o, int staged) if (!staged || !o->props.staged) continue; - // check if staged values exist + /* check if staged values exist */ if (MPR_PROP_EXTRA == p) p = mpr_tbl_get_prop_by_key(o->props.staged, key, &len, &type, &val, 0); else diff --git a/src/mapper/properties.c b/src/mapper/properties.c index f7edac7..d372394 100644 --- a/src/mapper/properties.c +++ b/src/mapper/properties.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -93,12 +93,13 @@ const char *mpr_steal_strings[] = int mpr_parse_names(const char *string, char **devnameptr, char **signameptr) { - RETURN_UNLESS(string, 0); - const char *devname = skip_slash(string); - RETURN_UNLESS(devname && devname[0] != '/', 0); + char *devname, *signame; + RETURN_ARG_UNLESS(string, 0); + devname = (char*)skip_slash(string); + RETURN_ARG_UNLESS(devname && devname[0] != '/', 0); if (devnameptr) *devnameptr = (char*) devname; - char *signame = strchr(devname+1, '/'); + signame = strchr(devname+1, '/'); if (!signame) { if (signameptr) *signameptr = 0; @@ -117,21 +118,22 @@ int mpr_parse_names(const char *string, char **devnameptr, char **signameptr) mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) { int i, slot_idx, num_props=0; - // get the number of props + mpr_msg msg; + mpr_msg_atom a; + const char *key; + + /* get the number of props */ for (i = 0; i < argc; i++) { if (types[i] != MPR_STR) continue; - if (argv[i]->s == '@' || (strncmp(&argv[i]->s, "-@", 2)==0) - || (strncmp(&argv[i]->s, "+@", 2)==0)) + if (argv[i]->s == '@' || !strncmp(&argv[i]->s, "-@", 2) || !strncmp(&argv[i]->s, "+@", 2)) ++num_props; } - RETURN_UNLESS(num_props, 0); + RETURN_ARG_UNLESS(num_props, 0); - mpr_msg msg = (mpr_msg) calloc(1, sizeof(struct _mpr_msg)); - msg->atoms = ((mpr_msg_atom_t*) - calloc(1, sizeof(struct _mpr_msg_atom) * num_props)); - mpr_msg_atom a = &msg->atoms[0]; - const char *key; + msg = (mpr_msg) calloc(1, sizeof(struct _mpr_msg)); + msg->atoms = ((mpr_msg_atom_t*) calloc(1, sizeof(struct _mpr_msg_atom) * num_props)); + a = &msg->atoms[0]; for (i = 0; i < argc; i++) { if (!mpr_type_get_is_str(types[i])) { @@ -146,7 +148,7 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) #if TRACING printf("parsing property key '%s'\n", &argv[i]->s); #endif - // new property + /* new property */ if (a->types || (a->prop & PROP_REMOVE)) ++msg->num_atoms; a = &msg->atoms[msg->num_atoms]; @@ -160,11 +162,11 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) a->prop = PROP_REMOVE; ++key; } - if (key[0] != '@') // not a property key + if (key[0] != '@') /* not a property key */ continue; a->key = key; - // try to find matching index for static props + /* try to find matching index for static props */ if (strncmp(a->key, "@dst@", 5)==0) { a->prop |= DST_SLOT_PROP; a->key += 5; @@ -175,7 +177,7 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) a->key += 5; } else if (a->key[4] == '.') { - // in form 'src.' + /* in form 'src.' */ slot_idx = atoi(a->key + 5); a->key = strchr(a->key + 5, '@'); if (!a->key || !(++a->key)) { @@ -202,8 +204,7 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) break; } else if (!type_match(types[i], a->types[0])) { - trace("Value vector for key '%s' has heterogeneous types.\n", - a->key); + trace("Value vector for key '%s' has heterogeneous types.\n", a->key); a->len = a->prop = 0; a->types = 0; break; @@ -218,7 +219,7 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) continue; } } - // check type against static props + /* check type against static props */ else if (MASK_PROP_BITFLAGS(a->prop) < MPR_PROP_EXTRA) { static_prop_t prop; prop = static_props[PROP_TO_INDEX(a->prop)]; @@ -272,7 +273,7 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) } } } - // reset last atom if no types unless "remove" flag is set + /* reset last atom if no types unless "remove" flag is set */ if (a->types || a->prop & PROP_REMOVE) ++msg->num_atoms; else { @@ -281,7 +282,7 @@ mpr_msg mpr_msg_parse_props(int argc, const mpr_type *types, lo_arg **argv) a->vals = 0; } #if TRACING - // print out parsed properties + /* print out parsed properties */ printf("%d parsed mpr_msgs:\n", msg->num_atoms); for (i = 0; i < msg->num_atoms; i++) { a = &msg->atoms[i]; @@ -320,7 +321,7 @@ mpr_msg_atom mpr_msg_get_prop(mpr_msg msg, mpr_prop prop) int i; for (i = 0; i < msg->num_atoms; i++) { if (msg->atoms[i].prop == prop) { - RETURN_UNLESS(msg->atoms[i].len && msg->atoms[i].types, 0); + RETURN_ARG_UNLESS(msg->atoms[i].len && msg->atoms[i].types, 0); return &msg->atoms[i]; } } @@ -332,8 +333,7 @@ for (i = 0; i < len; i++) \ lo_message_add_##TYPE(MSG, ((CAST*)VAL)[i]); \ /* helper for mpr_msg_varargs() */ -void mpr_msg_add_typed_val(lo_message msg, int len, mpr_type type, - const void *val) +void mpr_msg_add_typed_val(lo_message msg, int len, mpr_type type, const void *val) { int i; if (type && len < 1) @@ -341,29 +341,15 @@ void mpr_msg_add_typed_val(lo_message msg, int len, mpr_type type, switch (type) { case MPR_STR: - if (len == 1) - lo_message_add_string(msg, (char*)val); - else - LO_MESSAGE_ADD_VEC(msg, string, char*, val); - break; - case MPR_FLT: - LO_MESSAGE_ADD_VEC(msg, float, float, val); - break; - case MPR_DBL: - LO_MESSAGE_ADD_VEC(msg, double, double, val); - break; - case MPR_INT32: - LO_MESSAGE_ADD_VEC(msg, int32, int, val); - break; - case MPR_INT64: - LO_MESSAGE_ADD_VEC(msg, int64, int64_t, val); - break; - case MPR_TIME: - LO_MESSAGE_ADD_VEC(msg, timetag, mpr_time, val); - break; - case MPR_TYPE: - LO_MESSAGE_ADD_VEC(msg, char, mpr_type, val); - break; + if (len == 1) lo_message_add_string(msg, (char*)val); + else LO_MESSAGE_ADD_VEC(msg, string, char*, val); break; + case MPR_FLT: LO_MESSAGE_ADD_VEC(msg, float, float, val); break; + case MPR_DBL: LO_MESSAGE_ADD_VEC(msg, double, double, val); break; + case MPR_INT32: LO_MESSAGE_ADD_VEC(msg, int32, int, val); break; + case MPR_INT64: LO_MESSAGE_ADD_VEC(msg, int64, int64_t, val); break; + case MPR_TIME: LO_MESSAGE_ADD_VEC(msg, timetag, mpr_time, val); break; + case MPR_TYPE: LO_MESSAGE_ADD_VEC(msg, char, mpr_type, val); break; + case 0: lo_message_add_nil(msg); break; case MPR_BOOL: for (i = 0; i < len; i++) { if (((int*)val)[i]) @@ -372,10 +358,6 @@ void mpr_msg_add_typed_val(lo_message msg, int len, mpr_type type, lo_message_add_false(msg); } break; - case 0: { - lo_message_add_nil(msg); - break; - } default: break; } @@ -383,16 +365,17 @@ void mpr_msg_add_typed_val(lo_message msg, int len, mpr_type type, const char *mpr_prop_as_str(mpr_prop p, int skip_slash) { + const char *s; p = MASK_PROP_BITFLAGS(p); die_unless(p > MPR_PROP_UNKNOWN && p <= MPR_PROP_EXTRA, "called mpr_prop_as_str() with bad index %d.\n", p); - const char *s = static_props[PROP_TO_INDEX(p)].key; + s = static_props[PROP_TO_INDEX(p)].key; return skip_slash ? s + 1 : s; } mpr_prop mpr_prop_from_str(const char *string) { - // property keys are stored alphabetically so we can use a binary search + /* property keys are stored alphabetically so we can use a binary search */ int beg = PROP_TO_INDEX(MPR_PROP_UNKNOWN) + 1; int end = PROP_TO_INDEX(MPR_PROP_EXTRA) - 1; int mid = (beg + end) * 0.5, cmp; @@ -424,8 +407,8 @@ const char *mpr_loc_as_str(mpr_loc loc) mpr_loc mpr_loc_from_str(const char *str) { - RETURN_UNLESS(str, MPR_LOC_UNDEFINED); int i; + RETURN_ARG_UNLESS(str, MPR_LOC_UNDEFINED); for (i = MPR_LOC_UNDEFINED+1; i < 3; i++) { if (strcmp(str, mpr_loc_strings[i])==0) return i; @@ -442,8 +425,8 @@ const char *mpr_protocol_as_str(mpr_proto p) mpr_proto mpr_protocol_from_str(const char *str) { - RETURN_UNLESS(str, MPR_PROTO_UNDEFINED); int i; + RETURN_ARG_UNLESS(str, MPR_PROTO_UNDEFINED); for (i = MPR_PROTO_UNDEFINED+1; i < MPR_NUM_PROTO; i++) { if (strcmp(str, mpr_protocol_strings[i])==0) return i; @@ -458,7 +441,7 @@ const char *mpr_steal_as_str(mpr_steal_type stl) return mpr_steal_strings[stl]; } -// Helper for setting property value from different data types +/* Helper for setting property value from different data types */ int set_coerced_val(int src_len, mpr_type src_type, const void *src_val, int dst_len, mpr_type dst_type, void *dst_val) { @@ -469,9 +452,10 @@ int set_coerced_val(int src_len, mpr_type src_type, const void *src_val, do { memcpy(dst_val, src_val, size * min_len); dst_len -= min_len; + dst_val = (void*)((char*)dst_val + size * min_len); if (dst_len < min_len) min_len = dst_len; - } while (dst_len); + } while (dst_len > 0); return 0; } @@ -560,6 +544,33 @@ int set_coerced_val(int src_len, mpr_type src_type, const void *src_val, return 0; } +int match_pattern(const char* s, const char* p) +{ + int ends_wild; + char *str, *tok, *pat; + RETURN_ARG_UNLESS(s && p, 1); + RETURN_ARG_UNLESS(strchr(p, '*'), strcmp(s, p)); + + /* 1) tokenize pattern using strtok() with delimiter character '*' + * 2) use strstr() to check if token exists in offset string */ + str = (char*)s; + pat = alloca((strlen(p) + 1) * sizeof(char)); + strcpy(pat, p); + ends_wild = ('*' == p[strlen(p)-1]); + while (str && *str) { + tok = strtok(pat, "*"); + RETURN_ARG_UNLESS(tok, !ends_wild); + str = strstr(str, tok); + if (str && *str) + str += strlen(tok); + else + return 1; + /* subsequent calls to strtok() need first argument to be NULL */ + pat = NULL; + } + return 0; +} + void mpr_prop_print(int len, mpr_type type, const void *val) { int i; @@ -598,7 +609,7 @@ void mpr_prop_print(int len, mpr_type type, const void *val) break; case MPR_INT64: for (i = 0; i < len; i++) - printf("%" PRINTF_LL "d, ", (long long)((int64_t*)val)[i]); + printf("%" PRINTF_LL "d, ", ((int64_t*)val)[i]); break; case MPR_TIME: for (i = 0; i < len; i++) @@ -617,7 +628,7 @@ void mpr_prop_print(int len, mpr_type type, const void *val) } break; case MPR_DEV: - // just print device name + /* just print device name */ if (1 == len) printf("'%s', ", mpr_dev_get_name((mpr_dev)val)); else { @@ -626,7 +637,7 @@ void mpr_prop_print(int len, mpr_type type, const void *val) } break; case MPR_SIG: { - // just print signal name + /* just print signal name */ if (1 == len) { mpr_sig sig = (mpr_sig)val; printf("'%s:%s', ", mpr_dev_get_name(sig->dev), sig->name); @@ -634,8 +645,7 @@ void mpr_prop_print(int len, mpr_type type, const void *val) else { mpr_sig *sig = (mpr_sig*)val; for (i = 0; i < len; i++) - printf("'%s:%s', ", mpr_dev_get_name(sig[i]->dev), - sig[i]->name); + printf("'%s:%s', ", mpr_dev_get_name(sig[i]->dev), sig[i]->name); } break; } diff --git a/src/mapper/router.c b/src/mapper/router.c index 15921e3..788a94f 100644 --- a/src/mapper/router.c +++ b/src/mapper/router.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -9,10 +9,10 @@ #include "types_internal.h" #include -static int _is_map_in_scope(mpr_map map, mpr_id id) +static int _is_map_in_scope(mpr_local_map map, mpr_id id) { int i; - id &= 0xFFFFFFFF00000000; // interested in device hash part only + id &= 0xFFFFFFFF00000000; /* interested in device hash part only */ for (i = 0; i < map->num_scopes; i++) { if (map->scopes[i] == 0 || map->scopes[i]->obj.id == id) return 1; @@ -20,7 +20,7 @@ static int _is_map_in_scope(mpr_map map, mpr_id id) return 0; } -static mpr_rtr_sig _find_rtr_sig(mpr_rtr rtr, mpr_sig sig) +static mpr_rtr_sig _find_rtr_sig(mpr_rtr rtr, mpr_local_sig sig) { mpr_rtr_sig rs = rtr->sigs; while (rs && rs->sig != sig) @@ -28,7 +28,7 @@ static mpr_rtr_sig _find_rtr_sig(mpr_rtr rtr, mpr_sig sig) return rs; } -void mpr_rtr_remove_inst(mpr_rtr rtr, mpr_sig sig, int inst_idx) { +void mpr_rtr_remove_inst(mpr_rtr rtr, mpr_local_sig sig, int inst_idx) { int i; mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); RETURN_UNLESS(rs); @@ -36,17 +36,17 @@ void mpr_rtr_remove_inst(mpr_rtr rtr, mpr_sig sig, int inst_idx) { mpr_slot_remove_inst(rs->slots[i], inst_idx); } -// TODO: check for mismatched instance counts when using multiple sources -void mpr_rtr_num_inst_changed(mpr_rtr rtr, mpr_sig sig, int size) +/* TODO: check for mismatched instance counts when using multiple sources */ +void mpr_rtr_num_inst_changed(mpr_rtr rtr, mpr_local_sig sig, int size) { int i; - // check if we have a reference to this signal + /* check if we have a reference to this signal */ mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); RETURN_UNLESS(rs); - // for array of slots, may need to reallocate destination instances + /* for array of slots, may need to reallocate destination instances */ for (i = 0; i < rs->num_slots; i++) { - mpr_slot slot = rs->slots[i]; + mpr_local_slot slot = rs->slots[i]; if (slot) mpr_map_alloc_values(slot->map); } @@ -54,14 +54,14 @@ void mpr_rtr_num_inst_changed(mpr_rtr rtr, mpr_sig sig, int size) static void _update_map_count(mpr_rtr rtr) { - // find associated rtr_sig + /* find associated rtr_sig */ mpr_rtr_sig rs = rtr->sigs; int i, dev_maps_in = 0, dev_maps_out = 0; - mpr_dev dev = 0; + mpr_local_dev dev = 0; while (rs) { + int sig_maps_in = 0, sig_maps_out = 0; if (!dev) dev = rs->sig->dev; - int sig_maps_in = 0, sig_maps_out = 0; for (i = 0; i < rs->num_slots; i++) { if (!rs->slots[i] || rs->slots[i]->map->status < MPR_STATUS_ACTIVE) continue; @@ -80,71 +80,63 @@ static void _update_map_count(mpr_rtr rtr) dev->num_maps_out = dev_maps_out; } -void mpr_rtr_process_sig(mpr_rtr rtr, mpr_sig sig, int idmap_idx, const void *val, mpr_time t) +void mpr_rtr_process_sig(mpr_rtr rtr, mpr_local_sig sig, int idmap_idx, const void *val, mpr_time t) { - // abort if signal is already being processed - might be a local loop - if (sig->loc->locked) { + mpr_id_map idmap; + lo_message msg; + mpr_rtr_sig rs; + mpr_local_map map; + int i, j, inst_idx; + uint8_t bundle_idx, *lock; + + /* abort if signal is already being processed - might be a local loop */ + if (sig->locked) { trace_dev(rtr->dev, "Mapping loop detected on signal %s! (1)\n", sig->name); return; } - mpr_id_map idmap = sig->loc->idmaps[idmap_idx].map; - lo_message msg; + idmap = sig->idmaps[idmap_idx].map; - // find the router signal - mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); + /* find the router signal */ + rs = _find_rtr_sig(rtr, sig); RETURN_UNLESS(rs); - int i, j, inst_idx = sig->loc->idmaps[idmap_idx].inst->idx; - uint8_t bundle_idx = rtr->dev->loc->bundle_idx % NUM_BUNDLES; - rtr->dev->loc->updated = 1; // mark as updated - mpr_map map; - uint8_t *lock = &sig->loc->locked; + inst_idx = sig->idmaps[idmap_idx].inst->idx; + bundle_idx = rtr->dev->bundle_idx % NUM_BUNDLES; + /* TODO: remove duplicate flag set */ + rtr->dev->sending = 1; /* mark as updated */ + lock = &sig->locked; *lock = 1; if (!val) { - mpr_local_slot lslot; - mpr_slot slot; + mpr_local_slot slot, dst_slot; for (i = 0; i < rs->num_slots; i++) { + int in_scope; if (!rs->slots[i]) continue; slot = rs->slots[i]; map = slot->map; - if (!map->use_inst || map->status < MPR_STATUS_ACTIVE) + if (map->status < MPR_STATUS_ACTIVE) continue; - mpr_slot dst_slot = map->dst; - mpr_local_slot dst_lslot = dst_slot->loc; - int in_scope = _is_map_in_scope(map, idmap->GID); + dst_slot = map->dst; + in_scope = _is_map_in_scope(map, idmap->GID); - // reset associated output memory - mpr_value_reset_inst(&dst_lslot->val, inst_idx); - - // send release to downstream - if (slot->dir == MPR_DIR_OUT) { - msg = 0; - if (!map->use_inst || in_scope) { - msg = mpr_map_build_msg(map, slot, 0, 0, idmap); - mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, t, map->protocol, bundle_idx); - } - } - - // send release to upstream + /* send release to upstream */ for (j = 0; j < map->num_src; j++) { slot = map->src[j]; if (!slot->sig->use_inst) continue; - lslot = slot->loc; - // reset associated input memory - mpr_value_reset_inst(&lslot->val, inst_idx); + /* reset associated input memory */ + mpr_value_reset_inst(&slot->val, inst_idx); if (!in_scope) continue; - if (sig->loc->idmaps[idmap_idx].status & RELEASED_REMOTELY) + if (sig->idmaps[idmap_idx].status & RELEASED_REMOTELY) continue; if (slot->dir == MPR_DIR_IN) { @@ -152,22 +144,41 @@ void mpr_rtr_process_sig(mpr_rtr rtr, mpr_sig sig, int idmap_idx, const void *va mpr_link_add_msg(slot->link, slot->sig, msg, t, map->protocol, bundle_idx); } } + + if (!map->use_inst) + continue; + + /* reset associated output memory */ + mpr_value_reset_inst(&dst_slot->val, inst_idx); + + /* send release to downstream */ + if (slot->dir == MPR_DIR_OUT) { + msg = 0; + if (in_scope) { + msg = mpr_map_build_msg(map, slot, 0, 0, idmap); + mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, t, map->protocol, + bundle_idx); + } + } } *lock = 0; return; } for (i = 0; i < rs->num_slots; i++) { + mpr_local_slot slot; + struct _mpr_sig_idmap *idmaps; + int in_scope, all; if (!rs->slots[i]) continue; - mpr_slot slot = rs->slots[i]; + slot = rs->slots[i]; map = slot->map; if (map->status < MPR_STATUS_ACTIVE) continue; - int in_scope = _is_map_in_scope(map, sig->loc->idmaps[idmap_idx].map->GID); - // TODO: should we continue for out-of-scope local destination updates? + in_scope = _is_map_in_scope(map, sig->idmaps[idmap_idx].map->GID); + /* TODO: should we continue for out-of-scope local destination updates? */ if (map->use_inst && !in_scope) continue; @@ -176,99 +187,39 @@ void mpr_rtr_process_sig(mpr_rtr rtr, mpr_sig sig, int idmap_idx, const void *va /* If this signal is non-instanced but the map has other instanced * sources we will need to update all of the active map instances. */ - int all = (!sig->use_inst && map->num_src > 1 && map->loc->num_inst > 1); + all = (!sig->use_inst && map->num_src > 1 && map->num_inst > 1); if (MPR_LOC_DST == map->process_loc) { - // bypass map processing and bundle value without type coercion - char types[sig->len]; + /* bypass map processing and bundle value without type coercion */ + char *types = alloca(sig->len * sizeof(char)); memset(types, sig->type, sig->len); msg = mpr_map_build_msg(map, slot, val, types, sig->use_inst ? idmap : 0); mpr_link_add_msg(map->dst->link, map->dst->sig, msg, t, map->protocol, bundle_idx); continue; } - // copy input value - mpr_local_slot lslot = slot->loc; - mpr_value_set_sample(&lslot->val, inst_idx, (void*)val, t); + /* copy input value */ + mpr_value_set_sample(&slot->val, inst_idx, (void*)val, t); - if (map->process_loc == MPR_LOC_SRC && !slot->causes_update) + if (!slot->causes_update) continue; - mpr_slot dst_slot = map->dst; - mpr_slot to = (map->process_loc == MPR_LOC_SRC ? dst_slot : slot); - char src_types[slot->sig->len], dst_types[to->sig->len]; - memset(src_types, slot->sig->type, slot->sig->len); - memset(dst_types, to->sig->type, to->sig->len); - if (all) { - // find a source signal with more instances + /* find a source signal with more instances */ for (j = 0; j < map->num_src; j++) - if (map->src[j]->sig->loc && map->src[j]->num_inst > slot->num_inst) - sig = map->src[j]->sig; + if (map->src[j]->sig->is_local && map->src[j]->num_inst > slot->num_inst) + sig = (mpr_local_sig)map->src[j]->sig; idmap_idx = 0; } - int map_manages_inst = 0; - if (!sig->use_inst) { - if (mpr_expr_get_manages_inst(map->loc->expr)) { - map_manages_inst = 1; - idmap = map->idmap; - } - else - idmap = 0; - } - - struct _mpr_sig_idmap *idmaps = sig->loc->idmaps; - for (; idmap_idx < sig->loc->idmap_len; idmap_idx++) { - // check if map instance is active + idmaps = sig->idmaps; + for (; idmap_idx < sig->idmap_len; idmap_idx++) { + /* check if map instance is active */ if ((all || sig->use_inst) && !idmaps[idmap_idx].inst) continue; inst_idx = idmaps[idmap_idx].inst->idx; - int status = mpr_map_perform(map, dst_types, &t, inst_idx); - if (!status) { - // no updates or releases - if (!all) - break; - else - continue; - } - /* send instance release if dst is instanced and either src or map is also instanced. */ - if (idmap && status & EXPR_RELEASE_BEFORE_UPDATE && map->use_inst) { - msg = mpr_map_build_msg(map, slot, 0, 0, sig->use_inst ? idmaps[idmap_idx].map : idmap); - mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, t, map->protocol, bundle_idx); - if (map_manages_inst) { - mpr_dev_LID_decref(rtr->dev, 0, idmap); - idmap = map->idmap = 0; - } - } - if (status & EXPR_UPDATE) { - // send instance update - void *result = mpr_value_get_samp(&dst_slot->loc->val, inst_idx); - if (map_manages_inst) { - if (!idmap) { - // create an id_map and store it in the map - mpr_id GID = mpr_dev_generate_unique_id(sig->dev); - idmap = map->idmap = mpr_dev_add_idmap(sig->dev, 0, 0, GID); - } - msg = mpr_map_build_msg(map, slot, result, dst_types, map->idmap); - } - else { - msg = mpr_map_build_msg(map, slot, result, dst_types, idmaps[idmap_idx].map); - } - mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, - *(mpr_time*)mpr_value_get_time(&dst_slot->loc->val, inst_idx), - map->protocol, bundle_idx); - } - /* send instance release if dst is instanced and either src or map - * is also instanced. */ - if (idmap && status & EXPR_RELEASE_AFTER_UPDATE && map->use_inst) { - msg = mpr_map_build_msg(map, slot, 0, 0, sig->use_inst ? idmaps[idmap_idx].map : idmap); - mpr_link_add_msg(dst_slot->link, dst_slot->sig, msg, t, map->protocol, bundle_idx); - if (map_manages_inst) { - mpr_dev_LID_decref(rtr->dev, 0, idmap); - idmap = map->idmap = 0; - } - } + set_bitflag(map->updated_inst, inst_idx); + map->updated = 1; if (!all) break; } @@ -276,17 +227,17 @@ void mpr_rtr_process_sig(mpr_rtr rtr, mpr_sig sig, int idmap_idx, const void *va *lock = 0; } -static mpr_rtr_sig _add_rtr_sig(mpr_rtr rtr, mpr_sig sig) +static mpr_rtr_sig _add_rtr_sig(mpr_rtr rtr, mpr_local_sig sig) { - // find signal in rtr_sig list + /* find signal in rtr_sig list */ mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); - // if not found, create a new list entry + /* if not found, create a new list entry */ if (!rs) { rs = (mpr_rtr_sig)calloc(1, sizeof(struct _mpr_rtr_sig)); rs->sig = sig; rs->num_slots = 1; - rs->slots = malloc(sizeof(mpr_slot)); + rs->slots = malloc(sizeof(mpr_local_slot)); rs->slots[0] = 0; rs->next = rtr->sigs; rtr->sigs = rs; @@ -294,18 +245,18 @@ static mpr_rtr_sig _add_rtr_sig(mpr_rtr rtr, mpr_sig sig) return rs; } -static int _store_slot(mpr_rtr_sig rs, mpr_slot slot) +static int _store_slot(mpr_rtr_sig rs, mpr_local_slot slot) { int i; for (i = 0; i < rs->num_slots; i++) { if (!rs->slots[i]) { - // store pointer at empty index + /* store pointer at empty index */ rs->slots[i] = slot; return i; } } - // all indices occupied, allocate more - rs->slots = realloc(rs->slots, sizeof(mpr_slot) * rs->num_slots * 2); + /* all indices occupied, allocate more */ + rs->slots = realloc(rs->slots, sizeof(mpr_local_slot) * rs->num_slots * 2); rs->slots[rs->num_slots] = slot; for (i = rs->num_slots+1; i < rs->num_slots * 2; i++) rs->slots[i] = 0; @@ -314,15 +265,16 @@ static int _store_slot(mpr_rtr_sig rs, mpr_slot slot) return i; } -static mpr_id _get_unused_map_id(mpr_dev dev, mpr_rtr rtr) +static mpr_id _get_unused_map_id(mpr_local_dev dev, mpr_rtr rtr) { int i, done = 0; mpr_id id; + mpr_rtr_sig rs; while (!done) { done = 1; - id = mpr_dev_generate_unique_id(dev); - // check if map exists with this id - mpr_rtr_sig rs = rtr->sigs; + id = mpr_dev_generate_unique_id((mpr_dev)dev); + /* check if map exists with this id */ + rs = rtr->sigs; while (rs) { for (i = 0; i < rs->num_slots; i++) { if (!rs->slots[i]) @@ -338,14 +290,13 @@ static mpr_id _get_unused_map_id(mpr_dev dev, mpr_rtr rtr) return id; } -static void _add_local_slot(mpr_rtr rtr, mpr_slot slot, int is_src, - int *max_inst, int *use_inst) +static void _add_local_slot(mpr_rtr rtr, mpr_local_slot slot, int is_src, int *max_inst, + int *use_inst) { - slot->dir = (is_src ^ (slot->sig->loc ? 1 : 0)) ? MPR_DIR_IN : MPR_DIR_OUT; - slot->loc = (mpr_local_slot)calloc(1, sizeof(struct _mpr_local_slot)); - if (slot->sig->loc) { - slot->loc->rsig = _add_rtr_sig(rtr, slot->sig); - _store_slot(slot->loc->rsig, slot); + slot->dir = (is_src ^ (slot->sig->is_local ? 1 : 0)) ? MPR_DIR_IN : MPR_DIR_OUT; + if (slot->sig->is_local) { + slot->rsig = _add_rtr_sig(rtr, (mpr_local_sig)slot->sig); + _store_slot(slot->rsig, slot); if (slot->sig->num_inst > *max_inst) *max_inst = slot->sig->num_inst; @@ -354,61 +305,59 @@ static void _add_local_slot(mpr_rtr rtr, mpr_slot slot, int is_src, if (slot->sig->use_inst) *use_inst = 1; } - if (!slot->sig->loc || (is_src && slot->map->dst->sig->loc)) + if (!slot->sig->is_local || (is_src && slot->map->dst->sig->is_local)) slot->link = mpr_link_new(rtr->dev, slot->sig->dev); - // set some sensible defaults + /* set some sensible defaults */ slot->causes_update = 1; } -void mpr_rtr_add_map(mpr_rtr rtr, mpr_map map) +void mpr_rtr_add_map(mpr_rtr rtr, mpr_local_map map) { - RETURN_UNLESS(!map->loc); - int i, local_src = 0, local_dst = map->dst->sig->loc ? 1 : 0; + int i, local_src = 0, local_dst, max_num_inst = 0, use_inst = 0, scope_count; + RETURN_UNLESS(!map->is_local); for (i = 0; i < map->num_src; i++) { - if (map->src[i]->sig->loc) + if (map->src[i]->sig->is_local) ++local_src; } + local_dst = map->dst->sig->is_local ? 1 : 0; + map->rtr = rtr; + map->is_local = 1; - mpr_local_map lmap = (mpr_local_map)calloc(1, sizeof(struct _mpr_local_map)); - map->loc = lmap; - lmap->rtr = rtr; + /* TODO: configure number of instances available for each slot */ + map->num_inst = 0; - // TODO: configure number of instances available for each slot - lmap->num_inst = 0; - - // Add local slot structures - int max_num_inst = 0, use_inst = 0; + /* Add local slot structures */ for (i = 0; i < map->num_src; i++) _add_local_slot(rtr, map->src[i], 1, &max_num_inst, &use_inst); _add_local_slot(rtr, map->dst, 0, &max_num_inst, &use_inst); - // default to using instanced maps if any of the contributing signals are instanced + /* default to using instanced maps if any of the contributing signals are instanced */ map->use_inst = use_inst; map->protocol = use_inst ? MPR_PROTO_TCP : MPR_PROTO_UDP; - // assign a unique id to this map if we are the destination + /* assign a unique id to this map if we are the destination */ if (local_dst) map->obj.id = _get_unused_map_id(rtr->dev, rtr); /* assign indices to source slots */ if (local_dst) { for (i = 0; i < map->num_src; i++) - map->src[i]->obj.id = map->dst->loc->rsig->id_counter++; + map->src[i]->id = map->dst->rsig->id_counter++; } else { /* may be overwritten later by message */ for (i = 0; i < map->num_src; i++) - map->src[i]->obj.id = i; + map->src[i]->id = i; } - // add scopes - int scope_count = 0; + /* add scopes */ + scope_count = 0; map->num_scopes = map->num_src; map->scopes = (mpr_dev *) malloc(sizeof(mpr_dev) * map->num_scopes); for (i = 0; i < map->num_src; i++) { - // check that scope has not already been added + /* check that scope has not already been added */ int j, found = 0; for (j = 0; j < scope_count; j++) { if (map->scopes[j] == map->src[i]->sig->dev) { @@ -427,21 +376,21 @@ void mpr_rtr_add_map(mpr_rtr rtr, mpr_map map) map->scopes = realloc(map->scopes, sizeof(mpr_dev) * scope_count); } - // check if all sources belong to same remote device - lmap->one_src = 1; + /* check if all sources belong to same remote device */ + map->one_src = 1; for (i = 1; i < map->num_src; i++) { if (map->src[i]->link != map->src[0]->link) { - lmap->one_src = 0; + map->one_src = 0; break; } } - // default to processing at source device unless heterogeneous sources - map->process_loc = (lmap->one_src) ? MPR_LOC_SRC : MPR_LOC_DST; + /* default to processing at source device unless heterogeneous sources */ + map->process_loc = (map->is_local_only || map->one_src) ? MPR_LOC_SRC : MPR_LOC_DST; if (local_dst && (local_src == map->num_src)) { - // all reference signals are local - lmap->is_local_only = 1; + /* all reference signals are local */ + map->is_local_only = 1; map->dst->link = map->src[0]->link; } @@ -460,13 +409,14 @@ static void _check_link(mpr_rtr rtr, mpr_link link) void mpr_rtr_remove_link(mpr_rtr rtr, mpr_link link) { int i, j; - // check if any maps use this link + mpr_local_map map; + /* check if any maps use this link */ mpr_rtr_sig rs = rtr->sigs; while (rs) { for (i = 0; i < rs->num_slots; i++) { if (!rs->slots[i]) continue; - mpr_map map = rs->slots[i]->map; + map = rs->slots[i]->map; if (map->dst->link == link) { mpr_rtr_remove_map(rtr, map); continue; @@ -485,7 +435,7 @@ void mpr_rtr_remove_link(mpr_rtr rtr, mpr_link link) void mpr_rtr_remove_sig(mpr_rtr rtr, mpr_rtr_sig rs) { if (rtr && rs) { - // No maps remaining – we can remove the rtr_sig also + /* No maps remaining – we can remove the rtr_sig also */ mpr_rtr_sig *rstemp = &rtr->sigs; while (*rstemp) { if (*rstemp == rs) { @@ -499,51 +449,52 @@ void mpr_rtr_remove_sig(mpr_rtr rtr, mpr_rtr_sig rs) } } -int mpr_rtr_remove_map(mpr_rtr rtr, mpr_map map) +int mpr_rtr_remove_map(mpr_rtr rtr, mpr_local_map map) { - RETURN_UNLESS(map && map->loc, 1); - // do not free local names since they point to signal's copy + /* do not free local names since they point to signal's copy */ + int i, j; mpr_time t; + RETURN_ARG_UNLESS(map, 1); mpr_time_set(&t, MPR_NOW); if (map->idmap) { - // release map-generated instances - if (map->dst->loc->rsig) { + /* release map-generated instances */ + if (map->dst->rsig) { lo_message msg = mpr_map_build_msg(map, 0, 0, 0, map->idmap); mpr_dev_bundle_start(t, NULL); mpr_dev_handler(NULL, lo_message_get_types(msg), lo_message_get_argv(msg), - lo_message_get_argc(msg), msg, (void*)map->dst->sig->loc); + lo_message_get_argc(msg), msg, (void*)map->dst->sig); } else mpr_dev_LID_decref(rtr->dev, 0, map->idmap); } - // remove map and slots from rtr_sig lists if necessary - if (map->dst->loc->rsig) { - mpr_rtr_sig rs = map->dst->loc->rsig; - // release instances if necessary - // TODO: determine whether instances were activated through this map - // need to trigger "remote" release - mpr_sig s = rs->sig; - mpr_sig_idmap_t *maps = s->loc->idmaps; - for (i = 0; i < s->loc->idmap_len; i++) { + /* remove map and slots from rtr_sig lists if necessary */ + if (map->dst->rsig) { + mpr_rtr_sig rs = map->dst->rsig; + /* release instances if necessary */ + /* TODO: determine whether instances were activated through this map */ + /* need to trigger "remote" release */ + mpr_local_sig sig = rs->sig; + mpr_sig_idmap_t *maps = sig->idmaps; + for (i = 0; i < sig->idmap_len; i++) { if (!maps[i].map) continue; if (maps[i].status & RELEASED_LOCALLY) { - mpr_dev_GID_decref(rtr->dev, s->loc->group, maps[i].map); + mpr_dev_GID_decref(rtr->dev, sig->group, maps[i].map); maps[i].map = 0; } else { maps[i].status |= RELEASED_REMOTELY; - mpr_dev_GID_decref(rtr->dev, s->loc->group, maps[i].map); - if (s->use_inst) { - int evt = ( MPR_SIG_REL_UPSTRM & s->loc->event_flags + mpr_dev_GID_decref(rtr->dev, sig->group, maps[i].map); + if (sig->use_inst) { + int evt = ( MPR_SIG_REL_UPSTRM & sig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE); - mpr_sig_call_handler(s, evt, maps[i].map->LID, 0, 0, &t, 0); + mpr_sig_call_handler(sig, evt, maps[i].map->LID, 0, 0, &t, 0); } else { - mpr_dev_LID_decref(rtr->dev, s->loc->group, maps[i].map); + mpr_dev_LID_decref(rtr->dev, sig->group, maps[i].map); maps[i].map = 0; maps[i].inst->active = 0; maps[i].inst = 0; @@ -564,8 +515,8 @@ int mpr_rtr_remove_map(mpr_rtr rtr, mpr_map map) } mpr_slot_free_value(map->dst); for (i = 0; i < map->num_src; i++) { - if (map->src[i]->loc->rsig) { - mpr_rtr_sig rs = map->src[i]->loc->rsig; + if (map->src[i]->rsig) { + mpr_rtr_sig rs = map->src[i]->rsig; for (j = 0; j < rs->num_slots; j++) { if (rs->slots[j] == map->src[i]) rs->slots[j] = 0; @@ -578,64 +529,66 @@ int mpr_rtr_remove_map(mpr_rtr rtr, mpr_map map) mpr_slot_free_value(map->src[i]); } - // one more case: if map is local only need to decrement num_maps in local map - if (map->loc->is_local_only) { - mpr_link link = mpr_dev_get_link_by_remote(rtr->dev, rtr->dev); + /* one more case: if map is local only need to decrement num_maps in local map */ + if (map->is_local_only) { + mpr_link link = mpr_dev_get_link_by_remote(rtr->dev, (mpr_dev)rtr->dev); if (link) --link->num_maps[0]; } - // free buffers associated with user-defined expression variables - if (map->loc->vars) { - for (i = 0; i < map->loc->num_vars; i++) { - mpr_value_free(&map->loc->vars[i]); - free((void*)map->loc->var_names[i]); + /* free buffers associated with user-defined expression variables */ + if (map->vars) { + for (i = 0; i < map->num_vars; i++) { + mpr_value_free(&map->vars[i]); + free((void*)map->var_names[i]); } - free(map->loc->vars); - free(map->loc->var_names); + free(map->vars); + free(map->var_names); } - FUNC_IF(mpr_expr_free, map->loc->expr); - free(map->loc); + + FUNC_IF(free, map->updated_inst); + FUNC_IF(mpr_expr_free, map->expr); _update_map_count(rtr); return 0; } -int mpr_rtr_loop_check(mpr_rtr rtr, mpr_sig local_sig, int num_remotes, - const char **remotes) +int mpr_rtr_loop_check(mpr_rtr rtr, mpr_local_sig sig, int num_remotes, const char **remotes) { - mpr_rtr_sig rs = _find_rtr_sig(rtr, local_sig); - RETURN_UNLESS(rs, 0); int i, j; + mpr_local_map map; + mpr_local_slot slot; + mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); + RETURN_ARG_UNLESS(rs, 0); for (i = 0; i < rs->num_slots; i++) { if (!rs->slots[i] || rs->slots[i]->dir == MPR_DIR_IN) continue; - mpr_slot slot = rs->slots[i]; - mpr_map map = slot->map; + slot = rs->slots[i]; + map = slot->map; - // check destination + /* check destination */ for (j = 0; j < num_remotes; j++) { - if (!mpr_slot_match_full_name(map->dst, remotes[j])) + if (!mpr_slot_match_full_name((mpr_slot)map->dst, remotes[j])) return 1; } } return 0; } -mpr_slot mpr_rtr_get_slot(mpr_rtr rtr, mpr_sig sig, int slot_id) +/* TODO: speed this up with sorted slots and binary search */ +mpr_local_slot mpr_rtr_get_slot(mpr_rtr rtr, mpr_local_sig sig, int slot_id) { - // only interested in incoming slots - mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); - RETURN_UNLESS(rs, NULL); - int i, j; - mpr_map map; + mpr_local_map map; + /* only interested in incoming slots */ + mpr_rtr_sig rs = _find_rtr_sig(rtr, sig); + RETURN_ARG_UNLESS(rs, NULL); for (i = 0; i < rs->num_slots; i++) { - if (!rs->slots[i] || rs->slots[i]->dir == MPR_DIR_OUT) + if (!rs->slots[i] || sig->dir != rs->slots[i]->dir) continue; map = rs->slots[i]->map; - // check incoming slots for this map + /* check incoming slots for this map */ for (j = 0; j < map->num_src; j++) { - if ((int)map->src[j]->obj.id == slot_id) + if ((int)map->src[j]->id == slot_id) return map->src[j]; } } diff --git a/src/mapper/signal.c b/src/mapper/signal.c index 79351a4..17b9af5 100644 --- a/src/mapper/signal.c +++ b/src/mapper/signal.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -10,53 +10,59 @@ #include #define MAX_INSTANCES 128 +#define BUFFSIZE 512 + +/* TODO: MPR_DEFAULT_INST is actually a valid id - we should use + * another method for distinguishing non-instanced updates. */ +#define MPR_DEFAULT_INST -1 /* Function prototypes */ -static int _add_idmap(mpr_sig s, mpr_sig_inst si, mpr_id_map map); +static int _add_idmap(mpr_local_sig lsig, mpr_sig_inst si, mpr_id_map map); static int _compare_inst_ids(const void *l, const void *r) { return memcmp(&(*(mpr_sig_inst*)l)->id, &(*(mpr_sig_inst*)r)->id, sizeof(mpr_id)); } -static mpr_sig_inst _find_inst_by_id(mpr_sig s, mpr_id id) +static mpr_sig_inst _find_inst_by_id(mpr_local_sig lsig, mpr_id id) { - RETURN_UNLESS(s->num_inst, 0); - mpr_sig_inst_t si; - mpr_sig_inst sip = &si; + mpr_sig_inst_t si, *sip, **sipp; + RETURN_ARG_UNLESS(lsig->num_inst, 0); + sip = &si; si.id = id; - mpr_sig_inst *sipp = bsearch(&sip, s->loc->inst, s->num_inst, - sizeof(mpr_sig_inst), _compare_inst_ids); + sipp = bsearch(&sip, lsig->inst, lsig->num_inst, sizeof(mpr_sig_inst), _compare_inst_ids); return (sipp && *sipp) ? *sipp : 0; } -// Add a signal to a parent object. +/* Add a signal to a parent object. */ mpr_sig mpr_sig_new(mpr_dev dev, mpr_dir dir, const char *name, int len, mpr_type type, const char *unit, const void *min, const void *max, int *num_inst, mpr_sig_handler *h, int events) { - // For now we only allow adding signals to devices. - RETURN_UNLESS(dev && dev->loc, 0); - RETURN_UNLESS(name && !check_sig_length(len) && mpr_type_get_is_num(type), 0); + mpr_graph g; + mpr_local_sig lsig; + + /* For now we only allow adding signals to devices. */ + RETURN_ARG_UNLESS(dev && dev->is_local, 0); + RETURN_ARG_UNLESS(name && !check_sig_length(len) && mpr_type_get_is_num(type), 0); TRACE_RETURN_UNLESS(name[strlen(name)-1] != '/', 0, "trailing slash detected in signal name.\n"); TRACE_RETURN_UNLESS(dir == MPR_DIR_IN || dir == MPR_DIR_OUT, 0, "signal direction must be either input or output.\n") - mpr_graph g = dev->obj.graph; - mpr_sig s; - if ((s = mpr_dev_get_sig_by_name(dev, name))) - return s; - - s = (mpr_sig)mpr_list_add_item((void**)&g->sigs, sizeof(mpr_sig_t)); - s->loc = (mpr_local_sig)calloc(1, sizeof(mpr_local_sig_t)); - s->dev = dev; - s->obj.id = mpr_dev_get_unused_sig_id(dev); - s->obj.graph = g; - s->period = -1; - s->loc->handler = h; - s->loc->event_flags = events; - mpr_sig_init(s, dir, name, len, type, unit, min, max, num_inst); + g = dev->obj.graph; + if ((lsig = (mpr_local_sig)mpr_dev_get_sig_by_name(dev, name))) + return (mpr_sig)lsig; + + lsig = (mpr_local_sig)mpr_list_add_item((void**)&g->sigs, sizeof(mpr_local_sig_t)); + lsig->dev = (mpr_local_dev)dev; + lsig->obj.id = mpr_dev_get_unused_sig_id((mpr_local_dev)dev); + lsig->obj.graph = g; + lsig->period = -1; + lsig->handler = (void*)h; + lsig->event_flags = events; + lsig->is_local = 1; + mpr_sig_init((mpr_sig)lsig, dir, name, len, type, unit, min, max, num_inst); if (dir == MPR_DIR_IN) ++dev->num_inputs; @@ -65,84 +71,88 @@ mpr_sig mpr_sig_new(mpr_dev dev, mpr_dir dir, const char *name, int len, mpr_obj_increment_version((mpr_obj)dev); - mpr_dev_add_sig_methods(dev, s); - if (dev->loc->registered) { - // Notify subscribers - mpr_net_use_subscribers(&g->net, dev, ((dir == MPR_DIR_IN) ? MPR_SIG_IN : MPR_SIG_OUT)); - mpr_sig_send_state(s, MSG_SIG); + mpr_dev_add_sig_methods((mpr_local_dev)dev, lsig); + if (((mpr_local_dev)dev)->registered) { + /* Notify subscribers */ + mpr_net_use_subscribers(&g->net, (mpr_local_dev)dev, + ((dir == MPR_DIR_IN) ? MPR_SIG_IN : MPR_SIG_OUT)); + mpr_sig_send_state((mpr_sig)lsig, MSG_SIG); } - return s; + return (mpr_sig)lsig; } -void mpr_sig_init(mpr_sig s, mpr_dir dir, const char *name, int len, - mpr_type type, const char *unit, const void *min, - const void *max, int *num_inst) +void mpr_sig_init(mpr_sig sig, mpr_dir dir, const char *name, int len, mpr_type type, + const char *unit, const void *min, const void *max, int *num_inst) { + int i, str_len, loc_mod, rem_mod; + mpr_tbl tbl; RETURN_UNLESS(name); + name = skip_slash(name); - int i, str_len = strlen(name)+2; - s->path = malloc(str_len); - snprintf(s->path, str_len, "/%s", name); - s->name = (char*)s->path+1; - s->len = len; - s->type = type; - s->dir = dir ?: MPR_DIR_OUT; - s->unit = unit ? strdup(unit) : strdup("unknown"); - s->min = s->max = 0; - s->num_inst = 0; - s->use_inst = 0; - - if (s->loc) { - s->loc->vec_known = calloc(1, len / 8 + 1); + str_len = strlen(name)+2; + sig->path = malloc(str_len); + snprintf(sig->path, str_len, "/%s", name); + sig->name = (char*)sig->path+1; + sig->len = len; + sig->type = type; + sig->dir = dir ? dir : MPR_DIR_OUT; + sig->unit = unit ? strdup(unit) : strdup("unknown"); + sig->min = sig->max = 0; + sig->num_inst = 0; + sig->use_inst = 0; + + if (sig->is_local) { + mpr_local_sig lsig = (mpr_local_sig)sig; + lsig->vec_known = calloc(1, len / 8 + 1); for (i = 0; i < len; i++) - s->loc->vec_known[i/8] |= 1 << (i % 8); + set_bitflag(lsig->vec_known, i); + lsig->updated_inst = 0; if (num_inst) { - mpr_sig_reserve_inst(s, *num_inst, 0, 0); - s->use_inst = 1; + mpr_sig_reserve_inst((mpr_sig)lsig, *num_inst, 0, 0); + lsig->use_inst = 1; } else { - mpr_sig_reserve_inst(s, 1, 0, 0); + mpr_sig_reserve_inst((mpr_sig)lsig, 1, 0, 0); } - // Reserve one instance id map - s->loc->idmap_len = 1; - s->loc->idmaps = calloc(1, sizeof(struct _mpr_sig_idmap)); + /* Reserve one instance id map */ + lsig->idmap_len = 1; + lsig->idmaps = calloc(1, sizeof(struct _mpr_sig_idmap)); } else - s->obj.props.staged = mpr_tbl_new(); + sig->obj.props.staged = mpr_tbl_new(); - s->obj.type = MPR_SIG; - s->obj.props.synced = mpr_tbl_new(); - s->obj.props.mask = 0; + sig->obj.type = MPR_SIG; + sig->obj.props.synced = mpr_tbl_new(); - mpr_tbl t = s->obj.props.synced; - int loc_mod = s->loc ? MODIFIABLE : NON_MODIFIABLE; - int rem_mod = s->loc ? NON_MODIFIABLE : MODIFIABLE; + tbl = sig->obj.props.synced; + loc_mod = sig->is_local ? MODIFIABLE : NON_MODIFIABLE; + rem_mod = sig->is_local ? NON_MODIFIABLE : MODIFIABLE; - // these properties need to be added in alphabetical order - mpr_tbl_link(t, PROP(DATA), 1, MPR_PTR, &s->obj.data, + /* these properties need to be added in alphabetical order */ + mpr_tbl_link(tbl, PROP(DATA), 1, MPR_PTR, &sig->obj.data, LOCAL_MODIFY | INDIRECT | LOCAL_ACCESS_ONLY); - mpr_tbl_link(t, PROP(DEV), 1, MPR_DEV, &s->dev, + mpr_tbl_link(tbl, PROP(DEV), 1, MPR_DEV, &sig->dev, NON_MODIFIABLE | INDIRECT | LOCAL_ACCESS_ONLY); - mpr_tbl_link(t, PROP(DIR), 1, MPR_INT32, &s->dir, rem_mod); - mpr_tbl_link(t, PROP(ID), 1, MPR_INT64, &s->obj.id, rem_mod); - mpr_tbl_link(t, PROP(JITTER), 1, MPR_FLT, &s->jitter, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(LEN), 1, MPR_INT32, &s->len, rem_mod); - mpr_tbl_link(t, PROP(MAX), s->len, s->type, &s->max, MODIFIABLE | INDIRECT); - mpr_tbl_link(t, PROP(MIN), s->len, s->type, &s->min, MODIFIABLE | INDIRECT); - mpr_tbl_link(t, PROP(NAME), 1, MPR_STR, &s->name, NON_MODIFIABLE | INDIRECT); - mpr_tbl_link(t, PROP(NUM_INST), 1, MPR_INT32, &s->num_inst, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(NUM_MAPS_IN), 1, MPR_INT32, &s->num_maps_in, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(NUM_MAPS_OUT), 1, MPR_INT32, &s->num_maps_out, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(PERIOD), 1, MPR_FLT, &s->period, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(STEAL_MODE), 1, MPR_INT32, &s->steal_mode, MODIFIABLE); - mpr_tbl_link(t, PROP(TYPE), 1, MPR_TYPE, &s->type, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(UNIT), 1, MPR_STR, &s->unit, loc_mod | INDIRECT); - mpr_tbl_link(t, PROP(USE_INST), 1, MPR_BOOL, &s->use_inst, NON_MODIFIABLE); - mpr_tbl_link(t, PROP(VERSION), 1, MPR_INT32, &s->obj.version, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(DIR), 1, MPR_INT32, &sig->dir, MODIFIABLE); + mpr_tbl_link(tbl, PROP(ID), 1, MPR_INT64, &sig->obj.id, rem_mod); + mpr_tbl_link(tbl, PROP(JITTER), 1, MPR_FLT, &sig->jitter, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(LEN), 1, MPR_INT32, &sig->len, rem_mod); + mpr_tbl_link(tbl, PROP(MAX), sig->len, sig->type, &sig->max, MODIFIABLE | INDIRECT); + mpr_tbl_link(tbl, PROP(MIN), sig->len, sig->type, &sig->min, MODIFIABLE | INDIRECT); + mpr_tbl_link(tbl, PROP(NAME), 1, MPR_STR, &sig->name, NON_MODIFIABLE | INDIRECT); + mpr_tbl_link(tbl, PROP(NUM_INST), 1, MPR_INT32, &sig->num_inst, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(NUM_MAPS_IN), 1, MPR_INT32, &sig->num_maps_in, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(NUM_MAPS_OUT), 1, MPR_INT32, &sig->num_maps_out, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(PERIOD), 1, MPR_FLT, &sig->period, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(STEAL_MODE), 1, MPR_INT32, &sig->steal_mode, MODIFIABLE); + mpr_tbl_link(tbl, PROP(TYPE), 1, MPR_TYPE, &sig->type, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(UNIT), 1, MPR_STR, &sig->unit, loc_mod | INDIRECT); + mpr_tbl_link(tbl, PROP(USE_INST), 1, MPR_BOOL, &sig->use_inst, NON_MODIFIABLE); + mpr_tbl_link(tbl, PROP(VERSION), 1, MPR_INT32, &sig->obj.version, NON_MODIFIABLE); if (min && max) { - // make sure in the right order + /* make sure in the right order */ #define TYPED_CASE(TYPE, CTYPE) \ case TYPE: { \ for (i = 0; i < len; i++) { \ @@ -161,98 +171,105 @@ case TYPE: { \ } } if (min) - mpr_tbl_set(t, PROP(MIN), NULL, len, type, min, LOCAL_MODIFY); + mpr_tbl_set(tbl, PROP(MIN), NULL, len, type, min, LOCAL_MODIFY); if (max) - mpr_tbl_set(t, PROP(MAX), NULL, len, type, max, LOCAL_MODIFY); + mpr_tbl_set(tbl, PROP(MAX), NULL, len, type, max, LOCAL_MODIFY); - mpr_tbl_set(t, PROP(IS_LOCAL), NULL, 1, MPR_BOOL, &s->loc, LOCAL_ACCESS_ONLY | NON_MODIFIABLE); + mpr_tbl_set(tbl, PROP(IS_LOCAL), NULL, 1, MPR_BOOL, &sig->is_local, LOCAL_ACCESS_ONLY | NON_MODIFIABLE); } void mpr_sig_free(mpr_sig sig) { - RETURN_UNLESS(sig && sig->loc); int i; - mpr_dev dev = sig->dev; - - // release active instances - for (i = 0; i < sig->loc->idmap_len; i++) { - if (sig->loc->idmaps[i].inst) - mpr_dev_LID_decref(sig->dev, sig->loc->group, sig->loc->idmaps[i].map); + mpr_local_dev ldev; + mpr_net net; + mpr_local_sig lsig = (mpr_local_sig)sig; + mpr_rtr rtr; + mpr_rtr_sig rs; + RETURN_UNLESS(sig && sig->is_local); + ldev = (mpr_local_dev)sig->dev; + + /* release active instances */ + for (i = 0; i < lsig->idmap_len; i++) { + if (lsig->idmaps[i].inst) + mpr_dev_LID_decref(ldev, lsig->group, lsig->idmaps[i].map); } - // release associated OSC methods - mpr_dev_remove_sig_methods(dev, sig); - mpr_net net = &sig->obj.graph->net; - mpr_rtr rtr = net->rtr; - mpr_rtr_sig rs = rtr->sigs; - while (rs && rs->sig != sig) + /* release associated OSC methods */ + mpr_dev_remove_sig_methods(ldev, lsig); + net = &sig->obj.graph->net; + rtr = net->rtr; + rs = rtr->sigs; + while (rs && rs->sig != lsig) rs = rs->next; if (rs) { - // need to unmap + mpr_local_map map; + /* need to unmap */ for (i = 0; i < rs->num_slots; i++) { if (!rs->slots[i]) continue; - mpr_map m = rs->slots[i]->map; - mpr_map_release(m); - mpr_rtr_remove_map(rtr, m); + map = (mpr_local_map)rs->slots[i]->map; + mpr_map_release((mpr_map)map); + mpr_rtr_remove_map(rtr, map); } mpr_rtr_remove_sig(rtr, rs); } - if (dev->loc->registered) { - // Notify subscribers + if (ldev->registered) { + /* Notify subscribers */ int dir = (sig->dir == MPR_DIR_IN) ? MPR_SIG_IN : MPR_SIG_OUT; - mpr_net_use_subscribers(net, dev, dir); - mpr_sig_send_removed(sig); + mpr_net_use_subscribers(net, ldev, dir); + mpr_sig_send_removed(lsig); } - + free(lsig->updated_inst); mpr_graph_remove_sig(sig->obj.graph, sig, MPR_OBJ_REM); - mpr_obj_increment_version((mpr_obj)dev); + mpr_obj_increment_version((mpr_obj)ldev); } -void mpr_sig_free_internal(mpr_sig s) +void mpr_sig_free_internal(mpr_sig sig) { - RETURN_UNLESS(s); int i; - if (s->loc) { - // Free instances - for (i = 0; i < s->loc->idmap_len; i++) { - if (s->loc->idmaps[i].inst) - mpr_sig_release_inst_internal(s, i); + RETURN_UNLESS(sig); + if (sig->is_local) { + mpr_local_sig lsig = (mpr_local_sig)sig; + /* Free instances */ + for (i = 0; i < lsig->idmap_len; i++) { + if (lsig->idmaps[i].inst) + mpr_sig_release_inst_internal(lsig, i); } - free(s->loc->idmaps); - for (i = 0; i < s->num_inst; i++) { - FUNC_IF(free, s->loc->inst[i]->val); - FUNC_IF(free, s->loc->inst[i]->has_val_flags); - free(s->loc->inst[i]); + free(lsig->idmaps); + for (i = 0; i < lsig->num_inst; i++) { + FUNC_IF(free, lsig->inst[i]->val); + FUNC_IF(free, lsig->inst[i]->has_val_flags); + free(lsig->inst[i]); } - free(s->loc->inst); - FUNC_IF(free, s->loc->vec_known); - free(s->loc); + free(lsig->inst); + FUNC_IF(free, lsig->vec_known); } - FUNC_IF(mpr_tbl_free, s->obj.props.synced); - FUNC_IF(mpr_tbl_free, s->obj.props.staged); - FUNC_IF(free, s->max); - FUNC_IF(free, s->min); - FUNC_IF(free, s->path); - FUNC_IF(free, s->unit); + FUNC_IF(mpr_tbl_free, sig->obj.props.synced); + FUNC_IF(mpr_tbl_free, sig->obj.props.staged); + FUNC_IF(free, sig->max); + FUNC_IF(free, sig->min); + FUNC_IF(free, sig->path); + FUNC_IF(free, sig->unit); } -void mpr_sig_call_handler(mpr_sig sig, int evt, mpr_id inst, int len, +void mpr_sig_call_handler(mpr_local_sig lsig, int evt, mpr_id inst, int len, const void *val, mpr_time *time, float diff) { - // abort if signal is already being processed - might be a local loop - if (sig->loc->locked) { - trace_dev(sig->dev, "Mapping loop detected on signal %s! (2)\n", sig->name); + mpr_sig_handler *h; + /* abort if signal is already being processed - might be a local loop */ + if (lsig->locked) { + trace_dev(lsig->dev, "Mapping loop detected on signal %s! (2)\n", lsig->name); return; } - // non-instanced signals cannot have a null value - if (!val && !sig->use_inst) + /* non-instanced signals cannot have a null value */ + if (!val && !lsig->use_inst) return; - mpr_sig_update_timing_stats(sig, diff); - mpr_sig_handler *h = sig->loc->handler; - if (h && (evt & sig->loc->event_flags)) - h(sig, evt, inst, len, sig->type, val, *time); + mpr_sig_update_timing_stats(lsig, diff); + h = (mpr_sig_handler*)lsig->handler; + if (h && (evt & lsig->event_flags)) + h((mpr_sig)lsig, evt, lsig->use_inst ? inst : 0, len, lsig->type, val, *time); } /**** Instances ****/ @@ -264,39 +281,39 @@ static void _init_inst(mpr_sig_inst si) mpr_time_set(&si->time, si->created); } -static mpr_sig_inst _reserved_inst(mpr_sig s, mpr_id *id) +static mpr_sig_inst _reserved_inst(mpr_local_sig lsig, mpr_id *id) { int i; - for (i = 0; i < s->num_inst; i++) { - if (!s->loc->inst[i]->active) { + for (i = 0; i < lsig->num_inst; i++) { + if (!lsig->inst[i]->active) { if (id) - s->loc->inst[i]->id = *id; - qsort(s->loc->inst, s->num_inst, sizeof(mpr_sig_inst), _compare_inst_ids); - return s->loc->inst[i]; + lsig->inst[i]->id = *id; + qsort(lsig->inst, lsig->num_inst, sizeof(mpr_sig_inst), _compare_inst_ids); + return lsig->inst[i]; } } return 0; } -int _oldest_inst(mpr_sig sig) +int _oldest_inst(mpr_local_sig lsig) { - int i; + int i, oldest; mpr_sig_inst si; - for (i = 0; i < sig->loc->idmap_len; i++) { - if (sig->loc->idmaps[i].inst) + for (i = 0; i < lsig->idmap_len; i++) { + if (lsig->idmaps[i].inst) break; } - if (i == sig->loc->idmap_len) { - // no active instances to steal! + if (i == lsig->idmap_len) { + /* no active instances to steal! */ return -1; } - int oldest = i; - for (i = oldest+1; i < sig->loc->idmap_len; i++) { - if (!(si = sig->loc->idmaps[i].inst)) + oldest = i; + for (i = oldest+1; i < lsig->idmap_len; i++) { + if (!(si = lsig->idmaps[i].inst)) continue; - if ((si->created.sec < sig->loc->idmaps[oldest].inst->created.sec) || - (si->created.sec == sig->loc->idmaps[oldest].inst->created.sec && - si->created.frac < sig->loc->idmaps[oldest].inst->created.frac)) + if ((si->created.sec < lsig->idmaps[oldest].inst->created.sec) || + (si->created.sec == lsig->idmaps[oldest].inst->created.sec && + si->created.frac < lsig->idmaps[oldest].inst->created.frac)) oldest = i; } return oldest; @@ -304,30 +321,31 @@ int _oldest_inst(mpr_sig sig) mpr_id mpr_sig_get_oldest_inst_id(mpr_sig sig) { - RETURN_UNLESS(sig && sig->loc && sig->use_inst, 0); - int idx = _oldest_inst(sig); - return (idx >= 0) ? sig->loc->idmaps[idx].map->LID : 0; + int idx; + RETURN_ARG_UNLESS(sig && sig->is_local && sig->use_inst, 0); + idx = _oldest_inst((mpr_local_sig)sig); + return (idx >= 0) ? ((mpr_local_sig)sig)->idmaps[idx].map->LID : 0; } -int _newest_inst(mpr_sig sig) +int _newest_inst(mpr_local_sig lsig) { - int i; + int i, newest; mpr_sig_inst si; - for (i = 0; i < sig->loc->idmap_len; i++) { - if (sig->loc->idmaps[i].inst) + for (i = 0; i < lsig->idmap_len; i++) { + if (lsig->idmaps[i].inst) break; } - if (i == sig->loc->idmap_len) { - // no active instances to steal! + if (i == lsig->idmap_len) { + /* no active instances to steal! */ return -1; } - int newest = i; - for (i = newest+1; i < sig->loc->idmap_len; i++) { - if (!(si = sig->loc->idmaps[i].inst)) + newest = i; + for (i = newest + 1; i < lsig->idmap_len; i++) { + if (!(si = lsig->idmaps[i].inst)) continue; - if ((si->created.sec > sig->loc->idmaps[newest].inst->created.sec) || - (si->created.sec == sig->loc->idmaps[newest].inst->created.sec && - si->created.frac > sig->loc->idmaps[newest].inst->created.frac)) + if ((si->created.sec > lsig->idmaps[newest].inst->created.sec) || + (si->created.sec == lsig->idmaps[newest].inst->created.sec && + si->created.frac > lsig->idmaps[newest].inst->created.frac)) newest = i; } return newest; @@ -335,103 +353,108 @@ int _newest_inst(mpr_sig sig) mpr_id mpr_sig_get_newest_inst_id(mpr_sig sig) { - RETURN_UNLESS(sig && sig->loc && sig->use_inst, 0); - int idx = _newest_inst(sig); - return (idx >= 0) ? sig->loc->idmaps[idx].map->LID : 0; + int idx; + RETURN_ARG_UNLESS(sig && sig->is_local && sig->use_inst, 0); + idx = _newest_inst((mpr_local_sig)sig); + return (idx >= 0) ? ((mpr_local_sig)sig)->idmaps[idx].map->LID : 0; } -int mpr_sig_get_idmap_with_LID(mpr_sig s, mpr_id LID, int flags, mpr_time t, int activate) +int mpr_sig_get_idmap_with_LID(mpr_local_sig lsig, mpr_id LID, int flags, mpr_time t, int activate) { - RETURN_UNLESS(s && s->loc, -1); - mpr_sig_idmap_t *maps = s->loc->idmaps; - mpr_sig_handler *h = s->loc->handler; + mpr_sig_idmap_t *maps; + mpr_sig_handler *h; mpr_sig_inst si; + mpr_id_map map; int i; - for (i = 0; i < s->loc->idmap_len; i++) { + if (!lsig->use_inst) + LID = MPR_DEFAULT_INST; + maps = lsig->idmaps; + h = (mpr_sig_handler*)lsig->handler; + for (i = 0; i < lsig->idmap_len; i++) { if (maps[i].inst && maps[i].map->LID == LID) return (maps[i].status & ~flags) ? -1 : i; } - RETURN_UNLESS(activate, -1); + RETURN_ARG_UNLESS(activate, -1); - // check if device has record of id map - mpr_id_map map = mpr_dev_get_idmap_by_LID(s->dev, s->loc->group, LID); + /* check if device has record of id map */ + map = mpr_dev_get_idmap_by_LID((mpr_local_dev)lsig->dev, lsig->group, LID); /* No instance with that id exists - need to try to activate instance and * create new id map if necessary. */ - if ((si = _find_inst_by_id(s, LID)) || (si = _reserved_inst(s, &LID))) { + if ((si = _find_inst_by_id(lsig, LID)) || (si = _reserved_inst(lsig, &LID))) { if (!map) { - // Claim id map locally, add id map to device and link from signal - mpr_id GID = mpr_dev_generate_unique_id(s->dev); - map = mpr_dev_add_idmap(s->dev, s->loc->group, LID, GID); + /* Claim id map locally */ + map = mpr_dev_add_idmap((mpr_local_dev)lsig->dev, lsig->group, LID, 0); } else - mpr_dev_LID_incref(s->dev, map); + mpr_dev_LID_incref((mpr_local_dev)lsig->dev, map); - // store pointer to device map in a new signal map + /* store pointer to device map in a new signal map */ si->active = 1; _init_inst(si); - i = _add_idmap(s, si, map); - if (h && (s->loc->event_flags & MPR_SIG_INST_NEW)) - h(s, MPR_SIG_INST_NEW, LID, 0, s->type, NULL, t); + i = _add_idmap(lsig, si, map); + if (h && (lsig->event_flags & MPR_SIG_INST_NEW)) + h((mpr_sig)lsig, MPR_SIG_INST_NEW, LID, 0, lsig->type, NULL, t); return i; } - RETURN_UNLESS(h, -1); - if (s->loc->event_flags & MPR_SIG_INST_OFLW) { - // call instance event handler - h(s, MPR_SIG_INST_OFLW, 0, 0, s->type, NULL, t); + RETURN_ARG_UNLESS(h, -1); + if (lsig->event_flags & MPR_SIG_INST_OFLW) { + /* call instance event handler */ + h((mpr_sig)lsig, MPR_SIG_INST_OFLW, 0, 0, lsig->type, NULL, t); } - else if (s->steal_mode == MPR_STEAL_OLDEST) { - i = _oldest_inst(s); + else if (lsig->steal_mode == MPR_STEAL_OLDEST) { + i = _oldest_inst(lsig); if (i < 0) return -1; - int evt = (MPR_SIG_REL_UPSTRM & s->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE); - h(s, evt, s->loc->idmaps[i].map->LID, 0, s->type, 0, t); + h((mpr_sig)lsig, MPR_SIG_REL_UPSTRM & lsig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE, + lsig->idmaps[i].map->LID, 0, lsig->type, 0, t); } - else if (s->steal_mode == MPR_STEAL_NEWEST) { - i = _newest_inst(s); + else if (lsig->steal_mode == MPR_STEAL_NEWEST) { + i = _newest_inst(lsig); if (i < 0) return -1; - int evt = (MPR_SIG_REL_UPSTRM & s->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE); - h(s, evt, s->loc->idmaps[i].map->LID, 0, s->type, 0, t); + h((mpr_sig)lsig, MPR_SIG_REL_UPSTRM & lsig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE, + lsig->idmaps[i].map->LID, 0, lsig->type, 0, t); } else return -1; - // try again - if ((si = _find_inst_by_id(s, LID)) || (si = _reserved_inst(s, &LID))) { + /* try again */ + if ((si = _find_inst_by_id(lsig, LID)) || (si = _reserved_inst(lsig, &LID))) { if (!map) { - // Claim id map locally add id map to device and link from signal - mpr_id GID = mpr_dev_generate_unique_id(s->dev); - map = mpr_dev_add_idmap(s->dev, s->loc->group, LID, GID); + /* Claim id map locally */ + map = mpr_dev_add_idmap((mpr_local_dev)lsig->dev, lsig->group, LID, 0); } else - mpr_dev_LID_incref(s->dev, map); + mpr_dev_LID_incref((mpr_local_dev)lsig->dev, map); si->active = 1; _init_inst(si); - i = _add_idmap(s, si, map); - if (h && (s->loc->event_flags & MPR_SIG_INST_NEW)) - h(s, MPR_SIG_INST_NEW, LID, 0, s->type, NULL, t); + i = _add_idmap(lsig, si, map); + if (h && (lsig->event_flags & MPR_SIG_INST_NEW)) + h((mpr_sig)lsig, MPR_SIG_INST_NEW, LID, 0, lsig->type, NULL, t); return i; } return -1; } -int mpr_sig_get_idmap_with_GID(mpr_sig s, mpr_id GID, int flags, mpr_time t, int activate) +int mpr_sig_get_idmap_with_GID(mpr_local_sig lsig, mpr_id GID, int flags, mpr_time t, int activate) { - RETURN_UNLESS(s && s->loc, -1); - mpr_sig_idmap_t *maps = s->loc->idmaps; - mpr_sig_handler *h = s->loc->handler; + mpr_sig_idmap_t *maps; + mpr_sig_handler *h; mpr_sig_inst si; + mpr_id_map map; int i; - for (i = 0; i < s->loc->idmap_len; i++) { + maps = lsig->idmaps; + h = (mpr_sig_handler*)lsig->handler; + for (i = 0; i < lsig->idmap_len; i++) { if (maps[i].map && maps[i].map->GID == GID) return (maps[i].status & ~flags) ? -1 : i; } - RETURN_UNLESS(activate, -1); + RETURN_ARG_UNLESS(activate, -1); - // check if the device already has a map for this global id - mpr_id_map map = mpr_dev_get_idmap_by_GID(s->dev, s->loc->group, GID); + /* check if the device already has a map for this global id */ + map = mpr_dev_get_idmap_by_GID((mpr_local_dev)lsig->dev, lsig->group, GID); if (!map) { /* Here we still risk creating conflicting maps if two signals are * updated asynchronously. This is easy to avoid by not allowing a @@ -439,117 +462,117 @@ int mpr_sig_get_idmap_with_GID(mpr_sig s, mpr_id GID, int flags, mpr_time t, int * may wish to create devices with multiple object classes which do not * require mutual instance id synchronization - e.g. instance 1 of * object class A is not related to instance 1 of object B. */ - if ((si = _reserved_inst(s, NULL))) { - map = mpr_dev_add_idmap(s->dev, s->loc->group, si->id, GID); + if ((si = _reserved_inst(lsig, NULL))) { + map = mpr_dev_add_idmap((mpr_local_dev)lsig->dev, lsig->group, si->id, GID); map->GID_refcount = 1; si->active = 1; _init_inst(si); - i = _add_idmap(s, si, map); - if (h && (s->loc->event_flags & MPR_SIG_INST_NEW)) - h(s, MPR_SIG_INST_NEW, si->id, 0, s->type, NULL, t); + i = _add_idmap(lsig, si, map); + if (h && (lsig->event_flags & MPR_SIG_INST_NEW)) + h((mpr_sig)lsig, MPR_SIG_INST_NEW, si->id, 0, lsig->type, NULL, t); return i; } } - else if ((si = _find_inst_by_id(s, map->LID)) || (si = _reserved_inst(s, &map->LID))) { + else if ((si = _find_inst_by_id(lsig, map->LID)) || (si = _reserved_inst(lsig, &map->LID))) { if (!si->active) { si->active = 1; _init_inst(si); - i = _add_idmap(s, si, map); - mpr_dev_LID_incref(s->dev, map); - mpr_dev_GID_incref(s->dev, map); - if (h && (s->loc->event_flags & MPR_SIG_INST_NEW)) - h(s, MPR_SIG_INST_NEW, si->id, 0, s->type, NULL, t); + i = _add_idmap(lsig, si, map); + mpr_dev_LID_incref((mpr_local_dev)lsig->dev, map); + mpr_dev_GID_incref((mpr_local_dev)lsig->dev, map); + if (h && (lsig->event_flags & MPR_SIG_INST_NEW)) + h((mpr_sig)lsig, MPR_SIG_INST_NEW, si->id, 0, lsig->type, NULL, t); return i; } } else { /* TODO: Once signal groups are explicit, allow re-mapping to * another instance if possible. */ - trace("Signal %s has no instance %"PR_MPR_ID" available.\n", s->name, map->LID); + trace("Signal %s has no instance %"PR_MPR_ID" available.\n", lsig->name, map->LID); return -1; } - RETURN_UNLESS(h, -1); + RETURN_ARG_UNLESS(h, -1); - // try releasing instance in use - if (s->loc->event_flags & MPR_SIG_INST_OFLW) { - // call instance event handler - h(s, MPR_SIG_INST_OFLW, 0, 0, s->type, NULL, t); + /* try releasing instance in use */ + if (lsig->event_flags & MPR_SIG_INST_OFLW) { + /* call instance event handler */ + h((mpr_sig)lsig, MPR_SIG_INST_OFLW, 0, 0, lsig->type, NULL, t); } - else if (s->steal_mode == MPR_STEAL_OLDEST) { - i = _oldest_inst(s); + else if (lsig->steal_mode == MPR_STEAL_OLDEST) { + i = _oldest_inst(lsig); if (i < 0) return -1; - int evt = (MPR_SIG_REL_UPSTRM & s->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE); - h(s, evt, s->loc->idmaps[i].map->LID, 0, s->type, 0, t); + h((mpr_sig)lsig, MPR_SIG_REL_UPSTRM & lsig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE, + lsig->idmaps[i].map->LID, 0, lsig->type, 0, t); } - else if (s->steal_mode == MPR_STEAL_NEWEST) { - i = _newest_inst(s); + else if (lsig->steal_mode == MPR_STEAL_NEWEST) { + i = _newest_inst(lsig); if (i < 0) return -1; - int evt = (MPR_SIG_REL_UPSTRM & s->loc->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE); - h(s, evt, s->loc->idmaps[i].map->LID, 0, s->type, 0, t); + h((mpr_sig)lsig, MPR_SIG_REL_UPSTRM & lsig->event_flags ? MPR_SIG_REL_UPSTRM : MPR_SIG_UPDATE, + lsig->idmaps[i].map->LID, 0, lsig->type, 0, t); } else return -1; - // try again + /* try again */ if (!map) { - if ((si = _reserved_inst(s, NULL))) { - map = mpr_dev_add_idmap(s->dev, s->loc->group, si->id, GID); + if ((si = _reserved_inst(lsig, NULL))) { + map = mpr_dev_add_idmap((mpr_local_dev)lsig->dev, lsig->group, si->id, GID); map->GID_refcount = 1; si->active = 1; _init_inst(si); - i = _add_idmap(s, si, map); - if (h && (s->loc->event_flags & MPR_SIG_INST_NEW)) - h(s, MPR_SIG_INST_NEW, si->id, 0, s->type, NULL, t); + i = _add_idmap(lsig, si, map); + if (h && (lsig->event_flags & MPR_SIG_INST_NEW)) + h((mpr_sig)lsig, MPR_SIG_INST_NEW, si->id, 0, lsig->type, NULL, t); return i; } } else { - si = _find_inst_by_id(s, map->LID); + si = _find_inst_by_id(lsig, map->LID); TRACE_RETURN_UNLESS(si && !si->active, -1, "Signal %s has no instance %" - PR_MPR_ID" available.", s->name, map->LID); + PR_MPR_ID" available.", lsig->name, map->LID); si->active = 1; _init_inst(si); - i = _add_idmap(s, si, map); - mpr_dev_LID_incref(s->dev, map); - mpr_dev_GID_incref(s->dev, map); - if (h && (s->loc->event_flags & MPR_SIG_INST_NEW)) - h(s, MPR_SIG_INST_NEW, si->id, 0, s->type, NULL, t); + i = _add_idmap(lsig, si, map); + mpr_dev_LID_incref((mpr_local_dev)lsig->dev, map); + mpr_dev_GID_incref((mpr_local_dev)lsig->dev, map); + if (h && (lsig->event_flags & MPR_SIG_INST_NEW)) + h((mpr_sig)lsig, MPR_SIG_INST_NEW, si->id, 0, lsig->type, NULL, t); return i; } return -1; } -static int _reserve_inst(mpr_sig sig, mpr_id *id, void *data) +static int _reserve_inst(mpr_local_sig lsig, mpr_id *id, void *data) { - RETURN_UNLESS(sig->num_inst < MAX_INSTANCES, -1); int i, cont; mpr_sig_inst si; + RETURN_ARG_UNLESS(lsig->num_inst < MAX_INSTANCES, -1); - // check if instance with this id already exists! If so, stop here. - if (id && _find_inst_by_id(sig, *id)) + /* check if instance with this id already exists! If so, stop here. */ + if (id && _find_inst_by_id(lsig, *id)) return -1; - // reallocate array of instances - sig->loc->inst = realloc(sig->loc->inst, sizeof(mpr_sig_inst) * (sig->num_inst+1)); - sig->loc->inst[sig->num_inst] = (mpr_sig_inst) calloc(1, sizeof(struct _mpr_sig_inst)); - si = sig->loc->inst[sig->num_inst]; - si->val = calloc(1, mpr_sig_get_vector_bytes(sig)); - si->has_val_flags = calloc(1, sig->len / 8 + 1); + /* reallocate array of instances */ + lsig->inst = realloc(lsig->inst, sizeof(mpr_sig_inst) * (lsig->num_inst + 1)); + lsig->inst[lsig->num_inst] = (mpr_sig_inst) calloc(1, sizeof(struct _mpr_sig_inst)); + si = lsig->inst[lsig->num_inst]; + si->val = calloc(1, mpr_sig_get_vector_bytes((mpr_sig)lsig)); + si->has_val_flags = calloc(1, lsig->len / 8 + 1); si->has_val = 0; if (id) si->id = *id; else { - // find lowest unused id + /* find lowest unused id */ mpr_id lowest_id = 0; cont = 1; while (cont) { cont = 0; - for (i = 0; i < sig->num_inst; i++) { - if (sig->loc->inst[i]->id == lowest_id) { + for (i = 0; i < lsig->num_inst; i++) { + if (lsig->inst[i]->id == lowest_id) { cont = 1; break; } @@ -558,88 +581,112 @@ static int _reserve_inst(mpr_sig sig, mpr_id *id, void *data) } si->id = lowest_id; } - si->idx = sig->num_inst; + si->idx = lsig->num_inst; _init_inst(si); si->data = data; - if (++sig->num_inst > 1) { - if (!sig->use_inst) { - // TODO: modify associated maps for instanced signals + if (++lsig->num_inst > 1) { + if (!lsig->use_inst) { + /* TODO: modify associated maps for instanced signals */ } - sig->use_inst = 1; + lsig->use_inst = 1; } - qsort(sig->loc->inst, sig->num_inst, sizeof(mpr_sig_inst), _compare_inst_ids); - return sig->num_inst-1;; + qsort(lsig->inst, lsig->num_inst, sizeof(mpr_sig_inst), _compare_inst_ids); + return lsig->num_inst - 1;; } int mpr_sig_reserve_inst(mpr_sig sig, int num, mpr_id *ids, void **data) { - RETURN_UNLESS(sig && sig->loc && num, 0); - int i = 0, count = 0, highest = -1, result; - if (sig->num_inst == 1 && !sig->loc->inst[0]->id && !sig->loc->inst[0]->data) { - // we will overwite the default instance first + int i = 0, count = 0, highest = -1, result, old_num = sig->num_inst; + mpr_local_sig lsig = (mpr_local_sig)sig; + RETURN_ARG_UNLESS(sig && sig->is_local && num, 0); + + if (lsig->num_inst == 1 && !lsig->inst[0]->id && !lsig->inst[0]->data) { + /* we will overwite the default instance first */ if (ids) - sig->loc->inst[0]->id = ids[0]; + lsig->inst[0]->id = ids[0]; if (data) - sig->loc->inst[0]->data = data[0]; + lsig->inst[0]->data = data[0]; ++i; ++count; } for (; i < num; i++) { - result = _reserve_inst(sig, ids ? &ids[i] : 0, data ? data[i] : 0); + result = _reserve_inst(lsig, ids ? &ids[i] : 0, data ? data[i] : 0); if (result == -1) continue; highest = result; ++count; } if (highest != -1) - mpr_rtr_num_inst_changed(sig->obj.graph->net.rtr, sig, highest + 1); + mpr_rtr_num_inst_changed(lsig->obj.graph->net.rtr, lsig, highest + 1); + + if (old_num > 0 && (lsig->num_inst / 8) == (old_num / 8)) + return count; + + /* reallocate instance update bitflags */ + if (!lsig->updated_inst) + lsig->updated_inst = calloc(1, lsig->num_inst / 8 + 1); + else if ((old_num / 8) == (lsig->num_inst / 8)) + return count; + + lsig->updated_inst = realloc(lsig->updated_inst, lsig->num_inst / 8 + 1); + memset(lsig->updated_inst + old_num / 8 + 1, 0, (lsig->num_inst / 8) - (old_num / 8)); return count; } int mpr_sig_get_inst_is_active(mpr_sig sig, mpr_id id) { - RETURN_UNLESS(sig, 0); - int idmap_idx = mpr_sig_get_idmap_with_LID(sig, id, 0, MPR_NOW, 0); - return (idmap_idx >= 0) ? sig->loc->idmaps[idmap_idx].inst->active : 0; + int idmap_idx; + RETURN_ARG_UNLESS(sig && sig->is_local, 0); + RETURN_ARG_UNLESS(sig->use_inst, 1); + + idmap_idx = mpr_sig_get_idmap_with_LID((mpr_local_sig)sig, id, 0, MPR_NOW, 0); + return (idmap_idx >= 0) ? ((mpr_local_sig)sig)->idmaps[idmap_idx].inst->active : 0; } -void mpr_sig_update_timing_stats(mpr_sig sig, float diff) +void mpr_sig_update_timing_stats(mpr_local_sig lsig, float diff) { - if (-1 == sig->period) - sig->period = 0; - else if (0 == sig->period) - sig->period = diff; + /* make sure time is monotonic */ + if (diff < 0) + diff = 0; + if (-1 == lsig->period) + lsig->period = 0; + else if (0 == lsig->period) + lsig->period = diff; else { - sig->jitter *= 0.99; - sig->jitter += (0.01 * fabsf(sig->period - diff)); - sig->period *= 0.99; - sig->period += (0.01 * diff); + lsig->jitter *= 0.99; + lsig->jitter += (0.01 * fabsf(lsig->period - diff)); + lsig->period *= 0.99; + lsig->period += (0.01 * diff); } } void mpr_sig_set_value(mpr_sig sig, mpr_id id, int len, mpr_type type, const void *val) { - RETURN_UNLESS(sig && sig->loc); - if (!val) { + mpr_time time; + int idmap_idx; + mpr_local_sig lsig = (mpr_local_sig)sig; + mpr_sig_inst si; + RETURN_UNLESS(sig && sig->is_local); + if (!len || !val) { mpr_sig_release_inst(sig, id); return; } if (!mpr_type_get_is_num(type)) { #ifdef DEBUG - trace("called update on signal '%s' with non-number type '%c'\n", sig->name, type); + trace("called update on signal '%s' with non-number type '%c'\n", lsig->name, type); #endif return; } - if (len && (len != sig->len)) { + if (len && (len != lsig->len)) { #ifdef DEBUG - trace("called update on signal '%s' with value length %d (should be %d)\n", - sig->name, len, sig->len); + trace("called update on signal '%s' with value length %d (should be %d)\n", + lsig->name, len, lsig->len); #endif return; } if (type != MPR_INT32) { - // check for NaN + /* check for NaN */ int i; if (type == MPR_FLT) { for (i = 0; i < len; i++) @@ -650,135 +697,136 @@ void mpr_sig_set_value(mpr_sig sig, mpr_id id, int len, mpr_type type, const voi RETURN_UNLESS(((double*)val)[i] == ((double*)val)[i]); } } - - mpr_time time = mpr_dev_get_time(sig->dev); - int idmap_idx = mpr_sig_get_idmap_with_LID(sig, id, 0, time, 1); + time = mpr_dev_get_time(sig->dev); + idmap_idx = mpr_sig_get_idmap_with_LID(lsig, id, 0, time, 1); RETURN_UNLESS(idmap_idx >= 0); + si = lsig->idmaps[idmap_idx].inst; - mpr_sig_inst si = sig->loc->idmaps[idmap_idx].inst; - - // update timing statistics - double diff = mpr_time_get_diff(time, si->time); + /* update time */ + mpr_sig_update_timing_stats(lsig, si->has_val ? mpr_time_get_diff(time, si->time) : 0); memcpy(&si->time, &time, sizeof(mpr_time)); - mpr_sig_update_timing_stats(sig, diff); - - if (!len || !val) { - si->has_val = 0; - mpr_rtr_process_sig(sig->obj.graph->net.rtr, sig, idmap_idx, 0, si->time); - return; - } - size_t n = mpr_sig_get_vector_bytes(sig); + /* update value */ + if (type != lsig->type) + set_coerced_val(lsig->len, type, val, lsig->len, lsig->type, si->val); + else + memcpy(si->val, (void*)val, mpr_sig_get_vector_bytes(sig)); + si->has_val = 1; - void *coerced = (void*)val; - if (type != sig->type) { - coerced = alloca(n); - set_coerced_val(sig->len, type, val, sig->len, sig->type, coerced); - } + /* mark instance as updated */ + set_bitflag(lsig->updated_inst, si->idx); + ((mpr_local_dev)lsig->dev)->sending = lsig->updated = 1; - mpr_rtr_process_sig(sig->obj.graph->net.rtr, sig, idmap_idx, coerced, si->time); - memcpy(si->val, coerced, n); - si->has_val = 1; + mpr_rtr_process_sig(lsig->obj.graph->net.rtr, lsig, idmap_idx, si->has_val ? si->val : 0, si->time); } void mpr_sig_release_inst(mpr_sig sig, mpr_id id) { - RETURN_UNLESS(sig && sig->loc && sig->use_inst); - int idmap_idx = mpr_sig_get_idmap_with_LID(sig, id, RELEASED_REMOTELY, MPR_NOW, 0); + int idmap_idx; + RETURN_UNLESS(sig && sig->is_local && sig->use_inst); + idmap_idx = mpr_sig_get_idmap_with_LID((mpr_local_sig)sig, id, RELEASED_REMOTELY, MPR_NOW, 0); if (idmap_idx >= 0) - mpr_sig_release_inst_internal(sig, idmap_idx); + mpr_sig_release_inst_internal((mpr_local_sig)sig, idmap_idx); } -void mpr_sig_release_inst_internal(mpr_sig sig, int idmap_idx) +void mpr_sig_release_inst_internal(mpr_local_sig lsig, int idmap_idx) { - mpr_sig_idmap_t *smap = &sig->loc->idmaps[idmap_idx]; + mpr_sig_idmap_t *smap = &lsig->idmaps[idmap_idx]; RETURN_UNLESS(smap->inst); - mpr_time time = mpr_dev_get_time(sig->dev); + /* mark instance as updated */ + set_bitflag(lsig->updated_inst, smap->inst->idx); + ((mpr_local_dev)lsig->dev)->sending = lsig->updated = 1; - mpr_rtr_process_sig(sig->obj.graph->net.rtr, sig, idmap_idx, 0, time); + mpr_rtr_process_sig(lsig->obj.graph->net.rtr, lsig, idmap_idx, 0, smap->inst->time); - if (mpr_dev_LID_decref(sig->dev, sig->loc->group, smap->map)) + if (mpr_dev_LID_decref((mpr_local_dev)lsig->dev, lsig->group, smap->map)) smap->map = 0; - else if ((sig->dir & MPR_DIR_OUT) || smap->status & RELEASED_REMOTELY) { - // TODO: consider multiple upstream source instances? + else if ((lsig->dir & MPR_DIR_OUT) || smap->status & RELEASED_REMOTELY) { + /* TODO: consider multiple upstream source instances? */ smap->map = 0; } else { - // mark map as locally-released but do not remove it - sig->loc->idmaps[idmap_idx].status |= RELEASED_LOCALLY; + /* mark map as locally-released but do not remove it */ + smap->status |= RELEASED_LOCALLY; } - // Put instance back in reserve list + /* Put instance back in reserve list */ smap->inst->active = 0; smap->inst = 0; } void mpr_sig_remove_inst(mpr_sig sig, mpr_id id) { - RETURN_UNLESS(sig && sig->loc && sig->use_inst); - int i, remove_idx; - for (i = 0; i < sig->num_inst; i++) { - if (sig->loc->inst[i]->id == id) + mpr_local_sig lsig = (mpr_local_sig)sig; + RETURN_UNLESS(sig && sig->is_local && sig->use_inst); + for (i = 0; i < lsig->num_inst; i++) { + if (lsig->inst[i]->id == id) break; } - RETURN_UNLESS(i < sig->num_inst); + RETURN_UNLESS(i < lsig->num_inst); - if (sig->loc->inst[i]->active) { - // First release instance - mpr_sig_release_inst_internal(sig, i); + if (lsig->inst[i]->active) { + /* First release instance */ + mpr_sig_release_inst_internal(lsig, i); } - remove_idx = sig->loc->inst[i]->idx; + remove_idx = lsig->inst[i]->idx; - // Free value and timetag memory held by instance - FUNC_IF(free, sig->loc->inst[i]->val); - FUNC_IF(free, sig->loc->inst[i]->has_val_flags); - free(sig->loc->inst[i]); + /* Free value and timetag memory held by instance */ + FUNC_IF(free, lsig->inst[i]->val); + FUNC_IF(free, lsig->inst[i]->has_val_flags); + free(lsig->inst[i]); - for (++i; i < sig->num_inst; i++) - sig->loc->inst[i-1] = sig->loc->inst[i]; - --sig->num_inst; - sig->loc->inst = realloc(sig->loc->inst, sizeof(mpr_sig_inst) * sig->num_inst); + for (++i; i < lsig->num_inst; i++) + lsig->inst[i-1] = lsig->inst[i]; + --lsig->num_inst; + lsig->inst = realloc(lsig->inst, sizeof(mpr_sig_inst) * lsig->num_inst); - // Remove instance memory held by map slots - mpr_rtr_remove_inst(sig->obj.graph->net.rtr, sig, remove_idx); + /* Remove instance memory held by map slots */ + mpr_rtr_remove_inst(lsig->obj.graph->net.rtr, lsig, remove_idx); - for (i = 0; i < sig->num_inst; i++) { - if (sig->loc->inst[i]->idx > remove_idx) - --sig->loc->inst[i]->idx; + for (i = 0; i < lsig->num_inst; i++) { + if (lsig->inst[i]->idx > remove_idx) + --lsig->inst[i]->idx; } } const void *mpr_sig_get_value(mpr_sig sig, mpr_id id, mpr_time *time) { - RETURN_UNLESS(sig && sig->loc, 0); - int idmap_idx = mpr_sig_get_idmap_with_LID(sig, id, RELEASED_REMOTELY, MPR_NOW, 0); - RETURN_UNLESS(idmap_idx >= 0, 0); - mpr_sig_inst si = sig->loc->idmaps[idmap_idx].inst; - RETURN_UNLESS(si && si->has_val, 0) + mpr_local_sig lsig = (mpr_local_sig)sig; + mpr_sig_inst si; + mpr_time now; + RETURN_ARG_UNLESS(sig && sig->is_local, 0); + + if (!lsig->use_inst) + si = lsig->idmaps[0].inst; + else { + int idmap_idx = mpr_sig_get_idmap_with_LID(lsig, id, RELEASED_REMOTELY, MPR_NOW, 0); + RETURN_ARG_UNLESS(idmap_idx >= 0, 0); + si = lsig->idmaps[idmap_idx].inst; + } + RETURN_ARG_UNLESS(si && si->has_val, 0) if (time) { time->sec = si->time.sec; time->frac = si->time.frac; } - mpr_time now; mpr_time_set(&now, MPR_NOW); - double diff = mpr_time_get_diff(now, si->time); - mpr_sig_update_timing_stats(sig, diff); + mpr_sig_update_timing_stats(lsig, mpr_time_get_diff(now, si->time)); return si->val; } int mpr_sig_get_num_inst(mpr_sig sig, mpr_status status) { - RETURN_UNLESS(sig && sig->loc, 0); - RETURN_UNLESS(sig->use_inst, 1); - int i, j = 0, both = MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED; - if ((status & both) == both) + int i, j; + RETURN_ARG_UNLESS(sig && sig->is_local, 0); + RETURN_ARG_UNLESS(sig->use_inst, 1); + if ((status & (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED)) == (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED)) return sig->num_inst; status = status & MPR_STATUS_ACTIVE ? 1 : 0; - for (i = 0; i < sig->num_inst; i++) { - if (sig->loc->inst[i]->active == status) + for (i = 0, j = 0; i < sig->num_inst; i++) { + if (((mpr_local_sig)sig)->inst[i]->active == status) ++j; } return j; @@ -786,188 +834,198 @@ int mpr_sig_get_num_inst(mpr_sig sig, mpr_status status) mpr_id mpr_sig_get_inst_id(mpr_sig sig, int idx, mpr_status status) { - RETURN_UNLESS(sig && sig->loc, 0); - RETURN_UNLESS(sig->use_inst, 0); - RETURN_UNLESS(idx >= 0 && idx < sig->num_inst, 0); - int i, j = -1, both = MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED; - if ((status & both) == both) - return sig->loc->inst[idx]->id; + int i, j; + mpr_local_sig lsig = (mpr_local_sig)sig; + RETURN_ARG_UNLESS(sig && sig->is_local && sig->use_inst, 0); + RETURN_ARG_UNLESS(idx >= 0 && idx < sig->num_inst, 0); + if ((status & (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED)) == (MPR_STATUS_ACTIVE | MPR_STATUS_RESERVED)) + return lsig->inst[idx]->id; status = status & MPR_STATUS_ACTIVE ? 1 : 0; - for (i = 0; i < sig->num_inst; i++) { - if (sig->loc->inst[i]->active != status) + for (i = 0, j = -1; i < lsig->num_inst; i++) { + if (lsig->inst[i]->active != status) continue; if (++j == idx) - return sig->loc->inst[i]->id; + return lsig->inst[i]->id; } return 0; } int mpr_sig_activate_inst(mpr_sig sig, mpr_id id) { - RETURN_UNLESS(sig && sig->loc, 0); - RETURN_UNLESS(sig->use_inst, 0); - mpr_time time = mpr_dev_get_time(sig->dev); - int idmap_idx = mpr_sig_get_idmap_with_LID(sig, id, 0, time, 1); + int idmap_idx; + mpr_time time; + RETURN_ARG_UNLESS(sig && sig->is_local && sig->use_inst, 0); + time = mpr_dev_get_time(sig->dev); + idmap_idx = mpr_sig_get_idmap_with_LID((mpr_local_sig)sig, id, 0, time, 1); return idmap_idx >= 0; } void mpr_sig_set_inst_data(mpr_sig sig, mpr_id id, const void *data) { - RETURN_UNLESS(sig && sig->loc); - mpr_sig_inst si = _find_inst_by_id(sig, id); + mpr_sig_inst si; + RETURN_UNLESS(sig && sig->is_local && sig->use_inst); + si = _find_inst_by_id((mpr_local_sig)sig, id); if (si) si->data = (void*)data; } void *mpr_sig_get_inst_data(mpr_sig sig, mpr_id id) { - RETURN_UNLESS(sig && sig->loc, 0); - mpr_sig_inst si = _find_inst_by_id(sig, id); + mpr_sig_inst si; + RETURN_ARG_UNLESS(sig && sig->is_local && sig->use_inst, 0); + si = _find_inst_by_id((mpr_local_sig)sig, id); return si ? si->data : 0; } /**** Queries ****/ -void mpr_sig_set_cb(mpr_sig s, mpr_sig_handler *h, int events) +void mpr_sig_set_cb(mpr_sig sig, mpr_sig_handler *h, int events) { - RETURN_UNLESS(s && s->loc); - if (!s->loc->handler && h && events) { - // Need to register a new liblo methods - mpr_dev_add_sig_methods(s->dev, s); + mpr_local_sig lsig = (mpr_local_sig)sig; + RETURN_UNLESS(sig && sig->is_local); + if (!lsig->handler && h && events) { + /* Need to register a new liblo methods */ + mpr_dev_add_sig_methods((mpr_local_dev)sig->dev, lsig); } - else if (s->loc->handler && !(h || events)) { - // Need to remove liblo methods - mpr_dev_remove_sig_methods(s->dev, s); + else if (lsig->handler && !(h || events)) { + /* Need to remove liblo methods */ + mpr_dev_remove_sig_methods((mpr_local_dev)sig->dev, lsig); } - s->loc->handler = h; - s->loc->event_flags = events; + lsig->handler = (void*)h; + lsig->event_flags = events; } /**** Signal Properties ****/ -// Internal function only -int mpr_sig_full_name(mpr_sig s, char *name, int len) +/* Internal function only */ +int mpr_sig_full_name(mpr_sig sig, char *name, int len) { - const char *dev_name = mpr_dev_get_name(s->dev); - RETURN_UNLESS(dev_name, 0); + int dev_name_len; + const char *dev_name = mpr_dev_get_name(sig->dev); + RETURN_ARG_UNLESS(dev_name, 0); - int dev_name_len = strlen(dev_name); + dev_name_len = strlen(dev_name); if (dev_name_len >= len) return 0; - if ((dev_name_len + strlen(s->name) + 1) > len) + if ((dev_name_len + strlen(sig->name) + 1) > len) return 0; - snprintf(name, len, "%s%s", dev_name, s->path); + snprintf(name, len, "%s%s", dev_name, sig->path); return strlen(name); } -mpr_dev mpr_sig_get_dev(mpr_sig s) +mpr_dev mpr_sig_get_dev(mpr_sig sig) { - return s->dev; + return sig->dev; } static int cmp_qry_sig_maps(const void *context_data, mpr_map map) { - mpr_sig s = *(mpr_sig*)context_data; - int dir = *(int*)(context_data + sizeof(mpr_sig*)); + mpr_sig sig = *(mpr_sig*)context_data; + int dir = *(int*)((char*)context_data + sizeof(mpr_sig*)); if (!dir || (dir & MPR_DIR_OUT)) { int i; for (i = 0; i < map->num_src; i++) { - if (map->src[i]->sig == s) + if (map->src[i]->sig == sig) return 1; } } if (!dir || (dir & MPR_DIR_IN)) { - if (map->dst->sig == s) + if (map->dst->sig == sig) return 1; } return 0; } -mpr_list mpr_sig_get_maps(mpr_sig s, mpr_dir dir) +mpr_list mpr_sig_get_maps(mpr_sig sig, mpr_dir dir) { - RETURN_UNLESS(s && s->obj.graph->maps, 0); - mpr_list q = mpr_list_new_query((const void**)&s->obj.graph->maps, - cmp_qry_sig_maps, "vi", &s, dir); + mpr_list q; + RETURN_ARG_UNLESS(sig && sig->obj.graph->maps, 0); + q = mpr_list_new_query((const void**)&sig->obj.graph->maps, (void*)cmp_qry_sig_maps, + "vi", &sig, dir); return mpr_list_start(q); } -static int _add_idmap(mpr_sig s, mpr_sig_inst si, mpr_id_map map) +static int _add_idmap(mpr_local_sig lsig, mpr_sig_inst si, mpr_id_map map) { - // find unused signal map + /* find unused signal map */ int i; - for (i = 0; i < s->loc->idmap_len; i++) { - if (!s->loc->idmaps[i].map) + for (i = 0; i < lsig->idmap_len; i++) { + if (!lsig->idmaps[i].map) break; } - if (i == s->loc->idmap_len) { - // need more memory - if (s->loc->idmap_len >= MAX_INSTANCES) { - // Arbitrary limit to number of tracked idmaps + if (i == lsig->idmap_len) { + /* need more memory */ + if (lsig->idmap_len >= MAX_INSTANCES) { + /* Arbitrary limit to number of tracked idmaps */ + /* TODO: add checks for this return value */ return -1; } - s->loc->idmap_len = s->loc->idmap_len ? s->loc->idmap_len * 2 : 1; - s->loc->idmaps = realloc(s->loc->idmaps, (s->loc->idmap_len * - sizeof(struct _mpr_sig_idmap))); - memset(s->loc->idmaps + i, 0, ((s->loc->idmap_len - i) * sizeof(struct _mpr_sig_idmap))); - } - s->loc->idmaps[i].map = map; - s->loc->idmaps[i].inst = si; - s->loc->idmaps[i].status = 0; + lsig->idmap_len = lsig->idmap_len ? lsig->idmap_len * 2 : 1; + lsig->idmaps = realloc(lsig->idmaps, (lsig->idmap_len * sizeof(struct _mpr_sig_idmap))); + memset(lsig->idmaps + i, 0, ((lsig->idmap_len - i) * sizeof(struct _mpr_sig_idmap))); + } + lsig->idmaps[i].map = map; + lsig->idmaps[i].inst = si; + lsig->idmaps[i].status = 0; return i; } -void mpr_sig_send_state(mpr_sig s, net_msg_t cmd) +void mpr_sig_send_state(mpr_sig sig, net_msg_t cmd) { - RETURN_UNLESS(s); - NEW_LO_MSG(msg, return); + char str[BUFFSIZE]; + lo_message msg; + RETURN_UNLESS(sig); + msg = lo_message_new(); + RETURN_UNLESS(msg); - char str[1024]; if (cmd == MSG_SIG_MOD) { - lo_message_add_string(msg, s->name); + lo_message_add_string(msg, sig->name); /* properties */ - mpr_tbl_add_to_msg(s->loc ? s->obj.props.synced : 0, s->obj.props.staged, msg); + mpr_tbl_add_to_msg(sig->is_local ? sig->obj.props.synced : 0, sig->obj.props.staged, msg); - snprintf(str, 1024, "/%s/signal/modify", s->dev->name); - mpr_net_add_msg(&s->obj.graph->net, str, 0, msg); - // send immediately since path string is not cached - mpr_net_send(&s->obj.graph->net); + snprintf(str, BUFFSIZE, "/%s/signal/modify", sig->dev->name); + mpr_net_add_msg(&sig->obj.graph->net, str, 0, msg); + /* send immediately since path string is not cached */ + mpr_net_send(&sig->obj.graph->net); } else { - mpr_sig_full_name(s, str, 1024); + mpr_sig_full_name(sig, str, BUFFSIZE); lo_message_add_string(msg, str); /* properties */ - mpr_tbl_add_to_msg(s->loc ? s->obj.props.synced : 0, s->obj.props.staged, msg); - - mpr_net_add_msg(&s->obj.graph->net, 0, cmd, msg); + mpr_tbl_add_to_msg(sig->is_local ? sig->obj.props.synced : 0, sig->obj.props.staged, msg); + mpr_net_add_msg(&sig->obj.graph->net, 0, cmd, msg); } } -void mpr_sig_send_removed(mpr_sig s) +void mpr_sig_send_removed(mpr_local_sig lsig) { + char sig_name[BUFFSIZE]; NEW_LO_MSG(msg, return); - char sig_name[1024]; - mpr_sig_full_name(s, sig_name, 1024); + mpr_sig_full_name((mpr_sig)lsig, sig_name, BUFFSIZE); lo_message_add_string(msg, sig_name); - mpr_net_add_msg(&s->obj.graph->net, 0, MSG_SIG_REM, msg); + mpr_net_add_msg(&lsig->obj.graph->net, 0, MSG_SIG_REM, msg); } /*! Update information about a signal record based on message properties. */ -int mpr_sig_set_from_msg(mpr_sig s, mpr_msg msg) +int mpr_sig_set_from_msg(mpr_sig sig, mpr_msg msg) { - RETURN_UNLESS(msg, 0); - mpr_tbl tbl = s->obj.props.synced; mpr_msg_atom a; int i, updated = 0; + mpr_tbl tbl = sig->obj.props.synced; + RETURN_ARG_UNLESS(msg, 0); + for (i = 0; i < msg->num_atoms; i++) { a = &msg->atoms[i]; - if (s->loc && (MASK_PROP_BITFLAGS(a->prop) != PROP(EXTRA))) + if (sig->is_local && (MASK_PROP_BITFLAGS(a->prop) != PROP(EXTRA))) continue; switch (a->prop) { case PROP(DIR): { int dir = 0; + if (!mpr_type_get_is_str(a->types[0])) + break; if (strcmp(&(*a->vals)->s, "output")==0) dir = MPR_DIR_OUT; else if (strcmp(&(*a->vals)->s, "input")==0) @@ -979,14 +1037,16 @@ int mpr_sig_set_from_msg(mpr_sig s, mpr_msg msg) } case PROP(ID): if (a->types[0] == 'h') { - if (s->obj.id != (a->vals[0])->i64) { - s->obj.id = (a->vals[0])->i64; + if (sig->obj.id != (a->vals[0])->i64) { + sig->obj.id = (a->vals[0])->i64; ++updated; } } break; case PROP(STEAL_MODE): { int stl; + if (!mpr_type_get_is_str(a->types[0])) + break; if (strcmp(&(*a->vals)->s, "none")==0) stl = MPR_STEAL_NONE; else if (strcmp(&(*a->vals)->s, "oldest")==0) diff --git a/src/mapper/slot.c b/src/mapper/slot.c index 4b0743f..7235e92 100644 --- a/src/mapper/slot.c +++ b/src/mapper/slot.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -10,155 +10,136 @@ #include "types_internal.h" #include -mpr_slot mpr_slot_new(mpr_map map, mpr_sig sig, int is_src) +mpr_slot mpr_slot_new(mpr_map map, mpr_sig sig, unsigned char is_local, unsigned char is_src) { - mpr_slot slot = (mpr_slot)calloc(1, sizeof(struct _mpr_slot)); + size_t size = is_local ? sizeof(struct _mpr_local_slot) : sizeof(struct _mpr_slot); + mpr_slot slot = (mpr_slot)calloc(1, size); slot->map = map; slot->sig = sig; - slot->causes_update = 1; // default + slot->is_local = is_local; + slot->dir = (is_src == sig->is_local) ? MPR_DIR_OUT : MPR_DIR_IN; + slot->causes_update = 1; /* default */ return slot; } static int slot_mask(mpr_slot slot) { - return slot == slot->map->dst ? DST_SLOT_PROP : SRC_SLOT_PROP(slot->obj.id); -} - -void mpr_slot_init(mpr_slot slot) -{ - mpr_tbl t = slot->obj.props.synced = mpr_tbl_new(); - slot->obj.props.staged = mpr_tbl_new(); - int mask = slot_mask(slot); - - if (slot->sig->loc) - mpr_tbl_link(t, MPR_PROP_NUM_INST | mask, 1, MPR_INT32, - &slot->sig->num_inst, NON_MODIFIABLE); - mpr_tbl_link(t, MPR_PROP_SIG | mask, 1, MPR_SIG, &slot->sig, - NON_MODIFIABLE | INDIRECT | LOCAL_ACCESS_ONLY); - - slot->obj.props.mask = mask; + return slot == slot->map->dst ? DST_SLOT_PROP : SRC_SLOT_PROP(slot->id); } void mpr_slot_free(mpr_slot slot) { - FUNC_IF(mpr_tbl_free, slot->obj.props.synced); - FUNC_IF(mpr_tbl_free, slot->obj.props.staged); + free(slot); } -void mpr_slot_free_value(mpr_slot slot) +void mpr_slot_free_value(mpr_local_slot slot) { - RETURN_UNLESS(slot->loc); - // TODO: use rtr_sig for holding memory of local slots for effiency - mpr_value_free(&slot->loc->val); - free(slot->loc); - slot->loc = 0; + /* TODO: use rtr_sig for holding memory of local slots for effiency */ + mpr_value_free(&slot->val); } int mpr_slot_set_from_msg(mpr_slot slot, mpr_msg msg) { - RETURN_UNLESS(slot && msg, 0); - int i, updated = 0, mask = slot_mask(slot); + int updated = 0, mask; mpr_msg_atom a; - - /* type and length belong to parent signal */ - if (!slot->loc || !slot->loc->rsig) { - a = mpr_msg_get_prop(msg, MPR_PROP_LEN | mask); - if (a) { - mpr_prop prop = a->prop; - a->prop &= ~mask; - if (mpr_tbl_set_from_atom(slot->sig->obj.props.synced, a, REMOTE_MODIFY)) - ++updated; - a->prop = prop; - } - a = mpr_msg_get_prop(msg, MPR_PROP_TYPE | mask); - if (a) { - mpr_prop prop = a->prop; - a->prop &= ~mask; - if (mpr_tbl_set_from_atom(slot->sig->obj.props.synced, a, REMOTE_MODIFY)) - ++updated; - a->prop = prop; - } + RETURN_ARG_UNLESS(slot && (!slot->is_local || !((mpr_local_slot)slot)->rsig), 0); + mask = slot_mask(slot); + + a = mpr_msg_get_prop(msg, MPR_PROP_LEN | mask); + if (a) { + mpr_prop prop = a->prop; + a->prop &= ~mask; + if (mpr_tbl_set_from_atom(slot->sig->obj.props.synced, a, REMOTE_MODIFY)) + ++updated; + a->prop = prop; } - mpr_tbl slot_props = slot->obj.props.synced; - for (i = 0; i < msg->num_atoms; i++) { - a = &msg->atoms[i]; - if ((a->prop & ~0xFFFF) != mask) - continue; - switch (a->prop & ~mask) { - case MPR_PROP_LEN: - case MPR_PROP_TYPE: - // handled above - break; - case MPR_PROP_NUM_INST: - // static prop if slot is associated with a local map - if (slot->map->loc) - break; - default: - updated += mpr_tbl_set_from_atom(slot_props, a, REMOTE_MODIFY); - break; - } + a = mpr_msg_get_prop(msg, MPR_PROP_TYPE | mask); + if (a) { + mpr_prop prop = a->prop; + a->prop &= ~mask; + if (mpr_tbl_set_from_atom(slot->sig->obj.props.synced, a, REMOTE_MODIFY)) + ++updated; + a->prop = prop; + } + RETURN_ARG_UNLESS(!slot->is_local, 0); + a = mpr_msg_get_prop(msg, MPR_PROP_DIR | mask); + if (a && mpr_type_get_is_str(a->types[0])) { + int dir = 0; + if (strcmp(&(*a->vals)->s, "output")==0) + dir = MPR_DIR_OUT; + else if (strcmp(&(*a->vals)->s, "input")==0) + dir = MPR_DIR_IN; + if (dir) + updated += mpr_tbl_set(slot->sig->obj.props.synced, PROP(DIR), NULL, 1, MPR_INT32, + &dir, REMOTE_MODIFY); + } + a = mpr_msg_get_prop(msg, MPR_PROP_NUM_INST | mask); + if (a) { + slot->num_inst = a->vals[0]->i; } return updated; } void mpr_slot_add_props_to_msg(lo_message msg, mpr_slot slot, int is_dst, int staged) { + int len; char temp[16]; if (is_dst) snprintf(temp, 16, "@dst"); - else if (0 == (int)slot->obj.id) + else if (0 == (int)slot->id) snprintf(temp, 16, "@src"); else - snprintf(temp, 16, "@src.%d", (int)slot->obj.id); - int len = strlen(temp); + snprintf(temp, 16, "@src.%d", (int)slot->id); + len = strlen(temp); - if (!staged && slot->sig->loc) { - // include length from associated signal + if (!staged && slot->sig->is_local) { + /* include length from associated signal */ snprintf(temp+len, 16-len, "%s", mpr_prop_as_str(MPR_PROP_LEN, 0)); lo_message_add_string(msg, temp); lo_message_add_int32(msg, slot->sig->len); - // include type from associated signal + /* include type from associated signal */ snprintf(temp+len, 16-len, "%s", mpr_prop_as_str(MPR_PROP_TYPE, 0)); lo_message_add_string(msg, temp); lo_message_add_char(msg, slot->sig->type); - } - mpr_tbl_add_to_msg(0, (staged ? slot->obj.props.staged : slot->obj.props.synced), msg); - - // clear the staged properties - if (staged) - mpr_tbl_clear(slot->obj.props.staged); + /* include direction from associated signal */ + snprintf(temp+len, 16-len, "%s", mpr_prop_as_str(MPR_PROP_DIR, 0)); + lo_message_add_string(msg, temp); + lo_message_add_string(msg, slot->sig->dir == MPR_DIR_OUT ? "output" : "input"); + } } int mpr_slot_match_full_name(mpr_slot slot, const char *full_name) { - RETURN_UNLESS(full_name, 1); + int len; + const char *sig_name, *dev_name; + RETURN_ARG_UNLESS(full_name, 1); full_name += (full_name[0]=='/'); - const char *sig_name = strchr(full_name+1, '/'); - RETURN_UNLESS(sig_name, 1); - int len = sig_name - full_name; - const char *dev_name = slot->sig->dev->name; + sig_name = strchr(full_name+1, '/'); + RETURN_ARG_UNLESS(sig_name, 1); + len = sig_name - full_name; + dev_name = slot->sig->dev->name; return (strlen(dev_name) != len || strncmp(full_name, dev_name, len) || strcmp(sig_name+1, slot->sig->name)) ? 1 : 0; } -void mpr_slot_alloc_values(mpr_slot slot, int num_inst, int hist_size) +void mpr_slot_alloc_values(mpr_local_slot slot, int num_inst, int hist_size) { RETURN_UNLESS(num_inst && hist_size && slot->sig->type && slot->sig->len); - if (slot->sig->loc) + if (slot->sig->is_local) num_inst = slot->sig->num_inst; - // reallocate memory - mpr_value_realloc(&slot->loc->val, slot->sig->len, slot->sig->type, + /* reallocate memory */ + mpr_value_realloc(&slot->val, slot->sig->len, slot->sig->type, hist_size, num_inst, slot == slot->map->dst); slot->num_inst = num_inst; } -void mpr_slot_remove_inst(mpr_slot slot, int idx) +void mpr_slot_remove_inst(mpr_local_slot slot, int idx) { RETURN_UNLESS(slot && idx >= 0 && idx < slot->num_inst); - // TODO: remove slot->num_inst property - slot->num_inst = mpr_value_remove_inst(&slot->loc->val, idx); + /* TODO: remove slot->num_inst property */ + slot->num_inst = mpr_value_remove_inst(&slot->val, idx); } diff --git a/src/mapper/table.c b/src/mapper/table.c index ce1368b..b102337 100644 --- a/src/mapper/table.c +++ b/src/mapper/table.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include @@ -6,32 +6,7 @@ #include "mapper_internal.h" -static int match_pattern(const char* s, const char* p) -{ - RETURN_UNLESS(s && p, 1); - RETURN_UNLESS(strchr(p, '*'), strcmp(s, p)); - - // 1) tokenize pattern using strtok() with delimiter character '*' - // 2) use strstr() to check if token exists in offset string - char *str = (char*)s, *tok; - char dup[strlen(p)+1], *pat = dup; - strcpy(pat, p); - int ends_wild = ('*' == p[strlen(p)-1]); - while (str && *str) { - tok = strtok(pat, "*"); - RETURN_UNLESS(tok, !ends_wild); - str = strstr(str, tok); - if (str && *str) - str += strlen(tok); - else - return 1; - // subsequent calls to strtok() need first argument to be NULL - pat = NULL; - } - return 0; -} - -// we will sort so that indexed records come before keyed records +/* we will sort so that indexed records come before keyed records */ static int compare_rec(const void *l, const void *r) { mpr_tbl_record rec_l = (mpr_tbl_record)l; @@ -56,7 +31,7 @@ static int compare_rec(const void *l, const void *r) mpr_tbl mpr_tbl_new() { mpr_tbl t = (mpr_tbl)calloc(1, sizeof(mpr_tbl_t)); - RETURN_UNLESS(t, 0); + RETURN_ARG_UNLESS(t, 0); t->count = 0; t->alloced = 1; t->rec = (mpr_tbl_record)calloc(1, sizeof(mpr_tbl_record_t)); @@ -105,13 +80,14 @@ void mpr_tbl_free(mpr_tbl t) static mpr_tbl_record mpr_tbl_add(mpr_tbl t, mpr_prop prop, const char *key, int len, mpr_type type, void *val, int flags) { + mpr_tbl_record rec; t->count += 1; if (t->count > t->alloced) { while (t->count > t->alloced) t->alloced *= 2; t->rec = realloc(t->rec, t->alloced * sizeof(mpr_tbl_record_t)); } - mpr_tbl_record rec = &t->rec[t->count-1]; + rec = &t->rec[t->count-1]; if (MPR_PROP_EXTRA == prop) flags |= MODIFIABLE; rec->key = key ? strdup(key) : 0; @@ -140,18 +116,17 @@ int mpr_tbl_get_size(mpr_tbl t) mpr_tbl_record mpr_tbl_get(mpr_tbl t, mpr_prop prop, const char *key) { - RETURN_UNLESS(key || (MPR_PROP_UNKNOWN != prop && MPR_PROP_EXTRA != prop), 0); mpr_tbl_record_t tmp; + mpr_tbl_record rec = 0; + RETURN_ARG_UNLESS(key || (MPR_PROP_UNKNOWN != prop && MPR_PROP_EXTRA != prop), 0); tmp.prop = prop; tmp.key = key; - mpr_tbl_record rec = 0; - rec = bsearch(&tmp, t->rec, t->count, sizeof(mpr_tbl_record_t), - compare_rec); + rec = bsearch(&tmp, t->rec, t->count, sizeof(mpr_tbl_record_t), compare_rec); return rec; } -int mpr_tbl_get_prop_by_key(mpr_tbl t, const char *key, int *len, mpr_type *type, - const void **val, int *pub) +mpr_prop mpr_tbl_get_prop_by_key(mpr_tbl t, const char *key, int *len, mpr_type *type, + const void **val, int *pub) { int found = 1; mpr_prop prop = mpr_prop_from_str(key); @@ -174,15 +149,15 @@ int mpr_tbl_get_prop_by_key(mpr_tbl t, const char *key, int *len, mpr_type *type return found ? rec->prop : MPR_PROP_UNKNOWN; } -int mpr_tbl_get_prop_by_idx(mpr_tbl t, mpr_prop prop, const char **key, int *len, - mpr_type *type, const void **val, int *pub) +mpr_prop mpr_tbl_get_prop_by_idx(mpr_tbl t, mpr_prop prop, const char **key, int *len, + mpr_type *type, const void **val, int *pub) { int found = 1; int i, j = 0; mpr_tbl_record rec = 0; if (MASK_PROP_BITFLAGS(prop)) { - // use as mpr_prop instead of numerical index + /* use as mpr_prop instead of numerical index */ rec = mpr_tbl_get(t, MASK_PROP_BITFLAGS(prop), NULL); } else { @@ -222,16 +197,16 @@ int mpr_tbl_get_prop_by_idx(mpr_tbl t, mpr_prop prop, const char **key, int *len int mpr_tbl_remove(mpr_tbl t, mpr_prop prop, const char *key, int flags) { - int ret = 0; + int i, ret = 0; do { mpr_tbl_record rec = mpr_tbl_get(t, prop, key); - RETURN_UNLESS(rec && (rec->flags & MODIFIABLE) && rec->val, ret); + RETURN_ARG_UNLESS(rec && (rec->flags & MODIFIABLE) && rec->val, ret); prop = MASK_PROP_BITFLAGS(prop); if (prop != MPR_PROP_EXTRA && prop != MPR_PROP_LINKED) { - // set value to null rather than removing + /* set value to null rather than removing */ if (rec->flags & INDIRECT) { - if (rec->val && *rec->val) { + if (rec->val && *rec->val && rec->type != MPR_PTR) { free(*rec->val); *rec->val = 0; } @@ -246,8 +221,7 @@ int mpr_tbl_remove(mpr_tbl t, mpr_prop prop, const char *key, int flags) } /* Calculate its key in the records. */ - int i; - if (rec->val) { + if (rec->val && rec->type != MPR_PTR) { if ((rec->type == MPR_STR) && rec->len > 1) { char **vals = (char**)rec->val; for (i = 0; i < rec->len; i++) @@ -285,12 +259,13 @@ void mpr_tbl_clear_empty(mpr_tbl t) static int update_elements(mpr_tbl_record rec, unsigned int len, mpr_type type, const void *val) { - RETURN_UNLESS(len && (rec->val || !(rec->flags & INDIRECT)), 0); int i, updated = 0; - void *old_val = (rec->flags & INDIRECT) ? *rec->val : rec->val; - void *new_val = old_val; + void *old_val, *new_val; + RETURN_ARG_UNLESS(len && (rec->val || !(rec->flags & INDIRECT)), 0); + old_val = (rec->flags & INDIRECT) ? *rec->val : rec->val; + new_val = old_val; if (old_val && (len != rec->len || type != rec->type)) { - // free old values + /* free old values */ if (MPR_STR == rec->type && rec->len > 1) { for (i = 0; i < rec->len; i++) free(((char**)old_val)[i]); @@ -316,9 +291,10 @@ static int update_elements(mpr_tbl_record rec, unsigned int len, mpr_type type, } else { const char **from = (const char**)val; + char **to; if (!old_val) new_val = calloc(1, sizeof(char*) * len); - char **to = (char**)new_val; + to = (char**)new_val; for (i = 0; i < len; i++) { if (!to[i] || strcmp(from[i], to[i])) { int n = strlen(from[i]); @@ -362,14 +338,15 @@ int set_internal(mpr_tbl t, mpr_prop prop, const char *key, int len, int updated = 0; mpr_tbl_record rec = mpr_tbl_get(t, prop, key); if (rec) { - RETURN_UNLESS(rec->flags & MODIFIABLE, 0); + RETURN_ARG_UNLESS(rec->flags & MODIFIABLE, 0); if (prop & PROP_REMOVE) return mpr_tbl_remove(t, prop, key, flags); rec->prop &= ~PROP_REMOVE; - if (type != rec->type && (rec->flags & INDIRECT)) { - void *coerced = alloca(mpr_type_get_size(rec->type) * rec->len); + if ((rec->flags & INDIRECT) && (type != rec->type || len != rec->len)) { + void *coerced = malloc(mpr_type_get_size(rec->type) * rec->len); set_coerced_val(len, type, val, rec->len, rec->type, coerced); updated = t->dirty = update_elements(rec, rec->len, rec->type, coerced); + free(coerced); } else updated = t->dirty = update_elements(rec, len, type, val); @@ -406,13 +383,16 @@ void mpr_tbl_link(mpr_tbl t, mpr_prop prop, int len, mpr_type type, void *val, static int update_elements_osc(mpr_tbl_record rec, unsigned int len, const mpr_type *types, lo_arg **args) { - RETURN_UNLESS(len, 0); + int i, size, updated; + mpr_type type; + void *val; + RETURN_ARG_UNLESS(len, 0); if (MPR_STR == types[0] && 1 == len) return update_elements(rec, 1, MPR_STR, &args[0]->s); - mpr_type type = types[0]; - int i, size = mpr_type_get_size(types[0]) * len; - void *val = malloc(size); + type = types[0]; + size = mpr_type_get_size(types[0]) * len; + val = malloc(size); switch (type) { case MPR_STR: @@ -453,7 +433,7 @@ static int update_elements_osc(mpr_tbl_record rec, unsigned int len, break; } - int updated = update_elements(rec, len, type, val); + updated = update_elements(rec, len, type, val); free(val); return updated; } @@ -471,13 +451,11 @@ int mpr_tbl_set_from_atom(mpr_tbl t, mpr_msg_atom atom, int flags) if (rec) { if (atom->prop & PROP_REMOVE) return mpr_tbl_remove(t, atom->prop, atom->key, flags); - updated = t->dirty = update_elements_osc(rec, atom->len, atom->types, - atom->vals); + updated = t->dirty = update_elements_osc(rec, atom->len, atom->types, atom->vals); } else { /* Need to add a new entry. */ - rec = mpr_tbl_add(t, atom->prop, atom->key, 0, atom->types[0], 0, - flags | PROP_OWNED); + rec = mpr_tbl_add(t, atom->prop, atom->key, 0, atom->types[0], 0, flags | PROP_OWNED); rec->val = 0; update_elements_osc(rec, atom->len, atom->types, atom->vals); qsort(t->rec, t->count, sizeof(mpr_tbl_record_t), compare_rec); @@ -488,16 +466,18 @@ int mpr_tbl_set_from_atom(mpr_tbl t, mpr_msg_atom atom, int flags) static void mpr_record_add_to_msg(mpr_tbl_record rec, lo_message msg) { - RETURN_UNLESS(!(rec->flags & LOCAL_ACCESS_ONLY)); - int len = 0, - indirect = rec->flags & INDIRECT, - masked = MASK_PROP_BITFLAGS(rec->prop); char temp[256]; - void *val = rec->val ? (indirect ? *rec->val : rec->val) : NULL; - + int len = 0, indirect, masked; + void *val; mpr_list list = NULL; + RETURN_UNLESS(!(rec->flags & LOCAL_ACCESS_ONLY)); + + indirect = rec->flags & INDIRECT; + masked = MASK_PROP_BITFLAGS(rec->prop); + val = rec->val ? (indirect ? *rec->val : rec->val) : NULL; + if (MPR_LIST == rec->type) { - // use a copy of the list + /* use a copy of the list */ list = mpr_list_get_cpy((mpr_list)val); if (!list) { trace("skipping empty list property '%s'\n", @@ -508,8 +488,7 @@ static void mpr_record_add_to_msg(mpr_tbl_record rec, lo_message msg) } DONE_UNLESS(val || masked == MPR_PROP_EXTRA); - DONE_UNLESS(masked != MPR_PROP_DEV && masked != MPR_PROP_SIG - && masked != MPR_PROP_SLOT); + DONE_UNLESS(masked != MPR_PROP_DEV && masked != MPR_PROP_SIG && masked != MPR_PROP_SLOT); if (rec->prop & PROP_ADD) { snprintf(temp, 256, "+"); @@ -541,11 +520,11 @@ static void mpr_record_add_to_msg(mpr_tbl_record rec, lo_message msg) if (len) lo_message_add_string(msg, temp); else { - // can use static string + /* can use static string */ lo_message_add_string(msg, mpr_prop_as_str(masked, 0)); } DONE_UNLESS(val && rec->len && !(rec->prop & PROP_REMOVE)); - // add value + /* add value */ switch (masked) { case MPR_PROP_DIR: { int dir = *(int*)rec->val; @@ -564,7 +543,7 @@ static void mpr_record_add_to_msg(mpr_tbl_record rec, lo_message msg) case MPR_PROP_DEV: case MPR_PROP_SIG: case MPR_PROP_SLOT: - // do nothing + /* do nothing */ break; case MPR_PROP_SCOPE: case MPR_PROP_LINKED: { @@ -573,16 +552,14 @@ static void mpr_record_add_to_msg(mpr_tbl_record rec, lo_message msg) break; } while (list) { - const char *key = mpr_obj_get_prop_as_str((mpr_obj)*list, - MPR_PROP_NAME, NULL); + const char *key = mpr_obj_get_prop_as_str((mpr_obj)*list, MPR_PROP_NAME, NULL); lo_message_add_string(msg, key); list = mpr_list_get_next(list); } break; } default: - mpr_msg_add_typed_val(msg, rec->len, rec->type, - indirect ? *rec->val : rec->val); + mpr_msg_add_typed_val(msg, rec->len, rec->type, indirect ? *rec->val : rec->val); break; } done: @@ -593,15 +570,15 @@ static void mpr_record_add_to_msg(mpr_tbl_record rec, lo_message msg) void mpr_tbl_add_to_msg(mpr_tbl tbl, mpr_tbl new, lo_message msg) { int i; - // add all the updates + /* add all the updates */ if (new) { for (i = 0; i < new->count; i++) mpr_record_add_to_msg(&new->rec[i], msg); } RETURN_UNLESS(tbl); - // add remaining records + /* add remaining records */ for (i = 0; i < tbl->count; i++) { - // check if updated version exists + /* check if updated version exists */ if (!new || !mpr_tbl_get(new, tbl->rec[i].prop, tbl->rec[i].key)) mpr_record_add_to_msg(&tbl->rec[i], msg); } diff --git a/src/mapper/time.c b/src/mapper/time.c index 6caff78..48c1a6b 100644 --- a/src/mapper/time.c +++ b/src/mapper/time.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include "config.h" #include @@ -11,7 +11,7 @@ #include "types_internal.h" #include -static double multiplier = 1.0/((double)(1LL<<32)); +static double multiplier = 0.00000000023283064365; /*! Internal function to get the current time. */ double mpr_get_current_time() @@ -19,7 +19,7 @@ double mpr_get_current_time() #ifdef HAVE_GETTIMEOFDAY struct timeval tv; gettimeofday(&tv, NULL); - return (double)tv.tv_sec + tv.tv_usec / 1000000.0; + return (double)tv.tv_sec + ((double)tv.tv_usec) * 0.000001; #else #error No timing method known on this platform. #endif @@ -46,7 +46,7 @@ void mpr_time_add_dbl(mpr_time *t, double d) --t->sec; d = 1.0 - d; } - t->frac = (uint32_t) (((double)d) * (double)(1LL<<32)); + t->frac = (uint32_t) (((double)d) * 4294967296.); } } @@ -56,7 +56,7 @@ void mpr_time_mul(mpr_time *t, double d) d *= mpr_time_as_dbl(*t); t->sec = floor(d); d -= t->sec; - t->frac = (uint32_t) (d * (double)(1LL<<32)); + t->frac = (uint32_t) (d * 4294967296.); } else t->sec = t->frac = 0; @@ -66,7 +66,7 @@ void mpr_time_add(mpr_time *t, mpr_time addend) { t->sec += addend.sec; t->frac += addend.frac; - if (t->frac < addend.frac) // overflow + if (t->frac < addend.frac) /* overflow */ ++t->sec; } @@ -74,7 +74,7 @@ void mpr_time_sub(mpr_time *t, mpr_time subtrahend) { if (t->sec > subtrahend.sec) { t->sec -= subtrahend.sec; - if (t->frac < subtrahend.frac) // overflow + if (t->frac < subtrahend.frac) /* overflow */ --t->sec; t->frac -= subtrahend.frac; } @@ -92,7 +92,7 @@ void mpr_time_set_dbl(mpr_time *t, double value) if (value > 0.) { t->sec = floor(value); value -= t->sec; - t->frac = (uint32_t) (((double)value) * (double)(1LL<<32)); + t->frac = (uint32_t) (((double)value) * 4294967296.); } else t->sec = t->frac = 0; @@ -100,13 +100,13 @@ void mpr_time_set_dbl(mpr_time *t, double value) void mpr_time_set(mpr_time *l, mpr_time r) { - if (memcmp(&r, &MPR_NOW, sizeof(mpr_time)) == 0) + if (r.sec == 0 && r.frac == 1) /* MPR_NOW */ lo_timetag_now((lo_timetag*)l); else memcpy(l, &r, sizeof(mpr_time)); } -inline int mpr_time_cmp(mpr_time l, mpr_time r) +MPR_INLINE int mpr_time_cmp(mpr_time l, mpr_time r) { return l.sec == r.sec ? l.frac - r.frac : l.sec - r.sec; } diff --git a/src/mapper/types_internal.h b/src/mapper/types_internal.h index 2474774..b89a749 100644 --- a/src/mapper/types_internal.h +++ b/src/mapper/types_internal.h @@ -38,6 +38,8 @@ typedef struct _mpr_obj **mpr_list; struct _mpr_dev; typedef struct _mpr_dev mpr_dev_t; typedef struct _mpr_dev *mpr_dev; +typedef struct _mpr_local_dev mpr_local_dev_t; +typedef struct _mpr_local_dev *mpr_local_dev; struct _mpr_map; struct _mpr_allocated_t; struct _mpr_id_map; @@ -45,7 +47,7 @@ typedef int mpr_sig_group; /**** String tables ****/ -// bit flags for tracking permissions for modifying properties +/* bit flags for tracking permissions for modifying properties */ #define NON_MODIFIABLE 0x00 #define LOCAL_MODIFY 0x01 #define REMOTE_MODIFY 0x02 @@ -78,7 +80,6 @@ typedef struct _mpr_tbl { typedef struct _mpr_dict { struct _mpr_tbl *synced; struct _mpr_tbl *staged; - int mask; } mpr_dict_t, *mpr_dict; /**** Graph ****/ @@ -98,31 +99,24 @@ typedef struct _mpr_subscription { uint32_t lease_expiration_sec; } *mpr_subscription; +#define SERVER_ADMIN 0 +#define SERVER_BUS 0 /* Multicast comms. */ +#define SERVER_MESH 1 /* Mesh comms. */ + +#define SERVER_DEVICE 2 +#define SERVER_UDP 2 +#define SERVER_TCP 3 + /*! A structure that keeps information about network communications. */ typedef struct _mpr_net { struct _mpr_graph *graph; - struct { - union { - lo_server all[4]; - struct { - lo_server admin[2]; - lo_server dev[2]; - }; - struct { - lo_server bus; /*!< LibLo server for the multicast. */ - lo_server mesh; /*!< LibLo server for mesh comms. */ - - /*! Servers used to handle incoming signal messages. */ - lo_server udp; - lo_server tcp; - }; - }; - } server; + + lo_server servers[4]; struct { lo_address bus; /*!< LibLo address for the multicast bus. */ lo_address dst; - struct _mpr_dev *dev; + struct _mpr_local_dev *dev; char *url; } addr; @@ -131,7 +125,7 @@ typedef struct _mpr_net { struct in_addr addr; /*!< The IP address of network interface. */ } iface; - struct _mpr_dev **devs; /*!< Local devices managed by this network structure. */ + struct _mpr_local_dev **devs; /*!< Local devices managed by this network structure. */ lo_bundle bundle; /*!< Bundle pointer for sending messages on the multicast bus. */ struct { @@ -151,27 +145,6 @@ typedef struct _mpr_net { uint8_t graph_methods_added; } mpr_net_t, *mpr_net; -typedef struct _mpr_graph { - mpr_net_t net; - mpr_list devs; //!< List of devices. - mpr_list sigs; //!< List of signals. - mpr_list maps; //!< List of maps. - mpr_list links; //!< List of links. - fptr_list callbacks; //!< List of object record callbacks. - - /*! Linked-list of autorenewing device subscriptions. */ - mpr_subscription subscriptions; - - /*! Flags indicating whether information on signals and mappings should - * be automatically subscribed to when a new device is seen.*/ - int autosub; - - int own; - int staged_maps; - - uint32_t resource_counter; -} mpr_graph_t, *mpr_graph; - /**** Messages ****/ /*! Some useful strings for sending administrative messages. */ @@ -205,17 +178,17 @@ typedef void mpr_resource_on_collision(struct _mpr_allocated_t *resource); /*! Allocated resources */ typedef struct _mpr_allocated_t { - double count_time; //!< The last time collision count was updated. - double hints[8]; //!< Availability of a range of resource values. + double count_time; /*!< The last time collision count was updated. */ + double hints[8]; /*!< Availability of a range of resource values. */ - //!< Function to call when resource becomes locked. + /*!< Function to call when resource becomes locked. */ mpr_resource_on_lock *on_lock; - //! Function to call when resource collision occurs. + /*! Function to call when resource collision occurs. */ mpr_resource_on_collision *on_collision; - unsigned int val; //!< The resource to be allocated. - int collision_count; //!< The number of collisions detected. + unsigned int val; /*!< The resource to be allocated. */ + int collision_count; /*!< The number of collisions detected. */ uint8_t locked; /*!< Whether or not the value has been locked (allocated). */ uint8_t online; /*!< Whether or not we are connected to the * distributed allocation network. */ @@ -244,20 +217,42 @@ typedef struct _mpr_subscriber { int flags; } *mpr_subscriber; -#define TIMEOUT_SEC 10 // timeout after 10 seconds without ping +#define TIMEOUT_SEC 10 /* timeout after 10 seconds without ping */ /**** Object ****/ typedef struct _mpr_obj { - mpr_graph graph; //!< Pointer back to the graph. - mpr_id id; //!< Unique id for this object. - void *data; //!< User context pointer. - struct _mpr_dict props; //!< Properties associated with this signal. - int version; //!< Version number. - mpr_type type; //!< Object type. + struct _mpr_graph *graph; /*!< Pointer back to the graph. */ + mpr_id id; /*!< Unique id for this object. */ + void *data; /*!< User context pointer. */ + struct _mpr_dict props; /*!< Properties associated with this signal. */ + int version; /*!< Version number. */ + mpr_type type; /*!< Object type. */ } mpr_obj_t, *mpr_obj; +typedef struct _mpr_graph { + mpr_obj_t obj; /* always first */ + mpr_net_t net; + mpr_list devs; /*!< List of devices. */ + mpr_list sigs; /*!< List of signals. */ + mpr_list maps; /*!< List of maps. */ + mpr_list links; /*!< List of links. */ + fptr_list callbacks; /*!< List of object record callbacks. */ + + /*! Linked-list of autorenewing device subscriptions. */ + mpr_subscription subscriptions; + + /*! Flags indicating whether information on signals and mappings should + * be automatically subscribed to when a new device is seen.*/ + int autosub; + + int own; + int staged_maps; + + uint32_t resource_counter; +} mpr_graph_t, *mpr_graph; + /**** Signal ****/ /*! A structure that stores the current and historical values of a signal. The @@ -266,59 +261,94 @@ typedef struct _mpr_obj typedef struct _mpr_value_buffer { - void *samps; //!< Value for each sample of stored history. - mpr_time *times; //!< Time for each sample of stored history. - int8_t pos; //!< Current position in the circular buffer. + void *samps; /*!< Value for each sample of stored history. */ + mpr_time *times; /*!< Time for each sample of stored history. */ + int8_t pos; /*!< Current position in the circular buffer. */ + uint8_t full; /*!< Indicates whether complete buffer contains valid data. */ } mpr_value_buffer_t, *mpr_value_buffer; typedef struct _mpr_value { mpr_value_buffer inst; /*!< Array of value histories for each signal instance. */ - int vlen; //!< Vector length. - int num_inst; //!< Number of instances. - mpr_type type; //!< The type of this signal. - int8_t mlen; //!< History size of the buffer. + int vlen; /*!< Vector length. */ + uint8_t num_inst; /*!< Number of instances. */ + mpr_type type; /*!< The type of this signal. */ + int8_t mlen; /*!< History size of the buffer. */ } mpr_value_t, *mpr_value; -/*! Bit flags for indicating signal instance status. */ -#define RELEASED_LOCALLY 0x01 -#define RELEASED_REMOTELY 0x02 +/*! Bit flags for indicating instance id_map status. */ +#define UPDATED 0x01 +#define RELEASED_LOCALLY 0x02 +#define RELEASED_REMOTELY 0x04 #define EXPR_RELEASE_BEFORE_UPDATE 0x02 #define EXPR_RELEASE_AFTER_UPDATE 0x04 #define EXPR_MUTED_UPDATE 0x08 #define EXPR_UPDATE 0x10 +#define EXPR_EVAL_DONE 0x20 /*! A signal is defined as a vector of values, along with some metadata. */ +/* plan: remove idx? we shouldn't need it anymore */ typedef struct _mpr_sig_inst { - mpr_id id; //!< User-assignable instance id. - void *data; //!< User data of this instance. - mpr_time created; //!< The instance's creation timestamp. - char *has_val_flags; //!< Indicates which vector elements have a value. + mpr_id id; /*!< User-assignable instance id. */ + void *data; /*!< User data of this instance. */ + mpr_time created; /*!< The instance's creation timestamp. */ + char *has_val_flags; /*!< Indicates which vector elements have a value. */ - void *val; //!< The current value of this signal instance. - mpr_time time; //!< The time associated with the current value. + void *val; /*!< The current value of this signal instance. */ + mpr_time time; /*!< The time associated with the current value. */ - unsigned int idx; //!< Index for accessing value history. - uint8_t has_val; //!< Indicates whether this instance has a value. - uint8_t active; //!< Status of this instance. + uint8_t idx; /*!< Index for accessing value history. */ + uint8_t has_val; /*!< Indicates whether this instance has a value. */ + uint8_t active; /*!< Status of this instance. */ } mpr_sig_inst_t, *mpr_sig_inst; +/* plan: remove inst, add map/slot resource index (is this the same for all source signals?) */ typedef struct _mpr_sig_idmap { - struct _mpr_id_map *map; //!< Associated mpr_id_map. - struct _mpr_sig_inst *inst; //!< Signal instance. - int status; /*!< Either 0 or a combination of + struct _mpr_id_map *map; /*!< Associated mpr_id_map. */ + struct _mpr_sig_inst *inst; /*!< Signal instance. */ + int status; /*!< Either 0 or a combination of UPDATED, * RELEASED_LOCALLY and RELEASED_REMOTELY. */ } mpr_sig_idmap_t; +#define MPR_SIG_STRUCT_ITEMS \ + mpr_obj_t obj; /* always first */ \ + char *path; /*! OSC path. Must start with '/'. */ \ + char *name; /*! The name of this signal (path+1). */ \ + char *unit; /*!< The unit of this signal, or NULL for N/A. */ \ + void *min; /*!< The minimum of this signal, or NULL for N/A. */ \ + void *max; /*!< The maximum of this signal, or NULL for N/A. */ \ + float period; /*!< Estimate of the update rate of this signal. */ \ + float jitter; /*!< Estimate of the timing jitter of this signal. */ \ + int dir; /*!< DIR_OUTGOING / DIR_INCOMING / DIR_BOTH */ \ + int len; /*!< Length of the signal vector, or 1 for scalars. */ \ + int num_inst; /*!< Number of instances. */ \ + int use_inst; /*!< 1 if using instances, 0 otherwise. */ \ + int num_maps_in; /* TODO: use dynamic query instead? */ \ + int num_maps_out; /* TODO: use dynamic query instead? */ \ + mpr_steal_type steal_mode; /*!< Type of voice stealing to perform. */ \ + mpr_type type; /*!< The type of this signal. */ \ + int is_local; + +/*! A record that describes properties of a signal. */ +typedef struct _mpr_sig +{ + MPR_SIG_STRUCT_ITEMS + mpr_dev dev; +} mpr_sig_t, *mpr_sig; + typedef struct _mpr_local_sig { - struct _mpr_sig_idmap *idmaps; //!< ID maps and active instances. + MPR_SIG_STRUCT_ITEMS + mpr_local_dev dev; + + struct _mpr_sig_idmap *idmaps; /*!< ID maps and active instances. */ int idmap_len; - struct _mpr_sig_inst **inst; //!< Array of pointers to the signal insts. - char *vec_known; //!< Bitflags when entire vector is known. + struct _mpr_sig_inst **inst; /*!< Array of pointers to the signal insts. */ + char *vec_known; /*!< Bitflags when entire vector is known. */ + char *updated_inst; /*!< Bitflags to indicate updated instances. */ /*! An optional function to be called when the signal value changes or when * signal instance management events occur.. */ @@ -326,37 +356,11 @@ typedef struct _mpr_local_sig int event_flags; /*! Flags for deciding when to call the * instance event handler. */ - mpr_sig_group group; // TODO: replace with hierarchical instancing + mpr_sig_group group; /* TODO: replace with hierarchical instancing */ uint8_t locked; - uint8_t updated; // TODO: fold into updated_inst bitflags. + uint8_t updated; /* TODO: fold into updated_inst bitflags. */ } mpr_local_sig_t, *mpr_local_sig; -/*! A record that describes properties of a signal. */ -typedef struct _mpr_sig { - mpr_obj_t obj; // always first - mpr_local_sig loc; - mpr_dev dev; - char *path; //! OSC path. Must start with '/'. - char *name; //! The name of this signal (path+1). - - char *unit; //!< The unit of this signal, or NULL for N/A. - void *min; //!< The minimum of this signal, or NULL for N/A. - void *max; //!< The maximum of this signal, or NULL for N/A. - - float period; //!< Estimate of the update rate of this signal. - float jitter; //!< Estimate of the timing jitter of this signal. - - int dir; //!< DIR_OUTGOING / DIR_INCOMING / DIR_BOTH - int len; //!< Length of the signal vector, or 1 for scalars. - int num_inst; //!< Number of instances. - int use_inst; //!< 1 if using instances, 0 otherwise. - int num_maps_in; - int num_maps_out; - - mpr_type type; //!< The type of this signal. - mpr_steal_type steal_mode; //!< Type of voice stealing to perform. -} mpr_sig_t, *mpr_sig; - /**** Router ****/ typedef struct _mpr_bundle { @@ -364,105 +368,106 @@ typedef struct _mpr_bundle { lo_bundle tcp; } mpr_bundle_t, *mpr_bundle; -#define NUM_BUNDLES 8 +#define NUM_BUNDLES 1 +#define LOCAL_DEV 0 +#define REMOTE_DEV 1 typedef struct _mpr_link { - mpr_obj_t obj; // always first - union { - mpr_dev devs[2]; - struct { - mpr_dev local_dev; - mpr_dev remote_dev; - }; - }; + mpr_obj_t obj; /* always first */ + mpr_dev devs[2]; int *num_maps; struct { - lo_address admin; //!< Network address of remote endpoint - lo_address udp; //!< Network address of remote endpoint - lo_address tcp; //!< Network address of remote endpoint + lo_address admin; /*!< Network address of remote endpoint */ + lo_address udp; /*!< Network address of remote endpoint */ + lo_address tcp; /*!< Network address of remote endpoint */ } addr; - mpr_bundle_t bundles[NUM_BUNDLES]; //!< Circular buffer to handle interrupts during poll() + mpr_bundle_t bundles[NUM_BUNDLES]; /*!< Circular buffer to handle interrupts during poll() */ mpr_sync_clock_t clock; } mpr_link_t, *mpr_link; /**** Maps and Slots ****/ -#define MAX_NUM_MAP_SRC 8 // arbitrary -#define MAX_NUM_MAP_DST 8 // arbitrary +#define MAX_NUM_MAP_SRC 8 /* arbitrary */ +#define MAX_NUM_MAP_DST 8 /* arbitrary */ -typedef struct _mpr_local_slot { - // each slot can point to local signal or a remote link structure - struct _mpr_rtr_sig *rsig; //!< Parent signal if local - mpr_value_t val; /*!< Value histories for each signal instance. */ - char status; -} mpr_local_slot_t, *mpr_local_slot; +#define MPR_SLOT_STRUCT_ITEMS \ + mpr_sig sig; /*!< Pointer to parent signal */ \ + mpr_link link; \ + int id; \ + uint8_t num_inst; \ + char dir; /*!< DI_INCOMING or DI_OUTGOING */ \ + char causes_update; /*!< 1 if causes update, 0 otherwise. */ \ + char is_local; \ typedef struct _mpr_slot { - mpr_obj_t obj; // always first - mpr_local_slot loc; //!< Pointer to local resources if any - struct _mpr_map *map; //!< Pointer to parent map - mpr_sig sig; //!< Pointer to parent signal - mpr_link link; - - int num_inst; - - int dir; //!< DI_INCOMING or DI_OUTGOING - int causes_update; //!< 1 if causes update, 0 otherwise. + MPR_SLOT_STRUCT_ITEMS + struct _mpr_map *map; /*!< Pointer to parent map */ } mpr_slot_t, *mpr_slot; -/*! The mpr_local_map structure is a linked list of mappings for a given signal. - * Each signal can be associated with multiple inputs or outputs. This - * structure only contains state information used for performing mapping, the - * properties are publically defined in mpr_constants.h. */ -typedef struct _mpr_local_map { - struct _mpr_rtr *rtr; +typedef struct _mpr_local_slot { + MPR_SLOT_STRUCT_ITEMS + struct _mpr_local_map *map; /*!< Pointer to parent map */ - mpr_expr expr; //!< The mapping expression. - mpr_value_t *vars; //!< User variables values. - const char **var_names; //!< User variables names. - int num_vars; //!< Number of user variables. - int num_inst; //!< Number of local instances. + /* each slot can point to local signal or a remote link structure */ + struct _mpr_rtr_sig *rsig; /*!< Parent signal if local */ + mpr_value_t val; /*!< Value histories for each signal instance. */ + char status; +} mpr_local_slot_t, *mpr_local_slot; - uint8_t is_local_only; - uint8_t one_src; -} mpr_local_map_t, *mpr_local_map; +#define MPR_MAP_STRUCT_ITEMS \ + mpr_obj_t obj; /* always first */ \ + mpr_dev *scopes; \ + char *expr_str; \ + struct _mpr_id_map *idmap; /*!< Associated mpr_id_map. */ \ + int muted; /*!< 1 to mute mapping, 0 to unmute */ \ + int num_scopes; \ + int num_src; \ + mpr_loc process_loc; \ + int status; \ + int protocol; /*!< Data transport protocol. */ \ + int use_inst; /*!< 1 if using instances, 0 otherwise. */ \ + int is_local; /*! A record that describes the properties of a mapping. * @ingroup map */ typedef struct _mpr_map { - mpr_obj_t obj; // always first - mpr_local_map loc; + MPR_MAP_STRUCT_ITEMS mpr_slot *src; mpr_slot dst; +} mpr_map_t, *mpr_map; - mpr_dev *scopes; +typedef struct _mpr_local_map { + MPR_MAP_STRUCT_ITEMS + mpr_local_slot *src; + mpr_local_slot dst; - char *expr_str; + struct _mpr_rtr *rtr; - struct _mpr_id_map *idmap; //!< Associated mpr_id_map. + mpr_expr expr; /*!< The mapping expression. */ + char *updated_inst; /*!< Bitflags to indicate updated instances. */ + mpr_value_t *vars; /*!< User variables values. */ + const char **var_names; /*!< User variables names. */ + int num_vars; /*!< Number of user variables. */ + int num_inst; /*!< Number of local instances. */ - int muted; //!< 1 to mute mapping, 0 to unmute - int num_scopes; - int num_src; - mpr_loc process_loc; - int status; - int protocol; //!< Data transport protocol. - int use_inst; //!< 1 if using instances, 0 otherwise. -} mpr_map_t, *mpr_map; + uint8_t is_local_only; + uint8_t one_src; + uint8_t updated; +} mpr_local_map_t, *mpr_local_map; /*! The rtr_sig is a linked list containing a signal and a list of mapping * slots. TODO: This should be replaced with a more efficient approach * such as a hash table or search tree. */ typedef struct _mpr_rtr_sig { - struct _mpr_rtr_sig *next; //!< The next rtr_sig in the list. + struct _mpr_rtr_sig *next; /*!< The next rtr_sig in the list. */ - struct _mpr_rtr *link; //!< The parent link. - struct _mpr_sig *sig; //!< The associated signal. + struct _mpr_rtr *link; /*!< The parent link. */ + struct _mpr_local_sig *sig; /*!< The associated signal. */ - mpr_slot *slots; + mpr_local_slot *slots; int num_slots; int id_counter; @@ -470,34 +475,57 @@ typedef struct _mpr_rtr_sig { /*! The router structure. */ typedef struct _mpr_rtr { - struct _mpr_dev *dev; //!< The device associated with this link. - mpr_rtr_sig sigs; //!< The list of mappings for each signal. + struct _mpr_local_dev *dev; /*!< The device associated with this link. */ + mpr_rtr_sig sigs; /*!< The list of mappings for each signal. */ } mpr_rtr_t, *mpr_rtr; /*! The instance ID map is a linked list of int32 instance ids for coordinating * remote and local instances. */ typedef struct _mpr_id_map { - struct _mpr_id_map *next; //!< The next id map in the list. + struct _mpr_id_map *next; /*!< The next id map in the list. */ - mpr_id GID; //!< Hash for originating device. - mpr_id LID; //!< Local instance id to map. + mpr_id GID; /*!< Hash for originating device. */ + mpr_id LID; /*!< Local instance id to map. */ int LID_refcount; int GID_refcount; } mpr_id_map_t, *mpr_id_map; /**** Device ****/ -typedef struct _mpr_local_dev { - mpr_allocated_t ordinal; //!< A unique ordinal for this device instance. - int registered; //!< Non-zero if this device has been registered. +#define MPR_DEV_STRUCT_ITEMS \ + mpr_obj_t obj; /* always first */ \ + mpr_dev *linked; \ + char *prefix; /*!< The identifier (prefix) for this device. */\ + char *name; /*!< The full name for this device, or zero. */ \ + mpr_time synced; /*!< Timestamp of last sync. */ \ + int ordinal; \ + int num_inputs; /*!< Number of associated input signals. */ \ + int num_outputs; /*!< Number of associated output signals. */ \ + int num_maps_in; /*!< Number of associated incoming maps. */ \ + int num_maps_out; /*!< Number of associated outgoing maps. */ \ + int num_linked; /*!< Number of linked devices. */ \ + int status; \ + uint8_t subscribed; \ + int is_local; + +/*! A record that keeps information about a device. */ +struct _mpr_dev { + MPR_DEV_STRUCT_ITEMS +}; + +struct _mpr_local_dev { + MPR_DEV_STRUCT_ITEMS + + mpr_allocated_t ordinal_allocator; /*!< A unique ordinal for this device instance. */ + int registered; /*!< Non-zero if this device has been registered. */ int n_output_callbacks; - mpr_subscriber subscribers; /*!< Linked-list of subscribed peers. */ + mpr_subscriber subscribers; /*!< Linked-list of subscribed peers. */ struct { - struct _mpr_id_map **active; //!< The list of active instance id maps. - struct _mpr_id_map *reserve; //!< The list of reserve instance id maps. + struct _mpr_id_map **active; /*!< The list of active instance id maps. */ + struct _mpr_id_map *reserve; /*!< The list of reserve instance id maps. */ } idmaps; mpr_time time; @@ -505,31 +533,8 @@ typedef struct _mpr_local_dev { uint8_t time_is_stale; uint8_t polling; uint8_t bundle_idx; - uint8_t updated; -} mpr_local_dev_t, *mpr_local_dev; - - -/*! A record that keeps information about a device. */ -struct _mpr_dev { - mpr_obj_t obj; // always first - mpr_local_dev loc; - - mpr_dev *linked; - - char *prefix; //!< The identifier (prefix) for this device. - char *name; //!< The full name for this device, or zero. - - mpr_time synced; //!< Timestamp of last sync. - - int ordinal; - int num_inputs; //!< Number of associated input signals. - int num_outputs; //!< Number of associated output signals. - int num_maps_in; //!< Number of associated incoming maps. - int num_maps_out; //!< Number of associated outgoing maps. - int num_linked; //!< Number of linked devices. - int status; - - uint8_t subscribed; + uint8_t sending; + uint8_t receiving; }; /**** Messages ****/ @@ -569,4 +574,4 @@ typedef struct _mpr_msg int num_atoms; } *mpr_msg; -#endif // __MPR_TYPES_H__ +#endif /* __MPR_TYPES_H__ */ diff --git a/src/mapper/value.c b/src/mapper/value.c index d3e803f..cc0265e 100644 --- a/src/mapper/value.c +++ b/src/mapper/value.c @@ -1,4 +1,4 @@ -#include "compat.h" +#include #include #include #include @@ -11,12 +11,14 @@ #include "types_internal.h" #include -static inline int _min(int a, int b) { return a < b ? a : b; } +MPR_INLINE static int _min(int a, int b) { return a < b ? a : b; } void mpr_value_realloc(mpr_value v, int vlen, mpr_type type, int mlen, int num_inst, int is_input) { + int i, samp_size; + mpr_value_buffer_t *b, tmp; RETURN_UNLESS(v && mlen && num_inst >= v->num_inst); - int i, samp_size = vlen * mpr_type_get_size(type); + samp_size = vlen * mpr_type_get_size(type); if (!v->inst || num_inst > v->num_inst) { if (v->inst) @@ -25,23 +27,27 @@ void mpr_value_realloc(mpr_value v, int vlen, mpr_type type, int mlen, int num_i v->inst = malloc(sizeof(mpr_value_buffer_t) * num_inst); v->num_inst = 0; } - // initialize new instances + /* initialize new instances */ for (i = v->num_inst; i < num_inst; i++) { - mpr_value_buffer b = &v->inst[i]; + b = &v->inst[i]; b->samps = calloc(1, mlen * samp_size); b->times = calloc(1, mlen * sizeof(mpr_time)); b->pos = -1; + b->full = 0; } } if (!is_input || vlen != v->vlen || type != v->type) { + /* reallocate old instances (v->num_inst has not yet been updated) */ for (i = 0; i < v->num_inst; i++) { - mpr_value_buffer b = &v->inst[i]; + b = &v->inst[i]; b->samps = realloc(b->samps, mlen * samp_size); b->times = realloc(b->times, mlen * sizeof(mpr_time)); - // Initialize entire value to 0 + /* Initialize entire value to 0 */ memset(b->samps, 0, mlen * samp_size); + memset(b->times, 0, mlen * sizeof(mpr_time)); b->pos = -1; + b->full = 0; } goto done; } @@ -49,39 +55,43 @@ void mpr_value_realloc(mpr_value v, int vlen, mpr_type type, int mlen, int num_i if (mlen == v->mlen) goto done; - // only the memory size is different - mpr_value_buffer_t tmp; + /* only the memory size is different */ for (i = 0; i < v->num_inst; i++) { - mpr_value_buffer b = &v->inst[i]; + b = &v->inst[i]; tmp.samps = malloc(samp_size * mlen); tmp.times = malloc(sizeof(mpr_time) * mlen); + /* TODO: don't bother copying memory if pos is -1 */ if (mlen > v->mlen) { int npos = v->mlen - b->pos; - // copy from [v->pos, v->mlen] to [0, v->mlen - v->pos] - memcpy(tmp.samps, b->samps + b->pos * samp_size, npos * samp_size); - memcpy(tmp.times, b->times + b->pos * sizeof(mpr_time), npos * sizeof(mpr_time)); - // copy from [0, v->pos] to [v->mlen - v->pos, v->mlen] - memcpy(tmp.samps + npos * samp_size, b->samps, b->pos * samp_size); - memcpy(tmp.samps + npos * sizeof(mpr_time), b->samps, b->pos * sizeof(mpr_time)); - // zero remainder - memset(tmp.samps + v->mlen * samp_size, 0, (mlen - v->mlen) * samp_size); + /* copy from [v->pos, v->mlen] to [0, v->mlen - v->pos] */ + memcpy(tmp.samps, (char*)b->samps + b->pos * samp_size, npos * samp_size); + memcpy(tmp.times, &b->times[b->pos], npos * sizeof(mpr_time)); + /* copy from [0, v->pos] to [v->mlen - v->pos, v->mlen] */ + memcpy((char*)tmp.samps + npos * samp_size, b->samps, b->pos * samp_size); + memcpy(&tmp.times[npos], b->times, b->pos * sizeof(mpr_time)); + /* zero remainder */ + memset((char*)tmp.samps + v->mlen * samp_size, 0, (mlen - v->mlen) * samp_size); + memset(&tmp.times[v->mlen], 0, (mlen - v->mlen) * sizeof(mpr_time)); + b->pos = v->mlen; + b->full = 0; } else { int len = _min(v->mlen - b->pos, mlen); - memcpy(tmp.samps, b->samps + b->pos * samp_size, len * samp_size); - memcpy(tmp.times, b->times + b->pos * sizeof(mpr_time), len * sizeof(mpr_time)); + memcpy(tmp.samps, (char*)b->samps + b->pos * samp_size, len * samp_size); + memcpy(tmp.times, &b->times[b->pos], len * sizeof(mpr_time)); if (mlen > len) { - memcpy(tmp.samps + len * samp_size, b->samps, (mlen - len) * samp_size); - memcpy(tmp.times + len * sizeof(mpr_time), b->times, (mlen - len) * sizeof(mpr_time)); + memcpy((char*)tmp.samps + len * samp_size, b->samps, (mlen - len) * samp_size); + memcpy(&tmp.times[len], b->times, (mlen - len) * sizeof(mpr_time)); } + b->pos = len; + b->full = (b->pos > mlen); } free(b->samps); free(b->times); b->samps = tmp.samps; b->times = tmp.times; - b->pos = 0; } done: @@ -94,11 +104,11 @@ void mpr_value_realloc(mpr_value v, int vlen, mpr_type type, int mlen, int num_i int mpr_value_remove_inst(mpr_value v, int idx) { int i; - RETURN_UNLESS(idx >= 0 && idx < v->num_inst, v->num_inst); + RETURN_ARG_UNLESS(idx >= 0 && idx < v->num_inst, v->num_inst); free(v->inst[idx].samps); free(v->inst[idx].times); for (i = idx + 1; i < v->num_inst; i++) { - // shift values down + /* shift values down */ memcpy(&(v->inst[i-1]), &(v->inst[i]), sizeof(mpr_value_buffer_t)); } --v->num_inst; @@ -109,17 +119,23 @@ int mpr_value_remove_inst(mpr_value v, int idx) void mpr_value_reset_inst(mpr_value v, int idx) { + mpr_value_buffer b; RETURN_UNLESS(v->inst); - mpr_value_buffer b = &v->inst[idx]; + b = &v->inst[idx]; memset(b->samps, 0, v->mlen * v->vlen * mpr_type_get_size(v->type)); memset(b->times, 0, v->mlen * sizeof(mpr_time)); b->pos = -1; + b->full = 0; } void mpr_value_set_sample(mpr_value v, int idx, void *s, mpr_time t) { mpr_value_buffer b = &v->inst[idx]; - b->pos = ((b->pos + 1) % v->mlen); + b->pos += 1; + if (b->pos >= v->mlen) { + b->pos = 0; + b->full = 1; + } memcpy(mpr_value_get_samp(v, idx), s, v->vlen * mpr_type_get_size(v->type)); memcpy(mpr_value_get_time(v, idx), &t, sizeof(mpr_time)); } @@ -136,34 +152,53 @@ void mpr_value_free(mpr_value v) { } #ifdef DEBUG -void mpr_value_print(mpr_value v, int inst_idx) { - int i = inst_idx >= 0 ? inst_idx : 0, j; +static void _value_print(mpr_value v, int inst_idx, int hist_idx) { + int i; + if (v->inst[inst_idx].pos < 0) { + printf("NULL\n"); + return; + } + void *s = mpr_value_get_samp_hist(v, inst_idx, hist_idx); + mpr_time *t = mpr_value_get_time_hist(v, inst_idx, hist_idx); + printf("%08x.%08x | ", (*t).sec, (*t).frac); + if (v->vlen > 1) + printf("["); + switch (v->type) { -#define TYPED_CASE(MTYPE, TYPE, STR) \ - case MTYPE: \ - for (i = 0; i < v->num_inst; i++) { \ - printf("%d: ", i); \ - if (v->inst[i].pos >= 0) { \ - if (v->vlen > 1) \ - printf("["); \ - TYPE *samp = (TYPE*)mpr_value_get_samp(v, i); \ - for (j = 0; j < v->vlen; j++) \ - printf(STR, samp[j]); \ - if (v->vlen > 1) \ - printf("\b\b]\n"); \ - else \ - printf("\b\b\n"); \ - } \ - else \ - printf("NULL\n"); \ - if (inst_idx < 0) \ - break; \ - } \ +#define TYPED_CASE(MTYPE, TYPE, STR) \ + case MTYPE: \ + for (i = 0; i < v->vlen; i++) \ + printf(STR, ((TYPE*)s)[i]); \ break; TYPED_CASE(MPR_INT32, int, "%d, "); TYPED_CASE(MPR_FLT, float, "%f, "); TYPED_CASE(MPR_DBL, double, "%f, "); #undef TYPED_CASE } + + if (v->vlen > 1) + printf("\b\b] @%p -> %p\n", v->inst[inst_idx].samps, s); + else + printf("\b\b @%p -> %p\n", v->inst[inst_idx].samps, s); +} + +void mpr_value_print(mpr_value v, int inst_idx) { + RETURN_UNLESS(inst_idx < v->num_inst && v->inst[inst_idx].pos >= 0); + _value_print(v, inst_idx, v->inst[inst_idx].pos); } + +void mpr_value_print_hist(mpr_value v, int inst_idx) { + RETURN_UNLESS(inst_idx < v->num_inst && v->inst[inst_idx].pos >= 0); + + /* if history is full, print from pos+1 -> pos, else print from 0 -> pos */ + int i, hidx = v->inst[inst_idx].pos * -1; + for (i = 0; i < v->mlen; i++) { + printf("%s {%3d} ", hidx ? " " : "->", hidx); + _value_print(v, inst_idx, hidx); + ++hidx; + if (hidx > 0) + hidx -= v->mlen; + }; +} + #endif diff --git a/update-library.sh b/update-library.sh new file mode 100755 index 0000000..6c839ef --- /dev/null +++ b/update-library.sh @@ -0,0 +1,78 @@ +#!/bin/zsh +cd -- "$(dirname "$BASH_SOURCE")" + +rm -rf src +mkdir src + +cp mapper.h src/mapper.h + +mkdir -p tmp +cd tmp + +# libmapper +git clone git@github.com:mathiasbredholt/libmapper.git +cd libmapper +./autogen.sh +mkdir -p ../../src/mapper +# Include compat.h at beginning of each source file +for i in src/*.c; do sed -i '' '1i\ +#include +' $i ; done +cp src/*.c ../../src/mapper +cp src/*.h ../../src/mapper +cp include/mapper/*.h ../../src/mapper +cd .. +rm -rf libmapper + +# liblo +git clone git@github.com:radarsat1/liblo.git +cd liblo +./autogen.sh +mkdir -p ../../src/lo +# # Include compat.h at beginning of each source file +for i in src/*.c; do sed -i '' '1i\ +#include +' $i ; done +cp src/address.c ../../src/lo +cp src/blob.c ../../src/lo +cp src/bundle.c ../../src/lo +cp src/message.c ../../src/lo +cp src/method.c ../../src/lo +cp src/pattern_match.c ../../src/lo +cp src/send.c ../../src/lo +cp src/server.c ../../src/lo +cp src/server_thread.c ../../src/lo +cp src/timetag.c ../../src/lo +cp src/version.c ../../src/lo +cp src/*.h ../../src/lo +cp *.h ../../src/lo +cp lo/*.h ../../src/lo +cd .. +rm -rf liblo + +# compat-idf +git clone git@github.com:mathiasbredholt/compat-idf.git +cd compat-idf +git checkout origin/v4.0 +mkdir -p ../../src/compat +cp src/*.c ../../src/compat +cp include/*.h ../../src +cp -rf include/netinet ../../src +cd .. +rm -rf compat-idf + +# zlib +git clone git@github.com:madler/zlib.git +cd zlib +mkdir -p ../../src/zlib +cp crc32.c ../../src/zlib +cp crc32.h ../../src +cp zlib.h ../../src +cp zutil.h ../../src +cp zconf.h ../../src +cd .. +rm -rf zlib + +cd .. + +rm -rf tmp