diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c8741b..c9b112c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,10 @@ option(EXAMPLES_USE_GIT_MASTER "If enabled, some of the external testsuites in e option(ENABLE_HOST_CPU_DEVICES "Add host CPUs as OpenCL devices (basic and pthread)." ON) +option(ENABLE_PROTEUS "Enable the MCL simulated accelerator with fixed-functions." OFF) + +option(ENABLE_NVDLA "Enable the NVDLA" off) + option(ENABLE_ALMAIF_DEVICE "Enable the generic hardware accelerator device driver." OFF) option(ENABLE_POCLCC "Build poclcc. Defaults to ON" ON) @@ -1382,6 +1386,23 @@ if(ENABLE_PROXY_DEVICE) endif() +#################################################################### + +if(ENABLE_PROTEUS) + set(BUILD_BASIC 1) + set(BUILD_PROTEUS 1) + set(OCL_DRIVERS "${OCL_DRIVERS} proteus") +endif() + +if(ENABLE_NVDLA) + set(BUILD_BASIC 1) + set(BUILD_NVDLA 1) + set(OCL_DRIVERS "${OCL_DRIVERS} nvdla") + set(OCL_DRIVERS "${OCL_TARGETS} nvdla") + set(NVDLA_DEVICE_CL_VERSION "120") + set(NVDLA_DEVICE_CL_STD "1.2") +endif() + #################################################################### # Determine which device drivers to build. @@ -2029,6 +2050,8 @@ endif() MESSAGE(STATUS "ENABLE_IPO: ${ENABLE_IPO}") MESSAGE(STATUS "ENABLE_ICD: ${ENABLE_ICD}") MESSAGE(STATUS "ENABLE_TCE: ${ENABLE_TCE}") +MESSAGE(STATUS "ENABLE_PROTEUS: ${ENABLE_PROTEUS}") +MESSAGE(STATUS "ENABLE_NVDLA: ${ENABLE_NVDLA}") MESSAGE(STATUS "ENABLE_TCEMC: ${ENABLE_TCEMC}") MESSAGE(STATUS "ENABLE_HSA: ${ENABLE_HSA}") MESSAGE(STATUS "ENABLE_ALMAIF_DEVICE: ${ENABLE_ALMAIF_DEVICE}") diff --git a/cmake/FindNvdlaEmu.cmake b/cmake/FindNvdlaEmu.cmake new file mode 100644 index 0000000..8ebe3cd --- /dev/null +++ b/cmake/FindNvdlaEmu.cmake @@ -0,0 +1,57 @@ +# This module defines the following variables: +# +# :: +# +# NVDLAEMU_INCLUDE_DIRS +# NVDLAEMU_LIBS +# NVDLAEMU_FOUND +# + +# +# Hints +# ^^^^^ +# A user may set ``NVLDAEMU_ROOT`` to an installation root to tell this module where to look. +# + + + +set(_NVDLAEMU_SEARCHES) + +if(NVDLAEMU_ROOT) + set(_NVDLAEMU_SEARCH_ROOT PATHS ${NVDLAEMU_ROOT} NO_DEFAULT_PATH) + list(APPEND _NVDLAEMU_SEARCHES _NVDLAEMU_SEARCH_ROOT) +endif() + +# appends some common paths +set(_NVDLAEMU_SEARCH_NORMAL + PATHS "/usr/ /usr/local/ /usr/src/" +) +list(APPEND _NVDLAEMU_SEARCHES _NVDLAEMU_SEARCH_NORMAL) + +# Include dir +foreach(search ${_NVDLAEMU_SEARCHES}) + find_path(NVDLAEMU_INCLUDE_DIR NAMES Connection.h ${${search}} PATH_SUFFIXES include/nvdla_emu ) +endforeach() + +if(NOT NVDLAEMU_LIBRARY) + foreach(search ${_NVDLAEMU_SEARCHES}) + find_library(NVDLAEMU_LIBRARY NAMES nvdla_emu ${${search}} PATH_SUFFIXES lib ) + endforeach() +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(NVDLAEMU REQUIRED_VARS NVDLAEMU_LIBRARY NVDLAEMU_INCLUDE_DIR ) + +if(NVDLAEMU_FOUND) + set(NVDLAEMU_INCLUDE_DIRS ${NVDLAEMU_INCLUDE_DIR} ) + + if(NOT NVDLAEMU_LIBS) + set(NVDLAEMU_LIBS ${NVDLAEMU_LIBRARY}) + endif() + + if(NOT TARGET NVDLAEMU::NVDLAEMU) + add_library(NVDLAEMU::NVDLAEMU UNKNOWN IMPORTED) + set_target_properties(NVDLAEMU::NVDLAEMU PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${NVDLAEMU_INCLUDE_DIRS}") + set_property(TARGET NVDLAEMU::NVDLAEMU APPEND PROPERTY IMPORTED_LOCATION "${NVDLAEMU_LIBRARY}") + endif() +endif() \ No newline at end of file diff --git a/cmake/FindTensorRT.cmake b/cmake/FindTensorRT.cmake new file mode 100644 index 0000000..887decd --- /dev/null +++ b/cmake/FindTensorRT.cmake @@ -0,0 +1,76 @@ +# This module defines the following variables: +# +# :: +# +# TensorRT_INCLUDE_DIRS +# TensorRT_LIBRARIES +# TensorRT_FOUND +# +# :: +# +# TensorRT_VERSION_STRING - version (x.y.z) +# TensorRT_VERSION_MAJOR - major version (x) +# TensorRT_VERSION_MINOR - minor version (y) +# TensorRT_VERSION_PATCH - patch version (z) +# +# Hints +# ^^^^^ +# A user may set ``TensorRT_ROOT`` to an installation root to tell this module where to look. +# +# Source +# https://github.com/NVIDIA/tensorrt-laboratory/blob/master/cmake/FindTensorRT.cmake + + +set(_TensorRT_SEARCHES) + +if(TensorRT_ROOT) + set(_TensorRT_SEARCH_ROOT PATHS ${TensorRT_ROOT} NO_DEFAULT_PATH) + list(APPEND _TensorRT_SEARCHES _TensorRT_SEARCH_ROOT) +endif() + +# appends some common paths +set(_TensorRT_SEARCH_NORMAL + PATHS "/usr" +) +list(APPEND _TensorRT_SEARCHES _TensorRT_SEARCH_NORMAL) + +# Include dir +foreach(search ${_TensorRT_SEARCHES}) + find_path(TensorRT_INCLUDE_DIR NAMES NvInfer.h ${${search}} PATH_SUFFIXES include) +endforeach() + +if(NOT TensorRT_LIBRARY) + foreach(search ${_TensorRT_SEARCHES}) + find_library(TensorRT_LIBRARY NAMES nvinfer ${${search}} PATH_SUFFIXES lib) + endforeach() +endif() + +mark_as_advanced(TensorRT_INCLUDE_DIR) + +if(TensorRT_INCLUDE_DIR AND EXISTS "${TensorRT_INCLUDE_DIR}/NvInfer.h") + file(STRINGS "${TensorRT_INCLUDE_DIR}/NvInfer.h" TensorRT_MAJOR REGEX "^#define NV_TENSORRT_MAJOR [0-9]+.*$") + file(STRINGS "${TensorRT_INCLUDE_DIR}/NvInfer.h" TensorRT_MINOR REGEX "^#define NV_TENSORRT_MINOR [0-9]+.*$") + file(STRINGS "${TensorRT_INCLUDE_DIR}/NvInfer.h" TensorRT_PATCH REGEX "^#define NV_TENSORRT_PATCH [0-9]+.*$") + + string(REGEX REPLACE "^#define NV_TENSORRT_MAJOR ([0-9]+).*$" "\\1" TensorRT_VERSION_MAJOR "${TensorRT_MAJOR}") + string(REGEX REPLACE "^#define NV_TENSORRT_MINOR ([0-9]+).*$" "\\1" TensorRT_VERSION_MINOR "${TensorRT_MINOR}") + string(REGEX REPLACE "^#define NV_TENSORRT_PATCH ([0-9]+).*$" "\\1" TensorRT_VERSION_PATCH "${TensorRT_PATCH}") + set(TensorRT_VERSION_STRING "${TensorRT_VERSION_MAJOR}.${TensorRT_VERSION_MINOR}.${TensorRT_VERSION_PATCH}") +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TensorRT REQUIRED_VARS TensorRT_LIBRARY TensorRT_INCLUDE_DIR VERSION_VAR TensorRT_VERSION_STRING) + +if(TensorRT_FOUND) + set(TensorRT_INCLUDE_DIRS ${TensorRT_INCLUDE_DIR}) + + if(NOT TensorRT_LIBRARIES) + set(TensorRT_LIBRARIES ${TensorRT_LIBRARY}) + endif() + + if(NOT TARGET TensorRT::TensorRT) + add_library(TensorRT::TensorRT UNKNOWN IMPORTED) + set_target_properties(TensorRT::TensorRT PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${TensorRT_INCLUDE_DIRS}") + set_property(TARGET TensorRT::TensorRT APPEND PROPERTY IMPORTED_LOCATION "${TensorRT_LIBRARY}") + endif() +endif() \ No newline at end of file diff --git a/config.h.in.cmake b/config.h.in.cmake index 6f121d0..12954bd 100644 --- a/config.h.in.cmake +++ b/config.h.in.cmake @@ -3,6 +3,8 @@ #cmakedefine BUILD_CUDA #cmakedefine BUILD_BASIC #cmakedefine BUILD_PTHREAD +#cmakedefine BUILD_PROTEUS +#cmakedefine BUILD_NVDLA #cmakedefine BUILD_ALMAIF #cmakedefine BUILD_VULKAN diff --git a/lib/CL/devices/CMakeLists.txt b/lib/CL/devices/CMakeLists.txt index 0b492fa..d1242eb 100644 --- a/lib/CL/devices/CMakeLists.txt +++ b/lib/CL/devices/CMakeLists.txt @@ -66,6 +66,32 @@ if(BUILD_ALMAIF) "$") endif() +if(BUILD_PROTEUS) + add_subdirectory("proteus") +endif() + +if(BUILD_NVDLA) + add_subdirectory("nvdla") + message("devices build nvdlaemu ${BUILD_NVDLAEMU}") + if(BUILD_NVDLAEMU) + set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS}" + "$") + add_definitions(-DBUILD_NVDLAEMU) + if(NOT ENABLE_LOADABLE_DRIVERS) + list(APPEND POCL_DEVICES_LINK_LIST ${NVDLAEMU_LIBS}) + endif() + endif() + message("devices build xaiver ${BUILD_XAVIER}") + if(BUILD_XAVIER) + set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS}" + "$") + add_definitions(-DBUILD_XAVIER) + if(NOT ENABLE_LOADABLE_DRIVERS) + list(APPEND POCL_DEVICES_LINK_LIST ${XAVIER_LIBS}) + endif() + endif() +endif() + # for these drivers, use HWLOC if found if(ENABLE_HOST_CPU_DEVICES OR ENABLE_HSA) add_subdirectory("topology") diff --git a/lib/CL/devices/devices.c b/lib/CL/devices/devices.c index 2036168..9cc5038 100644 --- a/lib/CL/devices/devices.c +++ b/lib/CL/devices/devices.c @@ -87,6 +87,19 @@ #include "vulkan/pocl-vulkan.h" #endif +#ifdef BUILD_PROTEUS +#include "proteus/proteus.h" +#endif + +#if defined(BUILD_NVDLA) +#if defined(BUILD_NVDLAEMU) +#include "nvdla/emulator/nvdlaemu.hpp" +#endif +#if defined(BUILD_XAVIER) +#include "nvdla/xavier/xavier.hpp" +#endif +#endif + #define MAX_DEV_NAME_LEN 64 #ifndef PATH_MAX @@ -149,6 +162,17 @@ static init_device_ops pocl_devices_init_ops[] = { #ifdef BUILD_VULKAN INIT_DEV (vulkan), #endif +#ifdef BUILD_PROTEUS + INIT_DEV (proteus), +#endif +#if defined(BUILD_NVDLA) +#if defined(BUILD_NVDLAEMU) + INIT_DEV (nvdlaemu), +#endif +#if defined(BUILD_XAVIER) + INIT_DEV (xavier), +#endif +#endif }; #define POCL_NUM_DEVICE_TYPES (sizeof(pocl_devices_init_ops) / sizeof((pocl_devices_init_ops)[0])) @@ -178,6 +202,20 @@ char pocl_device_types[POCL_NUM_DEVICE_TYPES][30] = { #ifdef BUILD_VULKAN "vulkan", #endif +#ifdef BUILD_PROTEUS + "proteus", +#endif +#ifdef BUILD_NVDLA +#if defined(BUILD_NVDLAEMU) + "nvdlaemu", +#endif +#endif +#if defined(BUILD_XAVIER) + "xavier", +#endif +#ifdef BUILD_ACCEL + "accel", +#endif }; static struct pocl_device_ops pocl_device_ops[POCL_NUM_DEVICE_TYPES]; @@ -283,25 +321,30 @@ pocl_get_devices (cl_device_type device_type, cl_device_id *devices, { unsigned int i, dev_added = 0; - cl_device_type device_type_tmp = device_type; - if (device_type_tmp == CL_DEVICE_TYPE_ALL) - { - device_type_tmp = ~CL_DEVICE_TYPE_CUSTOM; - } + // Rizwan: including CUSTOM device type in listed devices. + // however, the spec requires that they are not listed. + // commented code below complies with the spec. + //cl_device_type device_type_tmp = device_type; + //if (device_type_tmp == CL_DEVICE_TYPE_ALL) + // { + // device_type_tmp = ~CL_DEVICE_TYPE_CUSTOM; + // } for (i = 0; i < pocl_num_devices; ++i) { if (!pocl_offline_compile && (pocl_devices[i].available == CL_FALSE)) continue; - if (device_type_tmp == CL_DEVICE_TYPE_DEFAULT) + //if (device_type_tmp == CL_DEVICE_TYPE_DEFAULT) + if (device_type == CL_DEVICE_TYPE_DEFAULT) { devices[dev_added] = &pocl_devices[i]; ++dev_added; break; } - if (pocl_devices[i].type & device_type_tmp) + //if (pocl_devices[i].type & device_type_tmp) + if (pocl_devices[i].type & device_type) { if (dev_added < num_devices) { @@ -323,21 +366,26 @@ pocl_get_device_type_count(cl_device_type device_type) unsigned int count = 0; unsigned int i; - cl_device_type device_type_tmp = device_type; - if (device_type_tmp == CL_DEVICE_TYPE_ALL) - { - device_type_tmp = ~CL_DEVICE_TYPE_CUSTOM; - } + // Rizwan: including CUSTOM device type in listed devices. + // however, the spec requires that they are not listed. + // commented code below complies with the spec. + //cl_device_type device_type_tmp = device_type; + //if (device_type_tmp == CL_DEVICE_TYPE_ALL) + // { + // device_type_tmp = ~CL_DEVICE_TYPE_CUSTOM; + // } for (i = 0; i < pocl_num_devices; ++i) { if (!pocl_offline_compile && (pocl_devices[i].available == CL_FALSE)) continue; - if (device_type_tmp == CL_DEVICE_TYPE_DEFAULT) + //if (device_type_tmp == CL_DEVICE_TYPE_DEFAULT) + if (device_type == CL_DEVICE_TYPE_DEFAULT) return 1; - if (pocl_devices[i].type & device_type_tmp) + //if (pocl_devices[i].type & device_type_tmp) + if (pocl_devices[i].type & device_type) { ++count; } @@ -558,6 +606,8 @@ pocl_init_devices () pocl_device_handles[i], init_device_ops_name); if (pocl_devices_init_ops[i] == NULL) { + POCL_MSG_WARN ("Loading %s failed.\n", device_library); + POCL_MSG_WARN ("Reason of dlopen fail %s\n", dlerror()); //RA POCL_MSG_ERR ("Loading symbol %s from %s failed: %s\n", init_device_ops_name, device_library, dlerror ()); diff --git a/lib/CL/devices/nvdla/CMakeLists.txt b/lib/CL/devices/nvdla/CMakeLists.txt new file mode 100644 index 0000000..1e2a338 --- /dev/null +++ b/lib/CL/devices/nvdla/CMakeLists.txt @@ -0,0 +1,19 @@ +add_subdirectory(emulator) +add_subdirectory(xavier) + +message("nvdla build nvdlaemu ${BUILD_NVDLAEMU}") +if(BUILD_NVDLAEMU) +# set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS};$" PARENT_SCOPE) + set(BUILD_NVDLAEMU "1" PARENT_SCOPE) + set(NVDLAEMU_LIBS ${NVDLAEMU_LIBS} PARENT_SCOPE) +endif() +message("nvdla build xavier ${BUILD_XAVIER}") +if(BUILD_XAVIER) +# set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS};$" PARENT_SCOPE) + set(BUILD_XAVIER "1" PARENT_SCOPE) + set(XAVIER_LIBS ${XAVIER_LIBS} PARENT_SCOPE) +endif() + +if(NOT BUILD_NVDLAEMU AND NOT BUILD_XAVIER) +message(FATAL_ERROR "ENABLENVDLA=1 but neither NVDLAEMU or XAVIER will be built") +endif() \ No newline at end of file diff --git a/lib/CL/devices/nvdla/emulator/CMakeLists.txt b/lib/CL/devices/nvdla/emulator/CMakeLists.txt new file mode 100644 index 0000000..e10f2aa --- /dev/null +++ b/lib/CL/devices/nvdla/emulator/CMakeLists.txt @@ -0,0 +1,24 @@ +find_package(NvdlaEmu) +if (NVDLAEMU_FOUND) +message(STATUS "NVDLAEMU_INCLUDE_DIRS = ${NVDLAEMU_INCLUDE_DIRS}") +message(STATUS "NVDLAEMU_LIBS = ${NVDLAEMU_LIBS}") + +#add_compile_options("-std=c++11") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXXFLAGS}") + +include_directories( ${NVDLAEMU_INCLUDE_DIRS} .. ) +# add_library("pocl-devices-nvdlaemu" OBJECT nvdlaemu.cpp nvdlaemu.hpp) +add_pocl_device_library(pocl-devices-nvdlaemu nvdlaemu.cpp nvdlaemu.hpp) +if(ENABLE_LOADABLE_DRIVERS) + target_link_libraries(pocl-devices-nvdlaemu PRIVATE pocl-devices-basic ${NVDLAEMU_LIBS}) +endif() +# set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS};$" PARENT_SCOPE) +set(BUILD_NVDLAEMU "1" PARENT_SCOPE) +# set(NVDLAEMU_LIBS ${NVDLAEMU_LIBS} PARENT_SCOPE) +endif() + + + + diff --git a/lib/CL/devices/nvdla/emulator/nvdlaemu.cpp b/lib/CL/devices/nvdla/emulator/nvdlaemu.cpp new file mode 100644 index 0000000..a753fd8 --- /dev/null +++ b/lib/CL/devices/nvdla/emulator/nvdlaemu.cpp @@ -0,0 +1,575 @@ + +#include "nvdlaemu.hpp" +#include "devices.h" +#include "pocl_cl.h" +#include "pocl_util.h" + +#include "limits.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Connection.h" +#include "Message.h" + + +/* default WG size in each dimension & total WG size. + * this should be reasonable for CPU */ +#define DEFAULT_WG_SIZE 4096 + +struct kernel_data{ + char* model_name; + std::vector* args; + kernel_data(char* m, std::vector* a) : model_name(m), args(a) + {} +}; + +struct model_data{ + char* buf; + size_t size; +}; + +struct data { + /* Currently loaded kernel. */ + cl_kernel current_kernel; + + std::unordered_map* context_cache[2]; + Connection* server; + + std::unordered_map* kernel_map; + std::unordered_map* model_map; + + /* List of commands ready to be executed */ + _cl_command_node * ready_list; + /* List of commands not yet ready to be executed */ + _cl_command_node * command_list; + /* Lock for command list related operations */ + pocl_lock_t cq_lock; + pocl_lock_t context_cache_lock; + /* printf buffer */ + void *printf_buffer; +}; + +pocl_argument_info* create_arg_info(const char *TypeName, const char *Name, pocl_argument_type Type, cl_kernel_arg_address_qualifier AQ) { + pocl_argument_info* arg = (pocl_argument_info*)calloc(1,sizeof(pocl_argument_info)); + arg->type = Type; + arg->address_qualifier = AQ; + arg->type_name = strdup(TypeName); + arg->name = strdup(Name); + return arg; +} +void destroy_arg_info(pocl_argument_info* arg){ + free(arg->name); + free(arg->type_name); + free(arg); +} + +void update_kernel_metadata( pocl_kernel_metadata_t *target, const char* name, std::vector *args ){ + target->builtin_kernel=1; + target->name=strdup(name); + target->num_args=args->size(); + target->arg_info = (pocl_argument_info*)calloc(target->num_args,sizeof(pocl_argument_info)); + + for (int i =0; i < args->size(); i ++){ + auto arg = args->operator[](i); + target->arg_info[i] = *(arg); + target->arg_info[i].name = strdup(arg->name); + target->arg_info[i].type_name = strdup(arg->type_name); + } +} + + +void pocl_nvdlaemu_init_device_ops(struct pocl_device_ops *ops) { + //std::cout<<__func__<device_name = "nvdlaemu"; + ops->init = pocl_nvdlaemu_init; + ops->uninit = pocl_nvdlaemu_uninit; + ops->probe = pocl_nvdlaemu_probe; + ops->build_hash = pocl_nvdlaemu_build_hash; + ops->setup_metadata = pocl_nvdlaemu_setup_metadata; + + ops->alloc_mem_obj = pocl_nvdlaemu_alloc_mem_obj; + ops->free = pocl_nvdlaemu_free; + ops->memfill = pocl_nvdlaemu_memfill; + + ops->submit = pocl_nvdlaemu_submit; + ops->flush = ops->join = pocl_nvdlaemu_join; + + ops->write = pocl_nvdlaemu_write; + ops->read = pocl_nvdlaemu_read; + ops->notify = pocl_nvdlaemu_notify; + ops->broadcast = pocl_broadcast; + ops->run = pocl_nvdlaemu_run; + ops->build_builtin = pocl_nvdlaemu_build_builtin; +} + +cl_int pocl_nvdlaemu_init(unsigned j, cl_device_id dev, const char *parameters) { + //std::cout<<__func__<type = CL_DEVICE_TYPE_CUSTOM; + dev->long_name = (char *)"NVIDIA DLA EMULATOR"; + dev->vendor = "pocl"; + dev->version = "3.1"; + dev->available = CL_TRUE; + dev->extensions = ""; + dev->profile = "FULL_PROFILE"; + dev->max_mem_alloc_size = 1024 * 1024 * 1024; + + // std::cout<<"NVDLA ADDR_PORT "<global_mem_id = 0; + dev->global_mem_size = (size_t)8*1024*1024*1024; + + data* d = new data(); + d->server = NULL; + + if (!parameters){ + std::cerr<<"ERROR MUST PROVIVDE ADDRESS:PORT for NVDLA EMULATOR e.g. POCL_NVDLAEMU0_PARAMETERS=\"127.0.0.1:5555\""<lock(); + if (sendPingMsg(con)){ + sendInitMsg(con); + num_devices = getNumDevices(con); + max_devices = getMaxDevices(con); + d->server = con; + }else{ + std::cerr<<"WARNING NO VALID NVDLAEMU SERVER RUNNING @"<server = NULL; + } + con->unlock(); + } + + dev->max_compute_units= max_devices; //two dla cores + dev->available = num_devices; + + if (d == NULL) + return CL_OUT_OF_HOST_MEMORY; + + dev->platform = 0; + + dev->max_work_item_dimensions = 3; + + int max_wg + = pocl_get_int_option ("POCL_MAX_WORK_GROUP_SIZE", DEFAULT_WG_SIZE); + assert (max_wg > 0); + max_wg = std::min (max_wg, DEFAULT_WG_SIZE); + if (max_wg < 0) + max_wg = DEFAULT_WG_SIZE; + dev->max_work_group_size = dev->max_work_item_sizes[0] = + dev->max_work_item_sizes[1] = dev->max_work_item_sizes[2] = max_wg; + + d->current_kernel = NULL; + d->kernel_map = new std::unordered_map(); + d->model_map = new std::unordered_map(); + d->context_cache[0] = new std::unordered_map(); + d->context_cache[1] = new std::unordered_map(); + d->ready_list = NULL; + d->command_list = NULL; + POCL_INIT_LOCK(d->cq_lock); + POCL_INIT_LOCK(d->context_cache_lock); + dev->data = d; + + dev->builtin_kernel_list = strdup(std::string("dataflow").c_str()); + return CL_SUCCESS; +} + +cl_int pocl_nvdlaemu_uninit(unsigned /*j*/, cl_device_id device) {//TODO need to free other things in data + //std::cout<<__func__<data; + for (int i = 0; i<2;i++){ + if (d->context_cache[i] != NULL){ + for (auto& it : *d->context_cache[i]){ + if (it.second != NULL){ + delete it.second; + it.second = NULL; + } + } + delete d->context_cache[i]; + } + } + + if (d->kernel_map != NULL) { + for (auto& [key,value] : *d->kernel_map){ + if (value!= NULL){ + free(value->model_name); + delete value->args; + delete value; + value = NULL; + } + } + delete d->kernel_map; + } + + if (d->model_map != NULL) { + for (auto& [key,value] : *d->model_map){ + if (value != NULL){ + free(value->buf); + delete value; + value = NULL; + } + } + delete d->model_map; + } + + if(d->server != NULL){ + delete d->server; + } + + delete d; + return CL_SUCCESS; +} + +char *pocl_nvdlaemu_build_hash(cl_device_id device) { + //std::cout<<__func__<kernel_map->operator[](std::string(kernel_name)); + if (d->model_map->count(std::string(kernel_name)) == 0) { //store the network bytes if not done already + std::ifstream model_ifs(kernel->model_name,std::ios::binary); + if (!model_ifs.is_open()){ + POCL_MSG_ERR("Unable to open nvdla network file: %s\n",kernel->model_name); + return -1; + } + model_ifs.unsetf(std::ios::skipws); + auto model_bytes_vec = std::vector((std::istreambuf_iterator(model_ifs)), + std::istreambuf_iterator()); + model_ifs.close(); + auto m_data = new model_data(); + m_data->size = model_bytes_vec.size(); + m_data->buf = (char*)malloc(m_data->size * sizeof(char)); + memcpy(m_data->buf,model_bytes_vec.data(),m_data->size * sizeof(char)); + d->model_map->insert({std::string(kernel->model_name),m_data}); + } + update_kernel_metadata(target,kernel_name,kernel->args); + } + else { + std::vector vec; + update_kernel_metadata(target,"dataflow",&vec); + } + return 0; +} + +int pocl_nvdlaemu_setup_metadata(cl_device_id device, cl_program program, + unsigned program_device_i) { + //std::cout<<__func__<builtin_kernel_names == nullptr) { + return 0; + } + + + program->num_kernels = program->num_builtin_kernels; + if (program->num_kernels) { + program->kernel_meta = (pocl_kernel_metadata_t *)calloc( + program->num_kernels, sizeof(pocl_kernel_metadata_t)); + + for (size_t i = 0; i < program->num_kernels; ++i) { + pocl_nvdlaemu_get_builtin_kernel_metadata(device->data, + program->builtin_kernel_names[i], + &program->kernel_meta[i]); + } + } + return 1; +} + +int parse_config(char* path,cl_program program,cl_uint device_i) { + auto dev = program->devices[device_i]; + struct data *d = (struct data*)(dev->data); + auto result = toml::parse_file(path); + if (!result){ + std::stringstream ss; + ss <<"Improperly formatted graph config file. "<builtin_kernel_list; + auto config = std::move(result).table(); + config["model"].as_table()->for_each([&config, &program, &d, &kss] (auto& model, auto& data){ + auto path = config["model"][model]["path"].as_string(); + config["model"][model]["kernels"].as_table()->for_each([ &program, &d, &kss, &path](auto& kernel, auto& args){ + auto pocl_args = new std::vector(); + args.as_table()->for_each([&pocl_args](auto& name, auto& type){ + pocl_args->push_back(create_arg_info("test", "test", POCL_ARG_TYPE_POINTER, CL_KERNEL_ARG_ADDRESS_GLOBAL)); + }); + auto k_str = kernel.data(); + auto kd = new kernel_data(strdup((*path)->c_str()),pocl_args); + d->kernel_map->insert({std::string(k_str),kd}); + kss<<";"<builtin_kernel_names[ program->num_builtin_kernels] = strdup(k_str); + program->num_builtin_kernels += 1; + }); + + }); + auto temp = dev->builtin_kernel_list; + dev->builtin_kernel_list = strdup(kss.str().c_str()); + POCL_MEM_FREE(temp); + return 0; +} + +int pocl_nvdlaemu_build_builtin(cl_program program, cl_uint device_i){ + //std::cout<<__func__<compiler_options; + const char* mcl_config = "-DMCL_CONFIG="; + char* arg = strtok(opts," "); + while (arg != NULL){ + char* mcl_arg = strstr(arg,mcl_config); + if (mcl_arg!=NULL) { + mcl_arg +=strlen(mcl_config); + parse_config(mcl_arg,program, device_i); + } + arg = strtok(NULL," "); + } + return 0; +} + +unsigned int pocl_nvdlaemu_probe(struct pocl_device_ops *ops) { + //std::cout<<__func__<device_name); + POCL_MSG_PRINT_INFO("num devices %d\n",env_count); + if (env_count < 0){ + return 0; + } + return env_count; +} + +cl_int +pocl_nvdlaemu_alloc_mem_obj (cl_device_id device, cl_mem mem_obj, void* host_ptr) +{ + //std::cout<<__func__<dev_id); + + void *b = calloc(mem_obj->size,1); // we wont actually alloc on the device until ready to infer (I think...) + if (b==NULL){ + return CL_MEM_OBJECT_ALLOCATION_FAILURE; + } + mem_obj->device_ptrs[device->dev_id].mem_ptr = b; + + return CL_SUCCESS; +} + +void pocl_nvdlaemu_free(cl_device_id device, cl_mem mem_obj) { + free(mem_obj->device_ptrs[device->dev_id].mem_ptr); + mem_obj->device_ptrs[device->dev_id].mem_ptr=NULL; +} + +void +pocl_nvdlaemu_memfill (void *data, pocl_mem_identifier *dst_mem_id, + cl_mem dst_buf, size_t size, size_t offset, + const void *__restrict__ pattern, size_t pattern_size) +{ + //std::cout<<__func__<ready_list)) + { + //std::cout<<__func__<event)); + assert (node->event->status == CL_SUBMITTED); + CDL_DELETE (d->ready_list, node); + POCL_UNLOCK (d->cq_lock); + pocl_exec_command (node); + POCL_LOCK (d->cq_lock); + } + return; +} + +void +pocl_nvdlaemu_notify (cl_device_id device, cl_event event, cl_event finished) +{ + //std::cout<<__func__<data; + _cl_command_node * volatile node = event->command; + + if (finished->status < CL_COMPLETE) + { + pocl_update_event_failed (event); + return; + } + + if (!node->ready) + return; + + if (pocl_command_is_ready (event)) + { + if (event->status == CL_QUEUED) + { + pocl_update_event_submitted (event); + POCL_LOCK (d->cq_lock); + CDL_DELETE (d->command_list, node); + CDL_PREPEND (d->ready_list, node); + nvdlaemu_command_scheduler (d); + POCL_UNLOCK (d->cq_lock); + } + return; + } +} + + +void +pocl_nvdlaemu_submit (_cl_command_node *node, cl_command_queue cq) +{ + //std::cout<<__func__<device->data; + + node->ready = 1; + POCL_LOCK (d->cq_lock); + pocl_command_push(node, &d->ready_list, &d->command_list); + + POCL_UNLOCK_OBJ (node->sync.event.event); + nvdlaemu_command_scheduler (d); + POCL_UNLOCK (d->cq_lock); + + return; +} + + +void pocl_nvdlaemu_flush (cl_device_id device, cl_command_queue cq) +{ + //std::cout<<__func__<data; + + POCL_LOCK (d->cq_lock); + nvdlaemu_command_scheduler (d); + POCL_UNLOCK (d->cq_lock); +} + +void +pocl_nvdlaemu_join (cl_device_id device, cl_command_queue cq) +{ + // //std::cout<<__func__<data; + + POCL_LOCK (d->cq_lock); + nvdlaemu_command_scheduler (d); + POCL_UNLOCK (d->cq_lock); + + return; +} + +void pocl_nvdlaemu_write(void *data, const void *__restrict__ src_host_ptr, + pocl_mem_identifier *dst_mem_id, cl_mem dst_buf, + size_t offset, size_t size) { + //std::cout<<__func__<mem_ptr; + POCL_MSG_PRINT_INFO("data: %p device_ptr: %p src_host_ptr: %p offset: %lu size: %lu\n",data,device_ptr, src_host_ptr, offset,size); + if (src_host_ptr == device_ptr) + return; + memcpy ((char *)device_ptr + offset, src_host_ptr, size); +} + +void +pocl_nvdlaemu_read (void *data, + void *__restrict__ host_ptr, + pocl_mem_identifier * src_mem_id, + cl_mem src_buf, + size_t offset, size_t size) +{ + //std::cout<<__func__<mem_ptr; + if (host_ptr == device_ptr) + return; + memcpy (host_ptr, (char *)device_ptr + offset, size); +} + + +bool initalizeServerFromBin(data* d, char* netbuf, uint64_t size, std::string binName){ + //std::cout<<__func__<server->lock(); + sendLoadBinary( d->server,(uint8_t*)netbuf,size,binName); + d->server->unlock(); + return true; +} + +void doInference(Connection* connection,float* input_data,size_t in_size, float* output_data, size_t out_size){ //probably need to include input and output sizes + //std::cout<<__func__<lock(); + sendInputData( connection,(uint8_t*)input_data,in_size); + bool ret =sendInfer(connection,(uint8_t*)output_data,out_size); + connection->unlock(); + +} + + +void +pocl_nvdlaemu_run (void *data, _cl_command_node *cmd) +{ + //std::cout<<__func__<command.run.kernel; + pocl_kernel_metadata_t *meta = kernel->meta; + struct pocl_context *pc = &cmd->command.run.pc; + POCL_MSG_PRINT_INFO("num args: %u\n",meta->num_args); + + auto kernel_name = std::string(meta->name); + POCL_LOCK(d->context_cache_lock); + if (d->kernel_map->count(kernel_name) > 0){ + auto kernel = d->kernel_map->operator[](kernel_name); + auto model = d->model_map->operator[](kernel->model_name); + auto ret = initalizeServerFromBin(d,model->buf,model->size,kernel_name); + } + else{ + POCL_MSG_ERR("KERNEL Name not found %s\n",meta->name); + } + POCL_UNLOCK(d->context_cache_lock); + + struct pocl_argument * input = &(cmd->command.run.arguments[0]); + cl_mem in_m = (*(cl_mem *)(input->value)); + float* in_buf = (float*) in_m->device_ptrs[cmd->device->dev_id].mem_ptr; + POCL_MSG_PRINT_INFO("inbuf p: %p size: %lu\n",in_buf,in_m->size); + + struct pocl_argument * output = &(cmd->command.run.arguments[1]); + cl_mem out_m = (*(cl_mem *)(output->value)); + float* out_buf = (float*) out_m->device_ptrs[cmd->device->dev_id].mem_ptr; + POCL_MSG_PRINT_INFO("outbuf p: %p size: %lu\n",out_buf,out_m->size); + + doInference(d->server,in_buf,in_m->size,out_buf,out_m->size); //probably need to send in and out size + +} + + + + diff --git a/lib/CL/devices/nvdla/emulator/nvdlaemu.hpp b/lib/CL/devices/nvdla/emulator/nvdlaemu.hpp new file mode 100644 index 0000000..49562ec --- /dev/null +++ b/lib/CL/devices/nvdla/emulator/nvdlaemu.hpp @@ -0,0 +1,21 @@ +#ifndef POCL_NVDLAEMU_H +#define POCL_NVDLAEMU_H + +#include "config.h" +#include "pocl_cl.h" +#include "pocl_icd.h" +#include "prototypes.inc" + +#ifdef __cplusplus +extern "C" +{ +#endif + + GEN_PROTOTYPES (basic) + GEN_PROTOTYPES (nvdlaemu) + +#ifdef __cplusplus +} +#endif + +#endif /* POCL_NVDLAEMU_H */ \ No newline at end of file diff --git a/lib/CL/devices/nvdla/toml.hpp b/lib/CL/devices/nvdla/toml.hpp new file mode 100644 index 0000000..628811f --- /dev/null +++ b/lib/CL/devices/nvdla/toml.hpp @@ -0,0 +1,17401 @@ +//---------------------------------------------------------------------------------------------------------------------- +// +// toml++ v3.3.0 +// https://github.com/marzer/tomlplusplus +// SPDX-License-Identifier: MIT +// +//---------------------------------------------------------------------------------------------------------------------- +// +// - THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY - +// +// If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this +// file was assembled from a number of smaller files by a python script, and code contributions should not be made +// against it directly. You should instead make your changes in the relevant source file(s). The file names of the files +// that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file. +// +//---------------------------------------------------------------------------------------------------------------------- +// +// TOML Language Specifications: +// latest: https://github.com/toml-lang/toml/blob/master/README.md +// v1.0.0: https://toml.io/en/v1.0.0 +// v0.5.0: https://toml.io/en/v0.5.0 +// changelog: https://github.com/toml-lang/toml/blob/master/CHANGELOG.md +// +//---------------------------------------------------------------------------------------------------------------------- +// +// MIT License +// +// Copyright (c) Mark Gillard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//---------------------------------------------------------------------------------------------------------------------- +#ifndef TOMLPLUSPLUS_H +#define TOMLPLUSPLUS_H + +#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3 + +//******** impl/preprocessor.h *************************************************************************************** + +#ifndef __cplusplus +#error toml++ is a C++ library. +#endif +#ifdef _MSVC_LANG +#define TOML_CPP _MSVC_LANG +#else +#define TOML_CPP __cplusplus +#endif +#if TOML_CPP >= 202002L +#undef TOML_CPP +#define TOML_CPP 20 +#elif TOML_CPP >= 201703L +#undef TOML_CPP +#define TOML_CPP 17 +#else +#if TOML_CPP < 201103L +#error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml +#elif TOML_CPP < 201703L +#error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11 +#endif +#endif + +#define TOML_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + ((patch))) + +#ifdef __clang__ +#define TOML_CLANG __clang_major__ +#define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +#define TOML_CLANG 0 +#endif +#ifdef __INTEL_COMPILER +#define TOML_ICC __INTEL_COMPILER +#ifdef __ICL +#define TOML_ICC_CL TOML_ICC +#else +#define TOML_ICC_CL 0 +#endif +#else +#define TOML_ICC 0 +#define TOML_ICC_CL 0 +#endif +#if defined(_MSC_VER) && !TOML_CLANG && !TOML_ICC +#define TOML_MSVC _MSC_VER +#else +#define TOML_MSVC 0 +#endif +#if defined(__GNUC__) && !TOML_CLANG && !TOML_ICC +#define TOML_GCC __GNUC__ +#else +#define TOML_GCC 0 +#endif +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) +#define TOML_WINDOWS 1 +#else +#define TOML_WINDOWS 0 +#endif +#if defined(DOXYGEN) || defined(__DOXYGEN__) || defined(__POXY__) || defined(__poxy__) +#define TOML_DOXYGEN 1 +#else +#define TOML_DOXYGEN 0 +#endif +#ifdef __INTELLISENSE__ +#define TOML_INTELLISENSE 1 +#else +#define TOML_INTELLISENSE 0 +#endif + +// special handling for apple clang; see: +// - https://github.com/marzer/tomlplusplus/issues/189 +// - https://en.wikipedia.org/wiki/Xcode +// - https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time +#if TOML_CLANG && defined(__apple_build_version__) +#undef TOML_CLANG +#if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0) +#define TOML_CLANG 14 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6) +#define TOML_CLANG 13 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0) +#define TOML_CLANG 12 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5) +#define TOML_CLANG 11 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0) +#define TOML_CLANG 10 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3) +#define TOML_CLANG 9 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0) +#define TOML_CLANG 8 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1) +#define TOML_CLANG 7 +#else +#define TOML_CLANG 6 // not strictly correct but doesn't matter below this +#endif +#endif + +// IA64 +#if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) +#define TOML_ARCH_ITANIUM 1 +#else +#define TOML_ARCH_ITANIUM 0 +#endif + +// AMD64 +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) +#define TOML_ARCH_AMD64 1 +#else +#define TOML_ARCH_AMD64 0 +#endif + +// 32-bit x86 +#if defined(__i386__) || defined(_M_IX86) +#define TOML_ARCH_X86 1 +#else +#define TOML_ARCH_X86 0 +#endif + +// ARM +#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \ + || defined(_M_ARM64EC) +#define TOML_ARCH_ARM32 0 +#define TOML_ARCH_ARM64 1 +#define TOML_ARCH_ARM 1 +#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE) +#define TOML_ARCH_ARM32 1 +#define TOML_ARCH_ARM64 0 +#define TOML_ARCH_ARM 1 +#else +#define TOML_ARCH_ARM32 0 +#define TOML_ARCH_ARM64 0 +#define TOML_ARCH_ARM 0 +#endif + +// TOML_HAS_INCLUDE +#ifdef __has_include +#define TOML_HAS_INCLUDE(header) __has_include(header) +#else +#define TOML_HAS_INCLUDE(header) 0 +#endif + +#ifdef __has_builtin +#define TOML_HAS_BUILTIN(name) __has_builtin(name) +#else +#define TOML_HAS_BUILTIN(name) 0 +#endif + +// TOML_HAS_FEATURE +#ifdef __has_feature +#define TOML_HAS_FEATURE(name) __has_feature(name) +#else +#define TOML_HAS_FEATURE(name) 0 +#endif + +// TOML_HAS_ATTR +#ifdef __has_attribute +#define TOML_HAS_ATTR(attr) __has_attribute(attr) +#else +#define TOML_HAS_ATTR(attr) 0 +#endif + +// TOML_HAS_CPP_ATTR +#ifdef __has_cpp_attribute +#define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr) +#else +#define TOML_HAS_CPP_ATTR(attr) 0 +#endif + +// TOML_COMPILER_HAS_EXCEPTIONS +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions) +#define TOML_COMPILER_HAS_EXCEPTIONS 1 +#else +#define TOML_COMPILER_HAS_EXCEPTIONS 0 +#endif + +// TOML_COMPILER_HAS_RTTI +#if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti) +#define TOML_COMPILER_HAS_RTTI 1 +#else +#define TOML_COMPILER_HAS_RTTI 0 +#endif + +// TOML_ATTR (gnu attributes) +#if TOML_CLANG || TOML_GCC || defined(__GNUC__) +#define TOML_ATTR(...) __attribute__((__VA_ARGS__)) +#else +#define TOML_ATTR(...) +#endif + +// TOML_DECLSPEC (msvc attributes) +#ifdef _MSC_VER +#define TOML_DECLSPEC(...) __declspec(__VA_ARGS__) +#else +#define TOML_DECLSPEC(...) +#endif + +// TOML_CONCAT +#define TOML_CONCAT_1(x, y) x##y +#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y) + +// TOML_MAKE_STRING +#define TOML_MAKE_STRING_1(s) #s +#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s) + +// TOML_PRAGMA_XXXX (compiler-specific pragmas) +#if TOML_CLANG +#define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl)) +#else +#define TOML_PRAGMA_CLANG(decl) +#endif +#if TOML_CLANG >= 9 +#define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_9(decl) +#endif +#if TOML_CLANG >= 10 +#define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_10(decl) +#endif +#if TOML_CLANG >= 11 +#define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_11(decl) +#endif +#if TOML_GCC +#define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl)) +#else +#define TOML_PRAGMA_GCC(decl) +#endif +#if TOML_MSVC +#define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__) +#else +#define TOML_PRAGMA_MSVC(...) +#endif +#if TOML_ICC +#define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__) +#else +#define TOML_PRAGMA_ICC(...) +#endif + +// TOML_ALWAYS_INLINE +#ifdef _MSC_VER +#define TOML_ALWAYS_INLINE __forceinline +#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__) +#define TOML_ALWAYS_INLINE \ + TOML_ATTR(__always_inline__) \ + inline +#else +#define TOML_ALWAYS_INLINE inline +#endif + +// TOML_NEVER_INLINE +#ifdef _MSC_VER +#define TOML_NEVER_INLINE TOML_DECLSPEC(noinline) +#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__) +#define TOML_NEVER_INLINE TOML_ATTR(__noinline__) +#else +#define TOML_NEVER_INLINE +#endif + +// MSVC attributes +#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable) +#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases) + +// TOML_TRIVIAL_ABI +#if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__) +#define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__) +#else +#define TOML_TRIVIAL_ABI +#endif + +// TOML_NODISCARD +#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603 +#define TOML_NODISCARD [[nodiscard]] +#elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__) +#define TOML_NODISCARD TOML_ATTR(__warn_unused_result__) +#else +#define TOML_NODISCARD +#endif + +// TOML_NODISCARD_CTOR +#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907 +#define TOML_NODISCARD_CTOR [[nodiscard]] +#else +#define TOML_NODISCARD_CTOR +#endif + +// pure + const +// clang-format off +#ifdef NDEBUG + #define TOML_PURE TOML_DECLSPEC(noalias) TOML_ATTR(__pure__) + #define TOML_CONST TOML_DECLSPEC(noalias) TOML_ATTR(__const__) + #define TOML_PURE_GETTER TOML_NODISCARD TOML_PURE + #define TOML_CONST_GETTER TOML_NODISCARD TOML_CONST + #define TOML_PURE_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE TOML_PURE + #define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE TOML_CONST +#else + #define TOML_PURE + #define TOML_CONST + #define TOML_PURE_GETTER TOML_NODISCARD + #define TOML_CONST_GETTER TOML_NODISCARD + #define TOML_PURE_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE + #define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE +#endif +// clang-format on + +// TOML_ASSUME +#ifdef _MSC_VER +#define TOML_ASSUME(...) __assume(__VA_ARGS__) +#elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume) +#define TOML_ASSUME(...) __builtin_assume(__VA_ARGS__) +#else +#define TOML_ASSUME(...) static_assert(true) +#endif + +// TOML_UNREACHABLE +#ifdef _MSC_VER +#define TOML_UNREACHABLE __assume(0) +#elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable) +#define TOML_UNREACHABLE __builtin_unreachable() +#else +#define TOML_UNREACHABLE static_assert(true) +#endif + +// TOML_LIKELY +#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803 +#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]] +#define TOML_LIKELY_CASE [[likely]] +#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) +#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1)) +#else +#define TOML_LIKELY(...) (__VA_ARGS__) +#endif +#ifndef TOML_LIKELY_CASE +#define TOML_LIKELY_CASE +#endif + +// TOML_UNLIKELY +#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803 +#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]] +#define TOML_UNLIKELY_CASE [[unlikely]] +#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) +#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0)) +#else +#define TOML_UNLIKELY(...) (__VA_ARGS__) +#endif +#ifndef TOML_UNLIKELY_CASE +#define TOML_UNLIKELY_CASE +#endif + +// TOML_FLAGS_ENUM +#if TOML_CLANG || TOML_HAS_ATTR(flag_enum) +#define TOML_FLAGS_ENUM __attribute__((flag_enum)) +#else +#define TOML_FLAGS_ENUM +#endif + +// TOML_OPEN_ENUM + TOML_CLOSED_ENUM +#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility) +#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open))) +#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed))) +#else +#define TOML_OPEN_ENUM +#define TOML_CLOSED_ENUM +#endif + +// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM +#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM +#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM + +// TOML_MAKE_FLAGS +#define TOML_MAKE_FLAGS_2(T, op, linkage) \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr T operator op(T lhs, T rhs) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(static_cast(lhs) op static_cast(rhs)); \ + } \ + \ + linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept \ + { \ + return lhs = (lhs op rhs); \ + } \ + \ + static_assert(true) +#define TOML_MAKE_FLAGS_1(T, linkage) \ + static_assert(std::is_enum_v); \ + \ + TOML_MAKE_FLAGS_2(T, &, linkage); \ + TOML_MAKE_FLAGS_2(T, |, linkage); \ + TOML_MAKE_FLAGS_2(T, ^, linkage); \ + \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr T operator~(T val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(~static_cast(val)); \ + } \ + \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr bool operator!(T val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return !static_cast(val); \ + } \ + \ + static_assert(true) +#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, ) + +#define TOML_UNUSED(...) static_cast(__VA_ARGS__) + +#define TOML_DELETE_DEFAULTS(T) \ + T(const T&) = delete; \ + T(T&&) = delete; \ + T& operator=(const T&) = delete; \ + T& operator=(T&&) = delete + +#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator==(RHS rhs, LHS lhs) noexcept \ + { \ + return lhs == rhs; \ + } \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator!=(LHS lhs, RHS rhs) noexcept \ + { \ + return !(lhs == rhs); \ + } \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator!=(RHS rhs, LHS lhs) noexcept \ + { \ + return !(lhs == rhs); \ + } \ + static_assert(true) + +#define TOML_EVAL_BOOL_1(T, F) T +#define TOML_EVAL_BOOL_0(T, F) F + +#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL) +#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__ +#endif + +// COMPILER-SPECIFIC WARNING MANAGEMENT + +#if TOML_CLANG + +#define TOML_PUSH_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic push) \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option") \ + static_assert(true) + +#define TOML_DISABLE_SWITCH_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch") \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow") \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported") \ + TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant") \ + TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded") \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic pop) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic push) \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything") \ + static_assert(true, "") + +#define TOML_ENABLE_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic pop) \ + static_assert(true) + +#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1 + +#elif TOML_MSVC + +#define TOML_PUSH_WARNINGS \ + __pragma(warning(push)) \ + static_assert(true) + +#if TOML_HAS_INCLUDE() +#pragma warning(push, 0) +#include +#pragma warning(pop) +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \ + __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) \ + static_assert(true) +#else +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) +#endif + +#define TOML_DISABLE_SWITCH_WARNINGS \ + __pragma(warning(disable : 4061)) \ + __pragma(warning(disable : 4062)) \ + __pragma(warning(disable : 4063)) \ + __pragma(warning(disable : 5262)) /* switch-case implicit fallthrough (false-positive) */ \ + __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */ \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + __pragma(warning(disable : 4127)) /* conditional expr is constant */ \ + __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */ \ + __pragma(warning(disable : 4348)) \ + __pragma(warning(disable : 4464)) /* relative include path contains '..' */ \ + __pragma(warning(disable : 4505)) /* unreferenced local function removed */ \ + __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */ \ + __pragma(warning(disable : 4582)) /* constructor is not implicitly called */ \ + __pragma(warning(disable : 4619)) /* there is no warning number 'XXXX' */ \ + __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */ \ + __pragma(warning(disable : 4710)) /* function not inlined */ \ + __pragma(warning(disable : 4711)) /* function selected for automatic expansion */ \ + __pragma(warning(disable : 4820)) /* N bytes padding added */ \ + __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */ \ + __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted */ \ + __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */ \ + __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */ \ + __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */ \ + __pragma(warning(disable : 26451)) \ + __pragma(warning(disable : 26490)) \ + __pragma(warning(disable : 26495)) \ + __pragma(warning(disable : 26812)) \ + __pragma(warning(disable : 26819)) \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */ \ + __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */ \ + __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */ \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + __pragma(warning(push, 0)) \ + __pragma(warning(disable : 4348)) \ + __pragma(warning(disable : 4668)) \ + __pragma(warning(disable : 5105)) \ + __pragma(warning(disable : 5264)) \ + TOML_DISABLE_CODE_ANALYSIS_WARNINGS; \ + TOML_DISABLE_SWITCH_WARNINGS; \ + TOML_DISABLE_SPAM_WARNINGS; \ + TOML_DISABLE_ARITHMETIC_WARNINGS; \ + static_assert(true) + +#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS + +#elif TOML_ICC + +#define TOML_PUSH_WARNINGS \ + __pragma(warning(push)) \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + __pragma(warning(disable : 82)) /* storage class is not first */ \ + __pragma(warning(disable : 111)) /* statement unreachable (false-positive) */ \ + __pragma(warning(disable : 869)) /* unreferenced parameter */ \ + __pragma(warning(disable : 1011)) /* missing return (false-positive) */ \ + __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */ \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + __pragma(warning(push, 0)) \ + TOML_DISABLE_SPAM_WARNINGS + +#define TOML_ENABLE_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#elif TOML_GCC + +#define TOML_PUSH_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic push) \ + static_assert(true) + +#define TOML_DISABLE_SWITCH_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default") \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ + static_assert(true) + +#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure") \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches") \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic pop) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic push) \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wall") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wextra") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic") \ + TOML_DISABLE_SWITCH_WARNINGS; \ + TOML_DISABLE_ARITHMETIC_WARNINGS; \ + TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \ + TOML_DISABLE_SPAM_WARNINGS; \ + static_assert(true) + +#define TOML_ENABLE_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic pop) \ + static_assert(true) + +#endif + +#ifndef TOML_PUSH_WARNINGS +#define TOML_PUSH_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SWITCH_WARNINGS +#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS +#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SPAM_WARNINGS +#define TOML_DISABLE_SPAM_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS +#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true) +#endif +#ifndef TOML_POP_WARNINGS +#define TOML_POP_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_WARNINGS +#define TOML_DISABLE_WARNINGS static_assert(true) +#endif +#ifndef TOML_ENABLE_WARNINGS +#define TOML_ENABLE_WARNINGS static_assert(true) +#endif +#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES +#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0 +#endif + +#ifdef TOML_CONFIG_HEADER +#include TOML_CONFIG_HEADER +#endif + +// is the library being built as a shared lib/dll using meson and friends? +#ifndef TOML_SHARED_LIB +#define TOML_SHARED_LIB 0 +#endif + +// header-only mode +#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0 +#define TOML_HEADER_ONLY TOML_ALL_INLINE +#endif +#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE +#undef TOML_HEADER_ONLY +#define TOML_HEADER_ONLY 1 +#endif +#if TOML_DOXYGEN || TOML_SHARED_LIB +#undef TOML_HEADER_ONLY +#define TOML_HEADER_ONLY 0 +#endif + +// internal implementation switch +#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY +#undef TOML_IMPLEMENTATION +#define TOML_IMPLEMENTATION 1 +#else +#define TOML_IMPLEMENTATION 0 +#endif + +// dll/shared lib function exports (legacy - TOML_API was the old name for this setting) +#if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && !defined(TOML_EXPORTED_STATIC_FUNCTION) \ + && !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && defined(TOML_API) +#define TOML_EXPORTED_MEMBER_FUNCTION TOML_API +#define TOML_EXPORTED_STATIC_FUNCTION TOML_API +#define TOML_EXPORTED_FREE_FUNCTION TOML_API +#endif + +// dll/shared lib exports +#if TOML_SHARED_LIB +#undef TOML_API +#undef TOML_EXPORTED_CLASS +#undef TOML_EXPORTED_MEMBER_FUNCTION +#undef TOML_EXPORTED_STATIC_FUNCTION +#undef TOML_EXPORTED_FREE_FUNCTION +#if TOML_WINDOWS +#if TOML_IMPLEMENTATION +#define TOML_EXPORTED_CLASS __declspec(dllexport) +#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport) +#else +#define TOML_EXPORTED_CLASS __declspec(dllimport) +#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport) +#endif +#ifndef TOML_CALLCONV +#define TOML_CALLCONV __cdecl +#endif +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define TOML_EXPORTED_CLASS __attribute__((visibility("default"))) +#define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default"))) +#define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default"))) +#define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default"))) +#endif +#endif +#ifndef TOML_EXPORTED_CLASS +#define TOML_EXPORTED_CLASS +#endif +#ifndef TOML_EXPORTED_MEMBER_FUNCTION +#define TOML_EXPORTED_MEMBER_FUNCTION +#endif +#ifndef TOML_EXPORTED_STATIC_FUNCTION +#define TOML_EXPORTED_STATIC_FUNCTION +#endif +#ifndef TOML_EXPORTED_FREE_FUNCTION +#define TOML_EXPORTED_FREE_FUNCTION +#endif + +// experimental language features +#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES + // pre-3.0 +#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES +#endif +#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE +#undef TOML_ENABLE_UNRELEASED_FEATURES +#define TOML_ENABLE_UNRELEASED_FEATURES 1 +#endif +#ifndef TOML_ENABLE_UNRELEASED_FEATURES +#define TOML_ENABLE_UNRELEASED_FEATURES 0 +#endif + +// parser +#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0 +#define TOML_ENABLE_PARSER TOML_PARSER +#endif +#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE +#undef TOML_ENABLE_PARSER +#define TOML_ENABLE_PARSER 1 +#endif + +// formatters +#if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE +#undef TOML_ENABLE_FORMATTERS +#define TOML_ENABLE_FORMATTERS 1 +#endif + +// SIMD +#if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE +#undef TOML_ENABLE_SIMD +#define TOML_ENABLE_SIMD 1 +#endif + +// windows compat +#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0 +#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT +#endif +#if !defined(TOML_ENABLE_WINDOWS_COMPAT) || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) \ + || TOML_INTELLISENSE +#undef TOML_ENABLE_WINDOWS_COMPAT +#define TOML_ENABLE_WINDOWS_COMPAT 1 +#endif + +#if !TOML_WINDOWS +#undef TOML_ENABLE_WINDOWS_COMPAT +#define TOML_ENABLE_WINDOWS_COMPAT 0 +#endif + +#ifndef TOML_INCLUDE_WINDOWS_H +#define TOML_INCLUDE_WINDOWS_H 0 +#endif + +// custom optional +#ifdef TOML_OPTIONAL_TYPE +#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1 +#else +#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0 +#endif + +// exceptions (library use) +#if TOML_COMPILER_HAS_EXCEPTIONS +#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS) +#undef TOML_EXCEPTIONS +#define TOML_EXCEPTIONS 1 +#endif +#else +#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS +#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler. +#endif +#undef TOML_EXCEPTIONS +#define TOML_EXCEPTIONS 0 +#endif + +// calling convention for static/free/friend functions +#ifndef TOML_CALLCONV +#define TOML_CALLCONV +#endif + +#ifndef TOML_UNDEF_MACROS +#define TOML_UNDEF_MACROS 1 +#endif + +#ifndef TOML_MAX_NESTED_VALUES +#define TOML_MAX_NESTED_VALUES 256 +// this refers to the depth of nested values, e.g. inline tables and arrays. +// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... +#endif + +#ifdef TOML_CHAR_8_STRINGS +#if TOML_CHAR_8_STRINGS +#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly. +#endif +#endif + +#ifdef TOML_LARGE_FILES +#if !TOML_LARGE_FILES +#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0. +#endif +#endif + +#ifndef TOML_LIFETIME_HOOKS +#define TOML_LIFETIME_HOOKS 0 +#endif + +#ifdef NDEBUG +#undef TOML_ASSERT +#define TOML_ASSERT(expr) static_assert(true) +#endif +#ifndef TOML_ASSERT +#ifndef assert +TOML_DISABLE_WARNINGS; +#include +TOML_ENABLE_WARNINGS; +#endif +#define TOML_ASSERT(expr) assert(expr) +#endif +#ifdef NDEBUG +#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr) +#else +#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr) +#endif + +#ifndef TOML_ENABLE_FLOAT16 +#define TOML_ENABLE_FLOAT16 0 +#endif + +#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)) +// not supported by any version of GCC or Clang as of 26/11/2020 +// not supported by any version of ICC on Linux as of 11/01/2021 +#define TOML_FLOAT_CHARCONV 0 +#endif +#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__)) +// causes link errors on emscripten +// causes Mac OS SDK version errors on some versions of Apple Clang +#define TOML_INT_CHARCONV 0 +#endif +#ifndef TOML_INT_CHARCONV +#define TOML_INT_CHARCONV 1 +#endif +#ifndef TOML_FLOAT_CHARCONV +#define TOML_FLOAT_CHARCONV 1 +#endif +#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE() +#undef TOML_INT_CHARCONV +#undef TOML_FLOAT_CHARCONV +#define TOML_INT_CHARCONV 0 +#define TOML_FLOAT_CHARCONV 0 +#endif + +#if defined(__cpp_concepts) && __cpp_concepts >= 201907 +#define TOML_REQUIRES(...) requires(__VA_ARGS__) +#else +#define TOML_REQUIRES(...) +#endif +#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0 +#define TOML_CONSTRAINED_TEMPLATE(condition, ...) \ + template <__VA_ARGS__ TOML_ENABLE_IF(condition)> \ + TOML_REQUIRES(condition) +#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__) + +#if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && defined(__LDBL_MANT_DIG__) \ + && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__ +#define TOML_FLOAT128 __float128 +#endif + +#ifdef __SIZEOF_INT128__ +#define TOML_INT128 __int128_t +#define TOML_UINT128 __uint128_t +#endif + +// clang-format off + +//******** impl/version.h ******************************************************************************************** + +#define TOML_LIB_MAJOR 3 +#define TOML_LIB_MINOR 3 +#define TOML_LIB_PATCH 0 + +#define TOML_LANG_MAJOR 1 +#define TOML_LANG_MINOR 0 +#define TOML_LANG_PATCH 0 + +//******** impl/preprocessor.h *************************************************************************************** + +#define TOML_LIB_SINGLE_HEADER 1 + +#if TOML_ENABLE_UNRELEASED_FEATURES + #define TOML_LANG_EFFECTIVE_VERSION \ + TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1) +#else + #define TOML_LANG_EFFECTIVE_VERSION \ + TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) +#endif + +#define TOML_LANG_HIGHER_THAN(major, minor, patch) \ + (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch)) + +#define TOML_LANG_AT_LEAST(major, minor, patch) \ + (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch)) + +#define TOML_LANG_UNRELEASED \ + TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) + +#ifndef TOML_ABI_NAMESPACES + #if TOML_DOXYGEN + #define TOML_ABI_NAMESPACES 0 + #else + #define TOML_ABI_NAMESPACES 1 + #endif +#endif +#if TOML_ABI_NAMESPACES + #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR) + #define TOML_NAMESPACE_END } static_assert(true) + #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR) + #define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true) + #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F)) + #define TOML_ABI_NAMESPACE_END } static_assert(true) +#else + #define TOML_NAMESPACE_START namespace toml + #define TOML_NAMESPACE_END static_assert(true) + #define TOML_NAMESPACE toml + #define TOML_ABI_NAMESPACE_START(...) static_assert(true) + #define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true) + #define TOML_ABI_NAMESPACE_END static_assert(true) +#endif +#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl +#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END +#if TOML_HEADER_ONLY + #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START + #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END + #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl + #define TOML_EXTERNAL_LINKAGE inline + #define TOML_INTERNAL_LINKAGE inline +#else + #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \ + using namespace toml; \ + namespace + #define TOML_ANON_NAMESPACE_END static_assert(true) + #define TOML_ANON_NAMESPACE + #define TOML_EXTERNAL_LINKAGE + #define TOML_INTERNAL_LINKAGE static +#endif + +// clang-format on + +// clang-format off + +#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES + + #define TOML_SA_NEWLINE " " + #define TOML_SA_LIST_SEP ", " + #define TOML_SA_LIST_BEG " (" + #define TOML_SA_LIST_END ")" + #define TOML_SA_LIST_NEW " " + #define TOML_SA_LIST_NXT ", " + +#else + + #define TOML_SA_NEWLINE "\n| " + #define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - " + #define TOML_SA_LIST_BEG TOML_SA_LIST_SEP + #define TOML_SA_LIST_END + #define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE + #define TOML_SA_LIST_NXT TOML_SA_LIST_NEW + +#endif + +#define TOML_SA_NATIVE_VALUE_TYPE_LIST \ + TOML_SA_LIST_BEG "std::string" \ + TOML_SA_LIST_SEP "int64_t" \ + TOML_SA_LIST_SEP "double" \ + TOML_SA_LIST_SEP "bool" \ + TOML_SA_LIST_SEP "toml::date" \ + TOML_SA_LIST_SEP "toml::time" \ + TOML_SA_LIST_SEP "toml::date_time" \ + TOML_SA_LIST_END + +#define TOML_SA_NODE_TYPE_LIST \ + TOML_SA_LIST_BEG "toml::table" \ + TOML_SA_LIST_SEP "toml::array" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_END + +#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \ + TOML_SA_LIST_NEW "A native TOML value type" \ + TOML_SA_NATIVE_VALUE_TYPE_LIST \ + \ + TOML_SA_LIST_NXT "A TOML node type" \ + TOML_SA_NODE_TYPE_LIST + +// clang-format on + +TOML_PUSH_WARNINGS; +TOML_DISABLE_SPAM_WARNINGS; +TOML_DISABLE_SWITCH_WARNINGS; +TOML_DISABLE_SUGGEST_ATTR_WARNINGS; + +// misc warning false-positives +#if TOML_MSVC +#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch +#if TOML_SHARED_LIB +#pragma warning(disable : 4251) // dll exports for std lib types +#endif +#elif TOML_CLANG +TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene") +#if TOML_CLANG >= 12 +TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions") +#endif +#if TOML_CLANG == 13 +TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier") +#endif +#endif + +//******** impl/std_new.h ******************************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +TOML_ENABLE_WARNINGS; + +#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914 +#define TOML_LAUNDER(x) __builtin_launder(x) +#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +#define TOML_LAUNDER(x) std::launder(x) +#else +#define TOML_LAUNDER(x) x +#endif + +//******** impl/std_string.h ***************************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +#include +TOML_ENABLE_WARNINGS; + +#if TOML_DOXYGEN \ + || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \ + && __cpp_lib_char8_t >= 201907) +#define TOML_HAS_CHAR8 1 +#else +#define TOML_HAS_CHAR8 0 +#endif + +namespace toml // non-abi namespace; this is not an error +{ + using namespace std::string_literals; + using namespace std::string_view_literals; +} + +#if TOML_ENABLE_WINDOWS_COMPAT + +TOML_IMPL_NAMESPACE_START +{ + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::string narrow(std::wstring_view); + + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::wstring widen(std::string_view); + +#if TOML_HAS_CHAR8 + + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::wstring widen(std::u8string_view); + +#endif +} +TOML_IMPL_NAMESPACE_END; + +#endif // TOML_ENABLE_WINDOWS_COMPAT + +//******** impl/std_optional.h *************************************************************************************** + +TOML_DISABLE_WARNINGS; +#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE +#include +#endif +TOML_ENABLE_WARNINGS; + +TOML_NAMESPACE_START +{ +#if TOML_HAS_CUSTOM_OPTIONAL_TYPE + + template + using optional = TOML_OPTIONAL_TYPE; + +#else + + template + using optional = std::optional; + +#endif +} +TOML_NAMESPACE_END; + +//******** impl/forward_declarations.h ******************************************************************************* + +TOML_DISABLE_WARNINGS; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +TOML_ENABLE_WARNINGS; +TOML_PUSH_WARNINGS; +#ifdef _MSC_VER +#ifndef __clang__ +#pragma inline_recursion(on) +#endif +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS +#define TOML_ENV_MESSAGE \ + "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \ + "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \ + "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \ + "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \ + "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. " \ + "Thanks!" + +static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE); +static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE); +static_assert('A' == 65, TOML_ENV_MESSAGE); +static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::is_iec559, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::digits == 53, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::digits10 == 15, TOML_ENV_MESSAGE); + +#undef TOML_ENV_MESSAGE +#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS + +// undocumented forward declarations are hidden from doxygen because they fuck it up =/ + +namespace toml // non-abi namespace; this is not an error +{ + using ::std::size_t; + using ::std::intptr_t; + using ::std::uintptr_t; + using ::std::ptrdiff_t; + using ::std::nullptr_t; + using ::std::int8_t; + using ::std::int16_t; + using ::std::int32_t; + using ::std::int64_t; + using ::std::uint8_t; + using ::std::uint16_t; + using ::std::uint32_t; + using ::std::uint64_t; + using ::std::uint_least32_t; + using ::std::uint_least64_t; +} + +TOML_NAMESPACE_START +{ + struct date; + struct time; + struct time_offset; + + TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt); + struct date_time; + TOML_ABI_NAMESPACE_END; + + struct source_position; + struct source_region; + + class node; + template + class node_view; + + class key; + class array; + class table; + template + class value; + + class path; + + class toml_formatter; + class json_formatter; + class yaml_formatter; + + TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex); +#if TOML_EXCEPTIONS + using parse_result = table; +#else + class parse_result; +#endif + TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS +} +TOML_NAMESPACE_END; + +TOML_IMPL_NAMESPACE_START +{ + using node_ptr = std::unique_ptr; + + TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex); + class parser; + TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS + + // clang-format off + + inline constexpr std::string_view control_char_escapes[] = + { + "\\u0000"sv, + "\\u0001"sv, + "\\u0002"sv, + "\\u0003"sv, + "\\u0004"sv, + "\\u0005"sv, + "\\u0006"sv, + "\\u0007"sv, + "\\b"sv, + "\\t"sv, + "\\n"sv, + "\\u000B"sv, + "\\f"sv, + "\\r"sv, + "\\u000E"sv, + "\\u000F"sv, + "\\u0010"sv, + "\\u0011"sv, + "\\u0012"sv, + "\\u0013"sv, + "\\u0014"sv, + "\\u0015"sv, + "\\u0016"sv, + "\\u0017"sv, + "\\u0018"sv, + "\\u0019"sv, + "\\u001A"sv, + "\\u001B"sv, + "\\u001C"sv, + "\\u001D"sv, + "\\u001E"sv, + "\\u001F"sv, + }; + + inline constexpr std::string_view node_type_friendly_names[] = + { + "none"sv, + "table"sv, + "array"sv, + "string"sv, + "integer"sv, + "floating-point"sv, + "boolean"sv, + "date"sv, + "time"sv, + "date-time"sv + }; + + // clang-format on +} +TOML_IMPL_NAMESPACE_END; + +#if TOML_ABI_NAMESPACES +#if TOML_EXCEPTIONS +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser +#else +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser +#endif +#else +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser +#endif + +namespace toml +{ +} + +TOML_NAMESPACE_START // abi namespace +{ + inline namespace literals + { + } + + enum class TOML_CLOSED_ENUM node_type : uint8_t + { + none, + table, + array, + string, + integer, + floating_point, + boolean, + date, + time, + date_time + }; + + template + inline std::basic_ostream& operator<<(std::basic_ostream& lhs, node_type rhs) + { + const auto str = impl::node_type_friendly_names[static_cast>(rhs)]; + using str_char_t = decltype(str)::value_type; + if constexpr (std::is_same_v) + return lhs << str; + else + { + if constexpr (sizeof(Char) == sizeof(str_char_t)) + return lhs << std::basic_string_view{ reinterpret_cast(str.data()), str.length() }; + else + return lhs << str.data(); + } + } + + enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error + { + none, + format_as_binary = 1, + format_as_octal = 2, + format_as_hexadecimal = 3, + }; + TOML_MAKE_FLAGS(value_flags); + + inline constexpr value_flags preserve_source_value_flags = + POXY_IMPLEMENTATION_DETAIL(value_flags{ static_cast>(-1) }); + + enum class TOML_CLOSED_FLAGS_ENUM format_flags : uint64_t + { + none, + quote_dates_and_times = (1ull << 0), + quote_infinities_and_nans = (1ull << 1), + allow_literal_strings = (1ull << 2), + allow_multi_line_strings = (1ull << 3), + allow_real_tabs_in_strings = (1ull << 4), + allow_unicode_strings = (1ull << 5), + allow_binary_integers = (1ull << 6), + allow_octal_integers = (1ull << 7), + allow_hexadecimal_integers = (1ull << 8), + indent_sub_tables = (1ull << 9), + indent_array_elements = (1ull << 10), + indentation = indent_sub_tables | indent_array_elements, + relaxed_float_precision = (1ull << 11), + terse_key_value_pairs = (1ull << 12), + }; + TOML_MAKE_FLAGS(format_flags); + + template + struct TOML_TRIVIAL_ABI inserter + { + static_assert(std::is_reference_v); + + T value; + }; + template + inserter(T &&) -> inserter; + template + inserter(T&) -> inserter; + + using default_formatter = toml_formatter; +} +TOML_NAMESPACE_END; + +TOML_IMPL_NAMESPACE_START +{ + template + using remove_cvref = std::remove_cv_t>; + + template + using common_signed_type = std::common_type_t...>; + + template + inline constexpr bool is_one_of = (false || ... || std::is_same_v); + + template + inline constexpr bool all_integral = (std::is_integral_v && ...); + + template + inline constexpr bool is_cvref = std::is_reference_v || std::is_const_v || std::is_volatile_v; + + template + inline constexpr bool is_wide_string = + is_one_of, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>; + + template + inline constexpr bool value_retrieval_is_nothrow = !std::is_same_v, std::string> +#if TOML_HAS_CHAR8 + && !std::is_same_v, std::u8string> +#endif + + && !is_wide_string; + + template + struct copy_ref_; + template + using copy_ref = typename copy_ref_::type; + + template + struct copy_ref_ + { + using type = Dest; + }; + + template + struct copy_ref_ + { + using type = std::add_lvalue_reference_t; + }; + + template + struct copy_ref_ + { + using type = std::add_rvalue_reference_t; + }; + + template + struct copy_cv_; + template + using copy_cv = typename copy_cv_::type; + + template + struct copy_cv_ + { + using type = Dest; + }; + + template + struct copy_cv_ + { + using type = std::add_const_t; + }; + + template + struct copy_cv_ + { + using type = std::add_volatile_t; + }; + + template + struct copy_cv_ + { + using type = std::add_cv_t; + }; + + template + using copy_cvref = + copy_ref, std::remove_reference_t>, Dest>, Src>; + + template + inline constexpr bool dependent_false = false; + + template + inline constexpr bool first_is_same = false; + template + inline constexpr bool first_is_same = true; + + // general value traits + // (as they relate to their equivalent native TOML type) + template + struct value_traits + { + using native_type = void; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = false; + static constexpr bool can_represent_native = false; + static constexpr bool can_partially_represent_native = false; + static constexpr auto type = node_type::none; + }; + + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + + // integer value_traits specializations - standard types + template + struct integer_limits + { + static constexpr auto min = (std::numeric_limits::min)(); + static constexpr auto max = (std::numeric_limits::max)(); + }; + template + struct integer_traits_base : integer_limits + { + using native_type = int64_t; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_signed = static_cast(-1) < T{}; // for impls not specializing std::is_signed + static constexpr auto type = node_type::integer; + static constexpr bool can_partially_represent_native = true; + }; + template + struct unsigned_integer_traits : integer_traits_base + { + static constexpr bool is_losslessly_convertible_to_native = integer_limits::max <= 9223372036854775807ULL; + static constexpr bool can_represent_native = false; + }; + template + struct signed_integer_traits : integer_traits_base + { + using native_type = int64_t; + static constexpr bool is_losslessly_convertible_to_native = + integer_limits::min >= (-9223372036854775807LL - 1LL) && integer_limits::max <= 9223372036854775807LL; + static constexpr bool can_represent_native = + integer_limits::min <= (-9223372036854775807LL - 1LL) && integer_limits::max >= 9223372036854775807LL; + }; + template ::is_signed> + struct integer_traits : signed_integer_traits + {}; + template + struct integer_traits : unsigned_integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + static_assert(value_traits::is_native); + static_assert(value_traits::is_signed); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // integer value_traits specializations - non-standard types +#ifdef TOML_INT128 + template <> + struct integer_limits + { + static constexpr TOML_INT128 max = + static_cast((TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1); + static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 }; + }; + template <> + struct integer_limits + { + static constexpr TOML_UINT128 min = TOML_UINT128{}; + static constexpr TOML_UINT128 max = (2u * static_cast(integer_limits::max)) + 1u; + }; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; +#endif +#ifdef TOML_SMALL_INT_TYPE + template <> + struct value_traits : signed_integer_traits + {}; +#endif + + // floating-point traits base + template + struct float_traits_base + { + static constexpr auto type = node_type::floating_point; + using native_type = double; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_signed = true; + + static constexpr int bits = static_cast(sizeof(T) * CHAR_BIT); + static constexpr int digits = MantissaDigits; + static constexpr int digits10 = DecimalDigits; + + static constexpr bool is_losslessly_convertible_to_native = bits <= 64 // + && digits <= 53 // DBL_MANT_DIG + && digits10 <= 15; // DBL_DIG + + static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG + && digits10 >= 15; // DBL_DIG + + static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0; + }; + template + struct float_traits : float_traits_base::digits, std::numeric_limits::digits10> + {}; +#if TOML_ENABLE_FLOAT16 + template <> + struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__> + {}; +#endif +#ifdef TOML_FLOAT128 + template <> + struct float_traits : float_traits_base + {}; +#endif + + // floating-point traits + template <> + struct value_traits : float_traits + {}; + template <> + struct value_traits : float_traits + {}; + template <> + struct value_traits : float_traits + {}; +#if TOML_ENABLE_FLOAT16 + template <> + struct value_traits<_Float16> : float_traits<_Float16> + {}; +#endif +#ifdef TOML_FLOAT128 + template <> + struct value_traits : float_traits + {}; +#endif +#ifdef TOML_SMALL_FLOAT_TYPE + template <> + struct value_traits : float_traits + {}; +#endif + static_assert(value_traits::is_native); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // string value_traits specializations - char-based strings + template + struct string_traits + { + using native_type = std::string; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native = + !std::is_array_v && (!std::is_pointer_v || std::is_const_v>); + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto type = node_type::string; + }; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + + // string value_traits specializations - char8_t-based strings +#if TOML_HAS_CHAR8 + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; +#endif + + // string value_traits specializations - wchar_t-based strings on Windows +#if TOML_ENABLE_WINDOWS_COMPAT + template + struct wstring_traits + { + using native_type = std::string; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = true; // narrow + static constexpr bool can_represent_native = std::is_same_v; // widen + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto type = node_type::string; + }; + template <> + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template + struct value_traits : wstring_traits + {}; +#endif + + // other 'native' value_traits specializations + template + struct native_value_traits + { + using native_type = T; + static constexpr bool is_native = true; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native = true; + static constexpr bool can_partially_represent_native = true; + static constexpr auto type = NodeType; + }; + template <> + struct value_traits : native_value_traits + {}; + template <> + struct value_traits : native_value_traits + {}; + template <> + struct value_traits