From 051590390b497ed3051b27aa4ef9111ecc49feb4 Mon Sep 17 00:00:00 2001 From: Johan Mabille Date: Mon, 27 May 2024 23:19:53 +0200 Subject: [PATCH] Removed dependency on xtl --- CMakeLists.txt | 9 +- environment-dev.yml | 1 - environment-wasm-host.yml | 1 - include/xeus/xbasic_fixed_string.hpp | 2419 ++++++++++++++++++++++++++ include/xeus/xguid.hpp | 5 +- include/xeus/xhash.hpp | 214 +++ include/xeus/xsystem.hpp | 6 + src/xsystem.cpp | 77 +- test/CMakeLists.txt | 4 + test/test_main.cpp | 2 +- test/test_xbasic_fixed_string.cpp | 1205 +++++++++++++ test/test_xhash.cpp | 200 +++ test/test_xsystem.cpp | 35 + xeusConfig.cmake.in | 1 - 14 files changed, 4162 insertions(+), 17 deletions(-) create mode 100644 include/xeus/xbasic_fixed_string.hpp create mode 100644 include/xeus/xhash.hpp create mode 100644 test/test_xbasic_fixed_string.cpp create mode 100644 test/test_xhash.cpp create mode 100644 test/test_xsystem.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index baa02d13..0fd9f918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,28 +81,24 @@ message(STATUS "XEUS_BUILD_TESTS: ${XEUS_BUILD_TESTS}") # search # directly for nlohmann_json, but rely on find_dependency called by # find_package(xeus) instead. set(nlohmann_json_REQUIRED_VERSION 3.11) -set(xtl_REQUIRED_VERSION 0.7) if (NOT TARGET nlohmann_json) find_package(nlohmann_json ${nlohmann_json_REQUIRED_VERSION} REQUIRED) message(STATUS "Found nlohmann_json ${nlohmann_json_VERSION}") endif () -if (NOT TARGET xtl) - find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED) - message(STATUS "Found xl ${xtl_VERSION}") -endif () - # Source files # ============ set(XEUS_HEADERS + ${XEUS_INCLUDE_DIR}/xeus/xbasic_fixed_string.hpp ${XEUS_INCLUDE_DIR}/xeus/xcomm.hpp ${XEUS_INCLUDE_DIR}/xeus/xcontrol_messenger.hpp ${XEUS_INCLUDE_DIR}/xeus/xdebugger.hpp ${XEUS_INCLUDE_DIR}/xeus/xeus.hpp ${XEUS_INCLUDE_DIR}/xeus/xeus_context.hpp ${XEUS_INCLUDE_DIR}/xeus/xguid.hpp + ${XEUS_INCLUDE_DIR}/xeus/xhash.hpp ${XEUS_INCLUDE_DIR}/xeus/xhistory_manager.hpp ${XEUS_INCLUDE_DIR}/xeus/xinput.hpp ${XEUS_INCLUDE_DIR}/xeus/xinterpreter.hpp @@ -175,7 +171,6 @@ macro(xeus_create_target target_name linkage output_name) target_link_libraries( ${target_name} PUBLIC nlohmann_json::nlohmann_json - PUBLIC xtl ) if (NOT MSVC AND NOT EMSCRIPTEN) diff --git a/environment-dev.yml b/environment-dev.yml index e7b1628f..458950de 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -8,7 +8,6 @@ dependencies: - ninja - pkg-config # Host dependencies - - xtl=0.7 - nlohmann_json # Test dependencies - doctest >= 2.4.6 diff --git a/environment-wasm-host.yml b/environment-wasm-host.yml index fbcefae0..20b9d6d4 100644 --- a/environment-wasm-host.yml +++ b/environment-wasm-host.yml @@ -3,6 +3,5 @@ channels: - https://repo.mamba.pm/emscripten-forge - https://repo.mamba.pm/conda-forge dependencies: - - xtl - nlohmann_json diff --git a/include/xeus/xbasic_fixed_string.hpp b/include/xeus/xbasic_fixed_string.hpp new file mode 100644 index 00000000..ddcaffe2 --- /dev/null +++ b/include/xeus/xbasic_fixed_string.hpp @@ -0,0 +1,2419 @@ +/*************************************************************************** +* Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XEUS_BASIC_FIXED_STRING_HPP +#define XEUS_BASIC_FIXED_STRING_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace xeus +{ + + namespace string_policy + { + template + struct silent_error; + + template + struct throwing_error; + } + + /*********************** + * xbasic_fixed_string * + ***********************/ + + enum storage_options + { + buffer = 1 << 0, + pointer = 1 << 1, + store_size = 1 << 2, + is_const = 1 << 3 + }; + + template class EP = string_policy::silent_error, class TR = std::char_traits> + class xbasic_fixed_string; + + template class EP, class TR> + std::basic_ostream& operator<<(std::basic_ostream& os, + const xbasic_fixed_string& str); + + template class EP, class TR> + std::basic_istream& operator>>(std::basic_istream& is, + xbasic_fixed_string& str); + + template + using xbasic_string_view = xbasic_fixed_string; + + namespace detail + { + template + struct select_storage; + + template + struct fixed_small_string_storage_impl; + + template + struct fixed_small_string_storage_impl + { + static_assert(N <= (1u << (8 * sizeof(T))), "small string"); + + fixed_small_string_storage_impl() + { + set_size(0); + } + + fixed_small_string_storage_impl(T ptr[N], std::size_t size) + : m_buffer(ptr) + { + m_buffer[N - 1] = N - size; + } + + T* buffer() + { + return m_buffer; + } + + const T* buffer() const + { + return m_buffer; + } + + std::size_t size() const + { + // Don't use std::make_unsinged_t here, this should remain C++11 compatible + using unsigned_type = typename std::make_unsigned::type; + return N - reinterpret_cast(m_buffer)[N - 1]; + } + + void set_size(std::size_t sz) + { + assert(sz < N && "setting a small size"); + // Don't use std::make_unsinged_t here, this should remain C++11 compatible + using unsigned_type = typename std::make_unsigned::type; + reinterpret_cast(m_buffer)[N - 1] = static_cast(N - sz); + m_buffer[sz] = '\0'; + } + + void adjust_size(std::ptrdiff_t val) + { + assert(size() + val >= 0 && "adjusting to positive size"); + set_size(static_cast(static_cast(size()) + val)); + } + + T m_buffer[N]; + }; + + template + struct fixed_string_storage_impl + { + fixed_string_storage_impl() = default; + + fixed_string_storage_impl(T ptr, std::size_t size) + : m_buffer(ptr), m_size(size) + { + } + + T& buffer() + { + return m_buffer; + } + + const T& buffer() const + { + return m_buffer; + } + + std::size_t size() const + { + return m_size; + } + + void set_size(std::size_t sz) + { + m_size = sz; + m_buffer[sz] = '\0'; + } + + void adjust_size(std::ptrdiff_t val) + { + m_size += std::size_t(val); + m_buffer[m_size] = '\0'; + } + + T m_buffer; + std::size_t m_size; + }; + + template + struct fixed_string_external_storage_impl + { + fixed_string_external_storage_impl() = default; + + fixed_string_external_storage_impl(T ptr, std::ptrdiff_t/*size*/) + { + m_buffer = ptr; + } + + T& buffer() + { + return m_buffer; + } + + const T& buffer() const + { + return m_buffer; + } + + void set_size(std::size_t sz) + { + m_buffer[sz] = '\0'; + } + + void adjust_size(std::ptrdiff_t val) + { + m_buffer[size() + val] = '\0'; + } + + std::size_t size() const + { + return std::strlen(m_buffer); + } + + T m_buffer; + }; + + template + struct select_fixed_storage { + using type = fixed_string_storage_impl; + }; + + template + struct select_fixed_storage { + using type = fixed_small_string_storage_impl; + }; + + template <> + struct select_storage + { + template + using type = typename select_fixed_storage::type; + }; + + template <> + struct select_storage + { + template + using type = fixed_string_external_storage_impl; + }; + } + + template class EP, + class TR> + class xbasic_fixed_string + { + public: + + using traits_type = TR; + using value_type = CT; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using storage_type = typename detail::select_storage::template type; + + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + + static const size_type npos; + + using self_type = xbasic_fixed_string; + using initializer_type = std::initializer_list; + using string_type = std::basic_string; + + using error_policy = EP; + + xbasic_fixed_string(); + + explicit xbasic_fixed_string(size_type count, value_type ch); + explicit xbasic_fixed_string(const self_type& other, + size_type pos, + size_type count = npos); + explicit xbasic_fixed_string(const string_type& other); + explicit xbasic_fixed_string(const string_type& other, + size_type pos, + size_type count = npos); + xbasic_fixed_string(const_pointer s, size_type count); + xbasic_fixed_string(const_pointer s); + xbasic_fixed_string(initializer_type ilist); + + template + xbasic_fixed_string(InputIt first, InputIt last); + + operator string_type() const; + + ~xbasic_fixed_string() = default; + + xbasic_fixed_string(const self_type&) = default; + xbasic_fixed_string(self_type&&) = default; + + self_type& operator=(const self_type&) = default; + self_type& operator=(self_type&&) = default; + self_type& operator=(const_pointer s); + self_type& operator=(value_type ch); + self_type& operator=(initializer_type ilist); + self_type& operator=(const string_type& str); + + self_type& assign(size_type count, value_type ch); + self_type& assign(const self_type& other, + size_type pos, + size_type count = npos); + self_type& assign(const_pointer s, size_type count); + self_type& assign(const_pointer s); + self_type& assign(initializer_type ilist); + template + self_type& assign(InputIt first, InputIt last); + self_type& assign(const self_type& rhs); + self_type& assign(self_type&& rhs); + self_type& assign(const string_type& str); + self_type& assign(const string_type& other, + size_type pos, + size_type count = npos); + + reference at(size_type pos); + const_reference at(size_type pos) const; + + reference operator[](size_type pos); + const_reference operator[](size_type pos) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + pointer data() noexcept; + const_pointer data() const noexcept; + + const_pointer c_str() const noexcept; + + iterator begin() noexcept; + iterator end() noexcept; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + reverse_iterator rbegin() noexcept; + reverse_iterator rend() noexcept; + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + bool empty() const noexcept; + size_type size() const noexcept; + size_type length() const noexcept; + size_type max_size() const noexcept; + + void clear() noexcept; + void push_back(value_type ch); + void pop_back(); + self_type substr(size_type pos = 0, size_type count = npos) const; + size_type copy(pointer dest, size_type count, size_type pos = 0) const; + void resize(size_type count); + void resize(size_type count, value_type ch); + void swap(self_type& rhs) noexcept; + + self_type& insert(size_type index, size_type count, value_type ch); + self_type& insert(size_type index, const_pointer s); + self_type& insert(size_type index, const_pointer s, size_type count); + self_type& insert(size_type index, const self_type& str); + self_type& insert(size_type index, const self_type& str, + size_type index_str, size_type count = npos); + self_type& insert(size_type index, const string_type& str); + self_type& insert(size_type index, const string_type& str, + size_type index_str, size_type count = npos); + iterator insert(const_iterator pos, value_type ch); + iterator insert(const_iterator pos, size_type count, value_type ch); + iterator insert(const_iterator pos, initializer_type ilist); + template + iterator insert(const_iterator pos, InputIt first, InputIt last); + + self_type& erase(size_type index = 0, size_type count = npos); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + self_type& append(size_type count, value_type ch); + self_type& append(const self_type& str); + self_type& append(const self_type& str, + size_type pos, size_type count = npos); + self_type& append(const string_type& str); + self_type& append(const string_type& str, + size_type pos, size_type count = npos); + self_type& append(const_pointer s, size_type count); + self_type& append(const_pointer s); + self_type& append(initializer_type ilist); + template + self_type& append(InputIt first, InputIt last); + + self_type& operator+=(const self_type& str); + self_type& operator+=(const string_type& str); + self_type& operator+=(value_type ch); + self_type& operator+=(const_pointer s); + self_type& operator+=(initializer_type ilist); + + int compare(const self_type& str) const noexcept; + int compare(size_type pos1, size_type count1, const self_type& str) const; + int compare(size_type pos1, size_type count1, const self_type& str, + size_type pos2, size_type count2 = npos) const; + int compare(const string_type& str) const noexcept; + int compare(size_type pos1, size_type count1, const string_type& str) const; + int compare(size_type pos1, size_type count1, const string_type& str, + size_type pos2, size_type count2 = npos) const; + int compare(const_pointer s) const noexcept; + int compare(size_type pos1, size_type count1, const_pointer s) const; + int compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const; + + self_type& replace(size_type pos, size_type count, const self_type& str); + self_type& replace(const_iterator first, const_iterator last, const self_type& str); + self_type& replace(size_type pos1, size_type count1, const self_type& str, + size_type pos2, size_type count2 = npos); + self_type& replace(size_type pos, size_type count, const string_type& str); + self_type& replace(const_iterator first, const_iterator last, const string_type& str); + self_type& replace(size_type pos1, size_type count1, const string_type& str, + size_type pos2, size_type count2 = npos); + self_type& replace(size_type pos, size_type count, const_pointer cstr, size_type count2); + self_type& replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count2); + self_type& replace(size_type pos, size_type count, const_pointer cstr); + self_type& replace(const_iterator first, const_iterator last, const_pointer cstr); + self_type& replace(size_type pos, size_type count, size_type count2, value_type ch); + self_type& replace(const_iterator first, const_iterator last, size_type count2, value_type ch); + self_type& replace(const_iterator first, const_iterator last, initializer_type ilist); + template + self_type& replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2); + + size_type find(const self_type& str, size_type pos = 0) const noexcept; + size_type find(const string_type& str, size_type pos = 0) const noexcept; + size_type find(const_pointer s, size_type pos, size_type count) const; + size_type find(const_pointer s, size_type pos = 0) const; + size_type find(value_type ch, size_type pos = 0) const; + + size_type rfind(const self_type& str, size_type pos = npos) const noexcept; + size_type rfind(const string_type& str, size_type pos = npos) const noexcept; + size_type rfind(const_pointer s, size_type pos, size_type count) const; + size_type rfind(const_pointer s, size_type pos = npos) const; + size_type rfind(value_type ch, size_type pos = npos) const; + + size_type find_first_of(const self_type& str, size_type pos = 0) const noexcept; + size_type find_first_of(const string_type& str, size_type pos = 0) const noexcept; + size_type find_first_of(const_pointer s, size_type pos, size_type count) const; + size_type find_first_of(const_pointer s, size_type pos = 0) const; + size_type find_first_of(value_type ch, size_type pos = 0) const; + + size_type find_first_not_of(const self_type& str, size_type pos = 0) const noexcept; + size_type find_first_not_of(const string_type& str, size_type pos = 0) const noexcept; + size_type find_first_not_of(const_pointer s, size_type pos, size_type count) const; + size_type find_first_not_of(const_pointer s, size_type pos = 0) const; + size_type find_first_not_of(value_type ch, size_type pos = 0) const; + + size_type find_last_of(const self_type& str, size_type pos = 0) const noexcept; + size_type find_last_of(const string_type& str, size_type pos = 0) const noexcept; + size_type find_last_of(const_pointer s, size_type pos, size_type count) const; + size_type find_last_of(const_pointer s, size_type pos = 0) const; + size_type find_last_of(value_type ch, size_type pos = 0) const; + + size_type find_last_not_of(const self_type& str, size_type pos = npos) const noexcept; + size_type find_last_not_of(const string_type& str, size_type pos = npos) const noexcept; + size_type find_last_not_of(const_pointer s, size_type pos, size_type count) const; + size_type find_last_not_of(const_pointer s, size_type pos = npos) const; + size_type find_last_not_of(value_type ch, size_type pos = npos) const; + + private: + + int compare_impl(const_pointer s1, size_type count1, const_pointer s2, size_type count2) const noexcept; + void update_null_termination() noexcept; + void check_index(size_type pos, size_type size, const char* what) const; + void check_index_strict(size_type pos, size_type size, const char* what) const; + + storage_type m_storage; + }; + + template class EP, class TR> + const typename xbasic_fixed_string::size_type xbasic_fixed_string::npos + = std::basic_string::npos; + + template + using xfixed_string = xbasic_fixed_string; + + template + using xwfixed_string = xbasic_fixed_string; + + template + using xu16fixed_string = xbasic_fixed_string; + + template + using xu32fixed_string = xbasic_fixed_string; + + /************************** + * Concatenation operator * + **************************/ + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + const CT* rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + CT rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const CT* lhs, + const xbasic_fixed_string& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(CT lhs, + const xbasic_fixed_string& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + const xbasic_fixed_string& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + const xbasic_fixed_string&& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + const xbasic_fixed_string&& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + const CT* rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + CT rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(const CT* lhs, + const xbasic_fixed_string&& rhs); + + template class EP, class TR> + xbasic_fixed_string + operator+(CT lhs, + const xbasic_fixed_string&& rhs); + + /************************ + * Comparison operators * + ************************/ + + template class EP, class TR> + bool operator==(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator==(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept; + + template class EP, class TR> + bool operator==(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator==(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept; + + template class EP, class TR> + bool operator==(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator!=(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator!=(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept; + + template class EP, class TR> + bool operator!=(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator!=(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept; + + template class EP, class TR> + bool operator!=(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator<(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator<(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept; + + template class EP, class TR> + bool operator<(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator<(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept; + + template class EP, class TR> + bool operator<(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator<=(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator<=(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept; + + template class EP, class TR> + bool operator<=(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator<=(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept; + + template class EP, class TR> + bool operator<=(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator>(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator>(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept; + + template class EP, class TR> + bool operator>(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator>(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept; + + template class EP, class TR> + bool operator>(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator>=(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator>=(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept; + + template class EP, class TR> + bool operator>=(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + bool operator>=(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept; + + template class EP, class TR> + bool operator>=(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept; + + template class EP, class TR> + void swap(xbasic_fixed_string& lhs, + xbasic_fixed_string& rhs); + + /****************************** + * Input / output declaration * + ******************************/ + + template class EP, class TR> + std::basic_istream& getline(std::basic_istream& input, + xbasic_fixed_string& str, + CT delim); + + template class EP, class TR> + std::basic_istream& getline(std::basic_istream&& input, + xbasic_fixed_string& str, + CT delim); + + template class EP, class TR> + std::basic_istream& getline(std::basic_istream& input, + xbasic_fixed_string& str); + + template class EP, class TR> + std::basic_istream& getline(std::basic_istream&& input, + xbasic_fixed_string& str); + +} // namespace xeus + +namespace std +{ + template class EP, class TR> + struct hash<::xeus::xbasic_fixed_string> + { + using argument_type = ::xeus::xbasic_fixed_string; + using result_type = std::size_t; + inline result_type operator()(const argument_type& arg) const + { + return ::xeus::hash_bytes(arg.data(), arg.size(), std::size_t(0xc70f6907)); + } + }; +} // namespace std + +namespace xeus +{ + /******************************** + * xbasic_fixed_string policies * + ********************************/ + + namespace string_policy + { + template + struct silent_error + { + inline static std::size_t check_size(std::size_t size) + { + return size; + } + inline static std::size_t check_add(std::size_t size1, std::size_t size2) + { + return size1 + size2; + } + }; + + template + struct throwing_error + { + inline static std::size_t check_size(std::size_t size) + { + if (size > N) + { + std::ostringstream oss; + oss << "Invalid size (" << size << ") for xbasic_fixed_string - maximal size: " << N; + throw std::length_error(oss.str()); + } + return size; + } + + inline static std::size_t check_add(std::size_t size1, std::size_t size2) + { + return check_size(size1 + size2); + } + }; + } // string_policy + + /************************************** + * xbasic_fixed_string implementation * + **************************************/ + + /**************** + * Constructors * + ****************/ + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string() + : m_storage() + { + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(size_type count, value_type ch) + : m_storage() + { + assign(count, ch); + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(const self_type& other, + size_type pos, + size_type count) + : m_storage() + { + assign(other, pos, count); + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(const string_type& other) + : m_storage() + { + assign(other); + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(const string_type& other, + size_type pos, + size_type count) + : m_storage() + { + assign(other, pos, count); + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(const_pointer s, size_type count) + : m_storage() + { + assign(s, count); + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(const_pointer s) + : m_storage() + { + assign(s); + } + + template class EP, class TR> + inline xbasic_fixed_string::xbasic_fixed_string(initializer_type ilist) + : m_storage() + { + assign(ilist); + } + + template class EP, class TR> + template + inline xbasic_fixed_string::xbasic_fixed_string(InputIt first, InputIt last) + : m_storage() + { + assign(first, last); + } + + template class EP, class TR> + inline xbasic_fixed_string::operator string_type() const + { + return string_type(data()); + } + + /************** + * Assignment * + **************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::operator=(const_pointer s) -> self_type& + { + return assign(s); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator=(value_type ch) -> self_type& + { + return assign(size_type(1), ch); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator=(initializer_type ilist) -> self_type& + { + return assign(ilist); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator=(const string_type& str) -> self_type& + { + return assign(str); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(size_type count, value_type ch) -> self_type& + { + m_storage.set_size(error_policy::check_size(count)); + traits_type::assign(data(), count, ch); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(const self_type& other, + size_type pos, + size_type count) -> self_type& + { + check_index_strict(pos, other.size(), "xbasic_fixed_string::assign"); + size_type copy_count = std::min(other.size() - pos, count); + m_storage.set_size(error_policy::check_size(copy_count)); + traits_type::copy(data(), other.data() + pos, copy_count); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(const_pointer s, size_type count) -> self_type& + { + m_storage.set_size(error_policy::check_size(count)); + traits_type::copy(data(), s, count); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(const_pointer s) -> self_type& + { + std::size_t ssize = traits_type::length(s); + return assign(s, ssize); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(initializer_type ilist) -> self_type& + { + return assign(ilist.begin(), ilist.end()); + } + + template class EP, class TR> + template + inline auto xbasic_fixed_string::assign(InputIt first, InputIt last) -> self_type& + { + m_storage.set_size(error_policy::check_size(static_cast(std::distance(first, last)))); + std::copy(first, last, data()); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(const self_type& rhs) -> self_type& + { + if (this != &rhs) + { + m_storage.set_size(rhs.size()); + traits_type::copy(data(), rhs.data(), rhs.size()); + } + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(self_type&& rhs) -> self_type& + { + if (this != &rhs) + { + m_storage.set_size(rhs.size()); + traits_type::copy(data(), rhs.data(), rhs.size()); + } + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(const string_type& other) -> self_type& + { + return assign(other.c_str()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::assign(const string_type& other, + size_type pos, + size_type count) -> self_type& + { + return assign(other.c_str() + pos, std::min(count, other.size() - pos)); + } + + /****************** + * Element access * + ******************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::at(size_type pos) -> reference + { + check_index(pos, size(), "basic_fixed_string::at"); + return this->operator[](pos); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::at(size_type pos) const -> const_reference + { + check_index(pos, size(), "basic_fixed_string::at"); + return this->operator[](pos); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator[](size_type pos) -> reference + { + return data()[pos]; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator[](size_type pos) const -> const_reference + { + return data()[pos]; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::front() -> reference + { + return this->operator[](0); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::front() const -> const_reference + { + return this->operator[](0); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::back() -> reference + { + return this->operator[](size() - 1); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::back() const -> const_reference + { + return this->operator[](size() - 1); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::data() noexcept -> pointer + { + return m_storage.buffer(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::data() const noexcept -> const_pointer + { + return m_storage.buffer(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::c_str() const noexcept -> const_pointer + { + return m_storage.buffer(); + } + + /************* + * Iterators * + *************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::begin() noexcept -> iterator + { + return data(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::end() noexcept -> iterator + { + return data() + size(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::begin() const noexcept -> const_iterator + { + return cbegin(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::end() const noexcept -> const_iterator + { + return cend(); + } + template class EP, class TR> + inline auto xbasic_fixed_string::cbegin() const noexcept -> const_iterator + { + return data(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::cend() const noexcept -> const_iterator + { + return data() + size(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rbegin() noexcept -> reverse_iterator + { + return reverse_iterator(end()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rend() noexcept -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rbegin() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rend() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::crbegin() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::crend() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + /************ + * Capacity * + ************/ + + template class EP, class TR> + inline bool xbasic_fixed_string::empty() const noexcept + { + return size() == 0; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::size() const noexcept -> size_type + { + return m_storage.size(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::length() const noexcept -> size_type + { + return m_storage.size(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::max_size() const noexcept -> size_type + { + return N; + } + + /************** + * Operations * + **************/ + + template class EP, class TR> + inline void xbasic_fixed_string::clear() noexcept + { + m_storage.set_size(0); + } + + template class EP, class TR> + inline void xbasic_fixed_string::push_back(value_type ch) + { + error_policy::check_add(size(), size_type(1)); + data()[size()] = ch; + m_storage.adjust_size(+1); + } + + template class EP, class TR> + inline void xbasic_fixed_string::pop_back() + { + m_storage.adjust_size(-1); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::substr(size_type pos, size_type count) const -> self_type + { + return self_type(*this, pos, count); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::copy(pointer dest, size_type count, size_type pos) const -> size_type + { + check_index_strict(pos, size(), "xbasic_fixed_string::copy"); + size_type nb_copied = std::min(count, size() - pos); + traits_type::copy(dest, data() + pos, nb_copied); + return nb_copied; + } + + template class EP, class TR> + inline void xbasic_fixed_string::resize(size_type count) + { + resize(count, value_type(' ')); // need to initialize with some value != \0 + } + + template class EP, class TR> + inline void xbasic_fixed_string::resize(size_type count, value_type ch) + { + size_type old_size = size(); + m_storage.set_size(error_policy::check_size(count)); + if (old_size < size()) + { + traits_type::assign(data() + old_size, size() - old_size, ch); + } + } + + template class EP, class TR> + inline void xbasic_fixed_string::swap(self_type& rhs) noexcept + { + self_type tmp(std::move(rhs)); + rhs = std::move(*this); + *this = std::move(tmp); + } + + /********** + * insert * + **********/ + + template class EP, class TR> + auto xbasic_fixed_string::insert(size_type index, size_type count, value_type ch) -> self_type& + { + check_index_strict(index, size(), "xbasic_fixed_string::insert"); + size_type old_size = size(); + m_storage.set_size(error_policy::check_add(size(), count)); + std::copy_backward(data() + index, data() + old_size, end()); + traits_type::assign(data() + index, count, ch); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(size_type index, const_pointer s) -> self_type& + { + return insert(index, s, traits_type::length(s)); + } + + template class EP, class TR> + auto xbasic_fixed_string::insert(size_type index, const_pointer s, size_type count) -> self_type& + { + check_index_strict(index, size(), "xbasic_fixed_string::insert"); + size_type old_size = size(); + m_storage.set_size(error_policy::check_add(size(), count)); + std::copy_backward(data() + index, data() + old_size, end()); + traits_type::copy(data() + index, s, count); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(size_type index, const self_type& str) -> self_type& + { + return insert(index, str.data(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(size_type index, const self_type& str, + size_type index_str, size_type count) -> self_type& + { + check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert"); + return insert(index, str.data() + index_str, std::min(count, str.size() - index_str)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(size_type index, const string_type& str) -> self_type& + { + return insert(index, str.c_str(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(size_type index, const string_type& str, + size_type index_str, size_type count) -> self_type& + { + check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert"); + return insert(index, str.c_str() + index_str, std::min(count, str.size() - index_str)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(const_iterator pos, value_type ch) -> iterator + { + return insert(pos, size_type(1), ch); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(const_iterator pos, size_type count, value_type ch) -> iterator + { + if (cbegin() <= pos && pos < cend()) + { + size_type index = static_cast(pos - cbegin()); + insert(index, count, ch); + return const_cast(pos); + } + return end(); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::insert(const_iterator pos, initializer_type ilist) -> iterator + { + return insert(pos, ilist.begin(), ilist.end()); + } + + template class EP, class TR> + template + auto xbasic_fixed_string::insert(const_iterator pos, InputIt first, InputIt last) -> iterator + { + if (cbegin() <= pos && pos < cend()) + { + size_type index = static_cast(pos - cbegin()); + size_type count = static_cast(std::distance(first, last)); + size_type old_size = size(); + m_storage.set_size(error_policy::check_add(size(), count)); + std::copy_backward(data() + index, data() + old_size, end()); + std::copy(first, last, data() + index); + return begin() + index; + } + return end(); + } + + /********* + * erase * + *********/ + + template class EP, class TR> + auto xbasic_fixed_string::erase(size_type index, size_type count) -> self_type& + { + check_index_strict(index, size(), "xbasic_fixed_string::erase"); + size_type erase_count = std::min(count, size() - index); + // cannot use traits_type::copy because of overlapping + std::copy(data() + index + erase_count, data() + size(), data() + index); + m_storage.adjust_size(-static_cast(erase_count)); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::erase(const_iterator position) -> iterator + { + return erase(position, position + 1); + } + + template class EP, class TR> + auto xbasic_fixed_string::erase(const_iterator first, const_iterator last) -> iterator + { + if (cbegin() <= first && first < cend()) + { + const_iterator adapted_last = std::min(last, cend()); + size_type erase_count = static_cast(adapted_last - first); + // cannot use traits_type::copy because of overlapping + std::copy(adapted_last, cend(), iterator(first)); + m_storage.adjust_size(-static_cast(erase_count)); + return const_cast(first); + } + return end(); + } + + /********** + * append * + **********/ + + template class EP, class TR> + inline auto xbasic_fixed_string::append(size_type count, value_type ch) -> self_type& + { + size_type old_size = m_storage.size(); + m_storage.set_size(error_policy::check_add(size(), count)); + traits_type::assign(data() + old_size, count, ch); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(const self_type& str) -> self_type& + { + return append(str.data(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(const self_type& str, + size_type pos, size_type count) -> self_type& + { + check_index_strict(pos, str.size(), "xbasic_fixed_string::append"); + return append(str.data() + pos, std::min(count, str.size() - pos)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(const string_type& str) -> self_type& + { + return append(str.c_str(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(const string_type& str, + size_type pos, size_type count) -> self_type& + { + check_index_strict(pos, str.size(), "xbasic_fixed_string::append"); + return append(str.c_str() + pos, std::min(count, str.size() - pos)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(const_pointer s, size_type count) -> self_type& + { + size_type old_size = m_storage.size(); + m_storage.set_size(error_policy::check_add(size(), count)); + traits_type::copy(data() + old_size, s, count); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(const_pointer s) -> self_type& + { + return append(s, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::append(initializer_type ilist) -> self_type& + { + return append(ilist.begin(), ilist.end()); + } + + template class EP, class TR> + template + inline auto xbasic_fixed_string::append(InputIt first, InputIt last) -> self_type& + { + size_type count = static_cast(std::distance(first, last)); + size_type old_size = m_storage.size(); + m_storage.set_size(error_policy::check_add(size(), count)); + std::copy(first, last, data() + old_size); + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator+=(const self_type& str) -> self_type& + { + return append(str); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator+=(const string_type& str) -> self_type& + { + return append(str); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator+=(value_type ch) -> self_type& + { + return append(size_type(1), ch); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator+=(const_pointer s) -> self_type& + { + return append(s); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::operator+=(initializer_type ilist) -> self_type& + { + return append(ilist); + } + + /*********** + * compare * + ***********/ + + template class EP, class TR> + inline int xbasic_fixed_string::compare(const self_type& str) const noexcept + { + return compare_impl(data(), size(), str.data(), str.size()); + } + + template class EP, class TR> + inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const self_type& str) const + { + check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); + return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size()); + } + + template class EP, class TR> + inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const self_type& str, + size_type pos2, size_type count2) const + { + check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); + check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare"); + return compare_impl(data() + pos1, std::min(count1, size() - pos1), + str.data() + pos2, std::min(count2, str.size() - pos2)); + } + + template class EP, class TR> + inline int xbasic_fixed_string::compare(const string_type& str) const noexcept + { + return compare_impl(data(), size(), str.data(), str.size()); + } + + template class EP, class TR> + inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const string_type& str) const + { + check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); + return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size()); + } + + template class EP, class TR> + inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const string_type& str, + size_type pos2, size_type count2) const + { + check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); + check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare"); + return compare_impl(data() + pos1, std::min(count1, size() - pos1), + str.data() + pos2, std::min(count2, str.size() - pos2)); + } + + template class EP, class TR> + inline int xbasic_fixed_string::compare(const_pointer s) const noexcept + { + return compare_impl(data(), size(), s, traits_type::length(s)); + } + + template class EP, class TR> + int xbasic_fixed_string::compare(size_type pos1, size_type count1, const_pointer s) const + { + return compare(pos1, count1, s, traits_type::length(s)); + } + + template class EP, class TR> + int xbasic_fixed_string::compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const + { + check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); + return compare_impl(data() + pos1, std::min(count1, size() - pos1), + s, count2); + } + + /*********** + * replace * + ***********/ + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const self_type& str) -> self_type& + { + return replace(pos, count, str.data(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + const self_type& str) -> self_type& + { + return replace(first, last, str.data(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(size_type pos1, size_type count1, const self_type& str, + size_type pos2, size_type count2) -> self_type& + { + check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace"); + return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const string_type& str) -> self_type& + { + return replace(pos, count, str.data(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + const string_type& str) -> self_type& + { + return replace(first, last, str.data(), str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(size_type pos1, size_type count1, const string_type& str, + size_type pos2, size_type count2) -> self_type& + { + check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace"); + return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2)); + } + + template class EP, class TR> + auto xbasic_fixed_string::replace(size_type pos, size_type count, + const_pointer cstr, size_type count2) -> self_type& + { + check_index_strict(pos, size(), "xbasic_fixed_string::replace"); + size_type erase_count = std::min(count, size() - pos); + size_type new_size = error_policy::check_add(size() - erase_count, count2); + if (erase_count > count2) + { + traits_type::copy(data() + pos, cstr, count2); + std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); + m_storage.set_size(new_size); + } + else if (erase_count < count2) + { + std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); + traits_type::copy(data() + pos, cstr, count2); + m_storage.set_size(new_size); + } + else + { + traits_type::copy(data() + pos, cstr, count2); + } + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + const_pointer cstr, size_type count2) -> self_type& + { + if (cbegin() <= first && first < last && last <= cend()) + { + size_type pos = static_cast(first - cbegin()); + size_type count = static_cast(last - first); + return replace(pos, count, cstr, count2); + } + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(size_type pos, size_type count, + const_pointer cstr) -> self_type& + { + return replace(pos, count, cstr, traits_type::length(cstr)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + const_pointer cstr) -> self_type& + { + return replace(first, last, cstr, traits_type::length(cstr)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(size_type pos, size_type count, + size_type count2, value_type ch) -> self_type& + { + check_index_strict(pos, size(), "xbasic_fixed_string::replace"); + size_type erase_count = std::min(count, size() - pos); + size_type new_size = error_policy::check_add(size() - erase_count, count2); + if (erase_count > count2) + { + traits_type::assign(data() + pos, count2, ch); + std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); + m_storage.set_size(new_size); + } + else if (erase_count < count2) + { + std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); + traits_type::assign(data() + pos, count2, ch); + m_storage.set_size(new_size); + } + else + { + traits_type::assign(data() + pos, count2, ch); + } + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + size_type count2, value_type ch) -> self_type& + { + if (cbegin() <= first && first < last && last <= cend()) + { + size_type pos = static_cast(first - cbegin()); + size_type count = static_cast(last - first); + return replace(pos, count, count2, ch); + } + return *this; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + initializer_type ilist) -> self_type& + { + return replace(first, last, ilist.begin(), ilist.end()); + } + + template class EP, class TR> + template + inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, + InputIt first2, InputIt last2) -> self_type& + { + if (cbegin() <= first && first < last && last <= cend()) + { + size_type pos = static_cast(first - cbegin()); + size_type erase_count = static_cast(last - first); + size_type count2 = static_cast(std::distance(first2, last2)); + size_type new_size = error_policy::check_add(size() - erase_count, count2); + if (erase_count > count2) + { + std::copy(first2, last2, data() + pos); + std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); + m_storage.set_size(new_size); + } + else if (erase_count < count2) + { + std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); + std::copy(first2, last2, data() + pos); + m_storage.set_size(new_size); + } + else + { + std::copy(first2, last2, data() + pos); + } + } + return *this; + } + + /******** + * find * + ********/ + + template class EP, class TR> + inline auto xbasic_fixed_string::find(const self_type& str, size_type pos) const noexcept -> size_type + { + return find(str.data(), pos, str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find(const string_type& str, size_type pos) const noexcept -> size_type + { + return find(str.data(), pos, str.size()); + } + + template class EP, class TR> + auto xbasic_fixed_string::find(const_pointer s, size_type pos, size_type count) const -> size_type + { + if (count == size_type(0) && pos <= size()) + { + return pos; + } + + size_type nm; + if (pos < size() && count <= (nm = size() - pos)) + { + const_pointer uptr, vptr; + for (nm -= count - 1, vptr = data() + pos; + (uptr = traits_type::find(vptr, nm, *s)) != 0; + nm -= size_type(uptr - vptr) + 1ul, vptr = uptr + 1ul) + { + if (traits_type::compare(uptr, s, count) == 0) + { + return size_type(uptr - data()); + } + } + } + return npos; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find(const_pointer s, size_type pos) const -> size_type + { + return find(s, pos, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find(value_type ch, size_type pos) const -> size_type + { + return find(&ch, pos, size_type(1)); + } + + /********* + * rfind * + *********/ + + template class EP, class TR> + inline auto xbasic_fixed_string::rfind(const self_type& str, size_type pos) const noexcept -> size_type + { + return rfind(str.data(), pos, str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rfind(const string_type& str, size_type pos) const noexcept -> size_type + { + return rfind(str.data(), pos, str.size()); + } + + template class EP, class TR> + auto xbasic_fixed_string::rfind(const_pointer s, size_type pos, size_type count) const -> size_type + { + if (count == 0) + { + return std::min(pos, size()); + } + + if (count <= size()) + { + const_pointer uptr = data() + std::min(pos, size() - count); + for (;; --uptr) + { + if (traits_type::eq(*uptr, *s) && traits_type::compare(uptr, s, count) == 0) + { + return size_type(uptr - data()); + } + else if (uptr == data()) + { + break; + } + } + } + return npos; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rfind(const_pointer s, size_type pos) const -> size_type + { + return rfind(s, pos, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::rfind(value_type ch, size_type pos) const -> size_type + { + return rfind(&ch, pos, size_type(1)); + } + + /***************** + * find_first_of * + *****************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_of(const self_type& str, size_type pos) const noexcept -> size_type + { + return find_first_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_of(const string_type& str, size_type pos) const noexcept -> size_type + { + return find_first_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + auto xbasic_fixed_string::find_first_of(const_pointer s, size_type pos, size_type count) const -> size_type + { + if (size_type(0) < count && pos < size()) + { + const_pointer vptr = data() + size(); + for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr) + { + if (traits_type::find(s, count, *uptr) != 0) + { + return size_type(uptr - data()); + } + } + } + return npos; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_of(const_pointer s, size_type pos) const -> size_type + { + return find_first_of(s, pos, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_of(value_type ch, size_type pos) const -> size_type + { + return find_first_of(&ch, pos, size_type(1)); + } + + /********************* + * find_first_not_of * + *********************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_not_of(const self_type& str, size_type pos) const noexcept -> size_type + { + return find_first_not_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_not_of(const string_type& str, size_type pos) const noexcept -> size_type + { + return find_first_not_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + auto xbasic_fixed_string::find_first_not_of(const_pointer s, size_type pos, size_type count) const -> size_type + { + if (pos < size()) + { + const_pointer vptr = data() + size(); + for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr) + { + if (traits_type::find(s, count, *uptr) == 0) + { + return size_type(uptr - data()); + } + } + } + return npos; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_not_of(const_pointer s, size_type pos) const -> size_type + { + return find_first_not_of(s, pos, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_first_not_of(value_type ch, size_type pos) const -> size_type + { + return find_first_not_of(&ch, pos, size_type(1)); + } + + /**************** + * find_last_of * + ****************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_of(const self_type& str, size_type pos) const noexcept -> size_type + { + return find_last_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_of(const string_type& str, size_type pos) const noexcept -> size_type + { + return find_last_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + auto xbasic_fixed_string::find_last_of(const_pointer s, size_type pos, size_type count) const -> size_type + { + if (size_type(0) < count && size_type(0) < size()) + { + const_pointer uptr = data() + std::min(pos, size() - 1); + for (;; --uptr) + { + if (traits_type::find(s, count, *uptr) != 0) + { + return size_type(uptr - data()); + } + else if (uptr == data()) + { + break; + } + } + } + return npos; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_of(const_pointer s, size_type pos) const -> size_type + { + return find_last_of(s, pos, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_of(value_type ch, size_type pos) const -> size_type + { + return find_last_of(&ch, pos, size_type(1)); + } + + /******************** + * find_last_not_of * + ********************/ + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_not_of(const self_type& str, size_type pos) const noexcept -> size_type + { + return find_last_not_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_not_of(const string_type& str, size_type pos) const noexcept -> size_type + { + return find_last_not_of(str.data(), pos, str.size()); + } + + template class EP, class TR> + auto xbasic_fixed_string::find_last_not_of(const_pointer s, size_type pos, size_type count) const -> size_type + { + if (size_type(0) < size()) + { + const_pointer uptr = data() + std::min(pos, size() - 1); + for (;; --uptr) + { + if (traits_type::find(s, count, *uptr) == 0) + { + return size_type(uptr - data()); + } + else if (uptr == data()) + { + break; + } + } + } + return npos; + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_not_of(const_pointer s, size_type pos) const -> size_type + { + return find_last_not_of(s, pos, traits_type::length(s)); + } + + template class EP, class TR> + inline auto xbasic_fixed_string::find_last_not_of(value_type ch, size_type pos) const -> size_type + { + return find_last_not_of(&ch, pos, size_type(1)); + } + + /******************* + * Private methods * + *******************/ + + template class EP, class TR> + int xbasic_fixed_string::compare_impl(const_pointer s1, size_type count1, + const_pointer s2, size_type count2) const noexcept + { + size_type rlen = std::min(count1, count2); + int res = traits_type::compare(s1, s2, rlen); + if (res == 0) + { + return count1 < count2 ? -1 : (count1 > count2 ? 1 : 0); + } + else + { + return res; + } + } + + template class EP, class TR> + inline void xbasic_fixed_string::update_null_termination() noexcept + { + data()[size()] = '\0'; + } + + template class EP, class TR> + void xbasic_fixed_string::check_index(size_type pos, size_type size, const char* what) const + { + if (pos >= size) + { + throw std::out_of_range(what); + } + } + + template class EP, class TR> + void xbasic_fixed_string::check_index_strict(size_type pos, size_type size, const char* what) const + { + check_index(pos, size + 1, what); + } + + /************************** + * Concatenation operator * + **************************/ + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) + { + xbasic_fixed_string res(lhs); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + const CT* rhs) + { + xbasic_fixed_string res(lhs); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + CT rhs) + { + xbasic_fixed_string res(lhs); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const CT* lhs, + const xbasic_fixed_string& rhs) + { + xbasic_fixed_string res(lhs); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(CT lhs, + const xbasic_fixed_string& rhs) + { + using size_type = typename xbasic_fixed_string::size_type; + xbasic_fixed_string res(size_type(1), lhs); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + const xbasic_fixed_string& rhs) + { + xbasic_fixed_string res(std::move(lhs)); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string& lhs, + const xbasic_fixed_string&& rhs) + { + xbasic_fixed_string res(lhs); + return res += std::move(rhs); + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + const xbasic_fixed_string&& rhs) + { + xbasic_fixed_string res(std::move(lhs)); + return res += std::move(rhs); + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + const CT* rhs) + { + xbasic_fixed_string res(std::move(lhs)); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const xbasic_fixed_string&& lhs, + CT rhs) + { + xbasic_fixed_string res(std::move(lhs)); + return res += rhs; + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(const CT* lhs, + const xbasic_fixed_string&& rhs) + { + xbasic_fixed_string res(lhs); + return res += std::move(rhs); + } + + template class EP, class TR> + inline xbasic_fixed_string + operator+(CT lhs, + const xbasic_fixed_string&& rhs) + { + using size_type = typename xbasic_fixed_string::size_type; + xbasic_fixed_string res(size_type(1), lhs); + return res += std::move(rhs); + } + + /************************ + * Comparison operators * + ************************/ + + template class EP, class TR> + inline bool operator==(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + + template class EP, class TR> + inline bool operator==(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + + template class EP, class TR> + inline bool operator==(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept + { + return rhs == lhs; + } + + template class EP, class TR> + inline bool operator==(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept + { + return lhs == rhs.c_str(); + } + + template class EP, class TR> + inline bool operator==(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.c_str() == rhs; + } + + template class EP, class TR> + inline bool operator!=(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + + template class EP, class TR> + inline bool operator!=(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + + template class EP, class TR> + inline bool operator!=(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept + { + return rhs != lhs; + } + + template class EP, class TR> + inline bool operator!=(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept + { + return lhs != rhs.c_str(); + } + + template class EP, class TR> + inline bool operator!=(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.c_str() != rhs; + } + + template class EP, class TR> + inline bool operator<(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + + template class EP, class TR> + inline bool operator<(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + + template class EP, class TR> + inline bool operator<(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept + { + return rhs > lhs; + } + + template class EP, class TR> + inline bool operator<(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept + { + return lhs < rhs.c_str(); + } + + template class EP, class TR> + inline bool operator<(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.c_str() < rhs; + } + + template class EP, class TR> + inline bool operator<=(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + + template class EP, class TR> + inline bool operator<=(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + + template class EP, class TR> + inline bool operator<=(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept + { + return rhs >= lhs; + } + + template class EP, class TR> + inline bool operator<=(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept + { + return lhs <= rhs.c_str(); + } + + template class EP, class TR> + inline bool operator<=(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.c_str() <= rhs; + } + + template class EP, class TR> + inline bool operator>(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + + template class EP, class TR> + inline bool operator>(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + + template class EP, class TR> + inline bool operator>(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept + { + return rhs < lhs; + } + + template class EP, class TR> + inline bool operator>(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept + { + return lhs > rhs.c_str(); + } + + template class EP, class TR> + inline bool operator>(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.c_str() > rhs; + } + + template class EP, class TR> + inline bool operator>=(const xbasic_fixed_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + + template class EP, class TR> + inline bool operator>=(const xbasic_fixed_string& lhs, + const CT* rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + + template class EP, class TR> + inline bool operator>=(const CT* lhs, + const xbasic_fixed_string& rhs) noexcept + { + return rhs <= lhs; + } + + template class EP, class TR> + inline bool operator>=(const xbasic_fixed_string& lhs, + const std::basic_string& rhs) noexcept + { + return lhs >= rhs.c_str(); + } + + template class EP, class TR> + inline bool operator>=(const std::basic_string& lhs, + const xbasic_fixed_string& rhs) noexcept + { + return lhs.c_str() >= rhs; + } + + template class EP, class TR> + inline void swap(xbasic_fixed_string& lhs, xbasic_fixed_string& rhs) + { + lhs.swap(rhs); + } + + /****************** + * Input / output * + ******************/ + + template class EP, class TR> + inline std::basic_ostream& operator<<(std::basic_ostream& os, + const xbasic_fixed_string& str) + { + os << str.c_str(); + return os; + } + +#ifdef __CLING__ + template class EP, class TR> + nlohmann::json mime_bundle_repr(const xbasic_fixed_string& str) + { + auto bundle = nlohmann::json::object(); + bundle["text/plain"] = str.c_str(); + return bundle; + } +#endif + + template class EP, class TR> + inline std::basic_istream& operator>>(std::basic_istream& is, + xbasic_fixed_string& str) + { + // Not optimal + std::string tmp; + is >> tmp; + str = tmp.c_str(); + return is; + } + + template class EP, class TR> + inline std::basic_istream& getline(std::basic_istream& input, + xbasic_fixed_string& str, + CT delim) + { + std::string tmp; + auto& ret = std::getline(input, tmp, delim); + str = tmp; + return ret; + } + + template class EP, class TR> + inline std::basic_istream& getline(std::basic_istream&& input, + xbasic_fixed_string& str, + CT delim) + { + std::string tmp; + auto& ret = std::getline(std::move(input), tmp, delim); + str = tmp; + return ret; + } + + template class EP, class TR> + inline std::basic_istream& getline(std::basic_istream& input, + xbasic_fixed_string& str) + { + std::string tmp; + auto& ret = std::getline(input, tmp); + str = tmp; + return ret; + } + + template class EP, class TR> + inline std::basic_istream& getline(std::basic_istream&& input, + xbasic_fixed_string& str) + { + std::string tmp; + auto& ret = std::getline(std::move(input), tmp); + str = tmp; + return ret; + } +} + +#endif // xeus diff --git a/include/xeus/xguid.hpp b/include/xeus/xguid.hpp index eb752025..d388194a 100644 --- a/include/xeus/xguid.hpp +++ b/include/xeus/xguid.hpp @@ -10,9 +10,8 @@ #ifndef XEUS_GUID_HPP #define XEUS_GUID_HPP -#include "xtl/xbasic_fixed_string.hpp" - #include "xeus/xeus.hpp" +#include "xeus/xbasic_fixed_string.hpp" namespace xeus { @@ -24,7 +23,7 @@ namespace xeus // multiple of the stackframe alignment (8 or 16 depending on the architecture // and compilers). // Here we want a size of 64 bytes, which gives room for 55 characters (64 - 8 - 1). - using xguid = xtl::xfixed_string<55>; + using xguid = xfixed_string<55>; XEUS_API xguid new_xguid(); } diff --git a/include/xeus/xhash.hpp b/include/xeus/xhash.hpp new file mode 100644 index 00000000..d6cf406d --- /dev/null +++ b/include/xeus/xhash.hpp @@ -0,0 +1,214 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XEUS_HASH_HPP +#define XEUS_HASH_HPP + +#include +#include +#include + +#include + +namespace xeus +{ + + std::size_t hash_bytes(const void* buffer, std::size_t length, std::size_t seed); + + uint32_t murmur2_x86(const void* buffer, std::size_t length, uint32_t seed); + uint64_t murmur2_x64(const void* buffer, std::size_t length, uint64_t seed); + + /****************************** + * hash_bytes implementation * + ******************************/ + + namespace detail + { + // Dummy hash implementation for unusual sizeof(std::size_t) + template + std::size_t murmur_hash(const void* buffer, std::size_t length, std::size_t seed) + { + std::size_t hash = seed; + const char* data = static_cast(buffer); + for (; length != 0; --length) + { + hash = (hash * 131) + static_cast(*data++); + } + return hash; + } + + // Murmur hash is an algorithm written by Austin Appleby. See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp + inline uint32_t murmur2_x86_impl(const void* buffer, std::size_t length, uint32_t seed) + { + const uint32_t m = 0x5bd1e995; + uint32_t len = static_cast(length); + + // Initialize the hash to a 'random' value + uint32_t h = seed ^ len; + + // Mix 4 bytes at a time into the hash + const unsigned char * data = static_cast(buffer); + + while(len >= 4) + { + uint32_t k = *reinterpret_cast(const_cast(data)); + k *= m; + k ^= k >> 24; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + if (len >= 3) + { + h ^= static_cast(data[2] << 16); + } + if (len >= 2) + { + h ^= static_cast(data[1] << 8); + } + if (len >= 1) + { + h ^= static_cast(data[0]); + h *= m; + } + + // Do a few final mixes of the hash to ensure the last few + // // bytes are well-incorporated. + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } + + template <> + inline std::size_t murmur_hash<4>(const void* buffer, std::size_t length, std::size_t seed) + { + return std::size_t(murmur2_x86_impl(buffer, length, static_cast(seed))); + } + + inline std::size_t load_bytes(const char* p, int n) + { + std::size_t result = 0; + --n; + do + { + result = (result << 8) + static_cast(p[n]); + } while (--n >= 0); + return result; + } + +#if INTPTR_MAX == INT64_MAX + // 64-bits hash for 64-bits platform + template <> + inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed) + { + constexpr std::size_t m = (std::size_t(0xc6a4a793) << 32) + + std::size_t(0x5bd1e995); + constexpr int r = 47; + const char* data = static_cast(buffer); + const char* end = data + (length & std::size_t(~0x7)); + std::size_t hash = seed ^ (length * m); + while (data != end) + { + std::size_t k; + std::memcpy(&k, data, sizeof(k)); + k *= m; + k ^= k >> r; + k *= m; + hash ^= k; + hash *= m; + data += 8; + } + if ((length & 0x7) != 0) + { + std::size_t k = load_bytes(end, length & 0x7); + hash ^= k; + hash *= m; + } + hash ^= hash >> r; + hash *= m; + hash ^= hash >> r; + + return hash; + } +#elif INTPTR_MAX == INT32_MAX + //64-bits hash for 32-bits platform + inline void mmix(uint32_t& h, uint32_t& k, uint32_t m, int r) + { + k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; + } + + template <> + inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed) + { + const uint32_t m = 0x5bd1e995; + const int r = 24; + uint32_t l = length; + + const auto* data = reinterpret_cast(buffer); + + uint32_t h = seed; + + while (length >= 4) + { + uint32_t k = *(uint32_t*)data; + + mmix(h, k, m, r); + + data += 4; + length -= 4; + } + + uint32_t t = 0; + + switch (length) + { + case 3: t ^= data[2] << 16; + case 2: t ^= data[1] << 8; + case 1: t ^= data[0]; + }; + + mmix(h, t, m, r); + mmix(h, l, m, r); + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } +#else +#error Unknown pointer size or missing size macros! +#endif + } + + inline std::size_t hash_bytes(const void* buffer, std::size_t length, std::size_t seed) + { + return detail::murmur_hash(buffer, length, seed); + } + + inline uint32_t murmur2_x86(const void* buffer, std::size_t length, uint32_t seed) + { + return detail::murmur2_x86_impl(buffer, length, seed); + } + + inline uint64_t murmur2_x64(const void* buffer, std::size_t length, uint64_t seed) + { + return detail::murmur_hash<8>(buffer, length, seed); + } +} + +#endif diff --git a/include/xeus/xsystem.hpp b/include/xeus/xsystem.hpp index 86f0fb12..ee109ce4 100644 --- a/include/xeus/xsystem.hpp +++ b/include/xeus/xsystem.hpp @@ -35,6 +35,12 @@ namespace xeus std::string get_cell_tmp_file(const std::string& prefix, const std::string& code, const std::string& suffix); + + XEUS_API + std::string executable_path(); + + XEUS_API + std::string prefix_path(); } #endif diff --git a/src/xsystem.cpp b/src/xsystem.cpp index cb79444d..e1444d90 100644 --- a/src/xsystem.cpp +++ b/src/xsystem.cpp @@ -19,9 +19,8 @@ #include #endif -#include "xtl/xhash.hpp" - #include "xeus/xsystem.hpp" +#include "xeus/xhash.hpp" namespace xeus { @@ -122,9 +121,81 @@ namespace xeus const std::string& suffix) { std::uint32_t seed = static_cast(get_tmp_hash_seed()); - std::string id = std::to_string(xtl::murmur2_x86(content.data(), content.size(), seed)); + std::string id = std::to_string(murmur2_x86(content.data(), content.size(), seed)); return prefix + id + suffix; } + + std::string executable_path() + { + std::string path; +#if defined(UNICODE) + wchar_t buffer[1024]; +#else + char buffer[1024]; +#endif + std::memset(buffer, '\0', sizeof(buffer)); +#if defined(__linux__) + if (readlink("/proc/self/exe", buffer, sizeof(buffer)) != -1) + { + path = buffer; + } + else + { + // failed to determine run path + } +#elif defined (_WIN32) + #if defined(UNICODE) + if (GetModuleFileNameW(nullptr, buffer, sizeof(buffer)) != 0) + { + // Convert wchar_t to std::string + std::wstring wideString(buffer); + std::string narrowString(wideString.begin(), wideString.end()); + path = narrowString; + } + #else + if (GetModuleFileNameA(nullptr, buffer, sizeof(buffer)) != 0) + { + path = buffer; + } + #endif + // failed to determine run path +#elif defined (__APPLE__) + std::uint32_t size = sizeof(buffer); + if(_NSGetExecutablePath(buffer, &size) == 0) + { + path = buffer; + } + else + { + // failed to determine run path + } +#elif defined (__FreeBSD__) + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + size_t buffer_size = sizeof(buffer); + if (sysctl(mib, 4, buffer, &buffer_size, NULL, 0) != -1) + { + path = buffer; + } + else + { + // failed to determine run path + } +#endif + return path; + } + + std::string prefix_path() + { + std::string path = executable_path(); +#if defined (_WIN32) + char separator = '\\'; +#else + char separator = '/'; +#endif + std::string bin_folder = path.substr(0, path.find_last_of(separator)); + std::string prefix = bin_folder.substr(0, bin_folder.find_last_of(separator)) + separator; + return prefix; + } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7887c9b6..62cf91cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,7 +49,10 @@ find_package(doctest REQUIRED) find_package(Threads) set(XEUS_TESTS + test_xbasic_fixed_string.cpp + test_xhash.cpp test_xin_memory_history_manager.cpp + test_xsystem.cpp test_unit_kernel.cpp ) @@ -81,6 +84,7 @@ foreach(filename IN LISTS XEUS_TESTS) get_filename_component(targetname ${filename} NAME_WE) add_executable(${targetname} test_main.cpp ${filename} ${XEUS_TEST_SRCS}) + target_compile_definitions(${targetname} PRIVATE DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) target_link_libraries(${targetname} PRIVATE ${xeus_TARGET} doctest::doctest Threads::Threads ${nlohmann_json_TARGET}) add_test(NAME ${targetname} COMMAND ${targetname}) endforeach() diff --git a/test/test_main.cpp b/test/test_main.cpp index 84684c03..9522fa7f 100644 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -1,2 +1,2 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include "doctest/doctest.h" \ No newline at end of file +#include "doctest/doctest.h" diff --git a/test/test_xbasic_fixed_string.cpp b/test/test_xbasic_fixed_string.cpp new file mode 100644 index 00000000..e2592c7f --- /dev/null +++ b/test/test_xbasic_fixed_string.cpp @@ -0,0 +1,1205 @@ +/*************************************************************************** +* Copyright (c) 2016, Sylvain Corlay and Johan Mabille * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#include "doctest/doctest.h" +#include "xeus/xbasic_fixed_string.hpp" + +namespace xeus +{ + using string_type = xbasic_fixed_string; + using numpy_string = xbasic_fixed_string; + using size_type = string_type::size_type; + + TEST_SUITE("xfixed_string") { + TEST_CASE("constructors") + { + // Default constructor + { + string_type s; + REQUIRE_EQ(s.size(), size_type(0)); + REQUIRE_EQ(s.c_str(), ""); + } + + // ch repeated n times + { + string_type s(size_type(4), 'a'); + REQUIRE_EQ(s.size(), size_type(4)); + REQUIRE_EQ(s.c_str(), "aaaa"); + } + + // From C string + { + const char* cstr = "constructor"; + string_type s(cstr); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), cstr); + } + + // From const char* with \0 inside + { + const char* cstr = "construc\0tor"; + string_type s(cstr, 12); + REQUIRE_EQ(s.size(), size_type(12)); + REQUIRE_EQ(s.c_str(), "construc"); + } + + // From substring + { + string_type s1("constructor"); + string_type s2(s1, size_type(1), size_type(4)); + REQUIRE_EQ(s2.size(), size_type(4)); + REQUIRE_EQ(s2.c_str(), "onst"); + string_type s3(s1, size_type(2), size_type(45)); + REQUIRE_EQ(s3.size(), size_type(9)); + REQUIRE_EQ(s3.c_str(), "nstructor"); + } + + // From initializer list + { + string_type s = { 'c', 'o', 'n', 's', 't' }; + REQUIRE_EQ(s.size(), size_type(5)); + REQUIRE_EQ(s.c_str(), "const"); + } + + // From iterators pair + { + std::string s1 = "constructor"; + string_type s2(s1.cbegin(), s1.cend()); + REQUIRE_EQ(s2.size(), size_type(11)); + REQUIRE_EQ(s2.c_str(), s1.c_str()); + } + + // From string + { + std::string s1 = "constructor"; + string_type s2(s1); + REQUIRE_EQ(s2.size(), size_type(11)); + REQUIRE_EQ(s2.c_str(), s1.c_str()); + + string_type s3(s1, size_type(1), size_type(4)); + REQUIRE_EQ(s3.size(), size_type(4)); + REQUIRE_EQ(s3.c_str(), "onst"); + + std::string s4 = s1; + REQUIRE_EQ(s4.size(), size_type(11)); + REQUIRE_EQ(s4.c_str(), s4.c_str()); + } + } + + TEST_CASE("copy_semantic") + { + string_type ref("constructor"); + string_type ref2("operator="); + string_type s(ref); + REQUIRE_EQ(s.size(), ref.size()); + REQUIRE_EQ(s.c_str(), ref.c_str()); + s = ref2; + REQUIRE_EQ(s.size(), ref2.size()); + REQUIRE_EQ(s.c_str(), ref2.c_str()); + } + + TEST_CASE("move_semantic") + { + string_type ref("constructor"); + string_type ref_tmp(ref); + string_type ref2("operator="); + string_type ref2_tmp(ref2); + string_type s(std::move(ref_tmp)); + REQUIRE_EQ(s.size(), ref.size()); + REQUIRE_EQ(s.c_str(), ref.c_str()); + s = std::move(ref2_tmp); + REQUIRE_EQ(s.size(), ref2.size()); + REQUIRE_EQ(s.c_str(), ref2.c_str()); + } + + TEST_CASE("assign_operator") + { + string_type ref("reference"); + + // From const char* + { + const char* cstr = "constructor"; + string_type s(ref); + s = cstr; + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), cstr); + } + + // From char + { + string_type s(ref); + s = 'b'; + REQUIRE_EQ(s.size(), size_type(1)); + REQUIRE_EQ(s.c_str(), "b"); + } + + // From initializer_list + { + string_type s(ref); + s = { 'c', 'o', 'n', 's', 't' }; + REQUIRE_EQ(s.size(), size_type(5)); + REQUIRE_EQ(s.c_str(), "const"); + } + + // From std::string + { + string_type s(ref); + std::string a("const"); + s = a; + REQUIRE_EQ(s.size(), size_type(5)); + REQUIRE_EQ(s.c_str(), "const"); + } + } + + TEST_CASE("assign") + { + string_type ref("reference"); + + // ch repeated n times + { + string_type s(ref); + s.assign(size_type(4), 'a'); + REQUIRE_EQ(s.size(), size_type(4)); + REQUIRE_EQ(s.c_str(), "aaaa"); + REQUIRE_THROWS_AS(s.assign(size_type(17), 'a'), std::length_error); + } + + // From substring + { + string_type to_assign("constructor"); + string_type s(ref); + s.assign(to_assign, 1, size_type(4)); + REQUIRE_EQ(s.size(), size_type(4)); + REQUIRE_EQ(s.c_str(), "onst"); + } + + // From const char* with \0 inside + { + const char* cstr = "construc\0tor"; + string_type s(ref); + s.assign(cstr, size_type(12)); + REQUIRE_EQ(s.size(), size_type(12)); + REQUIRE_EQ(s.c_str(), "construc"); + const char* ctothrow = "abcdefghij\0klmnopq"; + REQUIRE_THROWS_AS(s.assign(ctothrow, size_type(18)), std::length_error); + } + + // From const char* + { + const char* cstr = "constructor"; + string_type s(ref); + s.assign(cstr); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), cstr); + const char* ctothrow = "abcdefghijklmnopq"; + REQUIRE_THROWS_AS(s.assign(ctothrow, size_type(17)), std::length_error); + } + + // From initializer_list + { + string_type s(ref); + s.assign({ 'c', 'o', 'n', 's', 't' }); + REQUIRE_EQ(s.size(), size_type(5)); + REQUIRE_EQ(s.c_str(), "const"); +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-overflow=" +#endif + REQUIRE_THROWS_AS(s.assign({ 'a','b','c','a','b','c','a','b','c','a','b','c','a','b','c','a','b','c' }), std::length_error); +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + } + + // From iterators pair + { + string_type s(ref); + std::string s1 = "constructor"; + s.assign(s1.cbegin(), s1.cend()); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), s1.c_str()); + std::string ctothrow = "abcdefghijklmnopq"; + REQUIRE_THROWS_AS(s.assign(ctothrow.cbegin(), ctothrow.cend()), std::length_error); + } + + // From lvalue reference + { + string_type s(ref); + string_type s1 = "constructor"; + s.assign(s1); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), s1.c_str()); + } + + // From rvalue reference + { + string_type s(ref); + string_type s1 = "constructor"; + string_type s1_tmp(s1); + s.assign(std::move(s1_tmp)); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), s1.c_str()); + } + + // From string + { + string_type s(ref); + std::string s1 = "constructor"; + s.assign(s1); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), s1.c_str()); + s.assign(s1, 1, size_type(4)); + REQUIRE_EQ(s.size(), size_type(4)); + REQUIRE_EQ(s.c_str(), "onst"); + } + } + + TEST_CASE("element_access") + { + string_type s = "element_access"; + s[2] = 'E'; + REQUIRE_EQ(s[2], 'E'); + REQUIRE_EQ(s.c_str(), "elEment_access"); + + s.at(3) = 'M'; + REQUIRE_EQ(s.at(3), 'M'); + REQUIRE_EQ(s.c_str(), "elEMent_access"); + + s.front() = 'E'; + REQUIRE_EQ(s.front(), 'E'); + REQUIRE_EQ(s.c_str(), "ElEMent_access"); + + s.back() = 'S'; + REQUIRE_EQ(s.back(), 'S'); + REQUIRE_EQ(s.c_str(), "ElEMent_accesS"); + + REQUIRE_THROWS_AS(s.at(15), std::out_of_range); + + REQUIRE_EQ(s.data(), s.c_str()); + } + + TEST_CASE("iterator") + { + string_type s = "iterator"; + *(s.begin()) = 'I'; + REQUIRE_EQ(*(s.begin()), 'I'); + REQUIRE_EQ(*(s.cbegin()), 'I'); + + auto iter = s.begin(); + auto citer = s.cbegin(); + for (size_type count = 0; count < s.size(); ++iter, ++citer, ++count) {} + REQUIRE_EQ(iter, s.end()); + REQUIRE_EQ(citer, s.cend()); + + *(s.rbegin()) = 'R'; + REQUIRE_EQ(*(s.rbegin()), 'R'); + REQUIRE_EQ(*(s.crbegin()), 'R'); + + auto riter = s.rbegin(); + auto criter = s.crbegin(); + for (size_type count = 0; count < s.size(); ++riter, ++criter, ++count) {} + REQUIRE_EQ(riter, s.rend()); + REQUIRE_EQ(criter, s.crend()); + } + + TEST_CASE("capacity") + { + string_type s = "capacity"; + REQUIRE_EQ(s.size(), s.length()); + REQUIRE_FALSE(s.empty()); + REQUIRE_EQ(s.max_size(), size_type(16)); + } + + TEST_CASE("clear") + { + string_type s = "capacity"; + s.clear(); + REQUIRE_EQ(s.size(), size_type(0)); + REQUIRE_EQ(s.c_str(), ""); + } + + TEST_CASE("push_back") + { + string_type s = "operation"; + s.push_back('s'); + REQUIRE_EQ(s.size(), size_type(10)); + REQUIRE_EQ(s.c_str(), "operations"); + } + + TEST_CASE("pop_back") + { + string_type s = "operation"; + s.push_back('s'); + REQUIRE_EQ(s.size(), size_type(10)); + REQUIRE_EQ(s.c_str(), "operations"); + } + + TEST_CASE("substr") + { + string_type ref = "operation"; + string_type s1 = ref.substr(2, 5); + REQUIRE_EQ(s1.c_str(), "erati"); + string_type s2 = ref.substr(2, 45); + REQUIRE_EQ(s2.c_str(), "eration"); + REQUIRE_THROWS_AS(ref.substr(15, 4), std::out_of_range); + } + + TEST_CASE("copy") + { + string_type ref = "operation"; + string_type dst1 = "aaaa"; + string_type dst2 = "bbbbbb"; + + size_type cp1 = ref.copy(dst1.data(), 4, 2); + REQUIRE_EQ(cp1, size_type(4)); + REQUIRE_EQ(dst1.c_str(), "erat"); + + size_type cp2 = ref.copy(dst2.data(), 45, 3); + REQUIRE_EQ(cp2, size_type(6)); + REQUIRE_EQ(dst2.c_str(), "ration"); + + REQUIRE_THROWS_AS(ref.copy(dst2.data(), 4, 15), std::out_of_range); + } + + TEST_CASE("resize") + { + string_type s1 = "operation"; + string_type s2 = s1; + REQUIRE_EQ(s1.size(), size_type(9)); + s1.resize(11); + REQUIRE_EQ(s1.size(), size_type(11)); + s2.resize(11, 'a'); + REQUIRE_EQ(s2.size(), size_type(11)); + REQUIRE_EQ(s2.c_str(), "operationaa"); + } + + TEST_CASE("swap") + { + string_type s1 = "operation"; + string_type s2 = "swap"; + + s1.swap(s2); + REQUIRE_EQ(s1.c_str(), "swap"); + REQUIRE_EQ(s2.c_str(), "operation"); + + using std::swap; + swap(s1, s2); + REQUIRE_EQ(s1.c_str(), "operation"); + REQUIRE_EQ(s2.c_str(), "swap"); + } + + TEST_CASE("insert") + { + string_type ref = "operation"; + { + string_type s = ref; + s.insert(3, 2, 'a'); + REQUIRE_EQ(s.c_str(), "opeaaration"); + REQUIRE_THROWS_AS(s.insert(45, 2, 'b'), std::out_of_range); + } + + { + string_type s = ref; + s.insert(3, "bb"); + REQUIRE_EQ(s.c_str(), "opebbration"); + REQUIRE_THROWS_AS(s.insert(45, "bb"), std::out_of_range); + } + + { + string_type s = ref; + s.insert(3, "b\0b", 3); + REQUIRE_EQ(s.size(), size_type(12)); + REQUIRE_EQ(s.c_str(), "opeb"); + REQUIRE_THROWS_AS(s.insert(45, "b\0b", 3), std::out_of_range); + } + + { + string_type s = ref; + string_type ins = "aa"; + s.insert(3, ins); + REQUIRE_EQ(s.c_str(), "opeaaration"); + REQUIRE_THROWS_AS(s.insert(45, ins), std::out_of_range); + } + + { + string_type s = ref; + string_type ins = "abcdefgh"; + s.insert(3, ins, 2, 2); + REQUIRE_EQ(s.c_str(), "opecdration"); + s.insert(3, ins, 5, 15); + REQUIRE_EQ(s.c_str(), "opefghcdration"); + REQUIRE_THROWS_AS(s.insert(45, ins, 2, 2), std::out_of_range); + } + + { + string_type s = ref; + std::string ins = "aa"; + s.insert(3, ins); + REQUIRE_EQ(s.c_str(), "opeaaration"); + REQUIRE_THROWS_AS(s.insert(45, ins), std::out_of_range); + } + + { + string_type s = ref; + std::string ins = "abcdefgh"; + s.insert(3, ins, 2, 2); + REQUIRE_EQ(s.c_str(), "opecdration"); + s.insert(3, ins, 5, 15); + REQUIRE_EQ(s.c_str(), "opefghcdration"); + REQUIRE_THROWS_AS(s.insert(45, ins, 2, 2), std::out_of_range); + } + + { + string_type s = ref; + s.insert(s.begin() + 3, 'b'); + REQUIRE_EQ(s.c_str(), "opebration"); + } + + { + string_type s = ref; + s.insert(s.begin() + 3, 2, 'b'); + REQUIRE_EQ(s.c_str(), "opebbration"); + } + + { + string_type s = ref; + s.insert(s.begin() + 3, { 'a', 'b', 'c' }); + REQUIRE_EQ(s.c_str(), "opeabcration"); + } + + { + string_type s = ref; + string_type ins = "insert"; + s.insert(s.begin() + 3, ins.cbegin() + 2, ins.cbegin() + 4);; + REQUIRE_EQ(s.c_str(), "opeseration"); + } + } + + TEST_CASE("erase") + { + string_type ref = "operation"; + + { + string_type s = ref; + s.erase(2, 2); + REQUIRE_EQ(s.c_str(), "opation"); + s.erase(); + REQUIRE_EQ(s.c_str(), ""); + } + + { + string_type s = ref; + s.erase(s.cbegin() + 2); + REQUIRE_EQ(s.c_str(), "opration"); + } + + { + string_type s = ref; + s.erase(s.cbegin() + 2, s.cbegin() + 4); + REQUIRE_EQ(s.c_str(), "opation"); + } + } + + TEST_CASE("append") + { + string_type ref = "operation"; + + { + string_type s = ref; + s.append(2, 'a'); + REQUIRE_EQ(s.c_str(), "operationaa"); + REQUIRE_THROWS_AS(s.append(15, 'a'), std::length_error); + } + + { + string_type s = ref; + string_type ap = "abc"; + s.append(ap); + REQUIRE_EQ(s.c_str(), "operationabc"); + REQUIRE_THROWS_AS(s.append(string_type("operation")), std::length_error); + } + + { + string_type s = ref; + string_type ap = "abc"; + s.append(ap, 1, 2); + REQUIRE_EQ(s.c_str(), "operationbc"); + s.append(ap, 1, 15); + REQUIRE_EQ(s.c_str(), "operationbcbc"); + } + + { + string_type s = ref; + std::string ap = "abc"; + s.append(ap); + REQUIRE_EQ(s.c_str(), "operationabc"); + REQUIRE_THROWS_AS(s.append(string_type("operation")), std::length_error); + } + + { + string_type s = ref; + std::string ap = "abc"; + s.append(ap, 1, 2); + REQUIRE_EQ(s.c_str(), "operationbc"); + s.append(ap, 1, 15); + REQUIRE_EQ(s.c_str(), "operationbcbc"); + } + + { + string_type s = ref; + const char* ap = "ab\0cde"; + s.append(ap, 6); + REQUIRE_EQ(s.size(), size_type(15)); + REQUIRE_EQ(s.c_str(), "operationab"); + } + + { + string_type s = ref; + const char* ap = "ab\0cde"; + s.append(ap); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), "operationab"); + } + + { + string_type s = ref; + s.append({ 'a', 'b', 'c' }); + REQUIRE_EQ(s.c_str(), "operationabc"); + } + + { + string_type s = ref; + std::string ap = "append"; + s.append(ap.cbegin() + 1, ap.cbegin() + 5); + REQUIRE_EQ(s.c_str(), "operationppen"); + } + } + + TEST_CASE("operator_append") + { + string_type ref = "operation"; + + { + string_type s = ref; + string_type ap = "abc"; + s += (ap); + REQUIRE_EQ(s.c_str(), "operationabc"); + } + + { + string_type s = ref; + std::string ap = "abc"; + s += (ap); + REQUIRE_EQ(s.c_str(), "operationabc"); + } + + { + string_type s = ref; + s += 'a'; + REQUIRE_EQ(s.c_str(), "operationa"); + } + + { + string_type s = ref; + const char* ap = "ab"; + s += (ap); + REQUIRE_EQ(s.size(), size_type(11)); + REQUIRE_EQ(s.c_str(), "operationab"); + } + + { + string_type s = ref; + s += { 'a', 'b', 'c' }; + REQUIRE_EQ(s.c_str(), "operationabc"); + } + } + + TEST_CASE("compare") + { + string_type s1 = "aabcdef"; + string_type s2 = "abcdefg"; + string_type s3 = "aabcd"; + + { + int r1 = s1.compare(s2); + REQUIRE_LT(r1, 0); + int r2 = s1.compare(s1); + REQUIRE_EQ(r2, 0); + int r3 = s2.compare(s1); + REQUIRE_GT(r3, 0); + int r4 = s1.compare(s3); + REQUIRE_GT(r4, 0); + int r5 = s3.compare(s1); + REQUIRE_LT(r5, 0); + } + + { + int r1 = s1.compare(s2.c_str()); + REQUIRE_LT(r1, 0); + int r2 = s1.compare(s1.c_str()); + REQUIRE_EQ(r2, 0); + int r3 = s2.compare(s1.c_str()); + REQUIRE_GT(r3, 0); + int r4 = s1.compare(s3.c_str()); + REQUIRE_GT(r4, 0); + int r5 = s3.compare(s1.c_str()); + REQUIRE_LT(r5, 0); + } + + { + int r1 = s2.compare(0, 5, s3); + REQUIRE_GT(r1, 0); + int r2 = s1.compare(0, 5, s3); + REQUIRE_EQ(r2, 0); + } + + { + int r1 = s2.compare(0, 5, s3.c_str()); + REQUIRE_GT(r1, 0); + int r2 = s1.compare(0, 5, s3.c_str()); + REQUIRE_EQ(r2, 0); + } + + { + int r1 = s1.compare(2, 3, s2, 2, 3); + REQUIRE_LT(r1, 0); + int r2 = s1.compare(2, 3, s1, 2, 3); + REQUIRE_EQ(r2, 0); + int r3 = s2.compare(2, 3, s1, 2, 3); + REQUIRE_GT(r3, 0); + int r4 = s1.compare(2, 3, s3, 1, 2); + REQUIRE_GT(r4, 0); + int r5 = s3.compare(1, 2, s1, 2, 3); + REQUIRE_LT(r5, 0); + } + + { + int r1 = s1.compare(2, 3, s2.c_str() + 2, 3); + REQUIRE_LT(r1, 0); + int r2 = s1.compare(2, 3, s1.c_str() + 2, 3); + REQUIRE_EQ(r2, 0); + int r3 = s2.compare(2, 3, s1.c_str() + 2, 3); + REQUIRE_GT(r3, 0); + int r4 = s1.compare(2, 3, s3.c_str() + 1, 2); + REQUIRE_GT(r4, 0); + int r5 = s3.compare(1, 2, s1.c_str() + 2, 3); + REQUIRE_LT(r5, 0); + } + + { + std::string str1(s1.cbegin(), s1.cend()); + std::string str2(s2.cbegin(), s2.cend()); + std::string str3(s3.cbegin(), s3.cend()); + + int r1 = s1.compare(str2); + REQUIRE_LT(r1, 0); + int r2 = s1.compare(str1); + REQUIRE_EQ(r2, 0); + int r3 = s2.compare(str1); + REQUIRE_GT(r3, 0); + int r4 = s1.compare(str3); + REQUIRE_GT(r4, 0); + int r5 = s3.compare(str1); + REQUIRE_LT(r5, 0); + } + } + + TEST_CASE("replace") + { + string_type ref = "replace"; + string_type s = ref; + + string_type rep1 = "abc"; + s.replace(1, 4, rep1); + REQUIRE_EQ(s.c_str(), "rabcce"); + + string_type rep2 = "epla"; + s.replace(s.cbegin() + 1, s.cbegin() + 4, rep2); + REQUIRE_EQ(s.c_str(), ref.c_str()); + + string_type rep3 = "operation"; + s.replace(2, 2, rep3, 3, 4); + REQUIRE_EQ(s.c_str(), "reratiace"); + + const char* rep4 = "plabc"; + s.replace(2, 4, rep4, 2); + REQUIRE_EQ(s.c_str(), ref.c_str()); + + s.replace(s.cbegin() + 2, s.cbegin() + 4, rep3.c_str() + 3, 4); + REQUIRE_EQ(s.c_str(), "reratiace"); + + const char* rep5 = "pl"; + s.replace(2, 4, rep5); + REQUIRE_EQ(s.c_str(), ref.c_str()); + + s.replace(s.cbegin() + 2, s.cbegin() + 4, rep4); + REQUIRE_EQ(s.c_str(), "replabcace"); + + s.replace(2, 5, 3, 'c'); + REQUIRE_EQ(s.c_str(), "recccace"); + + s.replace(s.cbegin() + 2, s.cbegin() + 5, 2, 'b'); + REQUIRE_EQ(s.c_str(), "rebbace"); + + s.replace(s.cbegin() + 2, s.cbegin() + 4, { 'p', 'l' }); + REQUIRE_EQ(s.c_str(), ref.c_str()); + + s.replace(s.cbegin() + 2, s.cbegin() + 4, rep4 + 2, rep4 + 4); + REQUIRE_EQ(s.c_str(), "reabace"); + + std::string rep6 = "pl"; + s.replace(2, 2, rep6); + REQUIRE_EQ(s.c_str(), ref.c_str()); + + std::string rep7 = "zyx"; + s.replace(s.cbegin() + 2, s.cbegin() + 4, rep7); + REQUIRE_EQ(s.c_str(), "rezyxace"); + + std::string rep8 = "epla"; + s.replace(2, 3, rep8, 1, 2); + REQUIRE_EQ(s.c_str(), ref.c_str()); + } + + TEST_CASE("find") + { + string_type ref = "operationftionf"; + string_type sub = "tionf"; + + size_type r1 = ref.find(sub, 2); + REQUIRE_EQ(r1, size_type(5)); + size_type r2 = ref.find(sub, 11); + REQUIRE_EQ(r2, string_type::npos); + + size_type r3 = ref.find(sub.c_str(), 2, 3); + REQUIRE_EQ(r3, size_type(5)); + size_type r4 = ref.find(sub.c_str(), 11, 3); + REQUIRE_EQ(r4, string_type::npos); + + size_type r5 = ref.find(sub.c_str(), 2); + REQUIRE_EQ(r5, size_type(5)); + size_type r6 = ref.find(sub.c_str(), 11); + REQUIRE_EQ(r6, string_type::npos); + + size_type r7 = ref.find('a', 2); + REQUIRE_EQ(r7, size_type(4)); + size_type r8 = ref.find('a', 8); + REQUIRE_EQ(r8, string_type::npos); + + std::string ssub(sub.cbegin(), sub.cend()); + size_type r9 = ref.find(ssub, 2); + REQUIRE_EQ(r9, size_type(5)); + size_type r10 = ref.find(ssub, 11); + REQUIRE_EQ(r10, string_type::npos); + } + + TEST_CASE("rfind") + { + string_type ref = "operateration"; + string_type sub = "erat"; + + size_type r1 = ref.rfind(sub, 12); + REQUIRE_EQ(r1, size_type(6)); + size_type r2 = ref.rfind(sub, 1); + REQUIRE_EQ(r2, string_type::npos); + + size_type r3 = ref.rfind(sub.c_str(), 12, 3); + REQUIRE_EQ(r3, size_type(6)); + size_type r4 = ref.rfind(sub.c_str(), 1, 3); + REQUIRE_EQ(r4, string_type::npos); + + size_type r5 = ref.rfind(sub.c_str(), 12); + REQUIRE_EQ(r5, size_type(6)); + size_type r6 = ref.rfind(sub.c_str(), 1); + REQUIRE_EQ(r6, string_type::npos); + + size_type r7 = ref.rfind('a'); + REQUIRE_EQ(r7, size_type(8)); + size_type r8 = ref.rfind('a', 2); + REQUIRE_EQ(r8, string_type::npos); + + std::string ssub(sub.cbegin(), sub.cend()); + size_type r9 = ref.rfind(ssub, 12); + REQUIRE_EQ(r9, size_type(6)); + size_type r10 = ref.rfind(ssub, 1); + REQUIRE_EQ(r10, string_type::npos); + } + + TEST_CASE("find_first_of") + { + string_type ref = "Hello World!"; + string_type sub = "Good Bye!"; + string_type sub2 = "eo"; + + size_type r1 = ref.find_first_of(sub, 1); + REQUIRE_EQ(r1, size_type(1)); + size_type r2 = ref.find_first_of(sub, 3); + REQUIRE_EQ(r2, size_type(4)); + size_type r3 = ref.find_first_of(sub2, 8); + REQUIRE_EQ(r3, string_type::npos); + + size_type r4 = ref.find_first_of(sub.c_str(), 1); + REQUIRE_EQ(r4, size_type(1)); + size_type r5 = ref.find_first_of(sub.c_str(), 3); + REQUIRE_EQ(r5, size_type(4)); + size_type r6 = ref.find_first_of(sub2.c_str(), 8); + REQUIRE_EQ(r6, string_type::npos); + + size_type r7 = ref.find_first_of(sub.c_str(), 1, 4); + REQUIRE_EQ(r7, size_type(4)); + size_type r8 = ref.find_first_of(sub.c_str(), 5, 4); + REQUIRE_EQ(r8, size_type(7)); + size_type r9 = ref.find_first_of(sub2.c_str(), 8, 2); + REQUIRE_EQ(r9, string_type::npos); + + size_type r10 = ref.find_first_of('o', 2); + REQUIRE_EQ(r10, size_type(4)); + size_type r11 = ref.find_first_of('o', 5); + REQUIRE_EQ(r11, size_type(7)); + size_type r12 = ref.find_first_of('o', 8); + REQUIRE_EQ(r12, string_type::npos); + + std::string ssub = "Good Bye!"; + std::string ssub2 = "eo"; + size_type r13 = ref.find_first_of(ssub, 1); + REQUIRE_EQ(r13, size_type(1)); + size_type r14 = ref.find_first_of(ssub, 3); + REQUIRE_EQ(r14, size_type(4)); + size_type r15 = ref.find_first_of(ssub2, 8); + REQUIRE_EQ(r15, string_type::npos); + } + + TEST_CASE("find_first_not_of") + { + string_type ref = "Hello World!"; + string_type sub = "eo"; + + size_type r1 = ref.find_first_not_of(sub, 1); + REQUIRE_EQ(r1, size_type(2)); + size_type r2 = ref.find_first_not_of(sub, 4); + REQUIRE_EQ(r2, size_type(5)); + size_type r3 = ref.find_first_not_of(ref, 4); + REQUIRE_EQ(r3, string_type::npos); + + size_type r4 = ref.find_first_not_of(sub.c_str(), 1); + REQUIRE_EQ(r4, size_type(2)); + size_type r5 = ref.find_first_not_of(sub.c_str(), 4); + REQUIRE_EQ(r5, size_type(5)); + size_type r6 = ref.find_first_not_of(ref.c_str(), 4); + REQUIRE_EQ(r6, string_type::npos); + + size_type r7 = ref.find_first_not_of(sub.c_str(), 1, 2); + REQUIRE_EQ(r7, size_type(2)); + size_type r8 = ref.find_first_not_of(sub.c_str(), 4, 2); + REQUIRE_EQ(r8, size_type(5)); + size_type r9 = ref.find_first_not_of(ref.c_str(), 4, 12); + REQUIRE_EQ(r9, string_type::npos); + + size_type r10 = ref.find_first_not_of('l', 2); + REQUIRE_EQ(r10, size_type(4)); + + std::string ssub = "eo"; + size_type r11 = ref.find_first_not_of(ssub, 1); + REQUIRE_EQ(r11, size_type(2)); + size_type r12 = ref.find_first_not_of(ssub, 4); + REQUIRE_EQ(r12, size_type(5)); + } + + TEST_CASE("find_last_of") + { + string_type ref = "path/to/file"; + string_type sub = "/f"; + + size_type r1 = ref.find_last_of(sub, 11); + REQUIRE_EQ(r1, size_type(8)); + size_type r2 = ref.find_last_of(sub, 6); + REQUIRE_EQ(r2, size_type(4)); + size_type r3 = ref.find_last_of(sub, 3); + REQUIRE_EQ(r3, string_type::npos); + + size_type r4 = ref.find_last_of(sub.c_str(), 11); + REQUIRE_EQ(r4, size_type(8)); + size_type r5 = ref.find_last_of(sub.c_str(), 6); + REQUIRE_EQ(r5, size_type(4)); + size_type r6 = ref.find_last_of(sub.c_str(), 3); + REQUIRE_EQ(r6, string_type::npos); + + size_type r7 = ref.find_last_of(sub.c_str(), 11, 2); + REQUIRE_EQ(r7, size_type(8)); + size_type r8 = ref.find_last_of(sub.c_str(), 6, 2); + REQUIRE_EQ(r8, size_type(4)); + size_type r9 = ref.find_last_of(sub.c_str(), 3, 2); + REQUIRE_EQ(r9, string_type::npos); + + size_type r10 = ref.find_last_of('/', 11); + REQUIRE_EQ(r10, size_type(7)); + size_type r11 = ref.find_last_of('/', 6); + REQUIRE_EQ(r11, size_type(4)); + size_type r12 = ref.find_last_of('/', 3); + REQUIRE_EQ(r12, string_type::npos); + + std::string ssub = "/f"; + size_type r13 = ref.find_last_of(ssub, 11); + REQUIRE_EQ(r13, size_type(8)); + size_type r14 = ref.find_last_of(ssub, 6); + REQUIRE_EQ(r14, size_type(4)); + size_type r15 = ref.find_last_of(ssub, 3); + REQUIRE_EQ(r15, string_type::npos); + } + + TEST_CASE("find_last_not_of") + { + string_type ref = "path/to/file"; + string_type sub = "/f"; + + size_type r1 = ref.find_last_not_of(sub, 11); + REQUIRE_EQ(r1, size_type(11)); + size_type r2 = ref.find_last_not_of(sub, 4); + REQUIRE_EQ(r2, size_type(3)); + + size_type r3 = ref.find_last_not_of(sub.c_str(), 11); + REQUIRE_EQ(r3, size_type(11)); + size_type r4 = ref.find_last_not_of(sub.c_str(), 4); + REQUIRE_EQ(r4, size_type(3)); + + size_type r5 = ref.find_last_not_of(sub.c_str(), 11, 2); + REQUIRE_EQ(r5, size_type(11)); + size_type r6 = ref.find_last_not_of(sub.c_str(), 4, 2); + REQUIRE_EQ(r6, size_type(3)); + + size_type r10 = ref.find_last_not_of('/', 11); + REQUIRE_EQ(r10, size_type(11)); + size_type r11 = ref.find_last_not_of('/', 4); + REQUIRE_EQ(r11, size_type(3)); + + std::string ssub = "/f"; + size_type r12 = ref.find_last_not_of(ssub, 11); + REQUIRE_EQ(r12, size_type(11)); + size_type r13 = ref.find_last_not_of(ssub, 4); + REQUIRE_EQ(r13, size_type(3)); + } + + TEST_CASE("concatenation") + { + string_type s1 = "opera"; + string_type s2 = "tions"; + string_type ref = "operations"; + + string_type res1 = s1 + s2; + REQUIRE_EQ(res1.c_str(), ref.c_str()); + string_type res2 = s1 + s2.c_str(); + REQUIRE_EQ(res2.c_str(), ref.c_str()); + string_type res3 = s1 + 'b'; + REQUIRE_EQ(res3.c_str(), "operab"); + string_type res4 = s1.c_str() + s2; + REQUIRE_EQ(res4.c_str(), ref.c_str()); + string_type res5 = 'v' + s1; + REQUIRE_EQ(res5.c_str(), "vopera"); + + string_type s1bu = s1; + string_type res6 = std::move(s1bu) + s2; + REQUIRE_EQ(res6.c_str(), ref.c_str()); + + string_type s2bu = s2; + string_type res7 = s1 + std::move(s2bu); + REQUIRE_EQ(res7.c_str(), ref.c_str()); + + s1bu = s1; + s2bu = s2; + string_type res8 = std::move(s1bu) + std::move(s2bu); + REQUIRE_EQ(res8.c_str(), ref.c_str()); + + s1bu = s1; + string_type res9 = std::move(s1bu) + s2.c_str(); + REQUIRE_EQ(res9.c_str(), ref.c_str()); + + s1bu = s1; + string_type res10 = std::move(s1bu) + 'b'; + REQUIRE_EQ(res10.c_str(), "operab"); + + s2bu = s2; + string_type res11 = s1.c_str() + std::move(s2bu); + REQUIRE_EQ(res11.c_str(), ref.c_str()); + + s2bu = s2; + string_type res12 = 'b' + std::move(s2bu); + REQUIRE_EQ(res12.c_str(), "btions"); + } + + TEST_CASE("comparison_operators") + { + string_type s1 = "aabcdef"; + string_type s2 = "abcdefg"; + string_type s3 = "aabcd"; + + REQUIRE(s1 < s2); + REQUIRE(s1 <= s2); + REQUIRE(s1 <= s1); + REQUIRE(s1 == s1); + REQUIRE(s1 >= s1); + REQUIRE(s2 > s1); + REQUIRE(s2 >= s1); + + REQUIRE(s1.c_str() < s2); + REQUIRE(s1.c_str() <= s2); + REQUIRE(s1.c_str() <= s1); + REQUIRE(s1.c_str() == s1); + REQUIRE(s1.c_str() >= s1); + REQUIRE(s2.c_str() > s1); + REQUIRE(s2.c_str() >= s1); + + REQUIRE(s1 < s2.c_str()); + REQUIRE(s1 <= s2.c_str()); + REQUIRE(s1 <= s1.c_str()); + REQUIRE(s1 == s1.c_str()); + REQUIRE(s1 >= s1.c_str()); + REQUIRE(s2 > s1.c_str()); + REQUIRE(s2 >= s1.c_str()); + + std::string ss1 = "aabcdef"; + std::string ss2 = "abcdefg"; + std::string ss3 = "aabcd"; + + REQUIRE(s1 < ss2); + REQUIRE(s1 <= ss2); + REQUIRE(s1 <= ss1); + REQUIRE(s1 == ss1); + REQUIRE(s1 >= ss1); + REQUIRE(s2 > ss1); + REQUIRE(s2 >= ss1); + } + + TEST_CASE("input_output") + { + std::string s("input_output"); + string_type ref = "input_output"; + string_type res; + + std::istringstream iss(s); + iss >> res; + REQUIRE_EQ(ref.c_str(), res.c_str()); + + std::ostringstream oss; + oss << ref; + std::string res2 = oss.str(); + REQUIRE_EQ(res2.c_str(), ref.c_str()); + } + + TEST_CASE("hash") + { + std::hash h; + std::size_t res = h("test"); + REQUIRE(res != std::size_t(0)); + } + + TEST_CASE("limit") + { + using string_type = xbasic_fixed_string; + string_type s1 = "hello"; + static_assert(sizeof(s1) == 256 * sizeof(char), "minimal storage"); + } + } + + TEST_SUITE("numpy_string") { + TEST_CASE("constructor") + { + std::string s = "thisisatest"; + char buf[16]; + strcpy(buf, s.c_str()); + numpy_string* x = reinterpret_cast(buf); + + REQUIRE_EQ(*x, s); + (*x)[4] = '!'; + REQUIRE_EQ(buf[4], '!'); + REQUIRE_EQ(buf, *x); + } + + TEST_CASE("element_access") + { + char buf[16] = "element_access"; + numpy_string& s = *reinterpret_cast(buf); + s[2] = 'E'; + REQUIRE_EQ(s[2], 'E'); + REQUIRE_EQ(s.c_str(), "elEment_access"); + + s.at(3) = 'M'; + REQUIRE_EQ(s.at(3), 'M'); + REQUIRE_EQ(s.c_str(), "elEMent_access"); + + s.front() = 'E'; + REQUIRE_EQ(s.front(), 'E'); + REQUIRE_EQ(s.c_str(), "ElEMent_access"); + + s.back() = 'S'; + REQUIRE_EQ(s.back(), 'S'); + REQUIRE_EQ(s.c_str(), "ElEMent_accesS"); + + REQUIRE_THROWS_AS(s.at(15), std::out_of_range); + + REQUIRE_EQ(s.data(), s.c_str()); + REQUIRE_EQ(s.data(), buf); + } + + TEST_CASE("iterator") + { + numpy_string s("iterator"); + *(s.begin()) = 'I'; + REQUIRE_EQ(*(s.begin()), 'I'); + REQUIRE_EQ(*(s.cbegin()), 'I'); + + auto iter = s.begin(); + auto citer = s.cbegin(); + for (size_type count = 0; count < s.size(); ++iter, ++citer, ++count) {} + REQUIRE_EQ(iter, s.end()); + REQUIRE_EQ(citer, s.cend()); + + *(s.rbegin()) = 'R'; + REQUIRE_EQ(*(s.rbegin()), 'R'); + REQUIRE_EQ(*(s.crbegin()), 'R'); + + auto riter = s.rbegin(); + auto criter = s.crbegin(); + for (size_type count = 0; count < s.size(); ++riter, ++criter, ++count) {} + REQUIRE_EQ(riter, s.rend()); + REQUIRE_EQ(criter, s.crend()); + } + + TEST_CASE("find") + { + numpy_string ref("operationftionf"); + numpy_string sub("tionf"); + + size_type r1 = ref.find(sub, 2); + REQUIRE_EQ(r1, size_type(5)); + size_type r2 = ref.find(sub, 11); + REQUIRE_EQ(r2, string_type::npos); + + size_type r3 = ref.find(sub.c_str(), 2, 3); + REQUIRE_EQ(r3, size_type(5)); + size_type r4 = ref.find(sub.c_str(), 11, 3); + REQUIRE_EQ(r4, string_type::npos); + + size_type r5 = ref.find(sub.c_str(), 2); + REQUIRE_EQ(r5, size_type(5)); + size_type r6 = ref.find(sub.c_str(), 11); + REQUIRE_EQ(r6, string_type::npos); + + size_type r7 = ref.find('a', 2); + REQUIRE_EQ(r7, size_type(4)); + size_type r8 = ref.find('a', 8); + REQUIRE_EQ(r8, string_type::npos); + + std::string ssub(sub.cbegin(), sub.cend()); + size_type r9 = ref.find(ssub, 2); + REQUIRE_EQ(r9, size_type(5)); + size_type r10 = ref.find(ssub, 11); + REQUIRE_EQ(r10, string_type::npos); + } + } + + +} // xeus diff --git a/test/test_xhash.cpp b/test/test_xhash.cpp new file mode 100644 index 00000000..91f37059 --- /dev/null +++ b/test/test_xhash.cpp @@ -0,0 +1,200 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#include "doctest/doctest.h" + +#include +#include +#include + +#include "xeus/xhash.hpp" + +namespace xeus +{ + enum class endian + { + big_endian, + little_endian, + mixed + }; + + inline endian endianness() + { + uint32_t utmp = 0x01020304; + char btmp[sizeof(utmp)]; + std::memcpy(&btmp[0], &utmp, sizeof(utmp)); + switch(btmp[0]) + { + case 0x01: + return endian::big_endian; + case 0x04: + return endian::little_endian; + default: + return endian::mixed; + } + } + + // Adaptation of tests provided by Austin Appleby in https://github.com/aappleby/smhasher + template + uint32_t verification_test(F f, std::size_t hashbytes) + { + uint8_t* key = new uint8_t[256]; + uint8_t* hashes = new uint8_t[hashbytes * 256]; + uint8_t* res = new uint8_t[hashbytes]; + + std::memset(key, 0, 256); + std::memset(hashes, 0, hashbytes * 256); + std::memset(res, 0, hashbytes); + + // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as + // the seed + for(std::size_t i = 0; i < 256; i++) + { + key[i] = (uint8_t)i; + *reinterpret_cast(hashes + i * hashbytes) = f(key,i,256-i); + } + + // Then hash the result array + *reinterpret_cast(res) = f(hashes,hashbytes*256,0); + + // The first four bytes of that hash, interpreted as a little-endian integer, is our + // verification value + uint32_t verification = uint32_t((res[0] << 0) | (res[1] << 8) | (res[2] << 16) | (res[3] << 24)); + + delete [] key; + delete [] hashes; + delete [] res; + + return verification; + } + + void rand_p(void* buffer, int bytes) + { + uint32_t * blocks = reinterpret_cast(buffer); + + while(bytes >= 4) + { + blocks[0] = static_cast(std::rand()); + blocks++; + bytes -= 4; + } + + uint8_t* tail = reinterpret_cast(blocks); + for(int i = 0; i < bytes; i++) + { + tail[i] = static_cast(std::rand()); + } + } + + void flipbit(void * block, int len, uint32_t bit) + { + uint8_t * b = (uint8_t*)block; + int byte = int(bit >> 3); + bit = bit & 0x7; + if(byte < len) + { + b[byte] ^= static_cast(1 << bit); + } + } + + template + bool sanity_test(F f, std::size_t hashbytes) + { + std::srand(883741); + bool result = true; + + int reps = 10; + int keymax = 256; + int pad = 16; + int buflen = keymax + pad*3; + + uint8_t * buffer1 = new uint8_t[std::size_t(buflen)]; + uint8_t * buffer2 = new uint8_t[std::size_t(buflen)]; + + uint8_t * hash1 = new uint8_t[hashbytes]; + uint8_t * hash2 = new uint8_t[hashbytes]; + + for(int irep = 0; irep < reps; irep++) + { + for(int len = 4; len <= keymax; len++) + { + for(int offset = pad; offset < pad*2; offset++) + { + uint8_t * key1 = &buffer1[pad]; + uint8_t * key2 = &buffer2[pad+offset]; + + rand_p(buffer1,buflen); + rand_p(buffer2,buflen); + + std::memcpy(key2,key1,std::size_t(len)); + + *reinterpret_cast(hash1) = f(key1,std::size_t(len),0); + + for(int bit = 0; bit < (len * 8); bit++) + { + // Flip a bit, hash the key -> we should get a different result. + flipbit(key2,len,uint32_t(bit)); + *reinterpret_cast(hash2) = f(key2,std::size_t(len),0); + + if(std::memcmp(hash1,hash2,hashbytes) == 0) + { + result = false; + } + + flipbit(key2,len,uint32_t(bit)); + *reinterpret_cast(hash2) = f(key2,std::size_t(len),0); + + if(std::memcmp(hash1,hash2,hashbytes) != 0) + { + result = false; + } + } + } + } + } + + delete [] buffer1; + delete [] buffer2; + delete [] hash1; + delete [] hash2; + return result; + } + + TEST_SUITE("hash") { + TEST_CASE("verification") + { +#if INTPTR_MAX == INT64_MAX + uint32_t res; + switch(endianness()) { + case endian::big_endian: + res = 0x8fda498d; + break; + case endian::little_endian: + res = sizeof(std::size_t) == 4 ? 0x27864c1e : 0x1f0d3804; + break; + default: + CHECK_MESSAGE(false, "unsupported exotic architecture"); + } +#elif INTPTR_MAX == INT32_MAX + uint32_t res = sizeof(std::size_t) == 4 ? 0x27864c1e : 0xdd537c05; +#else +#error Unknown pointer size or missing size macros! +#endif + uint32_t actual = verification_test(&hash_bytes, sizeof(std::size_t)); + + REQUIRE_EQ(actual, res); + } + + TEST_CASE("sanity") + { + REQUIRE(sanity_test(&hash_bytes, sizeof(std::size_t))); + } + } +} + diff --git a/test/test_xsystem.cpp b/test/test_xsystem.cpp new file mode 100644 index 00000000..2a683ec8 --- /dev/null +++ b/test/test_xsystem.cpp @@ -0,0 +1,35 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#include "doctest/doctest.h" + +#include "xeus/xsystem.hpp" + +namespace xeus +{ + TEST_SUITE("xsystem") + { + TEST_CASE("executable_path") + { + std::string exec_path = executable_path(); + REQUIRE(!exec_path.empty()); + } + + TEST_CASE("prefix_path") + { + std::string prefix = prefix_path(); + std::string exec_path = executable_path(); + + REQUIRE_NE(prefix.size(), exec_path.size()); + REQUIRE(std::equal(prefix.cbegin(), prefix.cend(), exec_path.cbegin())); + bool res = (exec_path.find("test_xtl") != std::string::npos) || (exec_path.find("test_xsystem") != std::string::npos); + REQUIRE(res); + } + } +} diff --git a/xeusConfig.cmake.in b/xeusConfig.cmake.in index a94e26ed..5c1aded2 100644 --- a/xeusConfig.cmake.in +++ b/xeusConfig.cmake.in @@ -22,7 +22,6 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR};${CMAKE_MODULE_PATH}") @XEUS_CONFIG_CODE@ include(CMakeFindDependencyMacro) -find_dependency(xtl @xtl_REQUIRED_VERSION@) # nlohmann_json requires libraries that exchange json objects to be linked # with the same version of nlohmann_json. find_dependency(nlohmann_json @nlohmann_json_VERSION@ EXACT)